Probleme mit zwei Fenstern (Forms)

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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?

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2636
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)

Beitrag von m.fuchs »

Magst du uns vielleicht ein kleines bisschen Quellcode zeigen?
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

MacWomble
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)

Beitrag von MacWomble »

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.

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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


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.

shokwave
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)

Beitrag von shokwave »

Hallo,

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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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?

shokwave
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)

Beitrag von shokwave »

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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

So, ich hab das das mal probiert.. Aber ich krieg immer noch den Fehler..

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;   
 

shokwave
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)

Beitrag von shokwave »

Adromir hat geschrieben:Der bleibt zumindest aus wenn ich das Formular Komplet mit

Code: 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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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

shokwave
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)

Beitrag von shokwave »

Kann ich gerade überhaupt nicht nachvollziehen. Hab mal ein Minidemo erstellt, zum vergleichen.

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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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

Adromir
Beiträge: 37
Registriert: Sa 28. Apr 2018, 04:09

Re: Probleme mit zwei Fenstern (Forms)

Beitrag von Adromir »

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?

Antworten