Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Отрисовка в TScrollBox / 13 сообщений из 13, страница 1 из 1
23.07.2018, 18:09
    #39677860
Login_not_secure
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
Пытаюсь рисовать в TScrollBox, а он в отместку выносит мне мозг :(

Цель - статичные изображения, которые бы не меняли позицию при прокрутке. По логике делается очень просто - заливка фоном, отрисовка в фиксированном прямоугольнике. Однако не выходит - TScrollBox что-то очень хитрое творит с канвасом.

Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  end;

  TScrollBoxTest = class(Vcl.Forms.TScrollBox)
    procedure Paint(DC: HDC; const from: string);
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  end;

var
  Form1: TForm1;
  scr: TScrollBoxTest;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  scr.Refresh;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  scr := TScrollBoxTest.Create(Self);
  scr.Parent := Self;
  scr.Top := 10;
  scr.Left := 10;
  scr.Height := 300;
  scr.Width := 150;
  scr.HorzScrollBar.Range := 1000;
  scr.VertScrollBar.Range := 1000;
  scr.DoubleBuffered :=  True;
end;

{ TScrollBoxTest }

procedure TScrollBoxTest.Paint(DC: HDC; const from: string);
var r: TRect;
begin
  brush.Color := random(clWhite);
  r := rect(-1000,-1000,1000,1000); // чтобы уж наверняка
  FillRect(DC, r, Brush.Handle);
  brush.Color := (clWhite);
  Ellipse(DC, 0, 0, 100, 100);
end;

procedure TScrollBoxTest.WMPaint(var Message: TWMPaint);
var
  ps: TPaintStruct;
  hdc: Winapi.Windows.HDC;
begin
  try
    hdc := BeginPaint(Handle, ps);
    Paint(hdc, 'WMPaint');
  finally
    EndPaint(Handle, ps);
  end;
end;

end.



Такая картина после двух прокруток вниз и вправо

Адрес, если вставка заглючит http://i105.fastpic.ru/big/2018/0723/1d/a9d305b87c1cd6ea55ae9da7c1d5991d.jpg


А такая после рефреша и возврата на исходную позицию


Помогите, плз. Совсем голову сломал уже. Перепробовал все варианты - добавление csCustomPaint, перекрытие DefaultHandler, с DoubleBuffered и без, перекрытие PaintWindow.
...
Рейтинг: 0 / 0
23.07.2018, 18:16
    #39677868
Login_not_secure
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
Пока что нашел только один способ - первой строчкой в WMPaint поставить Invalidate.
...
Рейтинг: 0 / 0
23.07.2018, 18:42
    #39677883
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
А нужно добавить BeginPaint/EndPaint
...
Рейтинг: 0 / 0
24.07.2018, 09:28
    #39678063
Login_not_secure
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
_Vasilisk_, а код посмотреть?
...
Рейтинг: 0 / 0
24.07.2018, 11:42
    #39678154
Квейд
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
Login_not_secureПока что нашел только один способ - первой строчкой в WMPaint поставить Invalidate.Рукалицо
...
Рейтинг: 0 / 0
24.07.2018, 12:13
    #39678178
Квейд
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
Invalidate в начале WMPaint приведет к повторному вызову WMPaint, в начале которого стоит Invalidate.

Даю наводку в сторону того, как правильно делать:


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
procedure TScrollBoxTest.WMHScroll(var Message: TWMHScroll);
begin
  inherited;
  Invalidate
end;

procedure TScrollBoxTest.WMVScroll(var Message: TWMVScroll);
begin
  inherited;
  Invalidate
end;
...
Рейтинг: 0 / 0
24.07.2018, 14:13
    #39678296
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
Login_not_secureа код посмотреть?Какой код? Вызов двух функций?
...
Рейтинг: 0 / 0
24.07.2018, 14:15
    #39678300
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
КвейдInvalidate в начале WMPaint приведет к повторному вызову WMPaint, в начале которого стоит Invalidate.Не приведет. Invalidate установит флаг, что окну нужно перерисоваться. А перерисуется оно, когда будет запущен оконный цикл
...
Рейтинг: 0 / 0
24.07.2018, 15:37
    #39678366
Квейд
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
_Vasilisk_КвейдInvalidate в начале WMPaint приведет к повторному вызову WMPaint, в начале которого стоит Invalidate.Не приведет. Invalidate установит флаг, что окну нужно перерисоваться. А перерисуется оно, когда будет запущен оконный циклустанови Invalidate в код ТС, в начало авторского метода Paint, и посмотри что будет
...
Рейтинг: 0 / 0
24.07.2018, 15:38
    #39678367
Квейд
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
_Vasilisk_КвейдInvalidate в начале WMPaint приведет к повторному вызову WMPaint, в начале которого стоит Invalidate.Не приведет. Invalidate установит флаг, что окну нужно перерисоваться. А перерисуется оно, когда будет запущен оконный циклВсе верно, это у автора и приведет к повторному (бесконечному) вызову WMPaint
...
Рейтинг: 0 / 0
24.07.2018, 16:22
    #39678399
Login_not_secure
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
_Vasilisk_Login_not_secureа код посмотреть?Какой код? Вызов двух функций?
Нет, это было предложение посмотреть код в первом посте.

КвейдInvalidate в начале WMPaint приведет к повторному вызову WMPaint, в начале которого стоит Invalidate.

Даю наводку в сторону того, как правильно делать:


Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
procedure TScrollBoxTest.WMHScroll(var Message: TWMHScroll);
begin
  inherited;
  Invalidate
end;

procedure TScrollBoxTest.WMVScroll(var Message: TWMVScroll);
begin
  inherited;
  Invalidate
end;


Работает, спасибо (хотя я мог бы и сам догадаться).
Всё же ушёл от Begin/EndPaint в WMPaint, т.к. это делает бессмысленным механизм двойного буферирования. Итоговый вариант:
1) в WMPaint добавляется csCustomPaint в ControlState, вызов метода предка, состояние удаляется
2) перекрытие PaintWindow
3) перекрытие сообщений скролла с вызовом Invalidate

