Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Gedimmten Hintergrund im Canvas schneller (https://www.delphipraxis.net/175301-gedimmten-hintergrund-im-canvas-schneller.html)

Nic2012 11. Jun 2013 15:34

Gedimmten Hintergrund im Canvas schneller
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
habe das TShape für eine eigene Komponente abgeleitet, deren Hintergrund zwar transparent aber gedimmt sein soll. Im Paint rufe ich dazu:
Code:
procedure TExtShape.Paint;
  function Shadow(Color: TColor): TColor;
  const
    Delta = 0.7;
  begin
    Color := ColorToRGB(Color);
    Result := RGB(Round(GetRValue(Color) * Delta),
    Round(GetGValue(Color) * Delta),
    Round(GetBValue(Color) * Delta));
  end;
var y, x: Integer;
begin
  inherited Paint;

  if FIsDimmed then
    for Y := 0 to Height -1 do
      for X := 0 to Width -1 do
        SetPixelV( Canvas.Handle, X, Y, Shadow(GetPixel(Canvas.Handle, X, Y)));

  Canvas.Font := Font;
  Canvas.TextOut((Width - Canvas.TextWidth(Caption)) div 2, (Height - Canvas.TextHeight(Caption)) div 2, Caption);
end;
Das geht prinzipel, aber mit deutlichem Flackern beim Neuzeichnen. Stehe etwas auf dem Schlauch wie das mit z.B. ScanLine schneller bekomme, insbesondere soll das Shape mit RoundRectangle abgerundet sein, und nicht so wie im Screenshot.
Gruß,
Nic

Der schöne Günther 11. Jun 2013 15:40

AW: Gedimmten Hintergrund im Canvas schneller
 
Delphi Grafiksachen und die VCL überhaupt sind jetzt nicht mein Mileu, aber einzelne Pixel zu manipulieren ist sicher ziemlich langsam. Falls du wirklich absolute Performance brauchst, gibt es bestimmt irgendwo eine Methode, wo man an ein Byte-Array kommt...

Ansonsten hat ein TCanvas doch sicher auch eine BeginUpdate() und EndUpdate()-Methode? Dazwischen sollte dann dein Zeichnen stattfinden...

QuickAndDirty 11. Jun 2013 15:46

AW: Gedimmten Hintergrund im Canvas schneller
 
ja Scanline ist schneller...aber nicht so optimal.

Hm

Das schnellste ist wohl bitblt ot stretchblt mit bitmasken operationen
Am besten mit dwrop auf SRCPAINT

Zitat:

SRCPAINT Combines the colors of the source and destination rectangles by using the Boolean OR operator.
BITBLT hätte außerdem den vorteil das du nicht nur in das handel von einem canvas sondern auch z.b. in das händel ein Region kopieren kannst.
Eine Region kannst du dir in beliebiger Form bauen...
Du kannst aber auch z.t. eine Bitmap(schwarzweiß) als vorlage erzeugen so das nur die weißen oder schwarzen bereiche (je nach logische operation) von den kopier Operationen betroffen sind.

Wenn du nicht mit den GDI funktionen arbeiten willst
kannst du auch das nur unwesentlich langsamere
Tcanvas.copyrect
mit
Tcanvas.copymode
benutzen.

Nic2012 11. Jun 2013 18:25

AW: Gedimmten Hintergrund im Canvas schneller
 
Jo, mit Scanline geht das viel schneller, selbst im Designmodus kein Flackern mehr, Voraussetzung fürs Scanlinen ein temp. Bitmap:
Code:
procedure TExtShape.Paint;
  const
    Delta = 0.80;
  function ColorDimmed(Color: TColor): TColor;
  begin
    Color := ColorToRGB(Color);
    Result := RGB(Round(GetRValue(Color) * Delta),
                  Round(GetGValue(Color) * Delta),
                  Round(GetBValue(Color) * Delta));
  end;
type
  TRGB32 = packed record
    B, G, R, A: Byte;
  end;
  TRGB32Array = packed array[0..MaxInt div SizeOf(TRGB32)-1] of TRGB32;
  PRGB32Array = ^TRGB32Array;
var
  y, x: Integer;
  b: Graphics.TBitmap;
  Source: TRect;
  Dest: TRect;
  Row: PRGB32Array;
begin
  if FIsDimmed then begin

    b := Graphics.TBitmap.Create;
    try
      b.PixelFormat := pf32bit;
      b.Width := Width;
      b.Height := Height;

      Dest := Rect(0, 0, b.Width, b.Height);
      Source := Rect(0, 0, Width, Height);

      b.Canvas.CopyRect(Dest, Canvas, Source);

      for Y := 0 to Height -1 do begin
        Row := b.Scanline[Y];
        for X := 0 to Width -1 do begin
          Row^[X].R := Round(Row^[X].R * Delta);
          Row^[X].G := Round(Row^[X].G * Delta);
          Row^[X].B := Round(Row^[X].B * Delta);
        end;
      end;

      Canvas.CopyRect(Source, b.Canvas, Dest);

    finally
       b.Free;
    end;

    {
    for Y := 0 to Height -1 do
      for X := 0 to Width -1 do
        SetPixelV( Canvas.Handle, X, Y, ColorDimmed(GetPixel(Canvas.Handle, X, Y)));
    }
  end;

  inherited Paint;

  Canvas.Font := Font;
  Canvas.TextOut((Width - Canvas.TextWidth(Caption)) div 2, (Height - Canvas.TextHeight(Caption)) div 2, Caption);
end;

Der schöne Günther 5. Aug 2013 11:02

AW: Gedimmten Hintergrund im Canvas schneller
 
Nachträglich fällt mir da noch ein, dass du Komponenten auch zeitweilig einfrieren kannst: Erst einfrieren, in Ruhe zeichnen, wieder auftauen. Das geht allerdings an der VCL vorbei direkt über die WinAPI:

Delphi-Quellcode:
SendMessage(myComponent.Handle, WM_SETREDRAW, 0, 0);
try
   [Gedöns]
finally
   SendMessage(myComponent.Handle, WM_SETREDRAW, 1, 0);
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:20 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz