Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Компоненты";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Вниз

Мерцание, будь оно неладно!   Найти похожие ветки 

 
klyonov   (2004-05-31 21:57) [0]

всем привет!
вот такой вопрос:
решил сделать себе табличку, или даже список, с симпатичным внешним видом (вид a-la ObjectInspector). Однако столкнулся с мерцанием при скроллинге. не помогают ни WM_ERASEBKGND, ни csOpaque, ни Invalidate.
вообще, внешний вид и принцип его отрисовки я заимствовал у Сергея Гурина из его TObjectInspector. однако у него мерцания нет, а у меня есть.
прилагаю исходный код:

unit MyGrid;

interface

type
 TCustomMyGrid = class(TCustomControl)
 private
   FItems: TStringList;
   FRowHeight: Integer;
   FTopVisibleRow: Integer;
   FActiveRow: Integer;
   procedure WMEraseBkGnd(var AMessage: TWMEraseBkgnd); message WM_ERASEBKGND;
   procedure WMGetDlgCode(var AMessage: TWMGetDlgCode); message WM_GETDLGCODE;
   procedure WMVScroll(var AMessage: TWMScroll); message WM_VSCROLL;
 protected
   procedure CreateParams(var AParams: TCreateParams); override;
   procedure CreateWnd; override;
   procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
     X, Y: Integer); override;
   procedure KeyDown(var Key: Word; Shift: TShiftState); override;
   procedure Paint; override;
   procedure Resize; override;
   procedure UpdateScroll;
   property VisibleRowCount: Integer read GetVisibleRowCount;
   property TopVisibleRow: Integer read FTopVisibleRow write SetTopVisibleRow;
   property ActiveRow: Integer read FActiveRow write SetActiveRow;
 public
   constructor Create(AOwner: TComponent); override;
   destructor Destroy; override;
 end;

implementation

uses Graphics, Math, Types;

{ TCustomMyGrid }

constructor TCustomMyGrid.Create(AOwner: TComponent);
var i: Integer;
begin
 ControlStyle := ControlStyle + [csOpaque];
 inherited;
 Width := 200;
 Height := 300;
 FItems := TStringList.Create;
 FRowHeight := 16;
 FBorderStyle := bsSingle;
 Color := clBtnFace;
 for i := 0 to 50 do
   FItems.Add(Format("ITEM %d", [i, i]));
 Anchors := [akLeft, akTop, akBottom];
 FActiveRow := 10;
end;

procedure TCustomMyGrid.CreateParams(var AParams: TCreateParams);
const BorderStyles: array[TBorderStyle] of DWORD = (0, WS_BORDER);
begin
 inherited;
 with AParams do
 begin
   Style := Style or BorderStyles[FBorderStyle];
   if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then
   begin
     Style := Style and not WS_BORDER;
     ExStyle := ExStyle or WS_EX_CLIENTEDGE;
   end;
 end;
 with AParams.WindowClass do
   Style := Style and (CS_HREDRAW or CS_VREDRAW);
end;

procedure TCustomMyGrid.CreateWnd;
begin
 inherited;
 UpdateScroll;
end;

destructor TCustomMyGrid.Destroy;
begin
 FItems.Free;
 inherited;
end;

procedure TCustomMyGrid.KeyDown(var Key: Word; Shift: TShiftState);
begin
 inherited;
 case Key of
   VK_UP:
   begin
     ActiveRow := ActiveRow - 1;
     if ActiveRow < TopVisibleRow then
       TopVisibleRow := TopVisibleRow - 1;
   end;
   VK_DOWN:
   begin
     ActiveRow := ActiveRow + 1;
     if ActiveRow > TopVisibleRow + VisibleRowCount - 1 then
       TopVisibleRow := TopVisibleRow + 1;
   end;
 end;
end;

procedure TCustomMyGrid.Paint;

 procedure DrawLine(AColor: TColor; X0, Y0, X1, Y1: Integer);
 begin
   with Canvas do
   begin
     Pen.Color := AColor;
     MoveTo(X0, Y0);
     LineTo(X1, Y1);
   end;
 end;

 procedure DrawDotLine(AColor: TColor; X0, X1, Y0: Integer);
 var i: Integer;
 begin
   with Canvas do
   begin
     i := X0;
     while i < X1 do
     begin
       Canvas.Pixels[i, Y0] := AColor;
       inc(i, 2);
     end;
   end;
 end;

var i, j, k: Integer;
   dx, dy: Integer;
   R: TRect;