код для справки (добавил еще перемещаемый круг).
Код: pascal
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  end;

  TScrollBoxTest = class(Vcl.Forms.TScrollBox)
    procedure Paint(DC: HDC; const from: string);
    procedure PaintWindow(DC: HDC); override;
    procedure WMHScroll(var Message: TWMHScroll); message WM_HSCROLL;
    procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL;
    procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  end;

var
  Form1: TForm1;
  scr: TScrollBoxTest;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  scr.Refresh;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  scr := TScrollBoxTest.Create(Self);
  scr.Parent := Self;
  scr.Top := 10;
  scr.Left := 10;
  scr.Height := 300;
  scr.Width := 150;
  scr.HorzScrollBar.Range := 1000;
  scr.VertScrollBar.Range := 1000;
  scr.DoubleBuffered := True;
end;

{ TScrollBoxTest }

procedure TScrollBoxTest.Paint(DC: HDC; const from: string);
var r: TRect;
begin
  OutputDebugString(pchar(from));
  brush.Color := random(clWhite);
  r := ClientRect;
  FillRect(DC, r, Brush.Handle);
  brush.Color := clWhite;
  // static
  Ellipse(DC, 0, 0, 100, 100);
  // moveable
  Ellipse(DC,
    10-HorzScrollBar.Position,    10-VertScrollBar.Position,
    10-HorzScrollBar.Position+20, 10-VertScrollBar.Position+20);
end;

procedure TScrollBoxTest.PaintWindow(DC: HDC);
begin
  Paint(DC, 'PaintWindow');
end;

// ! Only with this state call chain TWinControl.WMPaint > PaintHandler > PaintWindow
// will be executed.
procedure TScrollBoxTest.WMPaint(var Message: TWMPaint);
begin
  ControlState := ControlState + [csCustomPaint];
  inherited;
  ControlState := ControlState - [csCustomPaint];
end;

procedure TScrollBoxTest.WMHScroll(var Message: TWMHScroll);
begin
  inherited;
  Invalidate;
end;

procedure TScrollBoxTest.WMVScroll(var Message: TWMVScroll);
begin
  inherited;
  Invalidate;
end;

end.



Собственно, примерно таким способом и реализован TCustomControl (всё новое - не найденное в исходниках старое).
Пока остановлюсь на таком варианте.
...
Рейтинг: 0 / 0
24.07.2018, 16:52
    #39678419
_Vasilisk_
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
КвейдВсе верно, это у автора и приведет к повторному (бесконечному) вызову WMPaintЭто да. Но учитывая, что у WM_PAINT низкий приоритет, то оно еще и работать будет :)
...
Рейтинг: 0 / 0
24.07.2018, 16:57
    #39678427
Login_not_secure
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Отрисовка в TScrollBox
_Vasilisk_КвейдВсе верно, это у автора и приведет к повторному (бесконечному) вызову WMPaintЭто да. Но учитывая, что у WM_PAINT низкий приоритет, то оно еще и работать будет :)
Именно так оно и работало, когда я поставил Invalidate в начале PaintWindow xD. WMPaint крутился постоянно, зато на вид все было ОК.
Дополнение к коду выше: в методах WM*Scroll сначала Invalidate, потом inherited - убирает мелькания.
...
Рейтинг: 0 / 0
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Отрисовка в TScrollBox / 13 сообщений из 13, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]