Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Für CopyRect passendes Ereignis? (https://www.delphipraxis.net/188019-fuer-copyrect-passendes-ereignis.html)

OrNEC 24. Jan 2016 20:27

Für CopyRect passendes Ereignis?
 
Hallo,

ich habe folgende Procedure (ohne Fehler):

Delphi-Quellcode:
procedure TMainForm.BackgroundToSpectrumImage();
var
  Quelle, Ziel: TRect;
begin
  Quelle := Rect(SpectrumBackgroundImage.Left{=13}, SpectrumBackgroundImage.Top{=112}, SpectrumBackgroundImage.Left + SpectrumBackgroundImage.Width{=42}, SpectrumBackgroundImage.Top + SpectrumBackgroundImage.Height{=184});
  Ziel := Rect(0, 0, SpectrumBackgroundImage.Width{=30}, SpectrumBackgroundImage.Height{=73});
  SpectrumBackgroundImage.Canvas.CopyRect(Ziel, MainBackgroundImage.Canvas, Quelle);
end;
Es wird also ein Stück Bild kopiert und in ein anderes gefüllt. Nun soll das sofort beim Start der Anwendung passieren, aber ich finde kein passendes Ereignis dafür. OnCreate, OnShow, OnPaint oder OnResize von Form1 bring da nichts, das Ziel wird schwarz.
MainBackgroundImagePictureChanged ruft einen Fehler aus... jah... bitte hier also um Hilfe.

P.S. ich programmiere mit Lazarus.

Medium 24. Jan 2016 20:49

AW: Für CopyRect passendes Ereignis?
 
"Sofort beim Start" heisst eigentlich OnCreate. Wann füllst du denn das Quellbild mit Inhalt? Das muss natürlich vor dem Umkopieren geschehen. Im Zweifel schickst du dir selbst halt eine Message von der Methode, die das Quellbild malt ans MainForm und reagierst darauf.

OrNEC 24. Jan 2016 21:16

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Medium (Beitrag 1328044)
"Sofort beim Start" heisst eigentlich OnCreate. Wann füllst du denn das Quellbild mit Inhalt? Das muss natürlich vor dem Umkopieren geschehen. Im Zweifel schickst du dir selbst halt eine Message von der Methode, die das Quellbild malt ans MainForm und reagierst darauf.

Das Quellbild habe ich im Entwurfsmodus eingefügt, im Objektinspektor. Weiß jetzt nicht wann genau Lazarus das füllt. Scheint so als ob das nach dem OnShow passiert (was eigentlich unlogisch ist).

Perlsau 24. Jan 2016 21:42

AW: Für CopyRect passendes Ereignis?
 
Was spricht dagegen, die bewußte Methode dann einfach am Ende von OnShow aufzurufen? Nach dem OnShow passiert erstmal nichts mehr, bis der Anwender oder sonstwert ein Ereignis auslöst. Was bringt dich zu der Annahme, daß das Bild erst nach OnShow aus der Ressourcendatei in das TImage geladen wird?

Sir Rufo 24. Jan 2016 21:45

AW: Für CopyRect passendes Ereignis?
 
In der Regel erfolgt das Malen im OnPaint Event.

Wenn man jetzt im OnPaint des MainBackgroundImages ein SpectrumBackgroundImage.Invalidate aufruft, sorgt man dafür, dass das neu gezeichnet wird.

Und im OnPaint des SpectrumBackgroundImage holt man sich das darunterliegende Bild.

Um die Koordinaten herauszufinden gibt es im Übrigen ClientToScreen und ScreenToClient Funktionen.
http://docwiki.embarcadero.com/Libra...ClientToScreen
(Sollte mit FPC analog funktionieren)

@Perlsau

Das Bild ist beim ersten OnShow schon geladen aber noch nicht gezeichnet, denn der Event kommt direkt vor dem Anzeigen.
Wenn man jetzt vom Canvas etwas kopiert, auf dem noch nichts gezeichnet wurde, dann kopiert man nichts ;)

Perlsau 24. Jan 2016 22:43

