2014-09-30 4 views
7

TScrollBar이있는 그래픽 하위 구성 요소 TCustomControl이 있습니다. 문제는 화살표 키를 눌러 커서를 이동하면 전체 캔버스가 배경색으로 스크롤 막대 영역을 포함하여 칠해진 다음 스크롤 막대가 다시 칠되어 스크롤 막대가 깜박이는 것입니다. 이 문제를 어떻게 해결할 수 있습니까?내 TCustomControl 하위 구성 요소의 깜박임을 멈추게하려면 어떻게해야합니까?

다음은 코드입니다.

unit Unit1; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, SuperList; 

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 
    List: TSuperList; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
List:=TSuperList.Create(self); 
List.Top:=50; List.Left:=50; 
List.Visible:=true; 
List.Parent:=Form1; 
end; 

end. 

SuperList.pas

unit SuperList; 

interface 

uses Windows, Controls, Graphics, Classes, Messages, SysUtils, StdCtrls, Forms; 

type 

    TSuperList = class(TCustomControl) 
    public 
    DX,DY: integer; 
    ScrollBar: TScrollBar; 
    procedure Paint; override; 
    constructor Create(AOwner: TComponent); override; 
    procedure WMKeyDown(var Message: TWMKeyDown); message WM_KEYDOWN; 
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE; 
    procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN; 
    published 
    property OnMouseMove; 
    property OnKeyPress; 
    property OnKeyDown; 
    property Color default clWindow; 
    property TabStop default true; 
    property Align; 
    property DoubleBuffered default true; 
    property BevelEdges; 
    property BevelInner; 
    property BevelKind default bkFlat; 
    property BevelOuter; 
    end; 

procedure Register; 

implementation 

procedure Register; 
begin 
    RegisterComponents('Marus', [TSuperList]); 
end; 

procedure TSuperList.WMGetDlgCode(var Message: TWMGetDlgCode); 
begin 
inherited; 
Message.Result:= Message.Result or DLGC_WANTARROWS; 
end; 

procedure TSuperList.WMKeyDown(var Message: TWMKeyDown); 
begin 
if Message.CharCode=VK_LEFT then begin dec(DX,3); Invalidate; exit; end; 
if Message.CharCode=VK_RIGHT then begin inc(DX,3); Invalidate; exit; end; 
if Message.CharCode=VK_UP then begin dec(DY,3); Invalidate; exit; end; 
if Message.CharCode=VK_DOWN then begin inc(DY,3); Invalidate; exit; end; 
inherited; 
end; 

procedure TSuperList.WMLButtonDown(var Message: TWMLButtonDown); 
begin 
DX:=Message.XPos; 
DY:=Message.YPos; 
SetFocus; 
Invalidate; 
inherited; 
end; 

constructor TSuperList.Create(AOwner: TComponent); 
begin 
inherited; 
DoubleBuffered:=true; 
TabStop:=true; 
Color:=clNone; Color:=clWindow; 
BevelKind:=bkFlat; 
Width:=200; 
Height:=100; 
DX:=5; DY:=50; 
ScrollBar:=TScrollBar.Create(self); 
ScrollBar.Kind:=sbVertical; 
ScrollBar.TabStop:=false; 
ScrollBar.Align:=alRight; 
ScrollBar.Visible:=true; 
ScrollBar.Parent:=self; 
end; 

procedure TSuperList.Paint; 
begin 
Canvas.Brush.Color:=Color; 
Canvas.FillRect(Canvas.ClipRect); 
Canvas.TextOut(10,10,'Press arrow keys !'); 
Canvas.Brush.Color:=clRed; 
Canvas.Pen.Color:=clBlue; 
Canvas.Rectangle(DX,DY,DX+30,DY+20); 
end; 

end. 

하여 Unit1.pas를 : 필요가 구성 요소를 설치하거나, ​​기본 폼에 뭔가를 넣어 그냥 코드를 복사 TForm1.FormCreate 이벤트를 할당 할 수있다

+0

중간 버퍼 비트 맵을 사용해 보셨습니까? 아이디어는 모든 그림을 보이지 않는 캔버스에서 마친 다음 작업이 끝나면 그 그림을 사용자가 컨트롤 할 수있게 만드는 것입니다. –

+0

나는 스크롤 바를 양육하는 것이 문제가 될 것이라고 말했다. 시스템에서 처리하는 것이 더 나을 것 같아요. 그리고 컨트롤에서'DoubleBuffered'를'True'로 설정하면 의심 스럽습니다. 버퍼를 두 배로 늘릴 필요는 없습니다. +1 우리가 필요로하는 모든 코드가 포함 된 매우 좋은 질문은 매우 잘립니다. –

+0

@JerryDodge 예. 'DoubleBuffered' 속성은 가능하고 모든 그림은 보이지 않는 비트 맵에서 만들어집니다. –

답변

5

내가 할 수있는 첫 번째 일은 스크롤 막대 컨트롤을 제거하는 것입니다. Windows에는 준비된 스크롤 막대가 있습니다. 당신은 그들을 활성화시켜야합니다.

따라서 구성 요소에서 ScrollBar을 제거하여 시작하십시오. 컨트롤은 이제 스크롤 막대를 가지고,

procedure TSuperList.CreateParams(var Params: TCreateParams); 
begin 
    inherited; 
    Params.Style := Params.Style or WS_VSCROLL; 
end; 

지루해 :

procedure CreateParams(var Params: TCreateParams); override; 

이처럼 구현 : 그럼 CreateParams 재정의를 추가 할 수 있습니다.

다음 당신은 WM_VSCROLL에 대한 처리기를 추가해야합니다

procedure WMVScroll(var Message: TWMVScroll); message WM_VSCROLL; 

을 그리고는 다음과 같이 구현 것 :

procedure TSuperList.WMVScroll(var Message: TWMVScroll); 
begin 
    case Message.ScrollCode of 
    SB_LINEUP: 
    begin 
     dec(DY, 3); 
     Invalidate; 
    end; 
    SB_LINEDOWN: 
    begin 
     inc(DY, 3); 
     Invalidate; 
    end; 
    ... 
    end; 
end; 

당신은 스크롤 코드의 나머지 부분을 작성해야합니다.

또한 구성 요소의 생성자에 DoubleBuffered을 설정하지 말 것을 제안합니다. 원하는 경우 사용자가 설정하도록하십시오. 이중 버퍼링이 필요한 제어가 필요하지 않습니다.

+0

Yeeees, 그게 다야! 더 이상 깜박임이 없습니다. David Heffernan 대단히 감사합니다!:) –

+2

스크롤 메시지 핸들러에서 (전체 클라이언트 사각형을 무효로 할지라도)'Invalidate'보다는'ScrollWindowEx' 함수를 사용하는 것을 선호해야합니다. '' – TLama

+1

@tlama 감사합니다. 나는이 시점에서 내 깊이에서 벗어났다. –