Programm ohne GUI

Für Fragen von Einsteigern und Programmieranfängern...
Antworten
DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Programm ohne GUI

Beitrag von DL3AD »

Hallo,

ich programmiere nun schon eine ganze weile mit Lazarus GUI Anwendungen - habe aber noch nie eine Anwendung ohne GUI gemacht.
Nun möchte ich mal ein einfaches Programm erstellen das im Hintergrund läuft bis ich es beende (mit exit).
Wenn ich ein neues Projekt erstelle dann wähle ich Programm und bekomme dann folgende Struktur vorgegeben

Code: Alles auswählen

 
program project1;
 
{$mode objfpc}{$H+}
 
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads;
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this };
 
begin
  writeln('TEST');//eingefügt zum Testen der Ausgabe auf Konsole
  readln;
end.         
 


Nun habe ich das Probelm dass ich nicht weiter komme aus Unwissenheit
Ich habe mit einer GUI Anwendung folgende Testfunktionalität erstellt und möchte diese nun in das Programm ohne GUI überführen.
Die Memoausgabe kann man ja testweise mit writeln erschlagen.

Code: Alles auswählen

 
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ExtCtrls, blcksock, uplaysound;
type
  { TForm1 }
  TForm1 = class(TForm)
    Memo1: TMemo;
    playsound1: Tplaysound;
    Timer1: TTimer;
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
    procedure InitSocket;
    procedure DeInitSocket;
  public
    { public declarations }
  end;
 
var
  Form1: TForm1;
  UDPResiveSocket: TUDPBlockSocket;
 
implementation
{$R *.lfm}
{ TForm1 }
//Initialisierungen
procedure TForm1.FormShow(Sender: TObject);
begin
  InitSocket;
end;
 
//Aktionen zum Form schließen
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  DeInitSocket;
end;
 
//Timer zum Daten abrufen
procedure TForm1.Timer1Timer(Sender: TObject);
var
  UDPRx: string;
begin
  Timer1.Enabled:= false;
  UDPRx:= UDPResiveSocket.RecvPacket(50);
  if UDPRx <> '' then
  begin
    Memo1.Lines.Add('>' + UDPRx);
    playsound1.SoundFile:='post.wav';
    playsound1.Execute;
  end;
  Timer1.Enabled:= true;
end;
 
//UDP Socket erzeugen
procedure TForm1.InitSocket;
begin
  if UDPResiveSocket <> nil then DeInitSocket;
 
  UDPResiveSocket:= TUDPBlockSocket.Create;
  UDPResiveSocket.CreateSocket;
  UDPResiveSocket.Bind('192.168.2.116','10001');
end;
 
//UDP Socket freigeben
procedure TForm1.DeInitSocket;
begin
  UDPResiveSocket.CloseSocket;
  UDPResiveSocket.Free;
  UDPResiveSocket:= nil;
end;
end.
 


Wie muss der Code aus der GUI Anwendung in das Programm eingefügt werden ?
Muss man hier dann eine "main loop"(mit Abbruchbedingung) erstellen ?

Gruß Frank

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Programm ohne GUI

Beitrag von Soner »

Code: Alles auswählen

program Project1;
uses crt;
var c: char;
begin
   repeat
 
     //hier ist "mainloop"
     Writeln('Läuft so lange bis du [ESC]-Taste drückst');
 
     delay(10); //warten, sonst wird die Cpu-Auslastung hoch, (lüfter bei laptops!)
 
     if KeyPressed then c:=ReadKey;
   until c=#27;
end.


Edit:
delay hinzugefügt.

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Programm ohne GUI

Beitrag von DL3AD »

... Dass mit der Mainloop habe ich mir ja schon gedacht - aber wie und wo binde ich den Rest ein wie z.B. TTimer, Tplaysound u.s.w. ?

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Programm ohne GUI

Beitrag von Soner »