begin
 inherited;
 if not HandleAllocated then
   Exit;
 Canvas.Brush.Color := Color;
 Canvas.FillRect(ClientRect);
 if FTopVisibleRow + VisibleRowCount > FItems.Count - 1 then
   j := FItems.Count - 1
 else
   j := FTopVisibleRow + VisibleRowCount - 1;
 dy := (FRowHeight div 2) - (Canvas.TextHeight("A") div 2) - 1;
 k := 0;
 for i := FTopVisibleRow to j do
 begin
   dx := 5;
   R := Rect(0, FRowHeight * k + 1, ClientWidth, FRowHeight * (k + 1) - 1);
   Canvas.Brush.Color := Color;
   Canvas.TextRect(R, dx, FRowHeight * k + 1 + dy, FItems[i]);
   // ????????? ??????? ??????
   DrawDotLine(clBtnShadow, 0, Width, FRowHeight * (k + 1));
   if i = FActiveRow then
   begin
     R := Rect(-1, FRowHeight * k, ClientWidth + 1, FRowHeight * (k + 1) + 1);
     DrawEdge(Canvas.Handle, R, BDR_SUNKEN, BF_TOPLEFT);
     DrawEdge(Canvas.Handle, R, BDR_SUNKEN, BF_BOTTOMRIGHT);
   end;
   inc(k);
 end;
end;

procedure TCustomMyGrid.Resize;
begin
 inherited;
 UpdateScroll;
 Invalidate;
end;

procedure TCustomMyGrid.SetActiveRow(const Value: Integer);
begin
 if (Value < 0) and (FActiveRow = 0) then
   Exit;
 if (Value > FItems.Count - 1) and (FActiveRow = FItems.Count - 1) then
   Exit;
 if FActiveRow = Value then
   Exit;
 FActiveRow := Value;
 if FActiveRow > FItems.Count - 1 then
   FActiveRow := FItems.Count - 1;
 if FActiveRow < 0 then
   FActiveRow := 0;
 Invalidate;
end;

procedure TCustomMyGrid.SetTopVisibleRow(const Value: Integer);
begin
 if (Value < 0) and (FTopVisibleRow = 0) then
   Exit;
 if (Value >= FItems.Count - VisibleRowCount) and
    (FTopVisibleRow = FItems.Count - VisibleRowCount) then
   Exit;
 if FTopVisibleRow = Value then
   Exit;
 FTopVisibleRow := Value;
 if FTopVisibleRow < 0 then
   FTopVisibleRow := 0;
 if FTopVisibleRow >= (FItems.Count - VisibleRowCount) then
   FTopVisibleRow := FItems.Count - VisibleRowCount;
 UpdateScroll;
 Invalidate;
end;

procedure TCustomMyGrid.UpdateScroll;
var AScrollInfo: TScrollInfo;
begin
 if not HandleAllocated then
   Exit;
 AScrollInfo.cbSize := SizeOf(AScrollInfo);
 AScrollInfo.fMask := SIF_PAGE or SIF_POS or SIF_RANGE;
 AScrollInfo.nMin := 0;
 if FItems.Count > VisibleRowCount then
   AScrollInfo.nMax := FItems.Count - 1
 else
   AScrollInfo.nMax := 0;
 if AScrollInfo.nMax > 0 then
   AScrollInfo.nPage := VisibleRowCount
 else
   AScrollInfo.nPage := 0;
 if (AScrollInfo.nMax > 0) and (FTopVisibleRow > 0) then
 begin
   AScrollInfo.nPos := FTopVisibleRow;
   AScrollInfo.nTrackPos := FTopVisibleRow;
 end
 else
 begin
   AScrollInfo.nPos := 0;
   AScrollInfo.nTrackPos := 0;
 end;
 SetScrollInfo(Handle, SB_VERT, AScrollInfo, True);
end;

procedure TCustomMyGrid.WMEraseBkGnd(var AMessage: TWMEraseBkgnd);
begin
 AMessage.Result := LRESULT(False);
end;

procedure TCustomMyGrid.WMGetDlgCode(var AMessage: TWMGetDlgCode);
begin
 inherited;
 AMessage.Result := DLGC_WANTARROWS;
end;

procedure TCustomMyGrid.WMVScroll(var AMessage: TWMScroll);
var AScrollInfo: TScrollInfo;
begin
 inherited;
 case AMessage.ScrollCode of
   SB_LINEUP: TopVisibleRow := TopVisibleRow - 1;
   SB_LINEDOWN: TopVisibleRow := TopVisibleRow + 1;
   SB_PAGEUP: TopVisibleRow := TopVisibleRow - VisibleRowCount;
   SB_PAGEDOWN: TopVisibleRow := TopVisibleRow + VisibleRowCount;
   SB_THUMBPOSITION, SB_THUMBTRACK:
   begin
     AScrollInfo.cbSize := SizeOf(AScrollInfo);
     AScrollInfo.fMask := SIF_TRACKPOS;
     GetScrollInfo(Handle, SB_VERT, AScrollInfo);
     TopVisibleRow := AScrollInfo.nTrackPos;
   end;
 end;
end;

