Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Wieder mal das leidige Thema "Flackern" (https://www.delphipraxis.net/201804-wieder-mal-das-leidige-thema-flackern.html)

skoschke 28. Aug 2019 09:18

Wieder mal das leidige Thema "Flackern"
 
Hallo,

in einen "Designer"-Programm muss ich einen Hintergrund sowie mehrere Linien und Bitmaps zeichnen, die mit der Maus bewegt werden können.
Nach vielen Versuchen bin ich nun zu einer Paintbox gekommen, in deren OnPaint nur

Delphi-Quellcode:
  BitBlt(Paintbox1.Canvas.Handle, 0, 0, offscreenbitmap.Width, offscreenbitmap.Height, offscreenbitmap.Canvas.Handle, 0,
    0, SRCCOPY);
steht.
Das ganze Zeichnen passiert in die offscreenbitmap beim Mousemove (hier testweise nur ein bildfüllendes Hintergrundbild, eine Linie und eine kleine Bitmap:

Delphi-Quellcode:
  //die Offscreenbitmap ist global vorhanden
  if ssLeft in Shift then
  begin
    lx := X;
    ly := Y;
    // Offscreen Bitmap bemalen
    r.Width := Paintbox1.Width;
    r.Height := Paintbox1.Height;
    //das Hintergrundbild
    offscreenbitmap.Canvas.StretchDraw(r, fbitmap1);
    //eine Linie
    offscreenbitmap.Canvas.MoveTo(0, Mouse.y);
    offscreenbitmap.Canvas.LineTo(Paintbox1.Width, Mouse.y);
    r.Left := Mouse.x;
    r.Top := Mouse.y;
    r.Width := 150;
    r.Height := 100;
    //das kleine Bitmap
    offscreenbitmap.Canvas.StretchDraw(r, fbitmap2);
    Paintbox1.Invalidate;
  end;
Das Ganze funktioniert zwar, flackert aber trotzdem entsetzlich, doublebuffered ist auf true gesetzt.

Ich vermute es liegt an der Größe (bildschirmfüllend) des Offscreenbitmaps, wie bekomme ich das Flackern weg???

Ciao
Stefan

TiGü 28. Aug 2019 09:24

AW: Wieder mal das leidige Thema "Flackern"
 
Jetzt ein gezipptes und minimales Formular-Projekt zum runterladen und dir wird geholfen.
Denn in 9 von 10 Fällen ist das Problem genau in der Codezeile, die du uns nicht zeigst.

Uwe Raabe 28. Aug 2019 09:27

AW: Wieder mal das leidige Thema "Flackern"
 
DoubleBuffered ist hier eher schädlich, da du ja selbst bereits das Bitmap offline zeichnest und dann per BitBlt auf den Bildschirm bringst. Wenn das noch DoubleBuffered ausgeführt wird, ist das doch doppelt gemoppelt.

KarstenK 28. Aug 2019 10:07

AW: Wieder mal das leidige Thema "Flackern"
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1443636)
DoubleBuffered ist hier eher schädlich, da du ja selbst bereits das Bitmap offline zeichnest und dann per BitBlt auf den Bildschirm bringst. Wenn das noch DoubleBuffered ausgeführt wird, ist das doch doppelt gemoppelt.

DoubleBuffered hilft hier (Zumindest noch Unter Delphi 2009). Soweit ich mich erinnere die Paintbox löscht/überschreibt mit einer Farbe ihre Zeichenfläche erst und ruft dann onpaint erst auf.

Alternative wenn ohne doublebuffered und das Bitmap die ganze Fläche ausfüllt, eine eigene Componente von der Paintbox ableiten ohne löschen des Hintergrundes.

stahli 28. Aug 2019 10:14

AW: Wieder mal das leidige Thema "Flackern"
 
Ich habe mal eigene "Controls" in einem Thread berechnen und auf einem Bitmap zeichnen lassen.
Die Ausgabe erfolgte dann synchronisiert im Mainthread durch kopieren des Bitmaps auf den Formularcanvas. Vom Mainthread aus wurden dann die Maus- und Tastaturereignisse auch wieder nur in den "Controls-Thread" gegeben.

Wie das aussah kannst Du hier sehen: https://www.delphipraxis.net/1294946-post59.html
Rappelschnell.

Leider habe ich die Quellen nicht mehr. Könnte mich gerade selbst in den A... beißen, weil ich damit gern noch etwas testen würde... :wall:

skoschke 28. Aug 2019 11:02

AW: Wieder mal das leidige Thema "Flackern"
 
Hallo Stahli,

ich habe mir die Exe mal angesehen, absolute Supersahne!

Im Prinzip geht es bei mir genau darum, ich erzeuge eigene Panels (von TPanel abgeleitet) und platziere die per Maus auf einem Hauptpanel mit einem TImage als Hintergrund.

Jetzt soll man diese per Maus anfassen und verschieben können.
Das flackerte entsetzlich (besonders wenn diese eigenen Panels Images enthalten) so daß ich dachte, ich mach einen Screenshot des gesamten Fensters und schiebe darin wiederum Bilder der Panels...

Bei Dir sieht es aber aus als ob dort Controls flackerfrei im Formular "rumtanzen", ist das richtig?

Wenn Du leider den Code nicht mehr hast, hast Du noch ein paar Denkanstöße zur Realisierung für mich?

Ich habe in Deinem Gesamtthread aber leider jetzt gesehen, dass es um FMX geht, ich muß (leider) ein VCL-Projekt erstellen!

Ciao
Stefan

skoschke 28. Aug 2019 11:26

AW: Wieder mal das leidige Thema "Flackern"
 
Zitat:

Zitat von TiGü (Beitrag 1443635)
Jetzt ein gezipptes und minimales Formular-Projekt zum runterladen und dir wird geholfen.
Denn in 9 von 10 Fällen ist das Problem genau in der Codezeile, die du uns nicht zeigst.

Siehe meine Antwort an Stahli, eigentlich möchte ich Controls flackerfrei bewegen können, der Umweg über die Paintbox war ein Ansatz das zu umgehen...

Ciao
Stefan

stahli 28. Aug 2019 11:28

AW: Wieder mal das leidige Thema "Flackern"
 
Danke für das Lob. :-)

Das ist rein VCL (quasi ein Versuch mal FMX-Light (sehr, sehr light ;-) ) umzusetzen.)

Es sind keine Controls, sie sollten sich nur so anfühlen.


Das funktioniert so:

Im "Control-Thread":
- Bitmap füllen mit Hintergrundfarbe.
- Pro "Control" Rechteck zeichnen (mit oder ohne Hintergrund, Rahmen, Text)
- Pro Control Z-Order und Positionen merken.
- evtl. 1 focussiertes Control merken.
- Bitmap an Mainthread übergeben

Im Mainthread:
- Bitmap auf Canvas kopieren
- Maus- und Tastaturereignise an den "Control-Thread" übergeben

Im "Control-Thread":
- Maus- und Tatsaturereignisse verarbeiten und z.B. Control-Positionen ändern.
- wieder zeichnen


Das Formular ist in dem Fall nur eine Zeichenfläche und Eingabeschnittstelle.


Wenn Bei Dir von der Bedienung her grundsätzlich alles schon in einer Paintbox funktioniert (abgesehen vom Flackern) und Du mit Threads umgehen kannst, dann sollte sich das bei Dir auch so realisieren lassen.

Die Maus- und Tastaturereignisse habe ich in Ques an den Thread übergeben und das Bitmap dann einfach synchronisiert an den Mainthread.

skoschke 28. Aug 2019 12:30

AW: Wieder mal das leidige Thema "Flackern"
 
Hallo,

danke für die Hinweise, da kann ich schon mal ansetzen.
Ein Problem, was ich dabei aber habe, ist, dass ich sozusagen die Inhalte der zu bewegenden Panels brauche um sie in die Bitmap zu kopieren.
Die zu bewegenden Panels können Texte, Images, etc. enthalten, ich brauchte dabei dann eben einen "Screenshot der Panels"...

Hast Du noch dazu eine Idee?

Ciao
Stefan

stahli 28. Aug 2019 13:09

AW: Wieder mal das leidige Thema "Flackern"
 
Nein, leider nicht.

Wenn es JETZT läuft kannst Du da auch nicht sicher sein, dass es auf dem nächsten Windows oder mit dem nächsten Delphi noch läuft.

