AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi TBitmap Grössenänderung langsam
Thema durchsuchen
Ansicht
Themen-Optionen

TBitmap Grössenänderung langsam

Offene Frage von "Bjoerk"
Ein Thema von toenne · begonnen am 15. Mär 2015 · letzter Beitrag vom 17. Mär 2015
Antwort Antwort
Seite 1 von 2  1 2      
toenne

Registriert seit: 13. Jan 2011
14 Beiträge
 
#1

TBitmap Grössenänderung langsam

  Alt 15. Mär 2015, 23:38
Ich hole mal ein bisschen aus um das Drumherum zu erklären:
Ich habe für den Töpferofen meiner Gattin eine Steuerung gebaut (AVR µC) welche die benötigten Temperaturkurven abfährt. Die jeweils aktuellen Mess- und Vorgabewerte werden sekündlich via RS232/BT rausgehauen und zunächst mittels einer kleinen Applikation auf meinem Laptop empfangen und in Textdateien geschrieben (jeweils eine für Ist-Temperatur, Soll-Temperatur, Schaltzustand des Steuerrelais, aktuelle Brennphase).
Das alles funzt prima, keine Probleme. Die Dateien umfassen dabei gut 30.000 Messwerte (so ein Brennvorgang dauert mehrere Stunden).

Ein weiteres Tool soll diese Daten dann später einlesen und grafisch darstellen, und da klemmt es.
Auf der Form liegt eine Scrollbox in Bildschirmbreite und z.B. 800px Höhe. Auf dieser Scrollbox liegt ein Image1 auf dessen Canvas die Brennkurve geschrieben wird. Zusätzlich gibts noch eine Scrollbar mit der ich die Ausgabe skalieren/stauchen kann, z.B. um die Brennkurve auch im Ganzen sehen zu können.
Auf der Scrollbox liegt ein weiteres Image2 mit der gleichen Grösse wie Image1, jedoch transparent.
Nachdem die Brennkurve gezeichnet wurde will ich ein Fadenkreuz (bzw. eine vertikale Linie) an der Mausposition einblenden um Messwerte an der Stelle lesen zu können (die werden in Labels eingeblendet, habe ich der Übersichtlichkeit halber im Code unten weggelassen).
Dazu erstelle ich ein transparentes TBitmap, setze es auf die gleiche Grösse wie Image1, zeichne an der Mausposition meine Linie, kopiere es mit image2.Picture.Bitmap.assign(Bmp) aufs Image2 und lösche das TBitmap wieder:

Delphi-Quellcode:
procedure TTempLogView.MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); // Aufruf über OnMouseMove von Image2
var bmp : tbitmap;
begin
  if mausflag = false then exit; // mausflag wird erst nach Zeichnen der Brennkurve auf TRUE gesetzt...quick&dirty, ich weiss...
  bmp := tbitmap.Create ;
  Bmp.Transparent := true;
  Bmp.TransparentColor := clwhite;
  Bmp.TransparentMode := tmFixed;
  bmp.canvas.pen.Color := clblue;

  bmp.Width := image1.Width; // z.B. 30000
  bmp.Height := image1.Height; // z.B. 800

  with bmp.Canvas do
  begin
   moveto(x,0);
   lineto(x,image1.Height);
  end;

  image2.Picture.Bitmap.assign(Bmp);

  FreeAndNil(bmp);
end;
Leider dauert die Änderung der Grösse des TBitmap sehr lange, geschätzt fast 1 Sekunde. Was natürlich bedeutet dass die Linie den Mausbewegungen nur sehr verzögert folgt.
Es ist definitiv die Grössenänderung die bremst, ich habe das durch ein Label getestet dass ich danach beschreibe und den Rest einfach auskommentiert, so dass ausser der Grössenänderung in der Prozedur nix passiert -> auch das Label wird mit dieser Verzögerung beschrieben, das kopieren aufs Image2 passiert z.B. blitzschnell. Und mache ich Image1 (und damit das TBitmap) mittels o.g. Scrollbar kleiner so wird die Ausgabe auch immer schneller, bis die Linie bei einem Image1 in Bildschirmbreite der Mausbewegung praktisch verzögerungsfrei folgt.
Das irritiert mich jetzt, wieso dauert die Grössenänderung so lange? Irgendeine Idee wie man das beschleunigen kann?

Danke & Gruss
Toenne


Achso, es handelt sich übrigens um XE5

Geändert von toenne (15. Mär 2015 um 23:41 Uhr)
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#2

AW: TBitmap Grössenänderung langsam

  Alt 15. Mär 2015, 23:44
