Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Das geheimnissvolle Controll (https://www.delphipraxis.net/198555-das-geheimnissvolle-controll.html)

Delbor 13. Nov 2018 17:52

Delphi-Version: 10.2 Tokyo

Das geheimnissvolle Controll
 
Hi zusammen

In einer Scrollbox möchte ich mehrere Instanzen eines TCustumControl-Nachfahhren platzieren. Dieses versuchen ich in einer Testanwendung so:

Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i: integer;
begin
  for i := 0 to 4 do
  begin
    FPDFView := TPdfView.Create(Self);
    FPdfView.Parent := Scrollbox1;
    FPdfView.Name := 'PdfView'+intToStr(i);
    FPdfView.Color := clyellow;
    FPdfView.Height := 120;
    FPdfView.Top := i * (FPdfView.Height + 8);
    FPdfView.Width := Scrollbox1.ClientWidth - 40;
    FPdfView.Left := (ScrollBox1.ClientWidth - FPdfView.Width) div 2;
    ScrollBox1.VertScrollBar.Range := ScrollBox1.VertScrollBar.Range + FPdfView.Height;
  end;
end;
Der Aufruf:
Delphi-Quellcode:
procedure TRSPdfFrame.ScrollBox1Resize(Sender: TObject);
begin
  PdfViewCreate;
  FReportlist.Add('ScrollBox1Resiz')
end;
Der Inhalt von FReportlist wird bei Programmende in eine Datei geschrieben. Deren Inhalt:
Delphi-Quellcode:
13.11.2018 17:32:28
----------------
ScrollBox1Resiz
Meine Fehlermeldung:

Zitat:

Benachrichtigung über Debugger-Exception
---------------------------
Im Projekt HomeOfficerMainProject.exe ist eine Exception der Klasse EComponentError mit der Meldung 'Komponente mit der Bezeichnung PdfView0 existiert bereits' aufgetreten.
---------------------------
Die DCUs und die EXE habe ich schon mehrmals gelöscht.
Was ist da falsch?

Gruss
Delbor

Schokohase 13. Nov 2018 17:56

AW: Das geheimnissvolle Controll
 
Führe doch bitte mal diese Änderungen aus
Delphi-Quellcode:
procedure TRSPdfFrame.ScrollBox1Resize(Sender: TObject);
begin
  FReportlist.Add('ScrollBox1Resiz ENTER');
  PdfViewCreate;
  FReportlist.Add('ScrollBox1Resiz EXIT');
end;
und zeige uns dann den Inhalt der Datei

Hobbycoder 13. Nov 2018 17:58

AW: Das geheimnissvolle Controll
 
Naja, du läßt bei jedem Resize TRSPdfFrame.PdfViewCreate durchlaufen. Und erzeugst nur. Demnach ist beim zweiten Resize ein Control mit dem Namen auch bereits vorhanden.

Wenn's anders nicht geht, sollte du die bereits erzeugten Controls vorher entfernen.
Besser wäre es natürlich im Resize auch die Controls in ihrer Größe zu ändern, als sie zu löschen und neu zu erzeugen.

DeddyH 13. Nov 2018 18:05

AW: Das geheimnissvolle Controll
 
Man muss übrigens beim dynamischen Erzeugen von Controls keinen Namen zuweisen.

Schokohase 13. Nov 2018 18:09

AW: Das geheimnissvolle Controll
 
Zitat:

Zitat von Hobbycoder (Beitrag 1417987)
Naja, du läßt bei jedem Resize TRSPdfFrame.PdfViewCreate durchlaufen. Und erzeugst nur. Demnach ist beim zweiten Resize ein Control mit dem Namen auch bereits vorhanden.

Ich wette das weiß er, aber diese "Log-Datei" hat ihn in die Irre geführt, weil er denkt, dass die Methode
Delphi-Quellcode:
TRSPdfFrame.ScrollBox1Resize
nur einmal ausgeführt wird.

Delbor 13. Nov 2018 18:21

AW: Das geheimnissvolle Controll
 
Hi Schokohase

Danke für deine schnelle Antwort!
Tja, das ist doch schon sehr speziell - wenigstens für mich im Moment:
Zitat:

13.11.2018 18:02:00
----------------
ScrollBox1Resiz ENTER
ScrollBox1Resiz ENTER
ScrollBox1Resiz EXIT
So der Dateiinhalt, und so der aktuelle Code:
Delphi-Quellcode:
procedure TRSPdfFrame.ScrollBox1Resize(Sender: TObject);
begin
//  FReportlist.Add('ScrollBox1Resiz')
  FReportlist.Add('ScrollBox1Resiz ENTER');
  PdfViewCreate;
  FReportlist.Add('ScrollBox1Resiz EXIT');
end;
Dass der Frame vor der Mainform erzeugt wird, ist mir schon klar, aber dass sich ein Ereignis widerholt, noch bevor es zu Ende ist...

Oder was verstehe ich jetzt falsch?

Okay, ich hab vor dem Anzeige der Vorschau die weiteren Beiträge gesehen und kann da nur mal bestätigen: Ja, ich weiss, der Anwender will die Form eventuell mehrmals resizen - ich muss das also kontrollieren.
Zur Zeit läüft der Test, wie ich die Dinger korrekt untereinander bringe. Das Stimmt insofern noch nicht, als dass die Form zu klein ist, um den gesammten Clientbereich der Scrollbox anzuzeigen. Mit dem Feler im Fokus hat mich die Sache mit dem Resize doch auf dem falschen Fuss erwischt.


Gruss
Delbor

Delphi.Narium 13. Nov 2018 18:31

AW: Das geheimnissvolle Controll
 
Das Erstellen der Controls gehört nicht ins Resize. Resize ist für Größenänderungen (wie der Name schon sagt).

Die Controls werden einmalig erstellt (z. B. im FormCreate oder einer daraus aufgerufenen Methode).

Hobbycoder 13. Nov 2018 18:33

AW: Das geheimnissvolle Controll
 
Zitat:

Zitat von Schokohase (Beitrag 1417989)
Ich wette das weiß er

Da war ich jetzt auch mal von ausgegangen. Aber manchmal......nach einem langen Arbeitstag...… :-D

Delbor 13. Nov 2018 18:47

AW: Das geheimnissvolle Controll
 
Hi zusammen

Zitat:

Zitat von DeddyH (Beitrag 1417988)
Man muss übrigens beim dynamischen Erzeugen von Controls keinen Namen zuweisen.

Ich werde später darauf zugreifen müssen - Okay, da täte es auch das Tag-Property.

Zitat:

Zitat von Schokohase (Beitrag 1417989)
Zitat:

Zitat von Hobbycoder (Beitrag 1417987)
Naja, du läßt bei jedem Resize TRSPdfFrame.PdfViewCreate durchlaufen. Und erzeugst nur. Demnach ist beim zweiten Resize ein Control mit dem Namen auch bereits vorhanden.

Ich wette das weiß er, aber diese "Log-Datei" hat ihn in die Irre geführt, weil er denkt, dass die Methode
Delphi-Quellcode:
TRSPdfFrame.ScrollBox1Resize
nur einmal ausgeführt wird.

Das heisst, dass es die Kontrolle auch dann braucht, wenn die Form nur in einer einzigen Gösse angezeigt wird.
Wie ist das denn mit dem Resize? Da ist mal der Basisframe - aber braucht der ein Resize? Der wird ja nie angezeigt.
Auf der Form habe ich gerade mal eine Frameinstanz - wäre nach meinem bisherigen Stand des Irrtums gerade mal ein Resize-Ereignis.

Anders sähe es wohl aus, wenn das Resize des Frames nach jedem Resize auf der Containerform aufgerufen würde - grundsätzlich könnte nach jedem Resize eines andern Elementes eine Anpssung nötig sein. Meine Frage hier wäre also: lösen Resize-Events anderer Elemente ein erneutes Resize aus?

Zitat:

Zitat von Hobbycoder (Beitrag 1418000)
Da war ich jetzt auch mal von ausgegangen. Aber manchmal......nach einem langen Arbeitstag...… :-D

Ich bin in Rente. Das heisst, zumindest jetzt nicht übermüdet.


Gruss
Delbor

Delbor 13. Nov 2018 19:39

AW: Das geheimnissvolle Controll
 
Hi Delphi.Narium

Zitat:

Zitat von Delphi.Narium (Beitrag 1417999)
Das Erstellen der Controls gehört nicht ins Resize. Resize ist für Größenänderungen (wie der Name schon sagt).

Die Controls werden einmalig erstellt (z. B. im FormCreate oder einer daraus aufgerufenen Methode).

Anfänglich rief ich die PdfCreate-Proedur aus dem Constructor des Frames auf - mit dem Resultat, das sämtlche Elemente übereinander erstellt wurden. Ist ja auch kein Wunder - zu dem Zeitpunkt gibts noch keine Form und eine Höhe eines Elements dieser Form schon gar nicht.
Ein Create oder sonst was(Activate, Show) kennt der Frame auch nicht. Wann also sollen diese Controls erzeugt werden?
Für den Produktiveinsatz stellt sich dieses Problem allerdings wohl nicht - hier ist dies Aufgabe zum Beispiel eines Eventhandlers, der auf das Öffnen einer Datei reagiert...

Gruss
Delbor

Delphi.Narium 13. Nov 2018 21:11

AW: Das geheimnissvolle Controll
 
ungetestet sowas in der Art?
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i: integer;
  myCompo : TComponent;
begin
  for i := 0 to 4 do
  begin
    myCompo := ScrollBox1.FindComponent('PdfView'+intToStr(i));
    if not Assigned(myCompo) then
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := 'PdfView'+intToStr(i);
      FPdfView.Color := clyellow;
    end
    else
    begin
      FPdfView := TPdfView(myCompo);
    end;
    FPdfView.Height := 120;
    FPdfView.Top := i * (FPdfView.Height + 8);
    FPdfView.Width := Scrollbox1.ClientWidth - 40;
    FPdfView.Left := (ScrollBox1.ClientWidth - FPdfView.Width) div 2;
    ScrollBox1.VertScrollBar.Range := ScrollBox1.VertScrollBar.Range + FPdfView.Height;
  end;
end;

Delbor 14. Nov 2018 14:40

AW: Das geheimnissvolle Controll
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi Delphi.Narium

Vielen Dank für dein Beispiel! Ich hab das allerdings etwas anders umgesetzt. Auf der Mainform hab ich einen Buton platziert:
Delphi-Quellcode:
procedure THomeOfficerMainForm.BitBtn1Click(Sender: TObject);
begin
  RSPdfContentFrame1.RSPdfFrame1.PdfViewCreate;
  Edit1.Text := 'Es wurden ' + IntToStr(Self.RSPdfContentFrame1.RSPdfFrame1.PdfList.Count);
end;
Auslöser ist schlussendlich das Öffnen eines PDFs, dessen Seiten jeweilsden Controls zugewiesen werden - für den Test geügt mir vorerst aber der Aufruf von PdfViewCreate. Da gehts dann so weiter:
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i: integer;
begin
  if FPdfList.Count = 0 then
  begin
    for i := 0 to 4 do
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := 'PdfView'+intToStr(i);
      FPdfView.Color := clyellow;
      FPdfView.Height := 120;
      FPdfView.Top := i * (FPdfView.Height + 8);
      FPdfView.Width := Scrollbox1.ClientWidth - 40;
      FPdfView.Left := (ScrollBox1.ClientWidth - FPdfView.Width) div 2;
      ScrollBox1.VertScrollBar.Range := ScrollBox1.VertScrollBar.Range + FPdfView.Height;
      FPdfList.Add(FPdfView);
     end;
  end
  else
    Showmessage('Die Seiten sind bereits vorhanden');
end;
FPdfList ist eine generische Objectliste. die - zumindest hier - bei Programmstart erzeugt und bei Ende zerstört wird. Interessant ist: Laut Help ist das Property OwnsObject dieser Liste per Voreinstellung True. Bevor ich das allerdings explizit zugewiesen hatte, erhielt ich immer bei Programmende eine Meldung. Die war zwar so schnell wieder weg, dass ich sie gar nicht lesen konnte.
Nach der Zuweisung war die Fehlermeldung weg...

Seltsam ist allerdings, dass nun die beiden letzten Controls weniger breit gezeichnet werden als die ersten drei. Im Anhang zeigt ein jpeg, wies zur Zeit aussieht.

Links von der Scrollbox mit den Controls befindet sich ein Splitter und eine weitere Scrollbox. Diese soll alle Seiten (teilweise im nichtsichtbaren Bereich) in Thumbnailgrösse entalten - standardmässig untereinander. Doch durch bewegen des Splitters soll diese Scrollbox die Thumbnails auch nebeneinander anzeigen können. Eine Herausforderung dürfte aber das Entwicklen eines entsprechenden Algorrytmus sein. Über Denkanstösse dazu würde ich mich freuen!


Gruss
Delbor

Delphi.Narium 14. Nov 2018 15:31

AW: Das geheimnissvolle Controll
 
Seltsam ist an der unterschiedlichen Breite garnichts.

Bis zum 3. Control wird keine Scrollbar benötigt, ab dem 4. aber schon, damit ändern sich automatisch ein paar Werte, die bei der Breitenberechnung berücksichtigt werden.

Einfachste Methode zur Lösung: Scrollbar immer anzeigen, auch wenn sie nicht benötigt wird, dann ändert sich der Wert von Scrollbox1.ClientWidth auch nicht und bei der Berechnung kommt immer der gleiche Wert raus.

Oder eventuell:
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var
  i : integer;
  iCount : Integer;
  iLeft : Integer;
  iHeight : Integer;
  iTop : Integer;
  iWidth : Integer;
begin
  if FPdfList.Count = 0 then
  begin
    iCount := 5; // Statt 0 bis 4 - 1 bis 5, damit kann man später besser weiterrechnen.
    iLeft := (ScrollBox1.ClientWidth - iWidth) div 2;
    iHeight := 120;
    iTop := iHeight + 8;
    iWidth := Scrollbox1.ClientWidth - 40;
    for i := 1 to iCount do
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := Format('PdfView%d',[i]);
      FPdfView.Color := clyellow;
      FPdfView.Height := iHeigth;
      FPdfView.Top := i * iTop;
      FPdfView.Width := iWidth;
      FPdfView.Left := iLeft;
      FPdfList.Add(FPdfView);
     end;
     ScrollBox1.VertScrollBar.Range := iCount * iHeight;
  end
  else
    Showmessage('Die Seiten sind bereits vorhanden');
end;
Und wenn man die hier im Quelltext zugewiesenen "Konstanten" als Parameter in den Aufruf von Create "verschiebt", kann man, ohne die Methode nochmal anfassen zu müssen, die Zahl der FPdfView in der Scrollbox variieren, deren Breite, Höhe und ggfls. deren "Oberkante" (Top) verändern ... Dies könnte man aber auch als Attribute der Klasse TRSPdfFrame realisieren.

DeddyH 14. Nov 2018 15:52

AW: Das geheimnissvolle Controll
 
Übersehe ich etwas, oder könnte man nicht auch einfach jeweils Align auf alTop setzen, dann spart man sich die ganze Rechnerei?

Delphi.Narium 14. Nov 2018 16:10

AW: Das geheimnissvolle Controll
 
Dann hat man aber keine 8 Pixel Abstand zwischen den einzelnen TPdfView ;-)