So eine Mischung kann halt immer Probleme machen weil Du nicht immer im Detail beeinflussen kannst, wann welche Teile vom System gezeichnet werden...


Aber warte mal....


Ich hatte da doch mal so etwas wie ein Raster....


Such mal in den 3 Threads nach "Raster"...
https://www.delphipraxis.net/184641-...e-basteln.html
https://www.delphipraxis.net/124761-...scrollbox.html
https://www.delphipraxis.net/109527-...-zeichnen.html

So hatte ich das bei mir umgesetzt:
https://youtu.be/BSNroTVq9FM?list=UU...Kph7r2dP3vtu_w

Ich hatte das damals so gelöst, weil es am flüssigsten war.
Details weiß ich aber nicht mehr.
Wenn Du Interesse hast, kann ich es mal raussuchen.

TiGü 28. Aug 2019 13:36

AW: Wieder mal das leidige Thema "Flackern"
 
Zitat:

Zitat von skoschke (Beitrag 1443666)

Siehe meine Antwort an Stahli, eigentlich möchte ich Controls flackerfrei bewegen können, der Umweg über die Paintbox war ein Ansatz das zu umgehen...

Ich verstehe immer nicht, warum es vielen so schwer fällt ein kleines Programm mit den minimal notwendigen Inhalten zu erstellen.
Kein Hexenwerk: File -> New -> VCL Forms Application
Dann die notwendigen Teile deines bisherigen Quelltextes reinkopieren, kompilieren, kurz testen, ob das Problem daran reproduziert werden kann und hochladen.

Das hätte dich schon viel weiter gebracht, anstatt dir den esoterischen Lösungsvorschlag von Stahli erläutern zu lassen.

skoschke 28. Aug 2019 13:48

AW: Wieder mal das leidige Thema "Flackern"
 
Wenn das mit dem kleinen Beispielprojekt so einfach wäre...

Im Original stecken etliche eigene Controls sowie Fremdkomponenten drin, da ein Miniprojekt basteln was Panels verschiebt, bringt mich da wenig weiter!
Und wenn ich es mit den Fremdkomponenten baue kann es niemand compilieren.

Das Projekt, bei dem es jetzt klemmt, ist reiner Source bereits 2MB groß!

Ciao
Stefan

TiGü 28. Aug 2019 14:03

AW: Wieder mal das leidige Thema "Flackern"
 
Aha, also flackern nicht die VCL-Standard-Controls wie Panel, Button, Label und Edit beim verschieben, sondern die externen Fremdkomponenten.
Ist das so richtig?

hoika 28. Aug 2019 15:42

AW: Wieder mal das leidige Thema "Flackern"
 
Hallo,
Zitat:

da ein Miniprojekt basteln was Panels verschiebt, bringt mich da wenig weiter!
Klar, wenn es flackert ...

Bei TeX hiess das auch immer: Minimal-Beispiel.

stahli 28. Aug 2019 15:55

AW: Wieder mal das leidige Thema "Flackern"
 
Zitat:

Zitat von TiGü (Beitrag 1443698)
Das hätte dich schon viel weiter gebracht, anstatt dir den esoterischen Lösungsvorschlag von Stahli erläutern zu lassen.

Es war ca. 2012/13, als ich das so umgesetzt hatte.
Details weiß ich jetzt so genau nicht mehr, aber es war nicht so einfach, Controls und Graphik drum herum nahtlos darzustellen.

Michael II 28. Aug 2019 23:13

AW: Wieder mal das leidige Thema "Flackern"
 
Wenn du das nicht mit FireMonkey programmieren willst/kannst, dann lade doch mal Graphics32 runter und verwende Layers.

Ein gutes Beispiel findest du unter:
Graphics32\Examples\Vcl\Layers\Sprites_Ex


Du kannst BitMaps (inkl. Transparenz, also ARGB) definieren, und die Z-Order festlegen.

Wenn du die Dinger dann rumschiebst, gibst du lediglich die neuen Koordinaten der Bitmaps an.

Das Ganze läuft ruckelfrei und schnell.

jziersch 30. Aug 2019 19:18

AW: Wieder mal das leidige Thema "Flackern"
 
Das Flackern kommt meist durch das löschen des Hintergrundes durch windows.
Wenn man die wmerasebk o.ae. message des hintergrund objektes bzw. Form abfängt kann man das Flackern verhindern.
Sorry, kann gerade kein Beispiel bauen

