So, ich hoffe es ist mir erlaubt diesen Thread einmal aus der Versenkung zu holen.
Ich habe das Problem mit dem Zittern nämlich lösen können, und möchte es gerne für die Nachwelt dokumentieren.
Also nochmal kurz:
Wenn mein selbsgezeichneter Fensterrahmen reskaliert wurde, laggte dieser etwas hinterher. Ich konnte mir da nie einen Reim drauf machen. Jetzt weiß ich woran es lag und wer schuld ist.
Wer ist Schuld? Microsoft
Was genau? DWM (Desktop Window Manager, stichwort Composition)
Das zuckeln tritt unter Windows7-Systemen auf(nicht bei allen, unter anderem wohl auch Treiberabhängig), undzwar aus folgendem Grund:
Nur weil etwas per
GDI gezeichnet wird, landet es nicht auch unbedingt sofort im Backbuffer für den DWM. Das bedeutet, dass dieser mitunter 1-2Frame alte Daten verarbeitet. Der updated den Backbuffer nämlich nur, wenn auch genug Pixeldaten vorhanden sind.
Also ist die Lösung, dem DWM das ganze einfach nochmals ins Gesicht zu hauen, als ob alle Pixel(oder sehr viele) neu/geändert wären.
Wie bekomm ich das nun hin?
Nicht ganz cpu-sparend, aber simpel:
Ich erstelle für meine Form einen TDirect2DCanvas. Und bevor ich im NCPaint oder WMPaint etwas mach(en lasse), rufe ich BeginDraw und danach EndDraw auf.
Dies sorgt dafür, dass die gesamte Formoberfläche rübergeschupst wird, und die Form rendert korrekt. Hiermal ein vergleichsvideo:
http://www.youtube.com/watch?v=vyQYidyRS_c
Über folgenden Entwickler aus dem FL-STudio Team(ebenfalls in Delphi Woot woot^^) bin ich auf diesen Hack gekommen:
http://stackoverflow.com/questions/1...-in-win7-8-gdi
Kurzfassung
Delphi-Quellcode:
unit Styles.Forms;
interface
uses
Classes, Types, Windows, Messages, Forms, Graphics, Direct2D;
type
TForm =
class(Forms.TForm)
private
FCanvas2D: TDirect2DCanvas;
procedure PaintNC(
var MSG: TWMNCPaint);
message WM_NCPAINT;
procedure WMPaint(
var MSG: TWMPaint);
message WM_PAINT;
public
constructor Create(AOwner: TComponent);
override;
end;
implementation
uses
uxTheme, Styles, Math;
{ TForm }
constructor TForm.Create(AOwner: TComponent);
begin
inherited;
FCanvas2D := TDirect2DCanvas.Create(
Handle);
end;
procedure TForm.PaintNC(
var MSG: TWMNCPaint);
begin
FCanvas2D.BeginDraw();
//paint NonClient-Stuff here
FCanvas2D.EndDraw;
end;
procedure TForm.WMPaint(
var MSG: TWMPaint);
begin
FCanvas2D.BeginDraw();
//we need to fill it with our background color as a Direct2D surface is black by default
FCanvas2D.Brush.Color := Color;
FCanvas2D.FillRect(Rect(0, 0, Width, Height));
inherited;
FCanvas2D.EndDraw;
end;
end.
Grüße
Memnarch