Ich würde den Mauszeiger in Form des Fadenkreuzes nicht über ein zweites TImage darstellen, sondern direkt ins erste TImage malen. Dazu zeichnest du die gewünschten Linien im Modus XOR, wobei das Fadenkreuz dort, wo bereits etwas gezeichnet wurde, invertiert dargestellt wird. Zum Löschen des alten Fadenkreuzes vor dem Zeichnen des neuen, was ja nach jeder Positionsänderung der Maus nötig ist, zeichnest du das alte Fadenkreuz noch einmal mit XOR und danach das neue ebenfalls wieder mit XOR. Das geht wesentlich schneller als die Darstellung über ein zweites TImage.
  Mit Zitat antworten Zitat
toenne

Registriert seit: 13. Jan 2011
14 Beiträge
 
#3

AW: TBitmap Grössenänderung langsam

  Alt 15. Mär 2015, 23:50
Kann ich mal ausprobieren, danke .

Dennoch würde mich die Lösung für mein ursprüngliches Problem interessieren. Im Speicher ein Bitmap von meinetwegen 30000x800px anlegen sollte doch eigentlich ruckzuck gehen? Das kopieren dieses Bitmaps aufs Canvas von Image2 geht ja auch schlagartig.
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#4

AW: TBitmap Grössenänderung langsam

  Alt 15. Mär 2015, 23:54
Im Zweifelsfall steckt hinter jeder Größenänderung eine Speicherallokation, einmal umkopieren und dann den alten Speicher freigeben. Das kann dauern, auch wenn eine Sekunde seehr lange wäre.

Im Prinzip kannst du deine Bitmap-Instanz wiederverwenden und nur dessen Größe ändern, wenn sich sich die Größe von image2 geändert hat.
  Mit Zitat antworten Zitat
toenne

Registriert seit: 13. Jan 2011
14 Beiträge
 
#5

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 00:09
Im Prinzip kannst du deine Bitmap-Instanz wiederverwenden und nur dessen Größe ändern, wenn sich sich die Größe von image2 geändert hat.
Dann bräuchte ich noch einen Trick wie ich den Inhalt des TBitmap wieder löschen könnte (*), ansonsten bleiben ja die Linien erhalten.
Das einfachste wäre es ja die Höhe und Breite dafür auf Null zu setzen...nur stehe ich dann wieder da wo ich jetzt bin, nämlich dass die Änderung auf die richtige Grösse für die nächste Linie wieder so lange dauert. Deswegen bin ich dazu übergegangen gleich 'Nägel mit Köpfen' zu machen und das TBitmap jeweils neu zu erstellen und anschliessend wieder komplett zu löschen. Macht von der Performance keinen Unterschied, die Grössenänderung ist das Problem.

(*) Hmm, vielleicht das TBitmap komplett mit einem weissen Rechteck füllen? Weiss = transparent, könnte ich auch mal probieren.
Heute aber nicht mehr, mein Bett ruft .

Bis hierhin erstmal Danke...lasst euch aber nicht abhalten weitere Tips zu posten.
Vielleicht will ja auch jemand das Verhalten einfach mal nachstellen?

Gruss
Toenne
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#6

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 01:53
Kann ich mal ausprobieren, danke .
Dennoch würde mich die Lösung für mein ursprüngliches Problem interessieren. Im Speicher ein Bitmap von meinetwegen 30000x800px anlegen sollte doch eigentlich ruckzuck gehen? Das kopieren dieses Bitmaps aufs Canvas von Image2 geht ja auch schlagartig.
Die Indianergeschichte mit dem toten Pferd kennst du, oder?

Wenn du den Aufwand, den du jetzt treibst, zu den Schwierigkeiten, die dein derzeitiges Konzept bereitet, dazuzählst, scheint mir der Aufwand mit dem einfachen Zeichnen des Fadenkreuzes im Vergleich dazu minimal. Übrigens machen Zeichenprogramme das auch nicht anders, wenn z.B. interaktiv eine Ellipse gezeichnet werden soll, wobei Größe und Breite der Ellipse den Bewegungen des Mauszeigers folgen. Vergleiche doch einmal, wieviele Pixel rumgeschaufelt werden müssen, um ein Fadenkreuz zu zeichnen, mit der Anzahl der Pixel, die bewegt werden müssen, um das komplette Bitmap zu kopieren. Offensichtlich ist Letzteres zu langsam, um einen flüssigen Ablauf zu gewährleisten.

Sollte das Motiv deiner Ablehnung meines Vorschlags darin liegen, daß du nicht weißt, wie man das Fadenkreuz dynamisch den Größenverhältnissen des Bitmaps anpaßt, helfe ich dir dabei gerne weiter.
  Mit Zitat antworten Zitat
toenne

Registriert seit: 13. Jan 2011
14 Beiträge
 
#7

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 20:22
Wieso Ablehnung? Ich habe doch gesagt ich probiere es aus. Und habe es auch gemacht: Funzt 1A, erwartungsgemäss.
Man muss halt nur daran denken in der OnChange-Routine der Scrollbar das alte Kreuz zu löschen und im nächsten OnMouseMove das Kreuz eben dann nicht zu löschen, dann ist alles gut. Nur übersichtlicher wird der Code dadurch natürlich auch nicht unbedingt...