Uwe Raabe 30. Aug 2019 22:57

AW: Wieder mal das leidige Thema "Flackern"
 
Einfach mal probeweise diese Klassendeklaration vor das Form schreiben, in dem die Paintbox liegt.
Delphi-Quellcode:
type
  TPaintBox = class(Vcl.ExtCtrls.TPaintBox)
  private
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  end;
Die Implementierung ist relativ simpel.
Delphi-Quellcode:
procedure TPaintBox.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
  Message.Result := 1;
end;

jziersch 31. Aug 2019 08:09

AW: Wieder mal das leidige Thema "Flackern"
 
Bei der TPaintBox klappt das nicht. Das muss ein WinControl sein. Also am besten in dem TForm welches das unmittelbare parent der TPaintBox ist.

Uwe Raabe 31. Aug 2019 08:39

AW: Wieder mal das leidige Thema "Flackern"
 
Zitat:

Zitat von jziersch (Beitrag 1444090)
Bei der TPaintBox klappt das nicht. Das muss ein WinControl sein. Also am besten in dem TForm welches das unmittelbare parent der TPaintBox ist.

Richtig :thumb:

Hier mal ein Beispiel, wie es funktionieren könnte:

Delphi-Quellcode:
object Form448: TForm448
  Left = 0
  Top = 0
  Caption = 'Form448'
  ClientHeight = 299
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnResize = FormResize
  PixelsPerInch = 96
  TextHeight = 13
  object PaintBox1: TPaintBox
    Left = 0
    Top = 0
    Width = 635
    Height = 299
    Align = alClient
    OnMouseMove = PaintBox1MouseMove
    OnPaint = PaintBox1Paint
    ExplicitLeft = 137
    ExplicitTop = 80
    ExplicitWidth = 105
    ExplicitHeight = 105
  end
end
Delphi-Quellcode:
unit Unit448;

interface

uses
  Winapi.Windows, Winapi.Messages,
  System.Classes, System.SysUtils,
  Vcl.Forms, Vcl.Controls, Vcl.ExtCtrls, Vcl.Graphics;

type
  TForm448 = class(TForm)
    PaintBox1: TPaintBox;
    procedure FormResize(Sender: TObject);
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1Paint(Sender: TObject);
  private
    FBitmap: TBitmap;
    function GetBitmap: TBitmap;
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
  public
    destructor Destroy; override;
    property Bitmap: TBitmap read GetBitmap;
  end;

var
  Form448: TForm448;

implementation

{$R *.dfm}

destructor TForm448.Destroy;
begin
  FBitmap.Free;
  inherited Destroy;
end;

procedure TForm448.FormResize(Sender: TObject);
begin
  Bitmap.SetSize(ClientWidth, ClientHeight);
end;

function TForm448.GetBitmap: TBitmap;
begin
  if FBitmap = nil then begin
    FBitmap := TBitmap.Create;
  end;
  Result := FBitmap;
end;

procedure TForm448.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  Bitmap.Canvas.Brush.Color := clGray;
  Bitmap.Canvas.FillRect(Rect(0, 0, Width, Height));
  Bitmap.Canvas.TextOut(10, 10, FormatDateTime('c', Now));
  Bitmap.Canvas.MoveTo(0, Y);
  Bitmap.Canvas.LineTo(Width, Y);
  PaintBox1.Invalidate;
end;

procedure TForm448.PaintBox1Paint(Sender: TObject);
begin
  BitBlt(Paintbox1.Canvas.Handle, 0, 0, Bitmap.Width, Bitmap.Height, Bitmap.Canvas.Handle, 0, 0, SRCCOPY);
end;

procedure TForm448.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
  Message.Result := 1;
end;

end.

stahli 1. Sep 2019 11:30

AW: Wieder mal das leidige Thema "Flackern"
 
Hier mal ein aktueller Stand meines oben beschriebenen Konzeptes: https://www.delphipraxis.net/1444229-post60.html
Das Formular dient quasi nur als leere Zeichenfläche.
Dadurch brauche ich keine Synchronisation verschiedener Zeichenvorgänge, muss aber eben auch alles selbst zeichnen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:19 Uhr.

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