-
Делаю графические контролы, обязательное требование у которых - отсутствие дрожания. Естественно для этого сделано следующее: procedure TGRushControl.SetParent(AParent: TWinControl);
begin
if AParent<>nil then begin
AParent.DoubleBuffered := TRUE;
end;
inherited SetParent(AParent);
end; Но тогда получается что когда я у одного контрола вызываю Invalidate, все контролы того же родителя тоже перерисовываются (вызывается их обработчик Paint). Как на старался достать область, действительно учавстующую в перерисовке API вызовами в обработчике Paint так и не удалось. procedure TControl.InvalidateControl(IsVisible, IsOpaque: Boolean);
var Rect: TRect;
.......
begin
if (IsVisible or (csDesigning in ComponentState) and
not (csNoDesignVisible in ControlStyle)) and (Parent <> nil) and
Parent.HandleAllocated then
begin
Rect := BoundsRect; InvalidateRect(Parent.Handle, @Rect, not (IsOpaque or
(csOpaque in Parent.ControlStyle) or BackgroundClipped));
end;
end; А ведь, если я буду его знать я смогу исключить прорисовку тех контролов, которые реально все равно заклипаны вызовом BeginPaint в TWinControl.WMPaint родителя контрола, а значит их прорисовка не отображается. Я пробовал получить злосчастный рэкт с помощью вызова GetUpdateRect(Parent.Handle, PS.rcPaint, TRUE) из Paint, но почему-то он возващает одни нули, хотя InvalidateRect, как видно из приведенного куска кода выше, вызывается с BoundsRect в качестве области инвалидирования. Такой-же эффект (нули вместо BoundsRect) получается и без использования DoubleBuffering
-
Кажется понял одну вешь: После вызова BeginPaint, GetUpdateRect будет давать только пустую область, т.к. BeginPaint похоже валидатит ее. Вопрос становится еще сложне...
-
Ну а зачем такие извращения? Почему не устраивает старый, проверенный способ, при котором наследник TGraphicControl отрисовывается на битмапе в памяти, а потом через BitBlt все копируется на Canvas. DoubleBuffered так, собственно, и работает.
-
> [2] Макс Черных © (05.03.07 02:24)
Подумай сам, как это может избавить от дрожания: есть 2 контрола, один частично перекрывает другой. Оба они забуферизованы предложенным тобой способом. Я делаю invalidate одного из них, при этом в область инвалидирования попадает и другой. Необходимость перерисовки становится известа родительскому контролу, он делает PaintControls, где ресуется и выводится на экран сначала первый, а затем второй контрол. Получаем еще то дрожание. В общем мои мзыскания продвинулись вот до чего: Если я ловлю нужный мне рект непосредственно в родителе, то все происходит так как мне нужно:
unti1.pas:
procedure TForm1.WMPaint(var Message: TWMPaint);
begin
GetUpdateRect(Handle, UpdateRect, FALSE);
inherited;
end;
GRushcontrol.pas:
procedure TGRushControl.Paint;
begin
IntersectRect(rct, BoundsRect, UpdateRect);
if (IsRectEmpty(rct)=FALSE) then begin
end;
end;
вопрос собственно как перехватить в родители WM_Paint средствами VCL. Про винапи средства (SetWindowLong) мне изсвестно.
-
Что в вашем понятии означает "Дрожание"
-
В общем, покритикуйте пожалуста мою реализацию:
const
PropWndProc:PChar = 'TWinControl_WndProc_OLD';
PropUpdateRect:PChar = 'TWinControl_UpdateRect_OLD';
function GRushWndProc(Window: HWND; Message, wParam, lParam: Longint): Longint; stdcall;
var
PrevWndProc: Pointer;
UpdateRect: PRect;
begin
if (Message = WM_PAINT) then begin
GetMem(UpdateRect, sizeof(TRect));
GetUpdateRect(Window, UpdateRect^, FALSE);
SetProp(Window, PropUpdateRect, DWORD(UpdateRect));
end;
PrevWndProc := Pointer(GetProp(Window, PropWndProc));
if PrevWndProc<>nil then
Result := CallWindowProc(PrevWndProc, Window, Message, wParam, lParam);
if (Message = WM_PAINT) then begin
FreeMem(UpdateRect);
RemoveProp(Window, PropUpdateRect);
end;
end;
procedure TGRushControl.SetParent(AParent: TWinControl);
var WinProc: DWORD;
begin
if Parent<>nil then begin
WinProc := RemoveProp(Parent.Handle, PropWndProc);;
if (WinProc<>0) then
SetWindowLong(Parent.Handle, GWL_WNDPROC, WinProc);
end;
inherited SetParent(AParent);
if Parent<>nil then with Parent do begin
DoubleBuffered := TRUE;
WinProc := GetWindowLong(Handle, GWL_WNDPROC);
if (WinProc <> DWORD(@GRushWndProc)) then begin
SetProp(Handle, PropWndProc, WinProc);
SetWindowLong(Handle, GWL_WNDPROC, DWORD(@GRushWndProc));
end;
end;
end;
procedure TGRushControl.Paint;
var
UpdateRect: PRect;
TR: TRect;
begin
UpdateRect := Pointer(GetProp(Parent.Handle, PropUpdateRect));
if UpdateRect<>nil then
IntersectRect(TR, BoundsRect, UpdateRect^);
if (IsRectEmpty(TR)=FALSE) OR (UpdateRect=nil) then begin
end;
end;
вроде раболает, как в рантайм, так и в дезайне. Но может какие подвожные камни есть? Кстати, еще вопрос: чем inherited SetParent(AParent); отличается от просто inhirated; и что в данном случае следует применять?
-
> Что в вашем понятии означает "Дрожание" когда прежде чем выводится компонент, на занимаемаемую им площадь рисуется другой или родитель, отсюда на долюсекундв, пока не прорисовался нужный компонет на занимаемой им площади отображается выведая не им картинка. я то думал что это уж совсем очевидно.
-
Полный изврат, нафика козе баян ? В данном случае inherited от inherited SetParent(AParent); ничем не отличаются, например реальное отличие
if тра-ля-ля
then inherited
else inherited SetParent(NewParent) но опят же можно просто inherited;
AParent = NewParent а вот в такой конструкции только так procedure SetValue(const Value: integer); var NewValue: integer; begin NewValue := 123456789; inherited SetValue(NewValue); end;
-
Так, об одном косяке уже подумал. Если кто-то поставит свой хук поверх моего, то WinProc <> DWORD(@GRushWndProc) всегдда даст TRUE, а значит я снова поставлю свой хук поверх и т.к. при этом затрется PropWndProc, то получится бесконечная рекурсия. Выход не в проверке адресса функции GWL_WNDPROC, а в проверки наличия PropWndProc. Вот так правильнее будет: procedure TGRushControl.SetParent(AParent: TWinControl);
var WinProc: DWORD;
begin
if Parent<>nil then begin
WinProc := RemoveProp(Parent.Handle, PropWndProc);;
if (WinProc<>0) then
SetWindowLong(Parent.Handle, GWL_WNDPROC, WinProc);
end;
inherited SetParent(AParent);
if Parent<>nil then with Parent do begin
DoubleBuffered := TRUE;
if (GetProp(Handle, PropWndProc) = 0) then begin
WinProc := SetWindowLong(Handle, GWL_WNDPROC, DWORD(@GRushWndProc));
SetProp(Handle, PropWndProc, WinProc);
end;
end;
end;
-
> Полный изврат, нафика козе баян ? Увеличение производительности в разы при большом количестве контроллов. Что-бы вместо 40-а при движении мыши перерисовывался только один, который и изменяется при движении мыши.
-
В этом то и отличие GraphicsControl от WinControl. Рассмотрите внимательнее TGraphicControl.WMPaint(var Message: TWMPaint); TWinControl.WMPaint(var Message: TWMPaint);
-
> В этом то и отличие GraphicsControl от WinControl.
Ну и отлично, и я от него избавился, кажется :)
На самом деле отличие в возможности рисовать прозрачные и полу-прозрачные компопенты, т.к. все компоненты рисуются на одной канве.
-
В таком случае возьмите за основу WinControl
-
> В таком случае возьмите за основу WinControl
я же уже ответил на этот вопрос заранее.
> На самом деле отличие в возможности рисовать прозрачные > и полу-прозрачные компопенты, т.к. все компоненты рисуются > на одной канве.
-
Все равно фигня получалась :) При удалении однго контрола весь механизм слетал, т.к. он снимался в принципе в SetParent. Правильнее перенсти этот механизм в WM_DESTROY. function GRushWndProc(Window: HWND; Message, wParam, lParam: Longint): Longint; stdcall;
var
PrevWndProc: Pointer;
UpdateRect: PRect;
begin
PrevWndProc := Pointer(GetProp(Window, PropWndProc));
case Message of
WM_PAINT: begin
GetMem(UpdateRect, sizeof(TRect));
GetUpdateRect(Window, UpdateRect^, FALSE);
SetProp(Window, PropUpdateRect, DWORD(UpdateRect));
end;
WM_DESTROY: begin
if PrevWndProc<>nil then begin
SetWindowLong(Window, GWL_WNDPROC, DWORD(PrevWndProc));
RemoveProp(Window, PropWndProc);
end;
end;
end;
if PrevWndProc<>nil then
Result := CallWindowProc(PrevWndProc, Window, Message, wParam, lParam);
if (Message = WM_PAINT) then begin
FreeMem(UpdateRect);
RemoveProp(Window, PropUpdateRect);
end;
end;
procedure TGRushControl.SetParent(AParent: TWinControl);
var WinProc: DWORD;
begin
inherited SetParent(AParent);
if Parent<>nil then with Parent do begin
DoubleBuffered := TRUE;
if (GetProp(Handle, PropWndProc) = 0) then begin
WinProc := SetWindowLong(Handle, GWL_WNDPROC, DWORD(@GRushWndProc));
SetProp(Handle, PropWndProc, WinProc);
end;
end;
end;
-
прозрачные и полу-прозрачные компопенты Эта проблема просто решается, а вот положите рядом Image и перекройте частично его Panelю. Теперь порпробуйте поднять картинкувыше панели...
-
> Эта проблема просто решается Да ну? И как интересно?
> Теперь порпробуйте поднять картинкувыше панели... Зачем? Я и сам знаю что невозможно. Да мне это не нужно. Да и никому другому думаю не нужно.
-
Просто 1. Сдвигаем Наш контрол в сторону (Left := -Left); 2. Даём паренту перерисоваться (Parent.Update) 3. Копируем содержимое на наш контрол по старым координатам 4. возвращаем контрол на место
-
> Просто > 1. Сдвигаем Наш контрол в сторону (Left := -Left); > 2. Даём паренту перерисоваться (Parent.Update) > 3. Копируем содержимое на наш контрол по старым координатам > 4. возвращаем контрол на место И того полностью избавляемся от дрожания??? Ну-ну..
-
Поменяйте монитор, дрожать перестанет.
-
> Поменяйте монитор, дрожать перестанет. А если нет, ты оплатишь расходы? Тогда я уже в магазин пошел за плазменной панелью побольше :)
А если серьезно, то неужели непонятно, что когда 2. Даём паренту перерисоваться (Parent.Update), то он и перерисовывается, соответсвенно изображение быстро меняется с пернта, на наш контрол в одном и то-же месте. Может хватит глупости говорить?
-
> 1. Сдвигаем Наш контрол в сторону (Left := -Left);
Ну был у меня Left = 0. Ну сделал я Left := -Left и чего? :)
-
Поставьте Left := - Width
-
Зачем? Я же сказал что предложенный способ получить прозрачность кривой.
-
Хочеш продолжать флуд, постучи в аську.
-
Разберёмся, почему "ДРОЖИТ". "Дрожит" потому что перерисовывается фон. Дабы фон не перерисовывался можно: 1. Запретить перерисовку DoubleBuffered := true;
ControlState := ControlState + [csOpaque];
procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
begin
Message.Result := 1;
end;
-
-
Вы можете чётко объяснить с какой целью вы наследуетесь от TGraphicsControl.
-
Могу.
Все вопросы от Вас теперь только в аську, если не трудно.
-
У меня нет аськи, если вы не хотите чтобы я пытался вам помочь, так и скажите.
-
Хорошо, мне нужно сделать контрол, имеющий прозрачные А возможно полу-прозрачные) области, при этом при его тображении не должно быть видно никаких серцаний других компонентов находящимся за ним и прочих артефактов.
-
Половина контролов библиотеки Raize унаследована от TRzCustomButton = class( TCustomControl ) в котором реализовано свойство Transparent и не ДРОЖАТ. Может прислушаемся к профессионалам ?
procedure TRzCustomButton.WMEraseBkgnd( var Msg: TWMEraseBkgnd );
begin
if FTransparent then
begin
DrawParentImage( Self, Msg.DC, True );
Msg.Result := 1;
end
else
inherited;
end;
procedure DrawParentImage( Control: TControl; DC: HDC; InvalidateParent: Boolean = False );
var
SaveIndex: Integer;
P: TPoint;
begin
if Control.Parent = nil then
Exit;
SaveIndex := SaveDC( DC );
GetViewportOrgEx( DC, P );
SetViewportOrgEx( DC, P.X - Control.Left, P.Y - Control.Top, nil );
IntersectClipRect( DC, 0, 0, Control.Parent.ClientWidth, Control.Parent.ClientHeight );
if not ( csDesigning in Control.ComponentState ) then
begin
Control.Parent.Perform( wm_EraseBkgnd, DC, 0 );
Control.Parent.Perform( wm_Paint, DC, 0 );
end
else
begin
try
Control.Parent.Perform( wm_EraseBkgnd, DC, 0 );
Control.Parent.Perform( wm_Paint, DC, 0 );
except
end;
end;
RestoreDC( DC, SaveIndex );
if InvalidateParent then
begin
if not ( Control.Parent is TCustomControl ) and
not ( Control.Parent is TCustomForm ) and
not ( csDesigning in Control.ComponentState ) then
begin
Control.Parent.Invalidate;
end;
end;
end;
-
Те же нотки в DevExpress
procedure DrawTransparentControlBackground(AControl: TWinControl;
ADrawCanvas: TCanvas; ADrawRect: TRect);
procedure PaintControlTo(ADrawingControl: TWinControl;
ADrawCanvas: TCanvas; AX, AY, AWidth, AHeight: Integer);
function ControlInDrawingRect(AControl: TWinControl; AOrg: TPoint): Boolean;
var
ARect: TRect;
begin
ARect.TopLeft := AOrg;
ARect.Top := ARect.Top + AControl.Top;
ARect.Left := ARect.Left + AControl.Left;
ARect.Bottom := ARect.Top + AControl.Height;
ARect.Right := ARect.Left + AControl.Width;
Result := IntersectRect(ARect, ARect, Rect(0, 0, AWidth, AHeight));
end;
procedure DrawEdgesAndBorders(ADrawCanvas: TCanvas);
var
AEdgeFlags, ABorderFlags: Integer;
R: TRect;
begin
ABorderFlags := 0;
AEdgeFlags := 0;
with ADrawingControl do
begin
if GetWindowLong(Handle, GWL_EXSTYLE) and WS_EX_CLIENTEDGE <> 0 then
begin
AEdgeFlags := EDGE_SUNKEN;
ABorderFlags := BF_RECT or BF_ADJUST
end
else
if GetWindowLong(Handle, GWL_STYLE) and WS_BORDER <> 0 then
begin
AEdgeFlags := BDR_OUTER;
ABorderFlags := BF_RECT or BF_ADJUST or BF_MONO;
end;
if ABorderFlags <> 0 then
begin
R := Rect(0, 0, Width, Height);
DrawEdge(ADrawCanvas.Handle, R, AEdgeFlags, ABorderFlags);
MoveWindowOrg(ADrawCanvas.Handle, R.Left, R.Top);
IntersectClipRect(ADrawCanvas.Handle, 0, 0,
R.Right - R.Left, R.Bottom - R.Top);
end;
end;
end;
var
AOrg: TPoint;
ASavedDC, AWindowRgnType, I: Integer;
AWindowRgn: HRGN;
begin
AWindowRgn := CreateRectRgnIndirect(cxEmptyRect);
try
AWindowRgnType := GetWindowRgn(ADrawingControl.Handle, AWindowRgn);
if AWindowRgnType = NULLREGION then
Exit;
ASavedDC := SaveDC(ADrawCanvas.Handle);
ADrawingControl.ControlState := ADrawingControl.ControlState + [csPaintCopy];
try
MoveWindowOrg(ADrawCanvas.Handle, AX, AY);
GetWindowOrgEx(ADrawCanvas.Handle, AOrg);
AOrg.X := -AOrg.X;
AOrg.Y := -AOrg.Y;
with ADrawingControl do
begin
if AWindowRgnType = ERROR then
IntersectClipRect(ADrawCanvas.Handle, 0, 0, Width, Height)
else
begin
OffsetRgn(AWindowRgn, AOrg.X, AOrg.Y);
ExtSelectClipRgn(ADrawCanvas.Handle, AWindowRgn, RGN_AND);
end;
if ADrawingControl <> AControl.Parent then
DrawEdgesAndBorders(ADrawCanvas);
ADrawCanvas.Lock;
try
Perform(WM_ERASEBKGND, ADrawCanvas.Handle, 0);
Perform(WM_PAINT, ADrawCanvas.Handle, 0);
finally
ADrawCanvas.Unlock;
end;
for I := 0 to ControlCount - 1 do
begin
if Controls[I] = AControl then
Break;
if Controls[I] is TWinControl then
if TWinControl(Controls[I]).Visible and
ControlInDrawingRect(TWinControl(Controls[I]), AOrg) then
begin
ADrawCanvas.Lock;
try
with TWinControl(Controls[I]) do
PaintControlTo(TWinControl(ADrawingControl.Controls[I]),
ADrawCanvas, Left, Top, AWidth, AHeight);
finally
ADrawCanvas.Unlock;
end;
end;
end;
end;
finally
ADrawingControl.ControlState := ADrawingControl.ControlState - [csPaintCopy];
RestoreDC(ADrawCanvas.Handle, ASavedDC);
end;
finally
DeleteObject(AWindowRgn);
end;
end;
var
AX, AY: Integer;
begin
if AControl.Parent <> nil then
begin
OffsetRect(ADrawRect, AControl.Left, AControl.Top);
AX := - ADrawRect.Left;
AY := - ADrawRect.Top;
PaintControlTo(AControl.Parent, ADrawCanvas, AX, AY,
ADrawRect.Right - ADrawRect.Left, ADrawRect.Bottom - ADrawRect.Top);
end;
end;
-
RxLib
procedure CopyParentImage(Control: TControl; Dest: TCanvas);
var
I, Count, X, Y, SaveIndex: Integer;
DC: HDC;
R, SelfR, CtlR: TRect;
begin
if (Control = nil) or (Control.Parent = nil) then Exit;
Count := Control.Parent.ControlCount;
DC := Dest.Handle;
with Control.Parent do ControlState := ControlState + [csPaintCopy];
try
with Control do begin
SelfR := Bounds(Left, Top, Width, Height);
X := -Left; Y := -Top;
end;
SaveIndex := SaveDC(DC);
try
SetViewportOrgEx(DC, X, Y, nil);
IntersectClipRect(DC, 0, 0, Control.Parent.ClientWidth,
Control.Parent.ClientHeight);
with TParentControl(Control.Parent) do begin
Perform(WM_ERASEBKGND, DC, 0);
PaintWindow(DC);
end;
finally
RestoreDC(DC, SaveIndex);
end;
for I := 0 to Count - 1 do begin
if Control.Parent.Controls[I] = Control then Break
else if (Control.Parent.Controls[I] <> nil) and
(Control.Parent.Controls[I] is TGraphicControl) then
begin
with TGraphicControl(Control.Parent.Controls[I]) do begin
CtlR := Bounds(Left, Top, Width, Height);
if Bool(IntersectRect(R, SelfR, CtlR)) and Visible then begin
ControlState := ControlState + [csPaintCopy];
SaveIndex := SaveDC(DC);
try
SaveIndex := SaveDC(DC);
SetViewportOrgEx(DC, Left + X, Top + Y, nil);
IntersectClipRect(DC, 0, 0, Width, Height);
Perform(WM_PAINT, DC, 0);
finally
RestoreDC(DC, SaveIndex);
ControlState := ControlState - [csPaintCopy];
end;
end;
end;
end;
end;
finally
with Control.Parent do ControlState := ControlState - [csPaintCopy];
end;
end;
-
Продолжить ?
-
> if not ( csDesigning in Control.ComponentState ) then > begin > Control.Parent.Perform( wm_EraseBkgnd, DC, 0 ); > Control.Parent.Perform( wm_Paint, DC, 0 ); > end > else > begin > try > Control.Parent.Perform( wm_EraseBkgnd, DC, 0 ); > Control.Parent.Perform( wm_Paint, DC, 0 ); > except > end; > end;
Отлично. Родителя я увижу (за счет его, дополнительной перерисовки, потеря производительности). А как насчет других компонентов, которые находятся под моим?
-
> Продолжить ?
Лучше ссылку дай, где можно скачать исходник хоть однго прозрачного компонента без дрожания, а то я для кфшяу нашел только 30-и метровую ссылищу :)
-
IMHO дрожание бывает двух видов: - при перерисовке, связанной с изменением внешнего вида компонента, - при перерисовке, связанной с перемещениями / ресайзами окна.
Первую я у себя лече двойной буферизацией, методом Макс Черных © (05.03.07 02:24) [2] , а вторую, устанавливая DoubleBuffered Parent-а, но на Parent-е, а не из компонента.
-
-
Извращенец. По-моему, подобные штуки надо в самом Parent делать. А зачем тебе UpdateRect? И че говорит Canvas.ClipRect? В VCL аналог SetWindowLong - TControl.WindowProc.
-
> По-моему, подобные штуки надо в самом Parent делать.
Как? Исходники VCL править? > А зачем тебе UpdateRect?
10 раз же сказано, что-бы проверять реально ли нуждается контрол в перерисовке, или нет. > И че говорит Canvas.ClipRect?
Canvas.ClipRect равен ClientRect, т.к. 1) этот дс не окна, которое перерисовывается(родителя), а бирмапа буфера 2) Это все равно будут КЛИЕНТСКИЕ координаты графического контрола. > В VCL аналог SetWindowLong - TControl.WindowProc.
А различия в чем? Если только в том что на апи я реализовал, а через эту штуку нет, то нафиг нада. К тому-же Use the WindowProc property to temporarily replace or subclass the window procedure of the control.
-
homm © (07.03.07 1:25) [40] Как? Исходники VCL править? Создать какой-нибудь TGraphicContainer от панели, за одно и другие (не твои) контролы не будут мерцать.
homm © (07.03.07 1:25) [40] А различия в чем? Если только в том что на апи я реализовал, а через эту штуку нет, то нафиг нада. WindowProc при RecreateWnd не пострадает.
homm © (07.03.07 1:25) [40] К тому-же Use the WindowProc property to temporarily replace or subclass the window procedure of the control. Это же относится и к SetWindowLong, т.к. если появятся другие контролы, желающие его изменить (в частности, другие твои), будут проблемы.
-
> WindowProc при RecreateWnd не пострадает. Странно, я думал при пересоздании SetParent вызывается. Проверил - нифига. Буду переделывать под WindowProc.
> Создать какой-нибудь TGraphicContainer от панели, за одно > и другие (не твои) контролы не будут мерцать. Любой WinControl итак ГрфикКонтайнер по идее. Мне не понятно только почему он не просто перерисовывает что ни поподя, а еще и не дает возможности исправить это самому. Просто вызова GetUpdateRgn для приходящей DC и SelectClipRgn для буферной ИМХО было бы достаточно, что-бы можно было проверять GetClipRgn из процедуры рисования самого контрола.
-
Потестил. D7. Проблема не наблюдается. Перерисовывается только то, что надо.
-
> Потестил. D7. Проблема не наблюдается. Перерисовывается > только то, что надо.
Какая проблема? С использованием моего варианта ограничения пррисовки? У меня тоже не наблюдается. Или имеется ввиду сама проблема выполнении процедуры переисовки того что нужно и нет? Если 2-е, то ...
Протестил. D5, D7, BDS2006. Проблема наблюдается. Выполняется код перерисовки и того что не надо в том числе.
-
Я тестировал без DoubleBuffered. При Invalidate перерисовывался только прямоугольник, в котором находится контрол.
-
> Я тестировал без DoubleBuffered. Непонятно зачем впустую тратил время...
-
вообщем читаю и удивляюсь. вся проблемы всего в procedure WMEraseBkgnd( var Msg: TWMEraseBkgnd ); message WM_EraseBkgnd просто опишите ее и код в ней просто begin end; :) у меня после этого все на ура! а чтобы не было мерцания то рисуйте все в памяти на TBitmap а потом на окно выкладывайте так быстрей и мерцания нет. в моем компоненте списке вообще никакого мерцания нет
-
> BOBAH13
Ну еще один :( Ну не дурак я. И не с ветряными мельницами мне нужно было боротся. Если 2 твоих компонента лежат один над нругим, то они оба накладываются попорядку, а значит в этот момент мерцают. Усе?
-
Перепроверил, при DeoubleBuffered перерисовываются все контролы, но дрожжания нет и не может быть.
-
> Перепроверил, при DeoubleBuffered перерисовываются все контролы, > но дрожжания нет и не может быть. Правильно. Верно. 12-раз об этом в этой ветке. Не надоело одно и то-же мусолить?
-
Начнём сначала. (под словом КОНТРОЛ я подразумеваю TGRushControl) Насколько я понял из всего выше сканного - требуется создать прозрачный контрол, который перерисовывает только свою видимую часть, дабы не сложилась такая ситуация - один прозрачный контрол перекрывает другой, при перерисовке рисуется сначала нижний, а потом верхний - тем самым область перекрытия сначала заполняется первым контролом, а затем вторым. Получаем ДРОЖАНИЕ. Как достигнуть данного я не представляю. Поскольку представляем такую ситуацию: имеется контрол с произвольным графическим рисунком, поверх него лежит другой контрол с рисунком имеющим прозрачные области. Что нужно сделать ? Нужно отрисовать области совпадающие с прозрачными областями в нижнем контроле. Есть какие-нибудь решения ?
-
> Начнём сначала. Народ, это развод, да?
> Есть какие-нибудь решения ? ДА!!!!! Вся ветка об это. Прокрути окно вверх. Если интересно, могу ехе выслать, где это уже работает на простом примере.
-
> Насколько я понял из всего выше сканного - требуется создать > прозрачный контрол, который перерисовывает только свою видимую > часть, дабы не сложилась такая ситуация - один прозрачный > контрол перекрывает другой
Неправильно понял. "требуется создать прозрачный контрол, который перерисовывает только свою видимую часть", дабы перерисовывалась только видимая часть, а на перерисовку остального не тратились рессурсы. > Есть какие-нибудь решения ? [5], [8], [14], и еще один ньюанс: дабы механизм не слетал при RecrateWnd добавляем первой строчкой в TGRushControl.Paint SetParent(Parent);
-
> Правильно. Верно. 12-раз об этом в этой ветке. Не надоело > одно и то-же мусолить?
Учись говрить. Перечитай свои посты - там не слово про то что при DoubleBuffered дрожжания не было. И ты наворотил подмену WindowProc родителя (далеко не безопасую) только ради уменьшения нагрузки на процессор?
-
> Неправильно понял. "требуется создать прозрачный контрол, > который перерисовывает только свою видимую часть", дабы > перерисовывалась только видимая часть, а на перерисовку > остального не тратились рессурсы.
Моя твоя непонимай. Должен ли рисоваться ВЕСЬ нижний контрол если он перекрыт верхним с прозрачными областями ? Или должны отрисоваться только перекрытые прозрачные области ???
-
> Учись говрить. Перечитай свои посты - там не слово про то > что при DoubleBuffered дрожжания не было.
Учись читать. > [0] homm © (04.03.07 19:32) > Делаю графические контролы, обязательное требование у которых > - отсутствие дрожания. Естественно для этого сделано следующее:
> procedure TGRushControl.SetParent(AParent: TWinControl);
> begin
> if AParent<>nil then begin
> AParent.DoubleBuffered := TRUE;
> end;
> inherited SetParent(AParent);
> end;
-
> Моя твоя непонимай. Должен ли рисоваться ВЕСЬ нижний контрол > если он перекрыт верхним с прозрачными областями ? Или должны > отрисоваться только перекрытые прозрачные области ???
Поступило сообщение на перерисовку родителя всех контроллов. При этом где-то внутри системы хранится область, которую нужно перерисовать. ВинКонтрол, у которого установлен ойно буфер, создает этот буфер, отрисовывает на нем все дочерние контролы, дальше что-бы сбросить отрисованые контролы в свое окно он вызывает BeginPaint. Вот тут то и начинается действо! Тот регон, который реально требуется для перерисовки достается из недр системы, и клипается для оконной канвы. В результате когда ВинКонтрол блитит туда свой буфер, на оконную канву попадает далеко не все изображение. Зато подготавливается все. А после вызова BeginPaint получить ту магическую область, которую нужно перерисовать не получается (с чего и начался разговор). Выход был найден в том что-бы тащит эту область ДО вызова BeginPaint ставля хук на родительское окно компонента.
> Должен ли рисоваться ВЕСЬ нижний контрол если он перекрыт > верхним с прозрачными областями ? Должен, если в область перерисовки перекрывает его хотя-бы частично.
-
> И ты наворотил подмену WindowProc родителя (далеко не безопасую) > только ради уменьшения нагрузки на процессор?
Я обошелся средствами АПИ в этом вопросе, как еще наши деды делали, у них все безопасно было. В топку такое "расширение функционала" средстваим ВСЛ.
-
homm © (12.03.07 17:13) [58] Я обошелся средствами АПИ в этом вопросе, как еще наши деды делали, у них все безопасно было.Какая разница API или VCL? Это не безопасно. Вот пример: Control1.SetHook: Control1.LastHook:=SetWindowLong(Control1.Hook);
Control2.SetHook: Control2.LastHook:=SetWindowLong(Control2.Hook);
Control1.Destroy: SetWindowLong(Control1.LastHook);
Control2.Destroy: SetWindowLong(Control2.LastHook); В результате у Parent'а останется Control1.Hook, а контрола уже не будет.
-
> В результате у Parent'а останется Control1.Hook, а контрола > уже не будет. Чего?? "Control1.Hook" это что за хрень? Как ты на апи окно объектно-ориентрованный хук поставишь? И нафиг тебе в самом хуке нужен объект, его установивший? Ты его просто не возьмешь никак (нет, ну есть функция которая по хендлу возвратит компонент, но мы сейчас как раз говорим что так делать ненадо). А раз ты его не будешь использовать, то какая нафиг разница есть он или нет? См [14] и медитировать над тем что там написано в GRushWndProc.
-
Вместо Control1.Hook подставь ObjectInstance или статический метод, имеющий отношение к Control1. А Control2 может быть чужим.
homm © (12.03.07 22:12) [60] См [14] Вижу. Ничего хорошего сказать не могу. Вместо запихивания в SetProp UpdateRect лучше сразу устанавливать на HDC, который в wParam приходит. (Случай wParam = 0 надо игнорировать)
-
> Вместо Control1.Hook подставь ObjectInstance или статический > метод, имеющий отношение к Control1.
Да не имеет GRushWndProc никакого отношения к Control1. Она работает только с апишным хэндлом окна. До существования Control1 ей нет дела. Если есть апишное окно, то ошибки не может быть, т.к. оно и нужно, а если его нет то ошибки не может быть по опредилению, потому что эта функция никак не может быть вызвана. > А Control2 может быть чужим.
Тем более до него нет дела. > Вижу. Ничего хорошего сказать не могу. Вместо запихивания > в SetProp UpdateRect лучше сразу устанавливать на HDC, который > в wParam приходит. (Случай wParam = 0 надо игнорировать)
Рассмотрим 2 случая. 1) wParam == 0Можем получить UpdateRect, но не имеем в распоряжении канвы, т.к. канва создается позже, когда дело доходит до WinControl.WM_PAINT. 2) wParam <> 0Имеем в распоряжении канву, на которой будет выводится изображение, с которой потом можно будет легко содрать ClipRect, НО в этот момент уже вызвана BeginPaint, а значит мы уже не можем получить тот региоин (или рект) который потребовался для перерисовки. > Случай wParam = 0 надо игнорировать
Тут я задумался, почему я не игнарирую случай wParam <> 0, ведь по идее там SetProp(PropUpdateRect) должа перекрывать реальный рект, при случае когда приходит уже буферная канва, потом взглянул в генофонд, и все встало на свои места: procedure TWinControl.WMPaint(var Message: TWMPaint);
....
DC := BeginPaint(Handle, PS);
Perform(WM_ERASEBKGND, MemDC, MemDC);
Message.DC := MemDC;
WMPaint(Message);
Message.DC := 0;
BitBlt(DC, 0, 0, ClientRect.Right, ClientRect.Bottom, MemDC, 0, 0, SRCCOPY);
EndPaint(Handle, PS);
....
end; Так что "Вместо запихивания в SetProp UpdateRect лучше сразу устанавливать на HDC, который в wParam приходит." не имеет никакого смысла.
-
Действительно, BeginPaint уже вызван. > WMPaint(Message); И на это не обратил внимания. Посмотрел еще. Тут я задумался, почему я не игнарирую случай wParam <> 0 Зря не игноришь, канва может прийти от PaintTo.
> Да не имеет GRushWndProc никакого отношения к Control1. Ты заменил оконную процедуру, потом еще одному разработчику пришла в голову эта "гениальная" идея. Control1 = TGRushControl, Control1.Hook = GRushWndProc. Все будет работать только если порядок установки WndProc будет равен порядку восстановления.
-
Все будет работать только если порядок установки WndProc будет равен порядку восстановления. Это и так понятно (только не равен а противоположен). Но я не знаю что я могу еще сделать что-бы обезапасить свой код. По идее снимаю хук в WM_DESTROY, если все остальные будут снимать так-же, то все хуки снимутся в том порядке, в каком нужно. Есть мысль дополнительно проверять текущую WndProc на равенство GRushWndProc и ставить PrevWndProc только если так и есть. Вроде ничего страшного не случится, если не снять GRushWndProc вообше, или если его снимит нижестоящий хук (тут правда вроде как утечка памяти в связи с неснятым SetProp возникает, опять-же до уничтожения контролла (а он так и так на уничтожение собирается)).
> Зря не игноришь, канва может прийти от PaintTo. Верно, подправлю.
-
В общем, такое надо делать в самом родителе.
-
> В общем, такое надо делать в самом родителе.
Так то оно так, но что-же мне VCL переписывать что-ли?
-
Свою панельку сделать. Я в свою, наверное, добавлю.
-
А нельзя, 1) Рисовать на битмапе, как уже сказали 2) Почем зре не перерисовывать, а только при действительной необходимости? Я там делал в последнем компоненте, который на MouseMove реагировать был должен, (ссылки перекрашивать) ничего не мигало нигде
-
> ничего не мигало нигде
Это видимость в следствии не заинтерисованости Вами в надлежащем тестировании "не мигания", либо плохого зрения.
-
TStas © (18.03.07 19:24) [68] 1) Рисовать на битмапе, как уже сказали Зачем? Это и так делает DoubleBuffered.
TStas © (18.03.07 19:24) [68] ничего не мигало нигде Видимо, csOpaque или вообще наследник TWinControl.
-
> В общем, покритикуйте пожалуста мою реализацию
Всё правильно, верный подход
-
DimaBr (05.03.07 15:38) [32]
У DevExpress круче. Только по-моему ты нарушаешь их авторское право, выкладывая исходник, нет ?
По сабжу - я на bitmap'е рисую и не мучаюсь.
|