Probleme mit zwei Fenstern (Forms)
Probleme mit zwei Fenstern (Forms)
Ich bin gerade dabei mir eine GUI für eine Konsolenanwendung zu Basteln. In diesem Program möchte ich zwei Fenster haben. Das eine in dem Man mit der Anwendung "interagiert" und das andere, in dem die Ausgabe der Anwendung angezeigt wird.
Beim Start des Programms sollen beide Fenster gleichzeitig geladen werden. Das bekomme ich zwar hin, über ein OnCreate Event im Hauptfenster (geht das noch eleganter?). Wenn ich aber jetzt den Output an das zweite Fenster sende, dann kriege ich ein Access Violation. Wie kann ich eine Variable aus dem einen Fenster (Formular) an das andere übergebe, schmeisst mir das einenSIGSEV Fehler aus. Ich such mir gerade einen wolf.. Das einzige was klappt ist das fenster direkt bei der Übergabe zu erschaffen und dann wieder zu zerstören, womit aber der Output der vorherigen eingabe verloren geht :/
Weiß jemand, wie ich das Hinkriege?
Beim Start des Programms sollen beide Fenster gleichzeitig geladen werden. Das bekomme ich zwar hin, über ein OnCreate Event im Hauptfenster (geht das noch eleganter?). Wenn ich aber jetzt den Output an das zweite Fenster sende, dann kriege ich ein Access Violation. Wie kann ich eine Variable aus dem einen Fenster (Formular) an das andere übergebe, schmeisst mir das einenSIGSEV Fehler aus. Ich such mir gerade einen wolf.. Das einzige was klappt ist das fenster direkt bei der Übergabe zu erschaffen und dann wieder zu zerstören, womit aber der Output der vorherigen eingabe verloren geht :/
Weiß jemand, wie ich das Hinkriege?
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2640
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Probleme mit zwei Fenstern (Forms)
Magst du uns vielleicht ein kleines bisschen Quellcode zeigen?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
-
- Lazarusforum e. V.
- Beiträge: 999
- Registriert: Do 17. Apr 2008, 01:59
- OS, Lazarus, FPC: Mint 21.1 Cinnamon / FPC 3.2.2/Lazarus 2.2.4
- CPU-Target: Intel i7-10750 64Bit
- Wohnort: Freiburg
Re: Probleme mit zwei Fenstern (Forms)
Für mich hört sich das nach einem Fall für den tiOPF-Mediator an, zumindest könnte man diesen hierzu elegant nutzen.
Alle sagten, dass es unmöglich sei - bis einer kam und es einfach gemacht hat.
Re: Probleme mit zwei Fenstern (Forms)
Also ich versuch es mal auf das wichtigste Runterzubrechen. Ich habe 3 Units main_window (das Hauptfenster), console_window (das Konsolenfenster) und eine Unit (ADBCommands) in der ich zur besseren Übersicht häufig gebrauchte Prozeduren/Funktionen auslagere.
die Unit main_window
Hier die Funktion zum Senden des Outputs:
das Konsolenfenster beinhaltet im Prinzip nur ein Formular mit namen adb_gui und einem TMemo (adb_console_output) in das die Ausgabe geschrieben wird.
So Schmeißt mir das ganze einen SIGSEV Fehler entgegen. Wenn ich direkt beim Start in der Hauptunit eine Ausgabe nach dem Öffnen des Fensters schicke per
anstelle der Funktion send2Console dann wird das Konsolenfenster mit einem Korrekten Output angezeigt. Jeder weitere Aufruf der Funktion führt zu dem SIGSEV fehler.
die Unit main_window
Code: Alles auswählen
uses
[...], ADBCommand, console_window;
[...]
{ Tadb_gui }
procedure Tadb_gui.oncreate(Sender: TObject);
var
adb_output : TStringList;
parameter : TStringList;
frm: Tadb_console;
begin
// Konsolen Fenster wird geöffnet)
frm := Tadb_console.Create(nil);
frm.Show;
parameter := TStringList.Create;
parameter.Add('devices');
parameter.Add('-l');
// Konsolenprogramm wird aufgerufen und der Rückgabewert (TStringList) an
//das Konsolenfenster gesendet
adb_output := adb(parameter);
ListUSBDevices(adb_output);
Send2Console(adb_output);
adb_output.Free;
end;
Hier die Funktion zum Senden des Outputs:
Code: Alles auswählen
procedure Send2Console(input: TStringList);
var
begin
adb_gui.adb_console_output.Lines.Assign(input);
end;
das Konsolenfenster beinhaltet im Prinzip nur ein Formular mit namen adb_gui und einem TMemo (adb_console_output) in das die Ausgabe geschrieben wird.
So Schmeißt mir das ganze einen SIGSEV Fehler entgegen. Wenn ich direkt beim Start in der Hauptunit eine Ausgabe nach dem Öffnen des Fensters schicke per
Code: Alles auswählen
frm.adb_console_output.Lines.Assign(adb_output);
anstelle der Funktion send2Console dann wird das Konsolenfenster mit einem Korrekten Output angezeigt. Jeder weitere Aufruf der Funktion führt zu dem SIGSEV fehler.
-
- Beiträge: 470
- Registriert: Do 15. Nov 2007, 16:58
- OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
- CPU-Target: i386, x64
- Wohnort: Gera
Re: Probleme mit zwei Fenstern (Forms)
Hallo,
man möge mich korrigieren wenn ich falsch liege, aber assign weist ein Objekt zu, welches du eine Zeile weiter zerstörst.
Damit scheitert jeder weitere Zugriff auf adb_gui.adb_console_output.Lines.
Meines Erachtens nach wäre es besser den Inhalt der Stringlist zu kopieren. z.B. so:
Habe es jetzt nicht getestet. Hoffe es hilft dir dennoch weiter.
man möge mich korrigieren wenn ich falsch liege, aber assign weist ein Objekt zu, welches du eine Zeile weiter zerstörst.
Code: Alles auswählen
Send2Console(adb_output); // <-- Zuweisung des Objekts adb_outut an adb_gui.adb_console_output.Lines
adb_output.Free; // <-- Zerstörung von adb_gui.adb_console_output.Lines
Damit scheitert jeder weitere Zugriff auf adb_gui.adb_console_output.Lines.
Meines Erachtens nach wäre es besser den Inhalt der Stringlist zu kopieren. z.B. so:
Code: Alles auswählen
procedure Send2Console(input: TStringList);
var
begin
adb_gui.adb_console_output.Lines.AddStrings(input);
end;
Habe es jetzt nicht getestet. Hoffe es hilft dir dennoch weiter.
mfg Ingo
Re: Probleme mit zwei Fenstern (Forms)
Ich werde es mal heute Abend testen. Danke für deine Idee.
Ich hab mir noch einen anderen Weg überlegt, obwohl ich nicht sicher bin, wie vernünftig das ist..
Ich schreibe den Output in eine globale Variable. Im Konsolenfenster wird diese periodisch mittels einer Schleife abgefragt und der Inhalt in das Memo kopiert und der Inhalt der Variable dann gelöscht.. Würde das so sinnvoll funktionieren?
Ich hab mir noch einen anderen Weg überlegt, obwohl ich nicht sicher bin, wie vernünftig das ist..
Ich schreibe den Output in eine globale Variable. Im Konsolenfenster wird diese periodisch mittels einer Schleife abgefragt und der Inhalt in das Memo kopiert und der Inhalt der Variable dann gelöscht.. Würde das so sinnvoll funktionieren?
-
- Beiträge: 470
- Registriert: Do 15. Nov 2007, 16:58
- OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
- CPU-Target: i386, x64
- Wohnort: Gera
Re: Probleme mit zwei Fenstern (Forms)
Adromir hat geschrieben:Ich schreibe den Output in eine globale Variable. Im Konsolenfenster wird diese periodisch mittels einer Schleife abgefragt und der Inhalt in das Memo kopiert und der Inhalt der Variable dann gelöscht.. Würde das so sinnvoll funktionieren?
Ich glaube der allgemeine Konsens hier im Forum ist, dass globale Variablen keine gute Lösung sind.
Wenn es dir um die Zugriffsverletzung beim Start des Programms geht, die auftritt, weil du auf die 2. Form zugreifst, bevor sie existiert, das umgehe ich üblicherweise, indem ich Form1 eine Variable gebe(z.B. isStartup), diese im OnCreate auf True setze und den Teil, der beim Start des Programms auf die 2. Form zugreift in OnShow ausführe, jedoch nur wenn isStartup True ist.(So viele Kommas und kein Punkt. Irgendwas stimmt da nicht...)
Etwa so:
Code: Alles auswählen
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs;
type
{ TForm1 }
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
private
isStartup: Boolean;
public
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
begin
isStartup:= true;
doPrepareStuff;
end;
procedure TForm1.FormShow(Sender: TObject);
begin
if isStartup then
begin
doStuffWithForm2;
Form2.Show
isStartup:= false;
end;
end;
end.
Das isStartup mache ich deswegen, weil OnShow nicht nur beim Start des Programms aufgerufen wird, sondern z.B. auch beim wieder anzeigen nach einem minimieren.
Ich hoffe ich habe mich halbwegs verständlich ausgedrückt.
mfg Ingo
Re: Probleme mit zwei Fenstern (Forms)
So, ich hab das das mal probiert.. Aber ich krieg immer noch den Fehler..
komischerweise, wenn ich das Form nur mit
aufrufe, kriege ich schon seinen SIGSEV fehler Der bleibt zumindest aus wenn ich das Formular Komplet mit
erzeuge. Danach aber wieder beim Senden an das Fenster den SIGSEV Fehler. Und der verweist immer auf die Funktion
komischerweise, wenn ich das Form nur mit
Code: Alles auswählen
adb_console.Show;
aufrufe, kriege ich schon seinen SIGSEV fehler Der bleibt zumindest aus wenn ich das Formular Komplet mit
Code: Alles auswählen
adb_console := Tadb_console.Create(nil);
adb_console.Show;
erzeuge. Danach aber wieder beim Senden an das Fenster den SIGSEV Fehler. Und der verweist immer auf die Funktion
Code: Alles auswählen
procedure Send2Console(input: TStringList);
begin
adb_console.adb_console_output.Lines.AddStrings(input);
end;
-
- Beiträge: 470
- Registriert: Do 15. Nov 2007, 16:58
- OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
- CPU-Target: i386, x64
- Wohnort: Gera
Re: Probleme mit zwei Fenstern (Forms)
Adromir hat geschrieben:Der bleibt zumindest aus wenn ich das Formular Komplet mitCode: Alles auswählen
adb_console := Tadb_console.Create(nil);
adb_console.Show;
erzeuge.
Wo erzeugst du "adb_console"? Im OnCreate/OnShow? Und wichtiger, wo zerstörst du es? Im OnClose der Hauptform, hoffe ich.
Diese SIGSEV-Fehler bedeuten, dass du auf ein Objekt zugreifst, welches noch nicht oder nicht mehr existiert.
mfg Ingo
Re: Probleme mit zwei Fenstern (Forms)
Also ich erzeuge das im Oncreate. Ich hab da soGar extra ein Sleep eingebaut, daß ich sicher sein kann, daß es existiert. Zerstören tue ich das momentan Gar nich
-
- Beiträge: 470
- Registriert: Do 15. Nov 2007, 16:58
- OS, Lazarus, FPC: Win11/Ubuntu Budgie (L 3.0 FPC 3.2.2)
- CPU-Target: i386, x64
- Wohnort: Gera
Re: Probleme mit zwei Fenstern (Forms)
Kann ich gerade überhaupt nicht nachvollziehen. Hab mal ein Minidemo erstellt, zum vergleichen.
Form2 enthält nur ein TMemo. Die Projektdatei sieht so aus:
Code: Alles auswählen
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, unit2,
StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
private
isStartup:Boolean;
testSL: TStringList;
public
procedure PrepareStuff;
procedure Send2Console(input: TStringList);
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
//Beim scließen von Form1
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
TestSL.Free;
Form2.Free; //Form2 zerstören
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2.Show;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
PrepareStuff;
Send2Console(TestSL);
end;
//Beim erstellen von Form1
procedure TForm1.FormCreate(Sender: TObject);
begin
testSL:= TStringlist.Create;
Form2:= TForm2.Create(nil); //Form2 erstellen
Randomize;
PrepareStuff;
isStartup:= True;
Send2Console(TestSL); //was hinschicken
end;
//Beim anzeigen von Form1
procedure TForm1.FormShow(Sender: TObject);
begin
if isStartup then
begin
Form2.Show; //Form2 anzeigen
Send2Console(TestSL); //nochmal das selbe hinschicken
end;
end;
procedure TForm1.PrepareStuff;
begin
testSL.Clear;
testSL.Add('Test' + IntToStr(Random(100)));
testSL.Add('Test' + IntToStr(Random(100)));
testSL.Add('Test' + IntToStr(Random(100)));
end;
procedure TForm1.Send2Console(input: TStringList);
begin
Form2.Memo1.Lines.AddStrings(input);
end;
end.
Form2 enthält nur ein TMemo. Die Projektdatei sieht so aus:
Code: Alles auswählen
program Project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Interfaces, // this includes the LCL widgetset
Forms, unit1, unit2
{ you can add units after this };
{$R *.res}
begin
RequireDerivedFormResource:=True;
Application.Initialize;
Application.CreateForm(TForm1, Form1);
// Application.CreateForm(TForm2, Form2); //Auskommentiert, da "von Hand" erstellt
Application.Run;
end.
mfg Ingo
Re: Probleme mit zwei Fenstern (Forms)
Allerherzlichsten Dank für deine Mühen. Ich werde mal schauen, ob ich das irgendwie eingebaut bekomme. Vielleicht macht es irgendwie auch zicken, daß ich die Funktion send2console in eine weitere Unit ausgelagert habe
Re: Probleme mit zwei Fenstern (Forms)
Bin wohl ein Hoffnungsloser Fall lol.. Hab versucht meinen Code an dein Beispiel anzupassen, hat nicht geklappt, immer noch die Sigsev Fehler. Bin wohl zu doof dafür. Hab jetzt dein Beispiel genommen um noch mal neu Anzufangen und bis her läuft es 1a. Danke dafür
Re: Probleme mit zwei Fenstern (Forms)
Falls ich nochmal stören darf.. Ich bin jetzt auf der Basis von shockwaves Code ziemlich weit gekommen. Nun habe ich ein kleines "kosmetisches" Problem. Wenn ich die Applikation starte, erscheint das Konsolenfenster in der Tableiste vor dem Hauptfenster. Kann man das irgendwie ändern?