In dem du entweder die Klasse TForm1 einfügst und anpasst oder alles als Prozeuduren neu einfügst.
Ich verstehe nicht wiese du :
UDPResiveSocket: TUDPBlockSocket;
global definiert hast. Das wird doch nur in dein Formular verwendet.

Ich habe für dein TForm1 eingefügt und angepasst, lies mein Kommentare, besonders für uplaysound.
Du mußt natürlich für das Projekt benötigte Packages einfügen.


Code: Alles auswählen

 
program project1;
 
{$mode objfpc}{$H+}
 
uses
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads;
  {$ENDIF}{$ENDIF}
  Classes
  { you can add units after this }
  ,crt,
 
  interfaces, // wegen uplaysound, z.B. mit uplaysound entfernen!
  uplaysound, // uplaysoundist problematisch das braucht lcl
              // du muß andere sound bibliothek nehmen, z.b. uos von fredvs
 
 
  blcksock,   // Abhängigkeit laz_synapse, OK
  fptimer     //NEU für timer
  ;
 
 
 
type
  { TForm1 }
  TForm1 = class(TComponent)//weg damit: (TForm)
    //weg damit: Memo1: TMemo;
    playsound1: Tplaysound;
    Timer1: TfpTimer; //<--- ändern TTImer
    procedure FormClose;//weg damit: (Sender: TObject; var CloseAction: TCloseAction);
    procedure FormShow(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { private declarations }
    procedure InitSocket;
    procedure DeInitSocket;
  public
    { public declarations }
    constructor Create(AOwner: TComponent); override;           //neu
  end;
 
var
  Form1: TForm1;
  UDPResiveSocket: TUDPBlockSocket;
 
//weg damit: implementation
//weg damit: {$R *.lfm}
 
{ TForm1 }
//NEU
constructor TForm1.Create(AOwner: TComponent);           //neu
begin
  inherited Create(AOwner);
  //die genauen parameter kannst du aus *.lfm Datei aus GUI Programm entnehmen
  playsound1:= Tplaysound.Create(self);
 
  Timer1:= TfpTimer.Create(self);
  Timer1.OnTimer:=@Timer1Timer;
  Timer1.Enabled:=true;//eigentlich sollte das starten in procedure TForm1.InitSocket; s
                       //weil UDPResiveSocket dort erstellt wird, wenn timer früher startet dann,
                       //hast du Problem
 
end;
 
//Initialisierungen
procedure TForm1.FormShow(Sender: TObject);
begin
  InitSocket;
end;
 
//Aktionen zum Form schließen
procedure TForm1.FormClose;//weg damit: (Sender: TObject; var CloseAction: TCloseAction);
begin
  Timer1.Enabled:=false; //NEU !
  DeInitSocket;
end;
 
//Timer zum Daten abrufen
procedure TForm1.Timer1Timer(Sender: TObject);
var
  UDPRx: string;
begin
  Timer1.Enabled:= false;
  UDPRx:= UDPResiveSocket.RecvPacket(50);
  if UDPRx <> '' then
  begin
    Writeln('>' + UDPRx);//weg damit: Memo1.Lines.Add('>' + UDPRx);
    playsound1.SoundFile:='post.wav';
    playsound1.Execute;
  end;
  Timer1.Enabled:= true;
end;
 
//UDP Socket erzeugen
procedure TForm1.InitSocket;
begin
  if UDPResiveSocket <> nil then DeInitSocket;
 
  UDPResiveSocket:= TUDPBlockSocket.Create;
  UDPResiveSocket.CreateSocket;
  UDPResiveSocket.Bind('192.168.2.116','10001');
end;
 
//UDP Socket freigeben
procedure TForm1.DeInitSocket;
begin
  UDPResiveSocket.CloseSocket;
  UDPResiveSocket.Free;
  UDPResiveSocket:= nil;
end;
 
var c: char;
begin
  Form1:= TForm1.Create(nil);
  try
 
   Form1.FormShow(Form1);
 
   repeat
 
     //hier ist "mainloop"
     Writeln('Läuft so lange bis du [ESC]-Taste drückst');
 
     delay(10); //warten, sonst wird die Cpu-Auslastung hoch, (lüfter bei laptops!)
 
     if KeyPressed then c:=ReadKey;
   until c=#27;
 
   Form1.FormClose;
 
 finally
   Form1.Free;
 end;
end.
 

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Programm ohne GUI

Beitrag von DL3AD »

... kann der ganze Form1 Kram nicht raus ?
Letztendlich möchte ich das GUI Beispiel als nicht GUI also auf Konsole haben.

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Programm ohne GUI

Beitrag von Mathias »

Natürlich kann man das Form Zeugs entfernen.
Dein Programm, muss aussehen wie zu TP-Zeiten.

Was soll dein Programm schlussendlich können ?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Soner
Beiträge: 623
Registriert: Do 27. Sep 2012, 00:07
OS, Lazarus, FPC: Win10Pro-64Bit, Immer letzte Lazarus Release mit SVN-Fixes
CPU-Target: x86_64-win64
Wohnort: Hamburg

Re: Programm ohne GUI

Beitrag von Soner »

Da ist doch kein GUI mehr. Wenn dich der Name TForm1 stört, dann benenne das um.
Du kannst es auch zu Prozeduren umwandeln, aber für den Timer.OnTimer brauchst du eine Klasse.
Das einzige was hier stört is uplaysound-Unit. Das habe ich ja als Kommentar geschrieben.

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Programm ohne GUI

Beitrag von DL3AD »

Hallo Mathias,

1. es soll im Hintergrund laufen
2. es soll in Abhängigkeit von einem eintreffendem UDP String eine zugehörige Sounddatei abspielen (muss dann noch implementiert werden)

Die simpelste Lösung währe Form1.Hide - aber ich möchte lernen wie man es ohne GUI macht, ohne schnikschnack und ganz simpel. :mrgreen:

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Programm ohne GUI

Beitrag von Mathias »

Mit folgender Grundstruktur müsste es gehen.

Code: Alles auswählen

udp Create
Repeat
  If udp then Sound
  Delay
Until esc
Udp Free


Somit braucht es auch keinen Timer.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Programm ohne GUI

Beitrag von DL3AD »

... ja, hmm mir fehlt die Kenntniss wie ich es in diese Struktur packe ich brauche immer ein konkretes Beispiel.
Hilfreich währe wenn jemand es mal anhand meines vorgegebenen GUI Beispieles macht.
Das was Soner gemacht hat ist irgendwie gefrickel - sorry ist nicht bös gemeint.

mse
Beiträge: 2013
Registriert: Do 16. Okt 2008, 10:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.6,git master FPC 3.0.4,fixes_3_0)
CPU-Target: x86,x64,ARM