Ich bin halt nach wie vor verblüfft wie lange die Grössenänderung des TBitmap dauert derweil das image2.Picture.Bitmap.assign(Bmp) ratzfatz geht. Vermutlich wird in letzterem Fall gar keine Datenmenge bewegt sondern lediglich ein Vektor auf den Speicherbereich des TBitmaps umgeleitet?
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.537 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 21:23
Also ich kann hier die Zeitdauer von 1 Sekunde nicht nachvollziehen.
Habe Deinen Code hier mal getestet, die beiden Zuweisungen für das Bitmap (Breite und Höhe) zusammen benötigen 0,72 ms, das ist weit entfernt von 1 Sekunde.

Man kann das aber noch etwas beschleunigen, mit

bmp.SetSize (Image1.width, Image1.height);

dauert es nur 0,58 ms.

Auf einem 7 Jahre alten PC getestet.

Geändert von Harry Stahl (16. Mär 2015 um 21:51 Uhr)
  Mit Zitat antworten Zitat
Perlsau
(Gast)

n/a Beiträge
 
#9

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 21:29
Wieso Ablehnung? Ich habe doch gesagt ich probiere es aus. Und habe es auch gemacht: Funzt 1A, erwartungsgemäss.
Okay, das mit der Ablehnung war nicht so gemeint, wie du es vielleicht verstanden hattest. Ich hatte den nächsten Satz so interpretiert, daß du dennoch bei deiner alten Methode bleiben möchtest.

Man muss halt nur daran denken in der OnChange-Routine der Scrollbar das alte Kreuz zu löschen und im nächsten OnMouseMove das Kreuz eben dann nicht zu löschen, dann ist alles gut. Nur übersichtlicher wird der Code dadurch natürlich auch nicht unbedingt...
Auch mit deiner Methode muß man auf OnChange reagieren. Wenn du beim nächsten MouseMove das Kreuz nicht löschst, sondern ein zweites zeichnest, hast du danach zwei Kreuze in deinem Bitmap. Du mußt dir aber auf jeden Fall in MouseMove die Mausposition merken, um das letzte Kreuz korrekt löschen sprich mit XOR übermalen zu können.

Ich bin halt nach wie vor verblüfft wie lange die Grössenänderung des TBitmap dauert derweil das image2.Picture.Bitmap.assign(Bmp) ratzfatz geht. Vermutlich wird in letzterem Fall gar keine Datenmenge bewegt sondern lediglich ein Vektor auf den Speicherbereich des TBitmaps umgeleitet?
Assign weist in der Tat lediglich einen Pointer zu, da der Speicherbereich, auf den der Quell-Pointer verweist, ja bereits existiert.
  Mit Zitat antworten Zitat
Bjoerk

Registriert seit: 28. Feb 2011
Ort: Mannheim
1.384 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: TBitmap Grössenänderung langsam

  Alt 16. Mär 2015, 22:17
Kann da auch keine Verzögerung feststellen?

Beispiel:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    ScrollBox1: TScrollBox;
    PaintBox1: TPaintBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure PaintBox1Paint(Sender: TObject);
    procedure PaintBox1MouseEnter(Sender: TObject);
    procedure PaintBox1MouseLeave(Sender: TObject);
  private
    FGraphic: TBitmap;
    FP: TPoint;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  FGraphic := TBitmap.Create;
  PaintBox1.Left := 0;
  PaintBox1.Top := 0;
  PaintBox1.Align := alNone;
  PaintBox1.Width := 3000;
  PaintBox1.Height := 3000;
  FGraphic.Width := PaintBox1.Width;
  FGraphic.Height :=PaintBox1.Height;
  ScrollBox1.DoubleBuffered := true;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FGraphic.Free;
end;

procedure TForm1.PaintBox1MouseEnter(Sender: TObject);
begin
  ShowCursor(false);
end;

procedure TForm1.PaintBox1MouseLeave(Sender: TObject);
begin
  ShowCursor(true);
end;

procedure TForm1.PaintBox1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  FP := Point(X, Y);
  PaintBox1.Invalidate;
end;

procedure TForm1.PaintBox1Paint(Sender: TObject);
begin
  PaintBox1.Canvas.Draw(0, 0, FGraphic);
  PaintBox1.Canvas.MoveTo(FP.X, 0);
  PaintBox1.Canvas.LineTo(FP.X, PaintBox1.Height);
  PaintBox1.Canvas.MoveTo(0, FP.Y);
  PaintBox1.Canvas.LineTo (PaintBox1.Width, FP.Y);
end;

end.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      

 

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 11:44 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