2017-08-11 3 views
3

Bitte beachten Sie den folgenden Code ein:TBitmap verliert Ausschneidebereich nach nicht verwandten Grafikcode

type 
    TBaseControl = class(TWinControl) 
    private 
    FBitmap : TBitmap; 
    public 
    constructor Create(AOwner : TComponent); override; 
    procedure DrawBorder; 
    end; 

    TForm1 = class(TForm) 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    public 
    end; 

var 
    Form1: TForm1; 
    NewC : TBaseControl; 

implementation 

{$R *.dfm} 

constructor TBaseControl.Create(AOwner : TComponent); 
begin 
    inherited Create(AOwner); 
    FBitmap := TBitmap.Create; 
    FBitmap.PixelFormat := pf24bit; 
    FBitmap.SetSize(100,100); 
end; 

procedure TBaseControl.DrawBorder; 
var 
    Region : HRGN; 
    ContentRect : TRect; 
begin 
    // Almost like a Client Area of a control 
    ContentRect := Rect(10,10,FBitmap.Width - 10,FBitmap.Height - 10); 

    // Create clipping region on FBitmap with ContentRect being excluded 
    Region := CreateRectRgnIndirect(Rect(0,0,Width,Height)); 
    SelectClipRgn(FBitmap.Canvas.Handle,Region); 
    ExcludeClipRect(FBitmap.Canvas.Handle,ContentRect.Left,ContentRect.Top, 
        ContentRect.Right,ContentRect.Bottom); 
    DeleteObject(Region); 

    // Do Pre-drawing 
    FBitmap.Canvas.Brush.Style := bsSolid; 
    FBitmap.Canvas.Brush.Color := clRed; 
    FBitmap.Canvas.FillRect(Rect(0,0,FBitmap.Width,FBitmap.Height)); 


    // Will comment out one of these statements 
    // The graphics one (.Caption) will cause the clipping to be lost. Any 
    // graphics code will do it as long as it is not related to FBitmap 
    // ======================================================================== 
    Form1.Caption := 'You have just lost your Bitmap''s clipping'; 
    // ----- 
    Form1.Tag := Random(1000); 
    // ======================================================================== 


    // Do some drawing afterwards 
    FBitmap.Canvas.Brush.Color := clGreen; 
    FBitmap.Canvas.FillRect(Rect(5,5,FBitmap.Width - 5,FBitmap.Height - 5)); 

    // Want to see what it looks like 
    FBitmap.SaveToFile('d:\test.bmp'); 
    // Test the tag setting 
    ShowMessage(InttoStr(Form1.Tag)); 
end; 

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    // Create an instance of TBaseControl 
    NewC := TBaseControl.Create(Self); 
    NewC.SetBounds(0,0,200,200); 
    NewC.Parent := Self; 
    // Tell it to draw 
    NewC.DrawBorder; 
end; 

In DrawBorder, wenn ich nur ohne die Beschriftung Form1 Tag gesetzt werden, dann FBitmap der Clipping-Bereich gehalten wird und im gesamten Zeichnungscode respektiert. FBitmap wird wie folgt aussehen:

enter image description here

Aber wenn Beschriftung des Form1 gesetzt ist, dann FBitmap seine Clippingbereichs verlieren und wie folgt aussehen:

enter image description here

So scheint es, dass nach Form1 Caption war set FBitmap hat seinen Clipping-Bereich verloren. WindowOrigins (festgelegt über SetWindowOrgEx) gehen ebenfalls verloren, wenn dies geschieht.

+0

Diese Bitmap hat ihre Zeichenfläche verloren (ihr Handle wird nach dem Ändern der Formularunterschrift in D2009 auf 0 gesetzt). Das Steuerelement wurde nicht neu erstellt. Hast du versucht, ein kleines braunes Eichhörnchen oder ein ähnliches Baumtier zu opfern? Es macht wirklich keinen Sinn. – Victoria

+1

@Victoria macht es Sinn, wenn Sie berücksichtigen, dass die VCL GDI-Ressourcen zwischenspeichert und häufig (während der Nachrichtenbehandlung) Canvas-HDCs freigibt, die nicht aktiv gesperrt sind. Erwarten Sie nicht, dass GDI-Einstellungen im Laufe der Zeit beibehalten werden. Setzen Sie sie zurück, wenn Sie etwas zeichnen müssen. Die durch 'DrawBorder' festgelegte Region ist möglicherweise nicht gültig, nachdem die Ausführung zur Hauptnachrichtenschleife zurückgekehrt ist (z. B. aufgrund eines Repaints, ausgelöst durch die 'Caption'-Änderung) –

Antwort

2

Nach dem Lesen der Kommentare von Victoria und Remy oben erkannte ich, dass die Leinwand Verriegelung könnte helfen, so habe ich versucht, den Zeichencode in FBitmap.Canvas.Lock und FBitmap.Canvas.UnLock Verpackung und das scheint das Problem behoben zu haben.

procedure TBaseControl.DrawBorder; 
var 
    Region : HRGN; 
    ContentRect : TRect; 
begin 
    FBitmap.Canvas.Lock; 

    // ....All the drawing code------------------- 
    // ....All the drawing code------------------- 

    FBitmap.Canvas.UnLock; 

    // Want to see what it looks like 
    FBitmap.SaveToFile('d:\test.bmp'); 
    // Test the tag setting 
    ShowMessage(InttoStr(Form1.Tag)); 
end; 
+2

Ich würde es einfach in einen' try..finally'-Block einschließen (es ist ein bisschen paranoid hier, aber immer noch). – Victoria

Verwandte Themen