Re: Programm ohne GUI

Beitrag von mse »

TTimer und allgemein Ereignis-gesteuerte Anwendungen brauchen eine "main event queue". AFAIK stellt Lazarus dies nur mittels zugrunde liegendem Widgetset zur Verfügung. In MSEgui würde man statt "uses msegui" "uses msenogui" schreiben, TApplication wird dann unabhängig von einem Graphik- und Fenstersystem. Beispiele sind hier:
https://gitlab.com/mseide-msegui/mseuni ... ials/nogui
Fred's "consoleplay" Beispiel zeigt eine andere Art von Programmen ohne GUI.
DL3AD hat geschrieben:aber ich möchte lernen wie man es ohne GUI macht, ohne schnikschnack und ganz simpel.

Konsolenprogramme werden leider sehr rasch nicht mehr simpel sobald asynchrone Ereignisse dazukommen. Die Entwicklung von ereignisgesteuerten Frameworks kommt ja nicht von Ungefähr...

DL3AD
Beiträge: 478
Registriert: Fr 13. Sep 2013, 12:07
OS, Lazarus, FPC: Debian Bullseye (L 2.2.0)
CPU-Target: 64Bit
Wohnort: Rügen

Re: Programm ohne GUI

Beitrag von DL3AD »

Hallo mse,

