2014-10-22 20 views
5

Ich habe ein benutzerdefiniertes Steuerelement mit beiden Bildlaufleisten aktiviert und ich möchte eine einfache rote Linie Rahmen um den Client-Bereich und die Bildlaufleisten, wie im Bild unten zu zeichnen. Wie mache ich das?Wie zeichne ich einen benutzerdefinierten Rahmen innerhalb des Nicht-Client-Bereichs eines Steuerelements mit Bildlaufleisten?

Example

Dies ist der Steuercode:

unit SuperList; 

interface 

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

type 

    TSuperList = class(TCustomControl) 
    protected 
    procedure Paint; override; 
    procedure CreateParams(var Params: TCreateParams); override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    end; 

implementation 

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

constructor TSuperList.Create(AOwner: TComponent); 
begin 
inherited; 
Color:=clBlack; 
Width:=300; 
Height:=250; 
end; 

procedure TSuperList.Paint; 
begin 
Canvas.Pen.Color:=clNavy; 
Canvas.Brush.Color:=clWhite; 
Canvas.Rectangle(ClientRect); // a test rectangle te see the client area 
end; 

end. 

Antwort

4

Veröffentlichen Sie das BorderWidth Eigentum und implementieren einen WM_NCPAINT Message-Handler, wie in this answer, mit dem Code in this answer kombiniert gezeigt:

type 
    TSuperList = class(TCustomControl) 
    private 
    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND; 
    procedure WMNCPaint(var Message: TWMNCPaint); message WM_NCPAINT; 
    protected 
    procedure CreateParams(var Params: TCreateParams); override; 
    procedure Paint; override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    published 
    property BorderWidth default 10; 
    end; 

implementation 

constructor TSuperList.Create(AOwner: TComponent); 
begin 
    inherited Create(Aowner); 
    ControlStyle := ControlStyle - [csOpaque]; 
    BorderWidth := 10; 
end; 

procedure TSuperList.CreateParams(var Params: TCreateParams); 
begin 
    inherited CreateParams(Params); 
    Params.Style := Params.Style or WS_VSCROLL or WS_HSCROLL; 
    Params.WindowClass.style := 
    Params.WindowClass.style and not (CS_HREDRAW or CS_VREDRAW); 
end; 

procedure TSuperList.Paint; 
begin 
    Canvas.Brush.Color := RGB(Random(255), Random(255), Random(255)); 
    Canvas.FillRect(Canvas.ClipRect); 
end; 

procedure TSuperList.WMEraseBkgnd(var Message: TWMEraseBkgnd); 
begin 
    Message.Result := 1; 
end; 

procedure TSuperList.WMNCPaint(var Message: TWMNCPaint); 
var 
    DC: HDC; 
    R: TRect; 
    WindowStyle: Integer; 
begin 
    inherited; 
    if BorderWidth > 0 then 
    begin 
    DC := GetWindowDC(Handle); 
    try 
     R := ClientRect; 
     OffsetRect(R, BorderWidth, BorderWidth); 
     ExcludeClipRect(DC, R.Left, R.Top, R.Right, R.Bottom); 
     WindowStyle := GetWindowLong(Handle, GWL_STYLE); 
     if WindowStyle and WS_VSCROLL <> 0 then 
     ExcludeClipRect(DC, R.Right, R.Top, 
      R.Right + GetSystemMetrics(SM_CXVSCROLL), R.Bottom); 
     if WindowStyle and WS_HSCROLL <> 0 then 
     ExcludeClipRect(DC, R.Left, R.Bottom, R.Right, 
      R.Bottom + GetSystemMetrics(SM_CXHSCROLL)); 
     SetRect(R, 0, 0, Width + BorderWidth, Height + BorderWidth); 
     Brush.Color := clRed; 
     FillRect(DC, R, Brush.Handle); 
    finally 
     ReleaseDC(Handle, DC); 
    end; 
    end; 
    Message.Result := 0; 
end; 
+0

Leider funktioniert dies nicht ordnungsgemäß in Windows 7 Home Premium, 64-Bit, Aero, Delphi 2009. Wenn Sie das Steuerelement teilweise außerhalb des Monitors und dann zurück bewegen, werden die Teile der Bildlaufleisten, die immer sichtbar waren, überstrichen . –

+0

@And Sorry, aber ich habe (noch) keine Lösung für dich. (Übrigens habe ich festgestellt, dass der Fehler auch bei einer 'TScrollBox' mit einer 'BorderWidth> 0' liegt, also hat es wahrscheinlich nichts mit diesem Code zu tun.) – NGLN

3

Sie versuchen, (teilweise) zu malen im Nonclient Area.
Sie könnten WS_DLGFRAME zu Params.Style hinzufügen und die Nachricht WM_NCPaint bearbeiten, um auf der HDC des Fensters zu malen.

TSuperList = class(TCustomControl) 
    private 
    procedure PaintBorder; 
    procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCActivate; 
    procedure WMNCPaint(var Msg: TWMNCPaint);message WM_NCPaint; 
    protected 
    procedure Paint; override; 
    procedure CreateParams(var Params: TCreateParams); override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    end; 

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

procedure TSuperList.WMNCActivate(var Msg: TWMNCActivate); 
begin 
    inherited; 
    PaintBorder; 
end; 

procedure TSuperList.WMNCPaint(var Msg: TWMNCPaint); 
begin 
    inherited; 
    PaintBorder; 
end; 

procedure TSuperList.PaintBorder; 
begin 
    Canvas.Handle := GetWindowDC(Handle); 
    Canvas.Pen.Color := clNavy; 
    Canvas.Pen.Width := 2; 
    Canvas.Brush.Style := bsClear; 
    Canvas.Rectangle(Rect(1,1,Width,Height)); 
    ReleaseDC(Handle,Canvas.Handle); 
end;  

constructor TSuperList.Create(AOwner: TComponent); 
begin 
inherited; 
Color:=clBlack; 
Width:=300; 
Height:=250; 
end; 

procedure TSuperList.Paint; 
begin 
Canvas.Brush.Color:=clWhite; 
Canvas.Pen.Style := psClear; 
Canvas.Rectangle(ClientRect); 
Canvas.Pen.Style := psSolid; 
Canvas.Ellipse(0,0,20,20); 
end; 

enter image description here

+0

Ok, aber ich mag die Breite der Rahmen soll variabel sein und 'WS_DLGFRAME' weist nur einen festen 2-Pixel-Rahmen auf. –

+0

WS_THICKFRAME würde Ihnen mehr Platz geben, wenn Sie einen Variablenraum benötigen, der vollständig unter Ihrer Kontrolle steht, können Sie eine Komponente mit der Superliste als Unterkomponente erstellen. – bummi