bcvs 14. Nov 2018 16:25

AW: Das geheimnissvolle Controll
 
Zitat:

Zitat von Delphi.Narium (Beitrag 1418083)
Dann hat man aber keine 8 Pixel Abstand zwischen den einzelnen TPdfView ;-)

Dann setzt man halt AlignWithMargins auf true und Margins.Top auf 8

Hobbycoder 14. Nov 2018 16:28

AW: Das geheimnissvolle Controll
 
Oder man rechnet bei der Breitenberechnung die Breite der Scollbar immer mit ein, auch wenn sie nicht angezeigt wird. Dann hätte man zwar einen breiteren rechten Rand, wenn die Scrollbar nicht angezeigt wird, aber es passt dann auch wenn sie angezeigt wird. Und alle PDFView's wären gleiche breit.

Delbor 14. Nov 2018 20:35

AW: Das geheimnissvolle Controll
 
Hi zusammen

Ich hab nun Delphi.Nariums Vorschlag mal umgesetzt. Allerdings habe ich lange nach einer Möglichkeit gesucht, die VertScrollbars standartmässig anzuzeigen - das hier hat mir dann wohl geholfen (Beitrag 3):
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i, iCount, iLeft, iHeight,
      iTop, iWidth : Integer;
begin
  if FPdfList.Count = 0 then
  begin
    iCount := 5; // Statt 0 bis 4 - 1 bis 5, damit kann man später besser weiterrechnen.
    iLeft := (ScrollBox1.ClientWidth - iWidth) div 2;
    iHeight := 120;
    iTop := iHeight + 8;  // Sehe allerdings gerade, dass dies falsch ist; danach ist das erste Top 128 statt 8
    iWidth := Scrollbox1.ClientWidth - 40;
    Scrollbox1.AutoScroll := False;
    Scrollbox1.VertScrollBar.Range := iTop * ICount;
    for i := 1 to 5 do
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := 'PdfView'+intToStr(i);
      FPdfView.Color := clyellow;

      FPdfView.Height := iHeight;
      FPdfView.Top := (i-1) * iTop;
      FPdfView.Width := iWidth;
      FPdfView.Left := iLeft;
      FPdfView.Visible := true;
//      ScrollBox1.VertScrollBar.Range := ScrollBox1.VertScrollBar.Range + FPdfView.Height;
      FPdfList.Add(FPdfView);
     end;
  end
  else
    Showmessage('Die Seiten sind bereits vorhanden');
end;
Leider wird mir keines der FPdfView angezeigt.

Der Vorschlag, mit den Margins zu arbeiten, gefällt mir irgendwie doch recht gut - sollen 2 oder mehrere Controls nebeneinander stehen, ist der notwendige Algorhytmus wohl sehr viel einfacher und übersichtlicher.

Gruss
Delbor

Delbor 14. Nov 2018 21:13

AW: Das geheimnissvolle Controll
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi zusammen

Nachdem ich die Wertzuweisungen an Left & Co wieder zurückgestellt habe (inkusive des Bereichs 0 bis 4) sieht das ganze so aus:
Anhang 50249
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i, iCount, iLeft, iHeight,
      iTop, iWidth : Integer;
begin
  if FPdfList.Count = 0 then
  begin
    iCount := 5; // Statt 0 bis 4 - 1 bis 5, damit kann man später besser weiterrechnen.
    iLeft := (ScrollBox1.ClientWidth - iWidth) div 2;
    iHeight := 120;
    iTop := iHeight + 8;
    iWidth := Scrollbox1.ClientWidth - 40;
    Scrollbox1.AutoScroll := False;
    Scrollbox1.VertScrollBar.Range := iTop * ICount;
    for i := 0 to 4 do
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := 'PdfView'+intToStr(i);
      FPdfView.Color := clyellow;

      FPdfView.Height := 120; //iHeight;
      FPdfView.Top := i * (FPdfView.Height + 8);
      FPdfView.Width := Scrollbox1.ClientWidth - 40;
      FPdfView.Left := (ScrollBox1.ClientWidth - FPdfView.Width) div 2;;
      FPdfView.Visible := true;
      FPdfList.Add(FPdfView);
     end;
  end
  else
    Showmessage('Die Seiten sind bereits vorhanden');
end;
Wieso mir allerdings unter Verwendung der i-Variablen nichts angrzeigt wirde, ist mir Schleierhaft...

Gruss
Delbor

Delbor 14. Nov 2018 21:20

AW: Das geheimnissvolle Controll
 
Hi zusammen

Nachdem ich die Wertzuweisungen an Left & Co wieder zurückgestellt habe (inkusive des Bereichs 0 bis 4) sieht das ganze so aus:
Anhang 50249
Delphi-Quellcode:
procedure TRSPdfFrame.PdfViewCreate;
  var i, iCount, iLeft, iHeight,
      iTop, iWidth : Integer;
begin
  if FPdfList.Count = 0 then
  begin
    iCount := 5; // Statt 0 bis 4 - 1 bis 5, damit kann man später besser weiterrechnen.
    iLeft := (ScrollBox1.ClientWidth - iWidth) div 2;
    iHeight := 120;
    iTop := iHeight + 8;
    iWidth := Scrollbox1.ClientWidth - 40;
    Scrollbox1.AutoScroll := False;
    Scrollbox1.VertScrollBar.Range := iTop * ICount;
    for i := 0 to 4 do
    begin
      FPDFView := TPdfView.Create(Self);
      FPdfView.Parent := Scrollbox1;
      FPdfView.Name := 'PdfView'+intToStr(i);
      FPdfView.Color := clyellow;

      FPdfView.Height := 120; //iHeight;
      FPdfView.Top := i * (FPdfView.Height + 8);
      FPdfView.Width := Scrollbox1.ClientWidth - 40;
      FPdfView.Left := (ScrollBox1.ClientWidth - FPdfView.Width) div 2;;
      FPdfView.Visible := true;
      FPdfList.Add(FPdfView);
     end;
  end
  else
    Showmessage('Die Seiten sind bereits vorhanden');
end;
Wieso mir allerdings unter Verwendung der i-Variablen nichts angrzeigt wirde, ist mir Schleierhaft...

Gruss
Delbor


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:17 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 by Thomas Breitkreuz