Danke für die Erklärungen und Danke an euch die mir helfen wollten.
Dann mache ich es mit Frorm.Hide - so läuft es dann auch im Hintergrund.

Gruß Frank

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Programm ohne GUI

Beitrag von Mathias »

Hilfreich währe wenn jemand es mal anhand meines vorgegebenen GUI Beispieles macht.

Das sieht dann so aus:

Code: Alles auswählen

program Project1;
uses
  Crt,  blcksock;
 
type
  TMyUDP = class(TObject)
  private
    playsound1: Tplaysound;
  public
    //    playsound1: Tplaysound;
    procedure Check;
    procedure InitSocket;
    procedure DeInitSocket;
  end;
 
var
  UDPResiveSocket: TUDPBlockSocket;
 
  procedure TMyUDP.Check;
  var
    UDPRx: string;
  begin
    UDPRx := UDPResiveSocket.RecvPacket(50);
    if UDPRx <> '' then begin
      WriteLn('>' + UDPRx);
      //      playsound1.SoundFile := 'post.wav';
      //      playsound1.Execute;
    end;
  end;
 
  //UDP Socket erzeugen
  procedure TMyUDP.InitSocket;
  begin
    if UDPResiveSocket <> nil then begin
      DeInitSocket;
    end;
 
    UDPResiveSocket := TUDPBlockSocket.Create;
    UDPResiveSocket.CreateSocket;
    UDPResiveSocket.Bind('192.168.2.116', '10001');
  end;
 
  //UDP Socket freigeben
  procedure TMyUDP.DeInitSocket;
  begin
    UDPResiveSocket.CloseSocket;
    UDPResiveSocket.Free;
    UDPResiveSocket := nil;
  end;
 
var
  MyUPD: TMyUDP;
  ch: char;
 
begin
  MyUPD := TMyUDP.Create;
  MyUPD.InitSocket;
  WriteLn('[ESC]= beenden');
  repeat
    MyUPD.Check;
    if KeyPressed then begin
      ch := ReadKey;
    end;
  until ch = #27;
  MyUPD.DeInitSocket;
  MyUPD.Free;
end.

Auf die Classe könnte man auch noch verzichten und einfache Proceduren machen.
Das Tplaysound müsstes du noch einbauen, bei mi fehlt diese Komponente.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

wp_xyz
Beiträge: 4869
Registriert: Fr 8. Apr 2011, 09:01

Re: Programm ohne GUI

Beitrag von wp_xyz »

Soner hat geschrieben:Das einzige was hier stört is uplaysound-Unit. Das habe ich ja als Kommentar geschrieben.

Aber das Ding braucht doch keine LCL. Da sind nur ein paar Units, die standardmäßig eingebunden aber nicht benötigt werden. Und 1x ShowMessage und die Aboutbox.

Im Anhang ist eine modifizierte uPlaySound, die in einem Konsolenprogramm läuft (Achtung: den Linux-Teil habe mir nicht angesehen - möglich, dass man da noch etwas anpassen muss). Das Programm mit das Package LazUtils einbinden. -- Ich werde mal dem Autor vorschlagen, die Komponente entsprechend abzuändern.
Dateianhänge
playsound_cmdline.zip
(3.54 KiB) 65-mal heruntergeladen

Mathias
Beiträge: 6160
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: Programm ohne GUI

Beitrag von Mathias »

Noch ein Hinweis zu folgendem Code. Wen dieser unter Linux in einem Datei-Manger gestartet wird, erscheint keine Konsole, obwohl dies im Hintergrund läuft.
Man kann es dann höchsten noch mit einem "Kill" Kommando oder was ähnlichem beenden,

Code: Alles auswählen

  WriteLn('[ESC]= beenden');
  repeat
    MyUPD.Check;
    if KeyPressed then begin
      ch := ReadKey;
    end;
  until ch = #27;
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten