AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

Ein Thema von hochundweit · begonnen am 22. Mär 2016 · letzter Beitrag vom 23. Mär 2016
Antwort Antwort
Seite 1 von 2  1 2   
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.356 Beiträge
 
Delphi 11 Alexandria
 
#1

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 11:59
Ich muss mal nachfragen:

Dein Screenshot beinhaltet 2000 Paintboxen und jede Paintbox stellt eine Farbe dar? Ein "Pixel" repräsentiert quasi einen Chip?

Dann haben die Kollegen schon eine sinnvolle Lösung genannt.
Erzeuge ein Bitmap, kopiere das auf den Canvas und verwalte "virtuell" in einem Array wo sich welches Rechteck mit welchen Informationen befindet.
Über Mousemove ermittelst Du, die Daten welches Rechteckes eingeblendet werden müssen.

In ähnlicher Form habe ich mal einen kleinen GUI-Test gebaut (Quellen habe ich aber nicht mehr).
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#2

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 12:24
Hier mal mein auf die Schnelle gebastelter Ansatz:
Delphi-Quellcode:
type
  TChipData = record
  public
    Quality: Integer;
    HasFocus: Boolean;
  end;

var
  ChipData: array[0..29] of array[0..29] of TChipData;
  FocusedChip: TPoint;

procedure TForm2.FormCreate(Sender: TObject);
var
  I, J: Integer;
begin
  FocusedChip := Point(-1, -1);
  // Generate random chip distribution and qualities
  Randomize;
  FillChar(ChipData, SizeOf(ChipData), #0);
  for I := Low(ChipData) to High(ChipData) do
  begin
    for J := Low(ChipData[I]) to High(ChipData[I]) do
    begin
      ChipData[I][J].Quality := Random(4);
    end;
  end;
end;

const
  CHIPSIZE = 12; // The width and height of a single chip rect in pixels

procedure TForm2.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
  CX, CY: Integer;
begin
  CX := X div CHIPSIZE;
  CY := Y div CHIPSIZE;
  if (CY <= High(ChipData)) and (CX <= High(ChipData[0])) then
  begin
    if (FocusedChip.X <> CX) or (FocusedChip.Y <> CY) then
    begin
      if (FocusedChip.X >= 0) and (FocusedChip.Y >= 0) then
      begin
        ChipData[FocusedChip.Y][FocusedChip.X].HasFocus := false;
        MouseLeave(FocusedChip.X, FocusedChip.Y);
        FocusedChip := Point(-1, -1);
      end;
      FocusedChip.X := CX;
      FocusedChip.Y := CY;
      ChipData[CY][CX].HasFocus := true;
      MouseEnter(CX, CY);
    end;
  end else if (FocusedChip.X >= 0) and (FocusedChip.Y >= 0) then
  begin
    ChipData[FocusedChip.Y][FocusedChip.X].HasFocus := false;
    MouseLeave(FocusedChip.X, FocusedChip.Y);
    FocusedChip := Point(-1, -1);
  end;
end;

procedure TForm2.FormPaint(Sender: TObject);
var
  X, Y: Integer;
  R: TRect;
begin
  Canvas.Brush.Color := Color;
  Canvas.FillRect(ClientRect);
  for Y := Low(ChipData) to High(ChipData) do
  begin
    for X := Low(ChipData[Y]) to High(ChipData[Y]) do
    begin
      case ChipData[Y][X].Quality of
        0: Canvas.Brush.Color := clWhite;
        1: Canvas.Brush.Color := clGreen;
        2: Canvas.Brush.Color := clBlue;
        3: Canvas.Brush.Color := clRed;
      end;
      R := Rect(X * CHIPSIZE, Y * CHIPSIZE, X * CHIPSIZE + CHIPSIZE,
        Y * CHIPSIZE + CHIPSIZE);
      Canvas.FillRect(R);
      if (ChipData[Y][X].HasFocus) then
      begin
        Canvas.TextRect(R, R.Left, R.Top, IntToStr(ChipData[Y][X].Quality));
      end;
    end;
  end;
end;

procedure TForm2.MouseEnter(CX, CY: Integer);
begin
  // This is a custom method! NOT the OnMouseEnter event of the form
  RepaintChip(CX, CY);
end;

procedure TForm2.MouseLeave(CX, CY: Integer);
begin
  // This is a custom method! NOT the OnMouseLeave event of the form
  RepaintChip(CX, CY);
end;

procedure TForm2.RepaintChip(CX, CY: Integer);
var
  R: TRect;
begin
  R := Rect(CX * CHIPSIZE, CY * CHIPSIZE, CX * CHIPSIZE + CHIPSIZE,
    CY * CHIPSIZE + CHIPSIZE);
  InvalidateRect(WindowHandle, R, false);
end;
Die Daten zu den einzelnen Chips befinden sich im 2-dimensionalen ChipData Array (ChipData[Y][X] erlaubt den Zugriff auf einen spezifischen Chip). Die Größe des Arrays ist zu testzwecken statisch, kann aber auch ohne Probleme dynamisch festgelegt werden.

Da du bei einem MouseEnter und MouseLeave neu zeichnen willst (Text anzeigen oder wieder entfernen), machen die Events momentan nichts weiter, als das OnPaint Event des Formulars neu auszulösen. Um Flackern zu vermeiden, benutze ich hierfür MSDN-Library durchsuchenInvalidateRect.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
hochundweit

Registriert seit: 9. Mär 2014
14 Beiträge
 
#3

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 12:44
Ich muss mal nachfragen:

Dein Screenshot beinhaltet 2000 Paintboxen und jede Paintbox stellt eine Farbe dar? Ein "Pixel" repräsentiert quasi einen Chip?
Ja, das ist korrekt.


Dann haben die Kollegen schon eine sinnvolle Lösung genannt.
Erzeuge ein Bitmap, kopiere das auf den Canvas und verwalte "virtuell" in einem Array wo sich welches Rechteck mit welchen Informationen befindet.
Über Mousemove ermittelst Du, die Daten welches Rechteckes eingeblendet werden müssen.
Das muss dann wohl so. Danke !
  Mit Zitat antworten Zitat
hochundweit

Registriert seit: 9. Mär 2014
14 Beiträge
 
#4

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 13:14
@Zacherl: wow, danke fuer den Einsatz, fertiger Code, womit habe ich das verdient. Wird sogleich ausprobiert !
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#5

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 13:21
Obwohl ich irgendwie das Gefühl habe, dass jeder Chip nicht als ein Pixel sondern als Fläche angezeigt werden soll.

Das Prinzip ist aber das Gleiche
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.399 Beiträge
 
Delphi 12 Athens
 
#6

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 13:26
Fertig ... naja

Statt in der Form das in eine TPaintBox.

Im Paint/OnPaint wird gezeichnet.
In einem Array stehen die Daten.
Und bei Datenänderung oder beim OnMouseEnter/OnMouseMove/OnMouseLeave wird ein Repaint ausgelöst.

Alternativ malt man auf ein TBitmap. die TPaintBox gibt im OnPaint das Bitmap aus und bei Änderungen am Bitmap wird anschließend das Repaint ausgelöst.
(Man kann auch ein TImage verwenden, was im Prinzip das Selbe macht, falls dich dessen negative Geschwindigkeit nicht stört)


1 Pixel: Sooo viele Chips sind selten auf einem Wafer und ich denk nicht, daß er den Wafer zu klein zeichnen will.

Ach ja, viele Grüße aus dem Silicon Saxony.
Ein Therapeut entspricht 1024 Gigapeut.

Geändert von himitsu (22. Mär 2016 um 13:31 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#7

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 13:34
Es macht auch Sinn, das in ein Control (sichtbare Komponente) zu packen.

Die dargestellten Items beinhalten dann nur die benötigten Daten für die Anzeige:
Delphi-Quellcode:
TFooItem = class
published
  property Color: TColor;
  property Text: string;
  property Hint: string;
end;
Das Control selber liefert einem das aktuell gewählte Item bzw. das Item, was sich unter der Maus befindet (was halt benötigt wird).

Um jetzt einen Chip anzuzeigen leitet man sich ein entsprechendes Item ab:
Delphi-Quellcode:
TChipItem = class( TFooItem )
...
end;
und befüllt intern die Eigenschaften.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
hochundweit

Registriert seit: 9. Mär 2014
14 Beiträge
 
#8

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 13:52
Gruesse zurueck nach Silicon Saxony !

In der Tat haben wir uebrigens wirklich so kleine "Nano-Gate" Chips, von denen 400.000 auf einen 8-Zoll Wafer passen.

Meist sind sie aber deutlich groesser, einige unserer AD-Converter haben einen Wafer-Count von knapp 500. Dagegen sind
die meisten CPU's schon Winzlinge....
  Mit Zitat antworten Zitat
Bentissimo

Registriert seit: 25. Apr 2006
Ort: Friedenfels
82 Beiträge
 
Delphi 11 Alexandria
 
#9

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 14:36
Ich hatte vor langer Zeit (Delphi 5) einen ähnlichen Anwendungsfall. Damals hatte ich für die Darstellung ein TGrid verwendet. Die Linien ausblenden und je nach Wafergrösse und Anzahl Chips Breite und Höhe der Spalten und Zeilen einstellen. Die Koordinaten erhältst Du damit praktisch automatisch geliefert.
Stephan Schmahl
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#10

AW: Auf's Neue: Performance bei vielen VCL Komponenten - anderer Ansatz ?

  Alt 22. Mär 2016, 15:40
Statt in der Form das in eine TPaintBox.
Hatte ich erst so, allerdings macht das keinen Unterschied, da die PaintBox sowieso nur auf das Canvas vom Parent (in diesem Falle das Form) zeichnet. Direkt das Form zu benutzen hat mir einen ClientToParent Aufruf vor dem MSDN-Library durchsuchenInvalidateRect erspart. Sinnvoll wäre höchstens die Kapselung in eine komplett eigene Komponente.

Im Paint/OnPaint wird gezeichnet.
In einem Array stehen die Daten.
Und bei Datenänderung oder beim OnMouseEnter/OnMouseMove/OnMouseLeave wird ein Repaint ausgelöst.
Die ersten beiden Punkte macht mein Beispielcode ja nicht anders. Full Repaint im OnMouseMove erzeugt massives Flackern (nur getestet mit DoubleBuffered = false, aber warum komplett neu zeichnen, wenn man nur die geänderten Bereiche aktualisieren muss?).

Wäre es Produktivcode, würde ich die Zeichen-Routinen definitiv in einer eigenen Komponente kapseln.

Des Weiteren sollte man eventuell noch Caching einbauen. MSDN-Library durchsuchenInvalidateRect clippt zwar den nicht geänderten Bereich (sorgt also dafür, dass unveränderte Teile nicht neu gezeichnet werden), die OnPaint Routine wird allerdings trotzdem komplett durchlaufen. Das komplette Zeichnen ist aber prinzipiell nur einmalig beim Start des Programms notwendig.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 09:48 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