AW: Für CopyRect passendes Ereignis?
 
@Sir Rufo
Würde da nicht ein Application.ProcessMessages das Zeichnen des geladenen Bildes anstoßen? Und erst danach kopiert man.

Sir Rufo 24. Jan 2016 23:09

AW: Für CopyRect passendes Ereignis?
 
Nicht zwangsläufig. OnShow beschreibt die Transition der Visible Eigenschaft von False nach True.

Ich bin immer skeptisch bei Application.ProcessMessages und innerhalb eines (nicht von mir definiertem) Event sowieso. Das kann eben auch nach hinten losgehen, weil sich z.B. die Implementierung auf eine bestimmte Reihenfolge velässt und man die damit etwas durcheinander bringen kann. Zudem kann die Message zum Zeichnen der Form auch erst nach dem OnShow geschickt werden, dann bringt es nichts die Nachrichten-Warteschlange abzuarbeiten.

Die VCL-Form ist gesichert komplett gezeichnet beim ersten Application.OnIdle Event nach dem Form.OnShow Event.

Medium 25. Jan 2016 01:33

AW: Für CopyRect passendes Ereignis?
 
Der sauberste Weg wäre es in dem Fall doch, das Bitmap nicht über den Form-Designer zu laden, sondern es selbst in eine Ressource zu packen. Dann hat man den Ladezeitpunkt definitiv in der Hand, kann das im OnCreate erledigen, und direkt danach gut leserlich und nachvollziehbar die Kopie machen.

OrNEC 25. Jan 2016 10:32

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Medium (Beitrag 1328058)
Der sauberste Weg wäre es in dem Fall doch, das Bitmap nicht über den Form-Designer zu laden, sondern es selbst in eine Ressource zu packen. Dann hat man den Ladezeitpunkt definitiv in der Hand, kann das im OnCreate erledigen, und direkt danach gut leserlich und nachvollziehbar die Kopie machen.

Werden die Ressourcen in die MeineAnwendung.exe gepackt, oder muss man die Bilder separat im Verzeichnis mitliefern?

DeddyH 25. Jan 2016 11:33

AW: Für CopyRect passendes Ereignis?
 
Im Kompilat gibt es einen eigenen Ressourcen-Abschnitt, darin landen u.a. alle eingebundenen Bilder. Du musst sie also nicht extern mitliefern.

OrNEC 25. Jan 2016 13:37

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Perlsau (Beitrag 1328050)
Was bringt dich zu der Annahme, daß das Bild erst nach OnShow aus der Ressourcendatei in das TImage geladen wird?

Weil das Bild anscheinend in der OnShow noch nicht zur Verfügung steht.

OrNEC 25. Jan 2016 13:41

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Medium (Beitrag 1328058)
Der sauberste Weg wäre es in dem Fall doch, das Bitmap nicht über den Form-Designer zu laden, sondern es selbst in eine Ressource zu packen. Dann hat man den Ladezeitpunkt definitiv in der Hand, kann das im OnCreate erledigen, und direkt danach gut leserlich und nachvollziehbar die Kopie machen.

Klappt auch nicht. Mit dem Klick auf den Button schon...
Delphi-Quellcode:
procedure TForm1.FormShow(Sender: TObject);
var
  Quelle, Ziel: TRect;
begin
  Image1.Picture.LoadFromLazarusResource('bg');
  Image2.Picture.LoadFromLazarusResource('5ge');

  Quelle := Rect(0, 0, 100, 100);
  Ziel := Rect(0, 0, 100, 100);
  Image2.Canvas.CopyRect(Ziel, Image1.Canvas, Quelle);
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Quelle, Ziel: TRect;
begin
  Quelle := Rect(0, 0, 100, 100);
  Ziel := Rect(0, 0, 100, 100);
  Image2.Canvas.CopyRect(Ziel, Image1.Canvas, Quelle);
end;

DeddyH 25. Jan 2016 13:45

AW: Für CopyRect passendes Ereignis?
 
Was passiert denn, wenn Du auf den Button klickst und anschließend mal ein anderes Fenster über Deins legst?

Sir Rufo 25. Jan 2016 13:51

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von OrNEC (Beitrag 1328112)
Zitat:

Zitat von Perlsau (Beitrag 1328050)
Was bringt dich zu der Annahme, daß das Bild erst nach OnShow aus der Ressourcendatei in das TImage geladen wird?

Weil das Bild anscheinend in der OnShow noch nicht zur Verfügung steht.

Das eine hat mit dem anderen nicht zwangsläufig etwas zu tun und egal ist es sowieso.
  • Erst wird die Form sichbar gesetzt
  • dann kommt die Benachrichtigung
    Delphi-Quellcode:
    OnShow
  • dann wird gezeichnet
Da du auf das Gezeichnete zugreifen möchtest ist es also unerheblich ob das Image die Grafik schon geladen hat oder nicht. Die Grafik ist auf jeden Fall noch nicht gezeichnet, denn das erfolgt erst nach
Delphi-Quellcode:
OnShow
.

OrNEC 25. Jan 2016 13:53

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von DeddyH (Beitrag 1328114)
Was passiert denn, wenn Du auf den Button klickst und anschließend mal ein anderes Fenster über Deins legst?

Passiert nichts, das andere Fenster hat keinen Einfluss auf mein Fenster.

OrNEC 25. Jan 2016 13:56

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Sir Rufo (Beitrag 1328117)
Die Grafik ist auf jeden Fall noch nicht gezeichnet, denn das erfolgt erst nach
Delphi-Quellcode:
OnShow
.

Das war auch meine Vermutung... dann muss ich wohl mit Timer arbeiten, oder gibt da doch eine Lösung?

Luckie 25. Jan 2016 16:27

AW: Für CopyRect passendes Ereignis?
 
Im oder nach OnPaint?

OrNEC 25. Jan 2016 16:29

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Luckie (Beitrag 1328160)
Im oder nach OnPaint?

Im OnPaint hängt sich das Programm auf. Und was meinst mit nach OnPaint?

Luckie 25. Jan 2016 17:49

AW: Für CopyRect passendes Ereignis?
 
Guck mal hier http://www.delphigroups.info/2/71/97729.html letzter Beitrag.

Perlsau 25. Jan 2016 18:00

AW: Für CopyRect passendes Ereignis?
 
Oben hatte SirRufo doch einen Hinweis auf OnIdle geliefert:

Die VCL-Form ist gesichert komplett gezeichnet beim ersten Application.OnIdle Event nach dem Form.OnShow Event.

Ist dieser Hinweis denn nicht brauchbar? Könnte man denn nicht einfach in der OnIdle-Ereignisbehandlung eine globale Boolean-Variable, die als Schalter fungiert, abfragen, so daß die Anweisungen nur dieses eine Mal ausgeführt werden? Z.B. so:
Delphi-Quellcode:
...
  private
    Var
      FirstIdlePassed : Boolean;
  public
    procedure MyOnIdleHandler(Sender: TObject; var Done: Boolean);
  end;

procedure TForm1.MyOnIdleHandler(Sender: TObject; var Done: Boolean);
begin
  Done := False;
  If FirstIdlePassed Then Exit;

  FirstIdlePassed := True;
  ShowMessage('Das erste OnIdle-Event!');
  ...
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FirstIdlePassed := False;
  Application.OnIdle := MyOnIdleHandler;
end;
Nachtrag:
Ob das dann auch in Lazarus funktioniert, muß man gegebenenfalls ausprobieren ... Ach ja, bei Lazarus muß man das @ davor setzen:
Delphi-Quellcode:
Application.OnIdle := @MyOnIdleHandler;

OrNEC 26. Jan 2016 10:28

AW: Für CopyRect passendes Ereignis?
 
@Perlsau danke Dir... Application.OnIdle Event war mir noch nicht vertraut.

An sich funktioniert es auch, die ShowMessage wird ausgegeben, aber das Bild wird nicht kopiert.

Ich würde für noch ein Paar Ideen sehr dankbar...

Medium 26. Jan 2016 16:03

AW: Für CopyRect passendes Ereignis?
 
Wobei ist das Problem mit dem Laden aus einer Ressource?

OrNEC 26. Jan 2016 17:28

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Medium (Beitrag 1328307)
Wobei ist das Problem mit dem Laden aus einer Ressource?

Ich glaube nicht, die Bilder werden schön geladen und angezeigt, aber nicht kopiert, ich meine die CopyRect funkt nicht.

himitsu 26. Jan 2016 22:42

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von OrNEC (Beitrag 1328315)
ich meine die CopyRect funkt nicht.

Eher unwahrscheinlich.
Bleibt also zu 99,9995% ein Fehler in deinem Code. :stupid:

Image.Canvas ist die "sichtbare" Zeichenfläche und Image.Picture.Canvas?, Image.Picture.Graphics.Canvas oder z.B. Image.Picture.Bitmap.Canvas ist der Canvas des internen Bildes.
PS: Rate mal was TImage mit dem Canvas der Oberfläche macht, wenn es das WM_PAINT bekommt. :roll:

In neueren Windowsen hat man zwar oft den Vorteil, daß sich der DesktopWindowManager (DWM) dazwischen klemmt, aber normaler Weise ist der Canvas des Fensters (und allem darauf) flüchtig.

OrNEC 27. Jan 2016 09:51

AW: Für CopyRect passendes Ereignis?
 
Zitat:

Zitat von Luckie (Beitrag 1328174)
Guck mal hier http://www.delphigroups.info/2/71/97729.html letzter Beitrag.


Hier wird nicht das Image1 kopiert, sondern der Desktop noch bevor meine Anwendung starten. Kann also nach dem Start im Image2 die Icons sehen die auf meinem Desktop liegen.


Delphi-Quellcode:
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, Windows;

const
  MY_MESSAGE = WM_USER + 1;

type

  { TForm1 }

  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Label1: TLabel;
    procedure FormShow(Sender: TObject);
  private
    { private declarations }
    procedure MyMessage(Var MSG: TMessage); message MY_MESSAGE;
  public
    { public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormShow(Sender: TObject);
begin
  PostMessage(Self.Handle, MY_MESSAGE, 0, 0);
end;

procedure TForm1.MyMessage(var MSG: TMessage);
var
  Quelle, Ziel: TRect;
begin
  Label1.Caption := 'Luluu';
  Quelle := Classes.Rect(0, 0, 100, 100);
  Ziel := Classes.Rect(0, 0, 100, 100);
  Image2.Canvas.CopyRect(Ziel, Image1.Canvas, Quelle);
end;


end.

himitsu 27. Jan 2016 12:00

AW: Für CopyRect passendes Ereignis?
 
NOCHMAL zum MITLESEN.

Das Ändern des Labels löst ein Neuzeichnen dessen Canvas aus (TLabel und TImage haben aber kein eigenes Canvas, sondern leiten die Operationen an ihren Parent weiter)
Fazit: Die Form wird neu gezeichnet und schmeißt die Zeichenausgabe deines FEHLERHAFTEN Codes weg. (übermalt das wieder)

Label1.Caption:=... zeichnet nicht sofort, sondern verzögert, also nach deinem Code. (quasi PostMessage WM_PAINT)

Zitat:

Zitat von himitsu (Beitrag 1328339)
Image.Canvas ist die "sichtbare" Zeichenfläche und Image.Picture.Canvas?, Image.Picture.Graphics.Canvas oder z.B. Image.Picture.Bitmap.Canvas ist der Canvas des internen Bildes.
PS: Rate mal was TImage mit dem Canvas der Oberfläche macht, wenn es das WM_PAINT bekommt. :roll:

In neueren Windowsen hat man zwar oft den Vorteil, daß sich der DesktopWindowManager (DWM) dazwischen klemmt, aber normaler Weise ist der Canvas des Fensters (und allem darauf) flüchtig.

CopyRect funktioniert, aber du vergisst bei einem Repaint der Form deine Ausgabe wieder herzustellen, bzw. du arbeitest auf der falschen Arbeitsfläche!


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:57 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