end.


 
jack128 ©   (2004-05-31 22:17) [1]

чесно говоря лень просматривать стролько кода, так что ты лудше сам скажи: DoubleBuffered := True; - имеется? Если нет - вставить (в конструктор)


 
klyonov   (2004-05-31 22:22) [2]

помогло, спасибо!


 
wicked ©   (2004-06-11 19:52) [3]

жють... :)
мой совет - при прорисовке в Paint делать проверять на clip по ClipRect (св-во у Canvas) и соответственно не рисовать ненужные части...
плюсы подхода - намного меньше прорисовок и соблюдение идеологии windows (рисовать только то, что необходимо)...
а DoubleBuffered - не панацея...


 
DVM ©   (2004-06-11 20:42) [4]


> и соответственно не рисовать ненужные части...

Так все функции Windows и так не рисуют невидимое за пределами области отсечения. Единственное это может сэкономить немного времени на подготовке к рисованию ненужных частей.


 
wicked ©   (2004-06-11 22:21) [5]


> Так все функции Windows и так не рисуют невидимое за пределами
> области отсечения.

я говорил в контексте кода процедуры Paint, приведенного в [0]...
тем более, что TCanvas.ClipRect aka GetClipBox вовсе не устанавливает область отсечения, он просто диктует bounding box invalid"ной области, т.е. той, которуй реально и надо перерисовать... никто не мешает нам рисовать во всей клиентской области окна, тем более, что стиль csOpaque как раз это и предполагает - контрол "саботирует" сообщение WM_ERASEBKGND...


 
jack128 ©   (2004-06-13 10:15) [6]


> Так все функции Windows и так не рисуют невидимое за пределами
> области отсечения. Единственное это может сэкономить немного
> времени на подготовке к рисованию ненужных частей.

а иногда даже наоборот увеличивает время на анализ того нужно ли рисовать эту часть уили нет ;-)

> TCanvas.ClipRect aka GetClipBox вовсе не устанавливает область
> отсечения, он просто диктует bounding box invalid"ной области,
> т.е. той, которуй реально и надо перерисовать... никто не
> мешает нам рисовать во всей клиентской области окна, тем
> более, что стиль csOpaque как раз это и предполагает - контрол
> "саботирует" сообщение WM_ERASEBKGND...

нечего не понял. Как это СlipRect - не область отсечения, когда я лично проверял - все что выходит за приделы СlipRect"a - не рисуется? И вообще не понимаю, как конторол может рисовать за своими границами - вот что в исходниках говорится по этому поводу:
procedure TWinControl.PaintControls(DC: HDC; First: TControl);
begin
...
with TControl(FControls[I]) do
 if (Visible or (csDesigning in ComponentState) and
    not (csNoDesignVisible in ControlStyle)) and
    RectVisible(DC, Rect(Left, Top, Left + Width, Top + Height)) then
 begin
   if csPaintCopy in Self.ControlState then
     Include(FControlState, csPaintCopy);
   SaveIndex := SaveDC(DC);
   MoveWindowOrg(DC, Left, Top);
   IntersectClipRect(DC, 0, 0, Width, Height);
   Perform(WM_PAINT, DC, 0);
   RestoreDC(DC, SaveIndex);
   Exclude(FControlState, csPaintCopy);
 end;
 ...
end;


 
vidiv ©   (2004-06-14 13:29) [7]

когда я столько кода дал - мое сообщение удалили :(


 
wicked ©   (2004-06-17 17:55) [8]


> а иногда даже наоборот увеличивает время на анализ того
> нужно ли рисовать эту часть уили нет ;-)

не обязательно... если анализ на нужность занимает гораздо больше времени, то, может, стоит пересмотреть алгоритм рисования?... ;)


> нечего не понял. Как это СlipRect - не область отсечения,
> когда я лично проверял - все что выходит за приделы СlipRect"a
> - не рисуется?

возможно... я видел только косвенные подтверждения моим словам...


 
Гоша   (2004-06-18 00:18) [9]

>vidiv ©  (14.06.04 13:29) [7]
>когда я столько кода дал - мое сообщение удалили :(

Дык. Ты его размазал на 4 сообщения :))



Страницы: 1 вся ветка

Форум: "Компоненты";
Текущий архив: 2005.06.06;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.49 MB
Время: 0.013 c
1-1116506572
Cat
2005-05-19 16:42
2005.06.06
строку по одной цифре раскидать в массив Integer


3-1114431135
normandia
2005-04-25 16:12
2005.06.06
Запрос по месяцам и кварталам


10-1093590350
AntonSh
2004-08-27 11:05
2005.06.06
COM сервер


1-1116926448
SergP.
2005-05-24 13:20
2005.06.06
Выравнивание в TEdit


3-1114680917
Bocman
2005-04-28 13:35
2005.06.06
автоинкремент в Paradox





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский