Kommander/GUI: Unterschied zwischen den Versionen

Aus Linupedia.org
Wechseln zu: Navigation, Suche
(fast fertig)
(Screenshots als thumbnails, Anpassung Links an linupedia)
 
(9 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
{{UnderConstruction}}  
+
{{Kommander_Navibox}}
 +
 
 +
== <font color="maroon"> Vorwort</font> ==
 +
Im Folgenden wird die Programmierung der Bedienoberfläche für das [[Dvb_script_gui/scriptcode|DVB-Script]] beschrieben.
 +
 
 +
Dieser Artikel mag für viele uninteressant erscheinen. Ich empfehle ihn dennoch zur Lektüre, zeigt er doch einiges von den Möglichkeiten, die in Kommander stecken. Wer sich also für den Weg, den ich hier gegangen bin, interessiert, der sei herzlich eingeladen, weiter zu lesen.
 +
 
 +
== <font color="maroon"> Einleitung</font> ==
 +
Das DVB-Script vereinfacht die Verarbeitung eines DVB-Streams zu einer Video-DVD.
  
{{Kommander_Navibox}}
+
Die Helferprogramme müssen nicht mehr mühevoll von Hand gestartet werden. Das Script macht das nun für uns. Es ruft die Programme in der korrekten Reihenfolge auf und übergibt dabei die notwendigen Daten.
 +
 
 +
Und das Script wird nun über die GUI bedient. Die gewünschte Aufgabe anklicken, eine leere DVD einschieben, warten, fertig!
  
 +
Die Bedienoberfläche wurde mit Kommander erstellt. So sieht das Ergebnis aus: [[Bild:Dvb_script_gui.png|thumb|center|GUI fürs DVB-Script]]
  
== <font color="green"> Das Editorfenster </font> ==
+
Und so sieht die GUI aus wenn sie zum Editieren mit dem kmdr-editor aufgerufen wird: [[Bild:Kmdr-Editor-DVB_Script_GUI.png|thumb|center|Editor-Dialog]]
So sieht die GUI aus wenn sie zum Editieren mit dem kmdr-editor aufgerufen wird: [http://wiki.linux-club.de/opensuse/Bild:Kmdr-Editor-DVB_Script_GUI.png Editor-Dialog]
 
  
== <font color="green"> Gliederung der GUI</font> ==
+
== <font color="maroon"> Gliederung der GUI</font> ==
Ich habe die GUI in vier große Abschnitte eingeteilt:
+
Ich habe die Bedienoberfläche in vier große Abschnitte eingeteilt:
  
=== <font color="purple">Aktionenauswahl</font> ===
+
=== <font color="black">Aktionenauswahl</font> ===
 
Links oben können die gewünschten Aktionen durch Drücken vom Buttons ausgewählt werden. Folgende Kommander-Widgets sind dabei beteiligt:
 
Links oben können die gewünschten Aktionen durch Drücken vom Buttons ausgewählt werden. Folgende Kommander-Widgets sind dabei beteiligt:
  
 +
* ''RadioButton:'' Auswahl der Aktionen (Brennen, Sichern, usw.)
 +
* ''Label:'' Dient zur Anzeige von Kommentaren (Video-DVD...)
 +
* ''ButtonGroup:'' Hierin sind die ''RadioButtons'' und die ''Labels'' organisiert
 +
* ''ExecButton:'' Damit wird die ausgewählte Aktion gestartet (Go)
 +
* ''EditorTabWidget:'' Weitere Aktionen können über Reiter sichtbar gemacht werden
 +
 +
=== <font color="black">Log</font> ===
 +
Im Log-Fenster links unten wird angezeigt, welcher Bearbeitungsschritt gerade am arbeiten ist. Hier bürgen folgende Widgets für das Gelingen:
  
* '''RadioButton:''' Auswahl der Aktionen (Brennen, Sichern, usw.)
+
* ''TextBrowser:'' Hierin erfolgt die Anzeige
* '''Label:''' Dient zur Anzeige von Kommentaren (Video-DVD...)
+
* ''GroupBox:'' Sieht einfach besser aus, wenn der ''TextBrowser'' da drin liegt
* '''ButtonGroup:''' Hierin sind die RadioButtons und die Labels organisiert
 
* '''ExecButton:''' Damit wird die ausgewählte Aktion gestartet (Go)
 
* '''EditorTabWidget:''' Weitere Aktionen können über Reiter sichtbar gemacht werden
 
  
=== <font color="purple">Log</font> ===
+
=== <font color="black">Debug-Log</font> ===
Im Log-Fenster links unten wird der Bearbeitungsfortschritt der gestarteten Aktion angezeigt. Hier bürgen folgende Widgets für das Gelingen:
+
Rechts unten ist das Debug-Log zu finden. Damit kann man, wenn es gewünscht wird, noch genauere Anzeigen zum laufenden Scripts bekommen. Da hier die Ausgabe des Standard-Fehlerkanal angezeigt wird, kann man gut nachverfolgen, wo es Probleme gegeben hat, wenn etwas nicht so klappt, wie man es sich eigentlich vorstellt.
  
* '''TextBrowser:''' Hierin erfolgt die Anzeige
+
* ''TextWidget:'' Ausgabe von ''stderr'' (Standard-Fehlerkanal)
* '''GroupBox:''' Sieht einfach besser aus, wenn der TextBrowser da drin liegt
+
* ''RadioButton:'' Steuern die Aktualisierung der Ausgabe (Ein, Aus)
 +
* ''ButtonGrop:'' Darin sind die ''RadioButtons'' organisiert
 +
* ''ExecButton:'' Fensteranzeige leeren (Clear)
 +
* ''GroupBox:'' Läßt das, was zusammen gehört, auch so erscheinen
  
=== <font color="purple">Debug-Log</font> ===
+
=== <font color="black">Unsichtbare Widgets</font> ===
Rechts unten ist das Debug-Log zu finden. Damit kann man, wenn es gewünscht wird, noch genauere Anzeigen des laufenden Scripts bekommen. Da hier die Ausgabe des Standard-Fehlerkanal angezeigt wird, kann man gut nachverfolgen, wo es Probleme gegeben hat, wenn etwas nicht so klappt, wie man es sich eigentlich vorstellt.
+
Klingt gut, der Titel, oder? Ja, die Widgets rechts oben sind tatsächlich unsichtbar im ''kmdr-executor''. Editiert man aber den Dialog mit dem ''kmdr-editor'', dann sieht man sie natürlich (wie durch Zauberei).
  
* '''TextWidget:''' Ausgabe von stderr (Standard-Fehlerkanal)
+
* ''ScriptObject:'' Diese drei Objekte enthalten ausführbaren Programm-Code
* '''RadioButton:''' Steuern die Aktualisierung der Ausgabe (Ein, Aus)
+
* ''Timer:'' Periodische Abfrage der Anzeigefenster
* '''ButtonGrop:''' Darin sind die RadioButtons organisiert
+
* ''blaue Abstandslinien:'' Sind für das Layout wichtig
* '''ExecButton:''' Fensteranzeige leeren (Clear)
 
* '''GroupBox:''' Läßt das, was zusammen gehört, auch so erscheinen
 
  
=== <font color="purple">Unsichtbare Widgets</font> ===
+
=== <font color="black">Playlist</font> ===
Klingt gut, der Titel, oder? Ja, die Widgets rechts oben sind tatsächlich unsichtbar im kmdr-executor. Editiert man aber den Dialog, sieht man sie (kmdr-editor).
+
Bei den "unsichtbaren Widgets" befindet sich noch ein Knopf mit dem Namen ''Playlist starten''.
  
* '''ScriptObject:''' Diese drei Objekte enthalten ausführbaren Kommander- bzw.Bash -Code
+
* ''ExecButton:'' Playlist starten
* '''Timer:''' Periodische Abfrage der Anzeigefenster bzw. Zeitverzögerung
 
* '''blaue Abstandslinien:''' Sind für das Layout wichtig
 
  
== <font color="green"> Das Formular </font> ==
+
== <font color="maroon"> Das Formular </font> ==
Wir haben bereits in der Einleitung gesehen, wie ein neuer Kommander-Dialog erstellt wird. Ganz kurz noch einmal zu Wiederholung:
+
Wir haben bereits in der [[Kommander|Einleitung]] gesehen, wie ein neuer Kommander-Dialog erstellt wird. Ganz kurz noch einmal zu Wiederholung:
  
 
* ''kmdr-editor'' starten
 
* ''kmdr-editor'' starten
Zeile 51: Zeile 65:
 
Das Formular (''EditorDialog'') bekommt von uns nun folgende Eigenschaften zugeteilt:
 
Das Formular (''EditorDialog'') bekommt von uns nun folgende Eigenschaften zugeteilt:
  
* '''name: '''GUI
+
* ''name:''''' '''GUI
* '''baseSize:''' Breite 1024, Höhe 768
+
* ''baseSize:'' Breite 1024, Höhe 768
* '''caption:''' dvb_wiki_script oder Vom DVB zur DVD und einiges mehr
+
* ''caption:'' dvb_wiki_script oder Vom DVB zur DVD und einiges mehr
 +
 
 +
''name''
 +
 
 +
Die Zuteilung eines aussagekräftigen Namens, mit dem das Element angesprochen werden kann, ist eminent wichtig. Ich hatte dies beim Programmieren der GUI versäumt. Erst, als die Zuordnung der Elemente mit steigender Komplexität des Dialogs immer undurchsichtiger wurde, musste ich nachträglich Namen vergeben, um das Chaos etwas einzudämmen. Drum, die Namensgebung der Widgets konsequent gleich von Beginn an durchziehen!
  
Die Zuteilung eines aussagekräftigen Namens, mit dem das Element angesprochen werden kann, ist eminent wichtig. Ich hatte dies beim Programmieren der GUI versäumt. Erst, als die Zuordnung der Elemente mit steigender Komplexität des Dialogs immer undurchsichtiger wurde, habe ich nachträglich Namen vergeben.
+
''baseSize''
  
 
Die Basis-Grösse ist die Fenstergrösse, mit der Kommander den Dialog startet. Man könnte auch sagen, der Dialog ist optimiert für eine Bildschirmgrösse von 1024 x 768 Pixel.
 
Die Basis-Grösse ist die Fenstergrösse, mit der Kommander den Dialog startet. Man könnte auch sagen, der Dialog ist optimiert für eine Bildschirmgrösse von 1024 x 768 Pixel.
 +
 +
''caption''
  
 
Und die Überschrift... Na ja, irgend etwas musste ich ja rein schreiben.
 
Und die Überschrift... Na ja, irgend etwas musste ich ja rein schreiben.
  
== <font color="green"> Das Log </font> ==
+
== <font color="maroon"> Das Log </font> ==
 
Weiter mit dem Log-Fenster links unten.
 
Weiter mit dem Log-Fenster links unten.
  
=== <font color="purple">Funktionsweise</font> ===
+
=== <font color="black">Funktionsweise</font> ===
Das DVB-Script ist so programmiert, daß immer wieder Meldungen über den aktuellen Fortschritt der Videobearbeitung in eine Datei geschrieben werden:
+
Das DVB-Script ist so programmiert, daß immer wieder Meldungen über den aktuellen Stand der Videobearbeitung in eine Datei geschrieben werden:
  
  text >> ~/.dvb_script_gui.ini/fortschrittfenster
+
  echo "text" >> ~/dvbscript/fenster_fortschritt
 +
  
Wie zu sehen ist, werden diese Texte zum schon vorhandenen Dateiinhalt hinzugefügt.
+
Diese Log-Datei wird von Kommander mit Hilfe eines ''Timers'' und eines ''ScriptObjects'' alle 500ms abgefragt. Das Ergebnis der Abfrage wird dann in das Log-Fenster (den ''TextBrowser'') geschrieben.
  
Diese Fortschrittsdatei wird von Kommander mit Hilfe eines Timers und eines ScriptObjects alle 500ms abgefragt. Das Ergebnis der Abfrage wird dann in das Log-Fenster (den TextBrowser) geschrieben.
+
=== <font color="black">Bausteine</font> ===
 +
==== <font color="gray">TextBrowser</font> ====
 +
Wir plazieren einen ''TextBrowser'' (aus der Symbolleiste) irgendwo auf dem Formular und stellen folgende Eigenschaften ein:
  
=== <font color="purple">Bausteine</font> ===
+
* ''name:''''' '''fenster1
==== <font color="brown">TextBrowser</font> ====
+
* ''minimumSize:'' Breite 490, Höhe 350
Wir plazieren einen TextBrowser (aus der Symbolleiste) irgendwo auf dem Formular und stellen folgende Eigenschaften ein:
 
 
 
* '''name: '''fenster1
 
* '''minimumSize:''' Breite 490, Höhe 350
 
  
 
Die Angabe einer Minimum-Größe ist notwendig, damit das Fenster beim Layout nicht geschrumpft wird.
 
Die Angabe einer Minimum-Größe ist notwendig, damit das Fenster beim Layout nicht geschrumpft wird.
  
==== <font color="brown">GroupBox</font> ====
+
==== <font color="gray">GroupBox</font> ====
 
Auch dieses Widget wird auf eine freie Stelle im Formular kopiert.
 
Auch dieses Widget wird auf eine freie Stelle im Formular kopiert.
  
* '''name:''' rahmen
+
* ''name:'' rahmen
* '''font-Punktgröße:''' 12
+
* ''font-Punktgröße:'' 12
* '''font-Fett:''' wahr
+
* ''font-Fett:'' wahr
* '''title:''' Log
+
* ''title:'' Log
* '''hAlign:''' AlignHCenter
+
* ''hAlign:'' AlignHCenter
* '''vAlign:''' AlignVCenter
+
* ''vAlign:'' AlignVCenter
 
 
Was ist hier besonderes?
 
  
 
Der Fenstertitel ''Log'' wird vertikal und horizontal zentriert (Align) dargestellt, erhält zur Hervorhebung eine Schriftgröße von 12 Punkten und wird zusätzlich ''fett'' formatiert.
 
Der Fenstertitel ''Log'' wird vertikal und horizontal zentriert (Align) dargestellt, erhält zur Hervorhebung eine Schriftgröße von 12 Punkten und wird zusätzlich ''fett'' formatiert.
  
==== <font color="brown">Layout</font> ====
+
==== <font color="gray">Layout</font> ====
* Mit der Maus wird die GroupBox so groß gemacht, daß der TextBrowser vollständig hineinpasst
+
* Mit der Maus wird die ''GroupBox'' so groß gemacht, daß der ''TextBrowser'' vollständig hineinpasst
 
* Anschließend wird der Browser in die Box geschoben
 
* Anschließend wird der Browser in die Box geschoben
* Die Groupbox wird markiert und aus dem Kontextmenue folgender Befehl ausgewählt:
+
* Die ''GroupBox'' wird markiert und aus dem Kontextmenue folgender Befehl ausgewählt:
 
* ''In einem Raster anordnen ''(Die neun kleinen Quadrate)
 
* ''In einem Raster anordnen ''(Die neun kleinen Quadrate)
  
Damit ist der TextBrowser fest in der GroupBox verankert und kann zusammen mit der Box an einen passenden Ort auf dem Formular geschoben werden.
+
Damit ist der ''TextBrowser'' fest in der ''GroupBox'' verankert und kann zusammen mit der Box an einen passenden Ort auf dem Formular geschoben werden.
  
 
Das Log-Fenster ist fertig. Es fehlt nur noch der Inhalt.
 
Das Log-Fenster ist fertig. Es fehlt nur noch der Inhalt.
  
==== <font color="brown">ScriptObject</font> ====
+
==== <font color="gray">ScriptObject</font> ====
 
Wir haben vorhin gesehen, daß der Bearbeitungsfortschritt des DVB-Scriptes in folgende Datei geschrieben wird:
 
Wir haben vorhin gesehen, daß der Bearbeitungsfortschritt des DVB-Scriptes in folgende Datei geschrieben wird:
  
  ~/.dvb_script_gui.ini/fortschrittfenster
+
  ~/dvbscript/fenster_fortschritt
  
Den Inhalt dieser Datei fragen wir mit einem ScriptObject ab.
+
Den Inhalt dieser Datei fragen wir mit einem ''ScriptObject'' ab.
  
 
Erzeugen wir also ein ScriptObject mit folgenden Eigenschaften:
 
Erzeugen wir also ein ScriptObject mit folgenden Eigenschaften:
  
* '''name:''' refresh_fenster1
+
* ''name:'' refresh_fenster1
* '''text:''' fen1
+
* ''text:'' fen1
  
Unser ScriptObject enthält, wie der Name schon andeutet, ausführbaren Scriptcode. In welcher Sprache wir das Script erstellen, bleibt uns überlassen. Verwenden wir diesmal den Kommander-Scriptcode:
+
Unser ''ScriptObject'' enthält, wie der Name schon andeutet, ausführbaren Scriptcode. In welcher Sprache wir das Script erstellen, bleibt uns überlassen. Verwenden wir diesmal den Kommander-Scriptcode:
  
  input=(env("HOME")+"/.dvb_script_gui.ini/fortschrittfenster")
+
  fenster1.setText(file_read(env("HOME")+"/dvbscript/fenster_fortschritt"))
text=file_read(input)
 
fenster1.setText(text)
 
  
Um diesen Code einzugeben, haben wir aus dem Kontextmenue des ScriptObjects natürlich den Punkt ''Kommander-Text bearbeiten ''ausgewählt.
+
Um diesen Code einzugeben, haben wir aus dem Kontextmenue des ''ScriptObjects'' natürlich den Punkt ''Kommander-Text bearbeiten ''ausgewählt.
  
Hier kommt nun eine kurze Erläuterung zu diesem Dreizeiler:
+
Hier kommt nun eine kurze Erläuterung, was diese Zeile bedeutet:
  
Die Shell-Variable HOME enthält den Pfad zum Heimatverzeichnis. In der ersten Zeile des Scriptes wird der Inhalt dieser Shell-Variablen'' ''mit dem String ''/.dvb_script_gui.ini/fortschrittfenster ''addiert.'' ''Das Ergebnis dieser String-Addition ist die vollständige Pfadangabe zm ''fortschrittfenster''. Dieser Pfad wird in die Variable ''input'' geschrieben.
+
Die Shell-Variable ''HOME'' enthält den Pfad zum Heimatverzeichnis des Nutzers. Mit env("HOME") wird diese Variable von Kommander ausgelesen. Der Pfad wird noch ergänzt (String-Addition), so daß in den Klammern dann folgendes steht: ~/dvbscript/fenster_fortschritt.
  
In der zweiten Zeile wird der Inhalt der Datei ''~'' ''/.dvb_script_gui.ini/fortschrittfenster'' gelesen und in die Variable ''text'' geschrieben.
 
  
Und in der dritten Zeile wird der Dateiinhalt als Text an das Widget ''fenster1'' übergeben.
+
Der Inhalt der Datei, auf die der Pfad zeigt, wird mit dem file_read-Befehl gelesen und dem Widget ''fenster1'' als Text übergeben.
  
==== <font color="brown">Zwischenbemerkung 1 </font> ====
+
==== <font color="gray">Zwischenbemerkung 1 </font> ====
 
Habe ich übrigens schon erwähnt, daß es nicht ganz ohne Sinn ist, die bisherige Arbeit von Zeit zu Zeit zu speichern? Falls nicht, dann erinnere ich hiermit daran. Falls doch, na ja, dann schadet es auch nichts, noch einmal davon zu sprechen.
 
Habe ich übrigens schon erwähnt, daß es nicht ganz ohne Sinn ist, die bisherige Arbeit von Zeit zu Zeit zu speichern? Falls nicht, dann erinnere ich hiermit daran. Falls doch, na ja, dann schadet es auch nichts, noch einmal davon zu sprechen.
  
==== <font color="brown">Zwischenbemerkung 2</font> ====
+
==== <font color="gray">Zwischenbemerkung 2</font> ====
 
Wir haben bis jetzt folgende Widgets installiert:
 
Wir haben bis jetzt folgende Widgets installiert:
  
* Formular mit dem Namen ''GUI''
+
* ''Formular'' mit dem Namen ''GUI''
* GroupBox mit dem Namen ''rahmen''
+
* ''GroupBox'' mit dem Namen ''rahmen''
* TextBrowser mit dem Namen ''fenster1''
+
* ''TextBrowser'' mit dem Namen ''fenster1''
* ScriptObject mit dem Namen ''refresh_fenster1''
+
* ''ScriptObject'' mit dem Namen ''refresh_fenster1''
  
Widgets lassen sich im Programm über ihre Namen ansprechen. Wir können die Eigenschaft ''text'' des ''TextBrowsers'' also auch per Programm füllen, was wir mit dem Dreizeiler ja tun. Dieser Text erscheint dann im Ausgabefenster des ''TextBrowsers'', also in unserem Log-Fenster.
+
Widgets lassen sich im Programm über ihre Namen ansprechen. Wir können die Eigenschaft ''text'' des ''TextBrowsers'' also auch per Programm füllen, was wir mit Hilfe des ''ScriptObjects'' ja tun. Dieser Text erscheint dann im Ausgabefenster des ''TextBrowsers'', also in unserem Log-Fenster.
  
Was uns nun noch fehlt, das ist, den Dreizeiler zu starten, und zwar regelmäßig. Doch auch hierfür bietet Kommander ein Widget an, nämlich den Timer, der in der Symbolleiste aussieht wie ein uralter Wecker.
+
Was uns nun noch fehlt, das ist, das ''ScriptObject'' zu starten, und zwar regelmäßig. Doch auch hierfür bietet Kommander ein Widget an, nämlich den ''Timer'', der aussieht wie ein uralter Wecker.
  
Also, installieren wir im Formular einen solchen Timer und geben ihm folgende Eigenschaften:
+
Also, installieren wir im ''Formular'' einen solchen ''Timer'' und geben ihm folgende Eigenschaften:
  
==== <font color="brown">Der Timer</font> ====
+
==== <font color="gray">Der Timer</font> ====
* '''name:''' Timer_Log
+
* ''name:'' Timer_Log
* '''interval:''' 500
+
* ''interval:'' 500
  
Das bedeutet, alle 500ms wird das getan, was wir in den Kommander-Text des Timers geschrieben haben bzw. jetzt schreiben werden:
+
Das bedeutet, alle 500ms wird das getan, was wir in den Kommander-Text des ''Timers'' geschrieben haben bzw. jetzt schreiben werden:
  
 
  refresh_fenster1.execute
 
  refresh_fenster1.execute
  
Diese Anweisung bewirkt, daß der im ScriptObject enthaltene Code alle halbe Sekunden ausgeführt wird.
+
Diese Anweisung bewirkt, daß der im ''ScriptObject'' enthaltene Code alle halbe Sekunden ausgeführt wird.
  
Jede halbe Sekunde wird also der Inhalt der Datei ''~'' ''/.dvb_script_gui.ini/fortschrittfenster'' in die Eigenschaft ''text'' von ''fenster1'' geschrieben und damit angezeigt.  
+
Jede halbe Sekunde wird also der Inhalt der Datei ''~/dvbscript/fenster_fortschritt'' in die Eigenschaft ''text'' von ''fenster1'' geschrieben und damit angezeigt.  
  
Ganz fertig sind wir aber immer noch nicht, denn der Timer muß erst einmal gestartet werden:
+
Ganz fertig sind wir aber immer noch nicht, denn der ''Timer'' muß erst einmal gestartet werden:
  
=== <font color="purple">Verbindungen (Signals und Slots)</font> ===
+
=== <font color="black">Verbindungen (Signals und Slots)</font> ===
 
Wie das mit den Verbindungen funktioniert, habe ich in der Einleitung zu erklären versucht. Hier die aktuelle Anwendung dieses Prinzips von ''signals and slots'':
 
Wie das mit den Verbindungen funktioniert, habe ich in der Einleitung zu erklären versucht. Hier die aktuelle Anwendung dieses Prinzips von ''signals and slots'':
  
* '''Signale:''' GUI widgetOpened()
+
* ''Signale:'' GUI widgetOpened()
* '''Slots:''' Timer_Log execute()
+
* ''Slots:'' Timer_Log execute()
  
Wenn das Formular mit dem Namen GUI geöffnet wird (was immer dann passiert, wenn wir den Dialog starten), dann läuft der Timer los.
+
Wenn das ''Formular'' mit dem Namen ''GUI'' geöffnet wird (was immer dann passiert, wenn wir den Dialog starten), dann läuft der ''Timer'' los.
  
 
Und damit ist, nebenbei gesagt, die Programmierung des Log-Fensters abgeschlossen. Weiter geht es mit dem DebugLog.
 
Und damit ist, nebenbei gesagt, die Programmierung des Log-Fensters abgeschlossen. Weiter geht es mit dem DebugLog.
  
== <font color="green"> Das Debug-Log </font> ==
+
== <font color="maroon"> Das Debug-Log </font> ==
=== <font color="purple">Funktionsweise</font> ===
+
=== <font color="black">Funktionsweise</font> ===
 
Das Debug-Log funktioniert ähnlich wie das normale Log, wobei ich gestehen muß, ein paar kleine Feinheiten eingebaut zu haben. Aber die schauen wir uns später an, zuerst der Überblick:
 
Das Debug-Log funktioniert ähnlich wie das normale Log, wobei ich gestehen muß, ein paar kleine Feinheiten eingebaut zu haben. Aber die schauen wir uns später an, zuerst der Überblick:
  
Im DVB-Script wird der Standard-Fehlerkanal (''stderr'') in eine Datei geschrieben:
+
Im [[Dvb_script_gui/scriptcode|DVB-Script]] wird der Standard-Fehlerkanal (''stderr'') in eine Datei geschrieben:
  
  exec 2> ~/.dvb_script_gui.ini/debugfenster
+
  exec 2> ~/dvbscript/fenster_debug
  
Die Datei, die alle 500ms abgefragt wird, heißt diesmal ''debugfenster''.  
+
Die Datei, die alle 500ms abgefragt wird, heißt diesmal also ''debugfenster''.  
  
 
Wer nun denkt, hier erscheinen nur Fehlermeldungen, der sieht sich getäuscht. Bash-Anweisungen bzw. -Tools schicken auch Betriebsmeldungen über ''stderr''. Wie gesprächig so eine Anweisung sein darf, das läßt sich oftmals einstellen über die Option ''--verbose''.
 
Wer nun denkt, hier erscheinen nur Fehlermeldungen, der sieht sich getäuscht. Bash-Anweisungen bzw. -Tools schicken auch Betriebsmeldungen über ''stderr''. Wie gesprächig so eine Anweisung sein darf, das läßt sich oftmals einstellen über die Option ''--verbose''.
Zeile 189: Zeile 203:
 
Über den Clear-Button läßt sich der Text im Debug-Log löschen (Nur die Anzeige, nicht der Dateiinhalt, der wird erst beim nächsten Scriptstart niedergemacht).
 
Über den Clear-Button läßt sich der Text im Debug-Log löschen (Nur die Anzeige, nicht der Dateiinhalt, der wird erst beim nächsten Scriptstart niedergemacht).
  
Die Ein-/Aus-Knöpfe dienen zum Ein- bzw. Ausschalten der Anzeige im Debug-Log (vor dem Script-Start). Nach Beendigung des Script-Laufes kann mit ihnen der Scroll-Modus des Log-Fensters eingeschalten werden. Dann kann das komplette Log betrachtet werden.
+
Die Ein-/Aus-Knöpfe dienen zum Ein- bzw. Ausschalten der Anzeige im Debug-Log (vor dem Script-Start). Nach Beendigung des Script-Laufes kann mit ihnen die Fokussierung des Log-Fensters auf die jeweils aktuellen Logzeilen ausgeschalten werden. Dann kann das komplette Log betrachtet werden.
  
 
Und noch eine letzte Kleinigkeit
 
Und noch eine letzte Kleinigkeit
  
Als Anzeigeobjekt habe ich diesmal nicht einen TextBrowser verwendet, sondern ein TextEdit-Feld, welches ich auf ReadOnly geschalten habe.
+
Als Anzeigeobjekt habe ich diesmal nicht einen ''TextBrowser'' verwendet, sondern ein ''TextEdit''-Widget, welches ich auf ''ReadOnly'' geschalten habe.
  
=== <font color="purple">Bekannte Bausteine 1</font> ===
+
=== <font color="black">Bekannte Bausteine 1</font> ===
==== <font color="brown">TextEdit</font> ====
+
==== <font color="gray">TextEdit</font> ====
* '''name: '''TextEdit_Debug_Log
+
* ''name:''''' '''TextEdit_Debug_Log
* '''minimumSize:''' Breite 470, Höhe 350
+
* ''minimumSize:'' Breite 470, Höhe 350
* '''readOnly:''' Wahr
+
* ''readOnly:'' Wahr
  
==== <font color="brown">GroupBox</font> ====
+
==== <font color="gray">GroupBox</font> ====
* '''name:''' GroupBox2
+
* ''name:'' GroupBox2
* '''title:''' LogDebug
+
* ''title:'' LogDebug
* '''hAlign:''' AlignHCenter
+
* ''hAlign:'' AlignHCenter
* '''vAlign:''' AlignVCenter
+
* ''vAlign:'' AlignVCenter
  
==== <font color="brown">ScriptObject</font> ====
+
==== <font color="gray">ScriptObject</font> ====
* '''name:''' refresh_fesnster2
+
* ''name:'' refresh_fesnster2
* '''text:''' fen2
+
* ''text:''' '''''fen2
 +
* ''Kommandertext:''
  
'''Kommandertext:'''
+
  TextEdit_Debug_Log.setText(textfile_read(env("HOME"+"/dvbscript/fenster_debug"))
 
 
  input=(env("HOME")+"/.dvb_script_gui.ini/debugfenster")
 
text=file_read(input)
 
TextEdit_Debug_Log.setText(text)
 
 
  TextEdit_Debug_Log.scrollToBottom
 
  TextEdit_Debug_Log.scrollToBottom
  
Zeile 224: Zeile 235:
 
Diese Funktion sorgt dafür, daß in unserem Debug-Log immer das Ende der Log-Datei angezeigt wird.
 
Diese Funktion sorgt dafür, daß in unserem Debug-Log immer das Ende der Log-Datei angezeigt wird.
  
==== <font color="brown">Der Timer</font> ====
+
==== <font color="gray">Der Timer</font> ====
* '''name:''' Timer_Debug
+
* ''name:'' Timer_Debug
* '''interval:''' 500
+
* ''interval:'' 500
 
+
* ''Kommandertext:''
'''Kommandertext:'''
 
  
 
  refresh_fenster2.execute
 
  refresh_fenster2.execute
  
==== <font color="brown">Verbindungen (Signals und Slots)</font> ====
+
==== <font color="gray">Verbindungen (Signals und Slots)</font> ====
'''Signale:''' GUI widgetOpened()
+
''Signale:'' GUI widgetOpened()
 
 
'''Slots:''' Timer_Debug execute()
 
  
 +
''Slots:'' Timer_Debug execute()
  
==== <font color="brown">Zwischenbemerkung 3 </font> ====
+
==== <font color="gray">Zwischenbemerkung 3 </font> ====
 
Bis jetzt war alles so, wie bein normalen Log-Fenster. Genauere Erklärungen erübrigen sich also. Kommen wir also nun zu den zusätzlichen Elementen:
 
Bis jetzt war alles so, wie bein normalen Log-Fenster. Genauere Erklärungen erübrigen sich also. Kommen wir also nun zu den zusätzlichen Elementen:
  
=== <font color="purple">Neue Bausteine</font> ===
+
=== <font color="black">Neue Bausteine</font> ===
==== <font color="brown">RadioButton </font> ====
+
==== <font color="gray">RadioButton </font> ====
'''Ein-Knopf'''
+
''Ein-Knopf''
  
* '''name:''' RadioButton_Ein
+
* ''name:'' RadioButton_Ein
* '''text:''' Ein
+
* ''text:'' Ein
* '''checked:''' Wahr
+
* ''checked:'' Wahr
  
Dieser Druckknopf hat zwei Zustände: gedrückt und nicht gedrückt. In diesem Fall wurde mit der Eigenschaft checked festgelegt, daß der Knopf per default gedrückt ist.
+
Dieser Druckknopf hat zwei Zustände: gedrückt und nicht gedrückt. In diesem Fall wurde mit der Eigenschaft ''checked'' festgelegt, daß der Knopf per default gedrückt ist.
  
 
Für die beiden Zustände kann auch unterschiedlicher Kommandertext eingegeben werden. Das bedeutet, wenn der Button gedrückt ist, wird etwas anderes ausgeführt als in ungdrücktem Zustand.
 
Für die beiden Zustände kann auch unterschiedlicher Kommandertext eingegeben werden. Das bedeutet, wenn der Button gedrückt ist, wird etwas anderes ausgeführt als in ungdrücktem Zustand.
Zeile 255: Zeile 264:
 
Dies aber nur zur Information. Wir benötigen in unserem Fall gar keinen Kommandertext, da wir den Knopf über die ''signals and slots'' abfragen werden.
 
Dies aber nur zur Information. Wir benötigen in unserem Fall gar keinen Kommandertext, da wir den Knopf über die ''signals and slots'' abfragen werden.
  
'''Aus-Knopf'''
+
''Aus-Knopf''
  
* '''name:''' RadioButton_Aus
+
* ''name:'' RadioButton_Aus
* '''text:''' Aus
+
* ''text:'' Aus
  
 
Der Aus-Knopf ist per default nicht gedrückt.
 
Der Aus-Knopf ist per default nicht gedrückt.
  
==== <font color="brown">ButtonGroup </font> ====
+
==== <font color="gray">ButtonGroup </font> ====
 
Die beiden ''RadioButtons'' dürfen nur selektiv angesprochen werden können. Wenn also der eine Knopf ''An'' ist, muß der andere ''Aus ''sein. Das können wir erreichen, indem wir die Buttons in eine ''ButtonGroup'' packen.
 
Die beiden ''RadioButtons'' dürfen nur selektiv angesprochen werden können. Wenn also der eine Knopf ''An'' ist, muß der andere ''Aus ''sein. Das können wir erreichen, indem wir die Buttons in eine ''ButtonGroup'' packen.
  
* '''name:''' ButtonGroup2
+
* ''name:'' ButtonGroup2
* '''minimumSize:''' Breite 60, Höhe 60
+
* ''minimumSize:'' Breite 60, Höhe 60
* '''exclusive:''' Wahr
+
* ''exclusive:'' Wahr
  
 
Die ''ButtonGroup'' kann also über die Bezeichnung ''ButtonGroup2 ''angesprochen werden, hat eine Mindestgröße von 60 x 60 Pixeln und stellt sicher, daß exclusiv nur einer der enthaltenen Buttons gedrückt ist.
 
Die ''ButtonGroup'' kann also über die Bezeichnung ''ButtonGroup2 ''angesprochen werden, hat eine Mindestgröße von 60 x 60 Pixeln und stellt sicher, daß exclusiv nur einer der enthaltenen Buttons gedrückt ist.
  
==== <font color="brown">Layout </font> ====
+
==== <font color="gray">Layout </font> ====
 
Das Layout ist schnell erledigt. Einfach die beiden ''RadioButtons'' in die ''Button Group'' schieben, diese markieren und auswählen: ''Bedienelemente im Raster anordnen''
 
Das Layout ist schnell erledigt. Einfach die beiden ''RadioButtons'' in die ''Button Group'' schieben, diese markieren und auswählen: ''Bedienelemente im Raster anordnen''
  
 +
=== <font color="black">Bekannte Bausteine 2</font> ===
 +
==== <font color="gray">ExecButton </font> ====
 +
* ''name:'' ExecButton_Clear
  
=== <font color="purple">Bekannte Bausteine 2</font> ===
+
* ''minimumSize:'' Breite 60, Höhe 60
==== <font color="brown">ExecButton </font> ====
+
* ''text:'' Clear
* '''name:''' ExecButton_Clear
+
* ''Kommandertext:''
 
 
* '''minimumSize:''' Breite 60, Höhe 60
 
* '''text:''' Clear
 
 
 
'''Kommandertext:'''
 
  
 
  RadioButton_Aus.setChecked(true)
 
  RadioButton_Aus.setChecked(true)
Zeile 290: Zeile 297:
 
Das Drücken des Clear-Buttons bewirkt also folgendes:
 
Das Drücken des Clear-Buttons bewirkt also folgendes:
  
* Der Aus-Knopf wird gedrückt (wodurch der Ein-Knopf wird über die Eigenschaft ''exclusive'' der ButtonGroup ausgeschalten).
+
* Der Aus-Knopf wird gedrückt (wodurch der Ein-Knopf wird über die Eigenschaft ''exclusive'' der ''ButtonGroup'' ausgeschalten).
* Der Timer, der das Debug-Fenster mit Hilfe des ScriptObjects ''refresh_fenster2'' ständig aktualisiert, wird gestoppt.
+
* Der ''Timer'', der das Debug-Fenster mit Hilfe des ScriptObjects ''refresh_fenster2'' ständig aktualisiert, wird gestoppt.
 
* Und das Debug-Log-Fenster wird geleert.
 
* Und das Debug-Log-Fenster wird geleert.
  
=== <font color="purple">Verbindungen (Signals and slots)</font> ===
+
=== <font color="black">Verbindungen (Signals and slots)</font> ===
'''für den Aus-Knopf'''
+
''für den Aus-Knopf''
  
* '''Signale:''' RadioButton_Aus pressed()
+
* ''Signale:'' RadioButton_Aus pressed()
* '''Slots:''' Timer_Debug cancel()
+
* ''Slots:'' Timer_Debug cancel()
  
 
Sobald der Aus-Knopf gedrückt wird, wird der Debug-Timer gestoppt.
 
Sobald der Aus-Knopf gedrückt wird, wird der Debug-Timer gestoppt.
  
  
'''für den Ein-Knopf'''
+
''für den Ein-Knopf''
  
* '''Signale:''' RadioButton_Ein pressed()
+
* ''Signale:'' RadioButton_Ein pressed()
* '''Slots: '''Timer_Debug execute()
+
* ''Slots:''''' '''Timer_Debug execute()
  
 
Mit dem Drücken des Ein-Knopfes wird der Debug-Timer gestartet.
 
Mit dem Drücken des Ein-Knopfes wird der Debug-Timer gestartet.
  
Diese Knöpfe lassen sich nicht mehr verändern, wenn eine Videobearbeitungsfunktion gestartet wurde. Sie müssen entweder vorher oder nach Abschluß der Bearbeitung eingestellt werden.
+
Diese Knöpfe lassen sich übrigens nicht mehr verändern, wenn eine Videobearbeitungsfunktion gestartet wurde. Sie müssen entweder vorher oder nach Abschluß der Bearbeitung eingestellt werden.
  
* '''vorher:''' Die Anzeige des Debug-Logs kann aktiviert oder deaktiviert werden
+
* ''vorher:'' Die Anzeige des Debug-Logs kann aktiviert oder deaktiviert werden
* '''nachher:''' Die Fokussierung der Anzeige auf das Dateiende kann ein- bzw. ausgeschalten werden.
+
* ''nachher:'' Die Fokussierung der Anzeige auf das Dateiende kann ein- bzw. ausgeschalten werden.
  
=== <font color="purple">Layout des Debug-Logs</font> ===
+
=== <font color="black">Layout des Debug-Logs</font> ===
 
So, die Programmierung des Debug-Logs ist nun abgeschlossen. Jetzt müssen nur noch die einzelnen Elemente dahin verfrachtet werden, wo sie in der fertigen GUI zu erscheinen haben.
 
So, die Programmierung des Debug-Logs ist nun abgeschlossen. Jetzt müssen nur noch die einzelnen Elemente dahin verfrachtet werden, wo sie in der fertigen GUI zu erscheinen haben.
  
Dazu machen wir die GroupBox so groß, daß alle eben erstellten Widgets hineinpassen. Und diese schieben nun wir in die Box (den ''Clear-Button'', die ''ButtonGroup'' mit den ''Radio-Buttons'' und das Anzeigefenster ''TextEdit'')
+
Dazu machen wir die ''GroupBox'' so groß, daß alle eben erstellten Widgets hineinpassen. Und diese schieben nun wir in die Box (den ''Clear-Button'', die ''ButtonGroup'' mit den ''Radio-Buttons'' und das Anzeigefenster ''TextEdit'')
  
 
Zwischen die ''ButtonGroup'' und den ''Clear-Button'' fügen wir nun noch einen Abstand ein (''Füge Abstand ein'', so heißt das dazu notwendige Teil oben aus der Symbolleiste)
 
Zwischen die ''ButtonGroup'' und den ''Clear-Button'' fügen wir nun noch einen Abstand ein (''Füge Abstand ein'', so heißt das dazu notwendige Teil oben aus der Symbolleiste)
  
Nun markieren wir die GroupBox und ordnen die enthaltenen Bedienelemente im Raster aus (kennen wir schon, den Befehl, oder?) und stellen fest, daß wir fertig sind mit dem Debug-Log.
+
Nun markieren wir die ''GroupBox'' und ordnen die enthaltenen Bedienelemente im Raster an (kennen wir schon, den Befehl, oder?) und stellen fest, daß wir fertig sind mit dem Debug-Log.
  
 
Übrigens, probiert es einmal aus und laßt den Abstand weg. Das gibt interessante Effekte beim Layout!
 
Übrigens, probiert es einmal aus und laßt den Abstand weg. Das gibt interessante Effekte beim Layout!
  
== <font color="green"> Die Aktionen </font> ==
+
== <font color="maroon"> Die Aktionen </font> ==
=== <font color="purple">Vorbemerkung</font> ===
+
=== <font color="black">Vorbemerkung</font> ===
 
Es gibt eine Vielzahl von Möglichkeiten der Videobearbeitung, von denen ich beispielhaft nur einige ausgewählt habe, um sie über die GUI anzusteuern. Der Grund ist alleine darin zu sehen, daß ich nicht die Absicht habe, ein fertiges Universalprogramm zu präsentieren. Vielmehr liegt die Intention darin, die Wege zu einem solchen Programm dem Leser näherzubringen und ihn damit in die Lage zu versetzen, selbst den Versuch zu wagen und sein eigenes Programm zu erstellen.
 
Es gibt eine Vielzahl von Möglichkeiten der Videobearbeitung, von denen ich beispielhaft nur einige ausgewählt habe, um sie über die GUI anzusteuern. Der Grund ist alleine darin zu sehen, daß ich nicht die Absicht habe, ein fertiges Universalprogramm zu präsentieren. Vielmehr liegt die Intention darin, die Wege zu einem solchen Programm dem Leser näherzubringen und ihn damit in die Lage zu versetzen, selbst den Versuch zu wagen und sein eigenes Programm zu erstellen.
  
=== <font color="purple">Funktionsweise</font> ===
+
=== <font color="black">Funktionsweise</font> ===
 
Ich habe die Aufgaben in drei Gruppen eingeteilt:
 
Ich habe die Aufgaben in drei Gruppen eingeteilt:
  
Zeile 345: Zeile 352:
 
* Auf ''Go'' drücken
 
* Auf ''Go'' drücken
  
=== <font color="purple">Vorbereitung</font> ===
+
=== <font color="black">Vorbereitung</font> ===
 
Im ''TabWidget'' befindet sich eine ''ButtonGroup'', in der die ''Radio-Buttons ''und ''Labels'' (Überschriften) organisiert sind. Bauen wir also zuerst die ''ButtonGroup'' mit Inhalt. Wie das funktioniert, wissen wir ja inzwischen.
 
Im ''TabWidget'' befindet sich eine ''ButtonGroup'', in der die ''Radio-Buttons ''und ''Labels'' (Überschriften) organisiert sind. Bauen wir also zuerst die ''ButtonGroup'' mit Inhalt. Wie das funktioniert, wissen wir ja inzwischen.
  
==== <font color="brown">RadioButtons </font> ====
+
==== <font color="gray">RadioButtons </font> ====
 
Im der Gruppe Video-DVD von oben nach unten:
 
Im der Gruppe Video-DVD von oben nach unten:
  
'''Brennen'''
+
''Brennen''
  
* '''name:''' RadioButton_11
+
* ''name:'' RadioButton_11
* '''text:''' Script.execute(11)
+
* ''text:'' Script.execute(11)
* '''checked:''' Wahr
+
* ''checked:'' Wahr
  
'''Sichern'''
+
''Sichern''
  
* '''name:''' RadioButton_12
+
* ''name:'' RadioButton_12
* '''text:''' Script.execute(12)
+
* ''text:'' Script.execute(12)
  
'''Brennen'''
+
''Brennen''
  
* '''name:''' RadioButton_13
+
* ''name:'' RadioButton_13
* '''text:''' Script.execute(13)
+
* ''text:'' Script.execute(13)
  
'''Bedrucken'''
+
''Bedrucken''
  
* '''name:''' RadioButton_81
+
* ''name:'' RadioButton_81
* '''text:''' Script.execute(81)
+
* ''text:'' Script.execute(81)
  
 
Es handelt sich jeweils um Kommandertext für den Zustand ''checked'' (also, Knopf gedrückt).
 
Es handelt sich jeweils um Kommandertext für den Zustand ''checked'' (also, Knopf gedrückt).
  
==== <font color="brown">Labels </font> ====
+
==== <font color="gray">Labels </font> ====
Im der Gruppe Video-DVD von oben nach unten:
+
In der Gruppe Video-DVD von oben nach unten:
 +
 
 +
''Label 1''
 +
 
 +
* ''name:'' Label1
 +
* ''text:'' DVB (mpeg2): Schneiden, Authoring und ...
 +
 
 +
''label 2''
  
* '''name:''' Label1
+
* ''name:'' Label2
* '''text:''' DVB (mpeg2): Schneiden, Authoring und ...
+
* ''text:'' Gesicherte DVD-Struktur ...
  
* '''name:''' Label2
+
''Label 3''
* '''text:''' Gesicherte DVD-Struktur ...
 
  
* '''name:''' Label3
+
* ''name:'' Label3
* '''text:''' Video-DVD ...
+
* ''text:'' Video-DVD ...
  
==== <font color="brown">ButtonGroup </font> ====
+
==== <font color="gray">ButtonGroup </font> ====
* '''name: '''ButtonGroup_Video_DVD
+
* ''name:''''' '''ButtonGroup_Video_DVD
* '''exclusive:''' Wahr
+
* ''exclusive:'' Wahr
  
 
Das Layout der ''ButtonGroup'' nicht vergesseen!
 
Das Layout der ''ButtonGroup'' nicht vergesseen!
  
  
Dann brauchen wir noch einen Exec-Button als Start-Knopf:
+
Dann brauchen wir noch einen ''ExecButton'' als Start-Knopf:
  
==== <font color="brown">ExecButton </font> ====
+
==== <font color="gray">ExecButton </font> ====
* '''name:''' ExecButton_Start_Video_DVD
+
* ''name:'' ExecButton_Start_Video_DVD
  
* '''minimumSize:''' Breite 60, Höhe 60
+
* ''minimumSize:'' Breite 60, Höhe 60
* '''text:''' Go
+
* ''text:'' Go
 
+
* ''Kommandertext:''
'''Kommandertext:'''
 
  
 
  ButtonGroup_Video_DVD.text
 
  ButtonGroup_Video_DVD.text
Zeile 408: Zeile 420:
 
Und wir brauchen das ''TabWidget'' selbst, in der die ganze Choose untergebracht ist.
 
Und wir brauchen das ''TabWidget'' selbst, in der die ganze Choose untergebracht ist.
  
==== <font color="brown">TabWidget </font> ====
+
==== <font color="gray">TabWidget </font> ====
* '''name:''' TabWidget1
+
* ''name:'' TabWidget1
* '''pageTitle:''' Video-DVD
+
* ''pageTitle:'' Video-DVD
  
Nun die ButtonGroup mit den ganzen Bedienelementen und den Go-Knopf ins Tab-Widget schieben, Layout erstellen und fertig!
+
Nun die ''ButtonGroup'' mit den ganzen Bedienelementen und den Go-Knopf ins ''TabWidget'' schieben, Layout erstellen und fertig!
  
  
 
Fertig? Nein, doch noch nicht ganz, denn uns fehlen ja noch die zwei anderen Reiter. Aber die sind auch geschwind erstellt, und zwar so:
 
Fertig? Nein, doch noch nicht ganz, denn uns fehlen ja noch die zwei anderen Reiter. Aber die sind auch geschwind erstellt, und zwar so:
  
* Rechtsklick auf das TabWidget
+
* Rechtsklick auf das ''TabWidget''
 
* Seite hinzufügen...
 
* Seite hinzufügen...
 
* Seitentitel bearbeiten... (Was hier eingetragen wird, das dürft ihr raten).
 
* Seitentitel bearbeiten... (Was hier eingetragen wird, das dürft ihr raten).
  
==== <font color="brown">Zwischbemerkung 3 </font> ====
+
==== <font color="gray">Zwischbemerkung 3 </font> ====
Die beiden eben erstellten Tab-Seiten brauchen natürlich auch noch Inhalte. Hier unterscheidet sich die Vorgehensweise nicht von dem, was wir gerade auf der ersten Tab-Seite produziert haben. Deshalb hier nur kurz und ohne weiteren Kommentar die Elemente und deren Inhalte:Gruppe Daten-DVD:
+
Die beiden letzten Tab-Seiten brauchen natürlich auch noch Inhalte. Hier unterscheidet sich die Vorgehensweise nicht von dem, was wir gerade auf der ersten Tab-Seite produziert haben. Deshalb hier nur kurz und ohne weiteren Kommentar die Elemente und deren Inhalte:
  
''RadioButtons''
 
  
'''Brennen'''
+
''RadioButtons der Gruppe Daten-DVD''
  
* '''name:''' RadioButton_21
+
''Brennen''
* '''text:''' Script.execute(21)
 
* '''checked:''' Wahr
 
  
'''Sichern'''
+
* ''name:'' RadioButton_21
 +
* ''text:'' Script.execute(21)
 +
* ''checked:'' Wahr
  
* '''name:''' RadioButton_22
+
''Sichern''
* '''text:''' Script.execute(22)
 
  
'''Brennen'''
+
* ''name:'' RadioButton_22
 +
* ''text:'' Script.execute(22)
  
* '''name:''' RadioButton_23
+
''Brennen''
* '''text:''' Script.execute(23)
 
  
'''Bedrucken'''
+
* ''name:'' RadioButton_23
 +
* ''text:'' Script.execute(23)
  
* '''name:''' RadioButton_82
+
''Bedrucken''
* '''text:''' Script.execute(82)
 
  
''Labels''
+
* ''name:'' RadioButton_82
 +
* ''text:'' Script.execute(82)
  
* '''name:''' Label4
+
.
* '''text:''' DVB (mpeg2): Schneiden, Wandeln zu TS und ...
 
  
* '''name:''' Label5
+
''Labels der Gruppe Daten-DVD''
* '''text:''' Gesicherte TS-Files ...
 
  
* '''name:''' Label6
+
''Label 4''
* '''text:''' Daten-DVD ...
 
  
''ExecButton''
+
* ''name:'' Label4
 +
* ''text:'' DVB (mpeg2): Schneiden, Wandeln zu TS und ...
  
* '''name:''' ExecButton_Start_Video_DVD_2
+
''Label 5''
  
* '''minimumSize:''' Breite 60, Höhe 60
+
* ''name:'' Label5
* '''text:''' Go
+
* ''text:'' Gesicherte TS-Files ...
  
'''Kommandertext:'''
+
Label 6
 +
 
 +
* ''name:'' Label6
 +
* ''text:'' Daten-DVD ...
 +
 
 +
.
 +
 
 +
''ExecButton der Gruppe Daten-DVD''
 +
 
 +
* ''name:'' ExecButton_Start_Video_DVD_2
 +
 
 +
* ''minimumSize:'' Breite 60, Höhe 60
 +
* ''text:'' Go
 +
* ''Kommandertext:''
  
 
  ButtonGroup_Daten_DVD.text
 
  ButtonGroup_Daten_DVD.text
  
  
''ButtonGroup''
+
''ButtonGroup der Gruppe Daten-DVD''
  
* '''name:''' ButtonGroup_Daten_DVD
+
* ''name:'' ButtonGroup_Daten_DVD
* '''exclusive:''' Wahr
 
  
Gruppe Videoclip:
+
* ''exclusive:'' Wahr
  
''RadioButtons''
+
''.''
  
'''Alle Tonspuren'''
+
''RadioButtons der Gruppe Videoclip''
  
* '''name:''' RadioButton_31
+
''Alle Tonspuren''
* '''text:''' Script.execute(31)
 
* '''checked:''' Wahr
 
  
'''AC3'''
+
* ''name:'' RadioButton_31
 +
* ''text:'' Script.execute(31)
 +
* ''checked:''' '''''Wahr
  
* '''name:''' RadioButton_32
+
''AC3''
* '''text:''' Script.execute(32)
 
  
'''MP2'''
+
* ''name:'' RadioButton_32
 +
* ''text:'' Script.execute(32)
  
* '''name:''' RadioButton_33
+
''MP2''
* '''text:''' Script.execute(33)
 
  
'''MP2 normalisiert'''
+
* ''name:'' RadioButton_33
 +
* ''text:'' Script.execute(33)
  
* '''name:''' RadioButton_37
+
''MP2 normalisiert''
* '''text:''' Script.execute(37)
 
  
'''MP2'''
+
* ''name:'' RadioButton_37
 +
* ''text:'' Script.execute(37)
  
* '''name:''' RadioButton_34
+
''MP2''
* '''text:''' Script.execute(34)
 
  
'''MP2 normalisiert'''
+
* ''name:'' RadioButton_34
 +
* ''text:'' Script.execute(34)
  
* '''name:''' RadioButton_38
+
''MP2 normalisiert''
* '''text:''' Script.execute(38)
 
  
''Labels''
+
* ''name:'' RadioButton_38
 +
* ''text:'' Script.execute(38)
  
* '''name:''' Label7
+
''.''
* '''text:''' Videoclip (mpeg2): Schneiden und speichern ...
 
  
* '''name:''' Label8
+
''Labels der Gruppe Videoclip''
* '''text:''' Videoclip (mpeg1) speichern ...
 
  
''ExecButton''
+
''Label 7''
  
* '''name:''' ExecButton_Start_Video_DVD_3
+
* ''name:'' Label7
 +
* text: Videoclip (mpeg2): Schneiden und speichern ...
  
* '''minimumSize:''' Breite 60, Höhe 60
+
''Label 8''
* '''text:''' Go
 
  
'''Kommandertext:'''
+
* ''name:'' Label8
 +
* ''text:'' Videoclip (mpeg1) speichern ...
  
ButtonGroup_Videoclip.text
+
.
 +
 
 +
''ExecButton der Gruppe Videoclip''
 +
 
 +
* ''name:'' ExecButton_Start_Video_DVD_3
  
 +
* ''minimumSize:'' Breite 60, Höhe 60
 +
* ''text:'' Go
 +
* ''Kommandertext:''
  
''ButtonGroup''
+
ButtonGroup_Videoclip.text
 +
  
* '''name:''' ButtonGroup_Videoclip
+
''ButtonGroup der Gruppe Videoclip''
* '''exclusive:''' Wahr
 
  
Etwas ganz wichtiges fehlt noch, nämlich das Teil, welches unser Arbeitsscript aufruft:
+
*  ''name:'' ButtonGroup_Videoclip
  
==== <font color="brown">ScriptObject</font> ====
+
* ''exclusive:'' Wahr
* '''name:''' Script
 
* '''text:''' Script
 
  
'''Kommandertext:'''
+
Nun fehlt aber doch noch etwas ganz wichtiges, nämlich das Teil, in dem unser Arbeitsscript stehtt:
  
<nowiki>#!/bin/bash</nowiki>
+
==== <font color="gray">ScriptObject</font> ====
uebergabe=`echo @Self.item(0)`
+
* ''name:'' Script
hauptverzeichnis=`cat ~/.dvb_script_gui.ini/pfad_hauptverzeichnis`
+
* ''text:'' Script
scriptpfad=${hauptverzeichnis}/script/scriptcode.sh
+
* ''Kommandertext: ''Der Code des Arbeitsscriptes
${scriptpfad} "${uebergabe}"
 
  
=== <font color="purple">Das Zusammenspiel der Elemente</font> ===
+
=== <font color="black">Das Zusammenspiel der Elemente</font> ===
Jetzt wird es interessant. Denn nachdem wir das Tab-Widget fertiggestellt haben, werden wir nun erfahren, wie das alles auch funktioniert. Also...
+
Jetzt wird es interessant. Denn nachdem wir das ''TabWidget'' fertiggestellt haben, werden wir nun erfahren, wie das alles auch funktioniert. Also...
  
==== <font color="brown">Das Prinzip</font> ====
+
==== <font color="gray">Das Prinzip</font> ====
In einem festgelegten Verzeichnis auf der Festplatte befindet sich das Arbeitsscript. Beim Aufruf wird diesem Script als Argument eine Kennzahl übergeben, an Hand derer die entsprechenden Arbeitsschritte gestarten werden.
+
Durch das Drücken eines ''RadioButtons'' wird die im Kommandertext enthaltene Kennzahl an das ''ScriptObject'' und damit an das [[Dvb_script_gui/scriptcode|Arbeitsscript]] weitergeleitet. Dieser Vorgang wird gestartet durch das Drücken auf den Go-Button.
  
Durch Anwahl eines RadioButtons wird also die im Kommandertext enthaltene Kennzahl als Argument an das ScriptObject übergeben und von dort an das Arbeitsscript selber weitergeleitet. Dieser Vorgang wird gestartet durch das Drücken auf den Go-Button.
+
Das Arbeitsscript übernimmt die Kennzahl, wertet sie aus und startet die gewünschten Arbeitsschritte zur Videobearbeitung,
  
 
Das schauen wir uns an einem Beispiel etwas genauer an:
 
Das schauen wir uns an einem Beispiel etwas genauer an:
  
==== <font color="brown">So geht's</font> ====
+
==== <font color="gray">So geht's</font> ====
Der erste ''RadioButton'' "Brennen" der Gruppe Video-DVD enthält den Kommandertext:
+
Der erste ''RadioButton'' "Brennen" der Gruppe ''Video-DVD'' enthält den Kommandertext:
  
 
  Script.execute(11)
 
  Script.execute(11)
Zeile 566: Zeile 590:
 
Da sich es sich hier um Kommandertext für den Zustand ''checked'' des ''RadioButtons'' handelt, wird der darin enthaltene Befehl nicht direkt ausgeführt, sondern steht für weitere Untaten zur Verfügung und zwar als Inhalt der ''ButtonGroup'', in der sich der ''RadioButton'' befindet.
 
Da sich es sich hier um Kommandertext für den Zustand ''checked'' des ''RadioButtons'' handelt, wird der darin enthaltene Befehl nicht direkt ausgeführt, sondern steht für weitere Untaten zur Verfügung und zwar als Inhalt der ''ButtonGroup'', in der sich der ''RadioButton'' befindet.
  
Dieser Inhalt wird vom ExecButton (Go) ausgelesen mit dem Befehl
+
Dieser Inhalt wird vom ''ExecButton'' (Go) ausgelesen mit dem Befehl
  
 
  ButtonGroup_Video_DVD.text
 
  ButtonGroup_Video_DVD.text
Zeile 575: Zeile 599:
 
Noch einmal:
 
Noch einmal:
  
Durch Drücken von Go wird der Befehl ''Script.execute(11) ''ausgeführt. Dieser Befehl startet das im ScriptObject befindliche Script und übergibt ihm dabei als Argument die Kennzahl 11.
+
Durch Drücken von Go wird der Befehl Script.execute(11) ausgeführt. Dieser Befehl startet das im ScriptObject befindliche Arbeitsscript und übergibt ihm dabei als Argument die Kennzahl 11. An Hand dieser Kennzahl werden nun vom Bashscript die einzelnen Arbeitsschritte der Videobearbeitung aufgerufen.
 +
 
 +
== <font color="maroon">Die Playlist</font> ==
 +
=== <font color="black">Der ExecButton</font> ===
 +
Wie oben schon erwähnt habe ich in der Nähe der "unsichtbaren Widgets" noch einen ''ExecButton'' eingebaut, mit dem die Playlist der Videoclips gestartet werden kann.
 +
 
 +
* ''name'': ExecButton5 (Da habe ich es doch glatt versäumt, einen anständigen Namen für den Knopf zu vergeben)
 +
* ''text:'' Playlist abspielen
 +
* ''Kommandertext'':
 +
 
 +
execBackground(file_read(env("HOME")+"/dvbscript/playlist_starten"))
 +
 
 +
=== <font color="black">Das Problem</font> ===
 +
Die Playlist soll als Hintergrundprozess starten und somit auch dann weiterlaufen, wenn die GUI beendet wird. Das ist in der Bash überhaupt kein Problem: Es genügt ein
 +
 
 +
nohup xine -P /pfad_zur_playlist/playlist &
 +
 
 +
Tippen wir diesen Befehl also in das Arbeitsscript ein und starten, wie von den Aktionen gewohnt durch Übergabe einer Kennzahl an das Arbeittsscript:
 +
 
 +
Script.execute(71)
  
Das Script im Einzelnen:
+
Wir werden feststellen, daß es nicht funktioniert. Kommander kommt mit dem & im Befehl nicht zurecht. Lassen wir das & weg, dann können wir die Wiedergabeliste starten. Allerdings wird sie beendet, wenn wir die GUI schließen.
  
<nowiki>#!/bin/bash</nowiki>
+
Das ist nicht so, wie wir uns das vorgestellt haben.
  
Es handelt sich um ein Bash-Script.
+
Macht aber nichts, tricksen wir halt ein bißchen:
  
  uebergabe=`echo @Self.item(0)`
+
  execBackground("xine -P /pfad_zur_playlist/playlist")
  
Das übergebene Argument wird gelesen und in einer Variablen zwischengespeichert.
+
Dieser Befehl in unserem ''execButton'' hinterlegt, würde das Problem lösen, ist aber noch ein bißchen unflexibel, da der im Arbeitsscript ermittelte xine-Pfad nicht übergeben werden kann.
  
hauptverzeichnis=`cat ~/.dvb_script_gui.ini/pfad_hauptverzeichnis`
+
=== <font color="black">Die Lösung</font> ===
 +
Macht wiederum nichts. Lassen wir das Arbeitsscript den Befehl, so wie er ausgeführt werden soll, in eine Textdadei zu schreiben:
  
Der Pfad zum Hauptverzeichnis des DVB-Scripts wird ermittelt und zwischengespeichert
+
echo "$xine -P $hauptverzeichnis/playlist -a 1 -l=shuffle" > $hauptverzeichnis/playlist_starten
  
scriptpfad=${hauptverzeichnis}/script/scriptcode.sh
+
und lesen diese Datei über den ''execButton'' aus:
  
Nun kann der Pfad zum Arbeitsscript zwischengespeichert werden
+
execBackground(.....)
  
${scriptpfad} "${uebergabe}"
+
Führe den Bashbefehl in den Klammern im Hintergrund aus
  
Das Arbeitsscript wird gestartet und bekommt als Argument die Kennzahl übermittelt, die über die Variable $1 ausgewertet werden kann:
+
file_read(....)
  
  was_tun=$1
+
Der Befehl Befindet sich in einer Dateo, die mit dieser Anweisung gelesen wird
 +
 
 +
  env("HOME")+"/dvbscript/playlist_starten"
 +
 
 +
Und das ist der Pfad zu dieser Datei
 +
 
 +
 
 +
== <font color="maroon">Nachbemerkung</font> ==
 +
Das war es dann wohl. Was bleibt noch zu sagen? Layout nicht vergessen! Und zwischendurch mal abspeichern, das Ganze ... oder hatte ich das schon mal erwähnt? ... Ich weiß es nicht mehr.
  
An Hand dieser Kennzahl werden nun die einzelnen Arbeitsschritte der Videobearbeitung aufgerufen.
 
  
=== <font color="purple">Nachbemerkung</font> ===
 
 
{{Kommander_Navibox}}
 
{{Kommander_Navibox}}
 +
 +
[[Programmierung | Zurück zur Programmierung]]
 +
 +
[[Category:Programmierung]]
 +
 +
[[Category:DVB-Weiterverarbeitung]]

Aktuelle Version vom 10. März 2009, 18:40 Uhr

Einführung: Der Weg zur GUI - Die Funktionen - Screenshots



Vorwort

Im Folgenden wird die Programmierung der Bedienoberfläche für das DVB-Script beschrieben.

Dieser Artikel mag für viele uninteressant erscheinen. Ich empfehle ihn dennoch zur Lektüre, zeigt er doch einiges von den Möglichkeiten, die in Kommander stecken. Wer sich also für den Weg, den ich hier gegangen bin, interessiert, der sei herzlich eingeladen, weiter zu lesen.

Einleitung

Das DVB-Script vereinfacht die Verarbeitung eines DVB-Streams zu einer Video-DVD.

Die Helferprogramme müssen nicht mehr mühevoll von Hand gestartet werden. Das Script macht das nun für uns. Es ruft die Programme in der korrekten Reihenfolge auf und übergibt dabei die notwendigen Daten.

Und das Script wird nun über die GUI bedient. Die gewünschte Aufgabe anklicken, eine leere DVD einschieben, warten, fertig!

Die Bedienoberfläche wurde mit Kommander erstellt. So sieht das Ergebnis aus:

GUI fürs DVB-Script

Und so sieht die GUI aus wenn sie zum Editieren mit dem kmdr-editor aufgerufen wird:

Editor-Dialog

Gliederung der GUI

Ich habe die Bedienoberfläche in vier große Abschnitte eingeteilt:

Aktionenauswahl

Links oben können die gewünschten Aktionen durch Drücken vom Buttons ausgewählt werden. Folgende Kommander-Widgets sind dabei beteiligt:

  • RadioButton: Auswahl der Aktionen (Brennen, Sichern, usw.)
  • Label: Dient zur Anzeige von Kommentaren (Video-DVD...)
  • ButtonGroup: Hierin sind die RadioButtons und die Labels organisiert
  • ExecButton: Damit wird die ausgewählte Aktion gestartet (Go)
  • EditorTabWidget: Weitere Aktionen können über Reiter sichtbar gemacht werden

Log

Im Log-Fenster links unten wird angezeigt, welcher Bearbeitungsschritt gerade am arbeiten ist. Hier bürgen folgende Widgets für das Gelingen:

  • TextBrowser: Hierin erfolgt die Anzeige
  • GroupBox: Sieht einfach besser aus, wenn der TextBrowser da drin liegt

Debug-Log

Rechts unten ist das Debug-Log zu finden. Damit kann man, wenn es gewünscht wird, noch genauere Anzeigen zum laufenden Scripts bekommen. Da hier die Ausgabe des Standard-Fehlerkanal angezeigt wird, kann man gut nachverfolgen, wo es Probleme gegeben hat, wenn etwas nicht so klappt, wie man es sich eigentlich vorstellt.

  • TextWidget: Ausgabe von stderr (Standard-Fehlerkanal)
  • RadioButton: Steuern die Aktualisierung der Ausgabe (Ein, Aus)
  • ButtonGrop: Darin sind die RadioButtons organisiert
  • ExecButton: Fensteranzeige leeren (Clear)
  • GroupBox: Läßt das, was zusammen gehört, auch so erscheinen

Unsichtbare Widgets

Klingt gut, der Titel, oder? Ja, die Widgets rechts oben sind tatsächlich unsichtbar im kmdr-executor. Editiert man aber den Dialog mit dem kmdr-editor, dann sieht man sie natürlich (wie durch Zauberei).

  • ScriptObject: Diese drei Objekte enthalten ausführbaren Programm-Code
  • Timer: Periodische Abfrage der Anzeigefenster
  • blaue Abstandslinien: Sind für das Layout wichtig

Playlist

Bei den "unsichtbaren Widgets" befindet sich noch ein Knopf mit dem Namen Playlist starten.

  • ExecButton: Playlist starten

Das Formular

Wir haben bereits in der Einleitung gesehen, wie ein neuer Kommander-Dialog erstellt wird. Ganz kurz noch einmal zu Wiederholung:

  • kmdr-editor starten
  • Dialog drücken bzw. Datei - neu
  • Den Dialog speichern unter einem sinnvollen Namen

Das Formular (EditorDialog) bekommt von uns nun folgende Eigenschaften zugeteilt:

  • name: GUI
  • baseSize: Breite 1024, Höhe 768
  • caption: dvb_wiki_script oder Vom DVB zur DVD und einiges mehr

name

Die Zuteilung eines aussagekräftigen Namens, mit dem das Element angesprochen werden kann, ist eminent wichtig. Ich hatte dies beim Programmieren der GUI versäumt. Erst, als die Zuordnung der Elemente mit steigender Komplexität des Dialogs immer undurchsichtiger wurde, musste ich nachträglich Namen vergeben, um das Chaos etwas einzudämmen. Drum, die Namensgebung der Widgets konsequent gleich von Beginn an durchziehen!

baseSize

Die Basis-Grösse ist die Fenstergrösse, mit der Kommander den Dialog startet. Man könnte auch sagen, der Dialog ist optimiert für eine Bildschirmgrösse von 1024 x 768 Pixel.

caption

Und die Überschrift... Na ja, irgend etwas musste ich ja rein schreiben.

Das Log

Weiter mit dem Log-Fenster links unten.

Funktionsweise

Das DVB-Script ist so programmiert, daß immer wieder Meldungen über den aktuellen Stand der Videobearbeitung in eine Datei geschrieben werden:

echo "text" >> ~/dvbscript/fenster_fortschritt

Diese Log-Datei wird von Kommander mit Hilfe eines Timers und eines ScriptObjects alle 500ms abgefragt. Das Ergebnis der Abfrage wird dann in das Log-Fenster (den TextBrowser) geschrieben.

Bausteine

TextBrowser

Wir plazieren einen TextBrowser (aus der Symbolleiste) irgendwo auf dem Formular und stellen folgende Eigenschaften ein:

  • name: fenster1
  • minimumSize: Breite 490, Höhe 350

Die Angabe einer Minimum-Größe ist notwendig, damit das Fenster beim Layout nicht geschrumpft wird.

GroupBox

Auch dieses Widget wird auf eine freie Stelle im Formular kopiert.

  • name: rahmen
  • font-Punktgröße: 12
  • font-Fett: wahr
  • title: Log
  • hAlign: AlignHCenter
  • vAlign: AlignVCenter

Der Fenstertitel Log wird vertikal und horizontal zentriert (Align) dargestellt, erhält zur Hervorhebung eine Schriftgröße von 12 Punkten und wird zusätzlich fett formatiert.

Layout

  • Mit der Maus wird die GroupBox so groß gemacht, daß der TextBrowser vollständig hineinpasst
  • Anschließend wird der Browser in die Box geschoben
  • Die GroupBox wird markiert und aus dem Kontextmenue folgender Befehl ausgewählt:
  • In einem Raster anordnen (Die neun kleinen Quadrate)

Damit ist der TextBrowser fest in der GroupBox verankert und kann zusammen mit der Box an einen passenden Ort auf dem Formular geschoben werden.

Das Log-Fenster ist fertig. Es fehlt nur noch der Inhalt.

ScriptObject

Wir haben vorhin gesehen, daß der Bearbeitungsfortschritt des DVB-Scriptes in folgende Datei geschrieben wird:

~/dvbscript/fenster_fortschritt

Den Inhalt dieser Datei fragen wir mit einem ScriptObject ab.

Erzeugen wir also ein ScriptObject mit folgenden Eigenschaften:

  • name: refresh_fenster1
  • text: fen1

Unser ScriptObject enthält, wie der Name schon andeutet, ausführbaren Scriptcode. In welcher Sprache wir das Script erstellen, bleibt uns überlassen. Verwenden wir diesmal den Kommander-Scriptcode:

fenster1.setText(file_read(env("HOME")+"/dvbscript/fenster_fortschritt"))

Um diesen Code einzugeben, haben wir aus dem Kontextmenue des ScriptObjects natürlich den Punkt Kommander-Text bearbeiten ausgewählt.

Hier kommt nun eine kurze Erläuterung, was diese Zeile bedeutet:

Die Shell-Variable HOME enthält den Pfad zum Heimatverzeichnis des Nutzers. Mit env("HOME") wird diese Variable von Kommander ausgelesen. Der Pfad wird noch ergänzt (String-Addition), so daß in den Klammern dann folgendes steht: ~/dvbscript/fenster_fortschritt.


Der Inhalt der Datei, auf die der Pfad zeigt, wird mit dem file_read-Befehl gelesen und dem Widget fenster1 als Text übergeben.

Zwischenbemerkung 1

Habe ich übrigens schon erwähnt, daß es nicht ganz ohne Sinn ist, die bisherige Arbeit von Zeit zu Zeit zu speichern? Falls nicht, dann erinnere ich hiermit daran. Falls doch, na ja, dann schadet es auch nichts, noch einmal davon zu sprechen.

Zwischenbemerkung 2

Wir haben bis jetzt folgende Widgets installiert:

  • Formular mit dem Namen GUI
  • GroupBox mit dem Namen rahmen
  • TextBrowser mit dem Namen fenster1
  • ScriptObject mit dem Namen refresh_fenster1

Widgets lassen sich im Programm über ihre Namen ansprechen. Wir können die Eigenschaft text des TextBrowsers also auch per Programm füllen, was wir mit Hilfe des ScriptObjects ja tun. Dieser Text erscheint dann im Ausgabefenster des TextBrowsers, also in unserem Log-Fenster.

Was uns nun noch fehlt, das ist, das ScriptObject zu starten, und zwar regelmäßig. Doch auch hierfür bietet Kommander ein Widget an, nämlich den Timer, der aussieht wie ein uralter Wecker.

Also, installieren wir im Formular einen solchen Timer und geben ihm folgende Eigenschaften:

Der Timer

  • name: Timer_Log
  • interval: 500

Das bedeutet, alle 500ms wird das getan, was wir in den Kommander-Text des Timers geschrieben haben bzw. jetzt schreiben werden:

refresh_fenster1.execute

Diese Anweisung bewirkt, daß der im ScriptObject enthaltene Code alle halbe Sekunden ausgeführt wird.

Jede halbe Sekunde wird also der Inhalt der Datei ~/dvbscript/fenster_fortschritt in die Eigenschaft text von fenster1 geschrieben und damit angezeigt.

Ganz fertig sind wir aber immer noch nicht, denn der Timer muß erst einmal gestartet werden:

Verbindungen (Signals und Slots)

Wie das mit den Verbindungen funktioniert, habe ich in der Einleitung zu erklären versucht. Hier die aktuelle Anwendung dieses Prinzips von signals and slots:

  • Signale: GUI widgetOpened()
  • Slots: Timer_Log execute()

Wenn das Formular mit dem Namen GUI geöffnet wird (was immer dann passiert, wenn wir den Dialog starten), dann läuft der Timer los.

Und damit ist, nebenbei gesagt, die Programmierung des Log-Fensters abgeschlossen. Weiter geht es mit dem DebugLog.

Das Debug-Log

Funktionsweise

Das Debug-Log funktioniert ähnlich wie das normale Log, wobei ich gestehen muß, ein paar kleine Feinheiten eingebaut zu haben. Aber die schauen wir uns später an, zuerst der Überblick:

Im DVB-Script wird der Standard-Fehlerkanal (stderr) in eine Datei geschrieben:

exec 2> ~/dvbscript/fenster_debug

Die Datei, die alle 500ms abgefragt wird, heißt diesmal also debugfenster.

Wer nun denkt, hier erscheinen nur Fehlermeldungen, der sieht sich getäuscht. Bash-Anweisungen bzw. -Tools schicken auch Betriebsmeldungen über stderr. Wie gesprächig so eine Anweisung sein darf, das läßt sich oftmals einstellen über die Option --verbose.

Über den Clear-Button läßt sich der Text im Debug-Log löschen (Nur die Anzeige, nicht der Dateiinhalt, der wird erst beim nächsten Scriptstart niedergemacht).

Die Ein-/Aus-Knöpfe dienen zum Ein- bzw. Ausschalten der Anzeige im Debug-Log (vor dem Script-Start). Nach Beendigung des Script-Laufes kann mit ihnen die Fokussierung des Log-Fensters auf die jeweils aktuellen Logzeilen ausgeschalten werden. Dann kann das komplette Log betrachtet werden.

Und noch eine letzte Kleinigkeit

Als Anzeigeobjekt habe ich diesmal nicht einen TextBrowser verwendet, sondern ein TextEdit-Widget, welches ich auf ReadOnly geschalten habe.

Bekannte Bausteine 1

TextEdit

  • name: TextEdit_Debug_Log
  • minimumSize: Breite 470, Höhe 350
  • readOnly: Wahr

GroupBox

  • name: GroupBox2
  • title: LogDebug
  • hAlign: AlignHCenter
  • vAlign: AlignVCenter

ScriptObject

  • name: refresh_fesnster2
  • text: fen2
  • Kommandertext:
TextEdit_Debug_Log.setText(textfile_read(env("HOME"+"/dvbscript/fenster_debug"))
TextEdit_Debug_Log.scrollToBottom

Hier ist eine neue Funktion hinzugekommen:

TextEdit_Debug_Log.scrollToBottom

Diese Funktion sorgt dafür, daß in unserem Debug-Log immer das Ende der Log-Datei angezeigt wird.

Der Timer

  • name: Timer_Debug
  • interval: 500
  • Kommandertext:
refresh_fenster2.execute

Verbindungen (Signals und Slots)

Signale: GUI widgetOpened()

Slots: Timer_Debug execute()

Zwischenbemerkung 3

Bis jetzt war alles so, wie bein normalen Log-Fenster. Genauere Erklärungen erübrigen sich also. Kommen wir also nun zu den zusätzlichen Elementen:

Neue Bausteine

RadioButton

Ein-Knopf

  • name: RadioButton_Ein
  • text: Ein
  • checked: Wahr

Dieser Druckknopf hat zwei Zustände: gedrückt und nicht gedrückt. In diesem Fall wurde mit der Eigenschaft checked festgelegt, daß der Knopf per default gedrückt ist.

Für die beiden Zustände kann auch unterschiedlicher Kommandertext eingegeben werden. Das bedeutet, wenn der Button gedrückt ist, wird etwas anderes ausgeführt als in ungdrücktem Zustand.

Dies aber nur zur Information. Wir benötigen in unserem Fall gar keinen Kommandertext, da wir den Knopf über die signals and slots abfragen werden.

Aus-Knopf

  • name: RadioButton_Aus
  • text: Aus

Der Aus-Knopf ist per default nicht gedrückt.

ButtonGroup

Die beiden RadioButtons dürfen nur selektiv angesprochen werden können. Wenn also der eine Knopf An ist, muß der andere Aus sein. Das können wir erreichen, indem wir die Buttons in eine ButtonGroup packen.

  • name: ButtonGroup2
  • minimumSize: Breite 60, Höhe 60
  • exclusive: Wahr

Die ButtonGroup kann also über die Bezeichnung ButtonGroup2 angesprochen werden, hat eine Mindestgröße von 60 x 60 Pixeln und stellt sicher, daß exclusiv nur einer der enthaltenen Buttons gedrückt ist.

Layout

Das Layout ist schnell erledigt. Einfach die beiden RadioButtons in die Button Group schieben, diese markieren und auswählen: Bedienelemente im Raster anordnen

Bekannte Bausteine 2

ExecButton

  • name: ExecButton_Clear
  • minimumSize: Breite 60, Höhe 60
  • text: Clear
  • Kommandertext:
RadioButton_Aus.setChecked(true)
Timer_Debug.cancel
TextEdit_Debug_Log.clear

Das Drücken des Clear-Buttons bewirkt also folgendes:

  • Der Aus-Knopf wird gedrückt (wodurch der Ein-Knopf wird über die Eigenschaft exclusive der ButtonGroup ausgeschalten).
  • Der Timer, der das Debug-Fenster mit Hilfe des ScriptObjects refresh_fenster2 ständig aktualisiert, wird gestoppt.
  • Und das Debug-Log-Fenster wird geleert.

Verbindungen (Signals and slots)

für den Aus-Knopf

  • Signale: RadioButton_Aus pressed()
  • Slots: Timer_Debug cancel()

Sobald der Aus-Knopf gedrückt wird, wird der Debug-Timer gestoppt.


für den Ein-Knopf

  • Signale: RadioButton_Ein pressed()
  • Slots: Timer_Debug execute()

Mit dem Drücken des Ein-Knopfes wird der Debug-Timer gestartet.

Diese Knöpfe lassen sich übrigens nicht mehr verändern, wenn eine Videobearbeitungsfunktion gestartet wurde. Sie müssen entweder vorher oder nach Abschluß der Bearbeitung eingestellt werden.

  • vorher: Die Anzeige des Debug-Logs kann aktiviert oder deaktiviert werden
  • nachher: Die Fokussierung der Anzeige auf das Dateiende kann ein- bzw. ausgeschalten werden.

Layout des Debug-Logs

So, die Programmierung des Debug-Logs ist nun abgeschlossen. Jetzt müssen nur noch die einzelnen Elemente dahin verfrachtet werden, wo sie in der fertigen GUI zu erscheinen haben.

Dazu machen wir die GroupBox so groß, daß alle eben erstellten Widgets hineinpassen. Und diese schieben nun wir in die Box (den Clear-Button, die ButtonGroup mit den Radio-Buttons und das Anzeigefenster TextEdit)

Zwischen die ButtonGroup und den Clear-Button fügen wir nun noch einen Abstand ein (Füge Abstand ein, so heißt das dazu notwendige Teil oben aus der Symbolleiste)

Nun markieren wir die GroupBox und ordnen die enthaltenen Bedienelemente im Raster an (kennen wir schon, den Befehl, oder?) und stellen fest, daß wir fertig sind mit dem Debug-Log.

Übrigens, probiert es einmal aus und laßt den Abstand weg. Das gibt interessante Effekte beim Layout!

Die Aktionen

Vorbemerkung

Es gibt eine Vielzahl von Möglichkeiten der Videobearbeitung, von denen ich beispielhaft nur einige ausgewählt habe, um sie über die GUI anzusteuern. Der Grund ist alleine darin zu sehen, daß ich nicht die Absicht habe, ein fertiges Universalprogramm zu präsentieren. Vielmehr liegt die Intention darin, die Wege zu einem solchen Programm dem Leser näherzubringen und ihn damit in die Lage zu versetzen, selbst den Versuch zu wagen und sein eigenes Programm zu erstellen.

Funktionsweise

Ich habe die Aufgaben in drei Gruppen eingeteilt:

  • DVB-Stream ==> Video-DVD
  • DVB-Stream ==> Daten-DVD
  • Videoclips ==> Playlist

Diese Gruppen sind über Reiter anwählbar. Die Reiter werden übrigens gerne auch einmal Tabs genannt und so ist es vielleicht verständlich, daß das hier zum Zuge kommende Kommander-Widget TabWidget heißt (wie alle anderen Bedienelemente auch in der Symblleiste zu finden).

Die Bedienung ist einfach:

  • gewünschte Gruppe auswählen
  • gewünschte Aktion markieren
  • Auf Go drücken

Vorbereitung

Im TabWidget befindet sich eine ButtonGroup, in der die Radio-Buttons und Labels (Überschriften) organisiert sind. Bauen wir also zuerst die ButtonGroup mit Inhalt. Wie das funktioniert, wissen wir ja inzwischen.

RadioButtons

Im der Gruppe Video-DVD von oben nach unten:

Brennen

  • name: RadioButton_11
  • text: Script.execute(11)
  • checked: Wahr

Sichern

  • name: RadioButton_12
  • text: Script.execute(12)

Brennen

  • name: RadioButton_13
  • text: Script.execute(13)

Bedrucken

  • name: RadioButton_81
  • text: Script.execute(81)

Es handelt sich jeweils um Kommandertext für den Zustand checked (also, Knopf gedrückt).

Labels

In der Gruppe Video-DVD von oben nach unten:

Label 1

  • name: Label1
  • text: DVB (mpeg2): Schneiden, Authoring und ...

label 2

  • name: Label2
  • text: Gesicherte DVD-Struktur ...

Label 3

  • name: Label3
  • text: Video-DVD ...

ButtonGroup

  • name: ButtonGroup_Video_DVD
  • exclusive: Wahr

Das Layout der ButtonGroup nicht vergesseen!


Dann brauchen wir noch einen ExecButton als Start-Knopf:

ExecButton

  • name: ExecButton_Start_Video_DVD
  • minimumSize: Breite 60, Höhe 60
  • text: Go
  • Kommandertext:
ButtonGroup_Video_DVD.text


Und wir brauchen das TabWidget selbst, in der die ganze Choose untergebracht ist.

TabWidget

  • name: TabWidget1
  • pageTitle: Video-DVD

Nun die ButtonGroup mit den ganzen Bedienelementen und den Go-Knopf ins TabWidget schieben, Layout erstellen und fertig!


Fertig? Nein, doch noch nicht ganz, denn uns fehlen ja noch die zwei anderen Reiter. Aber die sind auch geschwind erstellt, und zwar so:

  • Rechtsklick auf das TabWidget
  • Seite hinzufügen...
  • Seitentitel bearbeiten... (Was hier eingetragen wird, das dürft ihr raten).

Zwischbemerkung 3

Die beiden letzten Tab-Seiten brauchen natürlich auch noch Inhalte. Hier unterscheidet sich die Vorgehensweise nicht von dem, was wir gerade auf der ersten Tab-Seite produziert haben. Deshalb hier nur kurz und ohne weiteren Kommentar die Elemente und deren Inhalte:


RadioButtons der Gruppe Daten-DVD

Brennen

  • name: RadioButton_21
  • text: Script.execute(21)
  • checked: Wahr

Sichern

  • name: RadioButton_22
  • text: Script.execute(22)

Brennen

  • name: RadioButton_23
  • text: Script.execute(23)

Bedrucken

  • name: RadioButton_82
  • text: Script.execute(82)

.

Labels der Gruppe Daten-DVD

Label 4

  • name: Label4
  • text: DVB (mpeg2): Schneiden, Wandeln zu TS und ...

Label 5

  • name: Label5
  • text: Gesicherte TS-Files ...

Label 6

  • name: Label6
  • text: Daten-DVD ...

.

ExecButton der Gruppe Daten-DVD

  • name: ExecButton_Start_Video_DVD_2
  • minimumSize: Breite 60, Höhe 60
  • text: Go
  • Kommandertext:
ButtonGroup_Daten_DVD.text


ButtonGroup der Gruppe Daten-DVD

  • name: ButtonGroup_Daten_DVD
  • exclusive: Wahr

.

RadioButtons der Gruppe Videoclip

Alle Tonspuren

  • name: RadioButton_31
  • text: Script.execute(31)
  • checked: Wahr

AC3

  • name: RadioButton_32
  • text: Script.execute(32)

MP2

  • name: RadioButton_33
  • text: Script.execute(33)

MP2 normalisiert

  • name: RadioButton_37
  • text: Script.execute(37)

MP2

  • name: RadioButton_34
  • text: Script.execute(34)

MP2 normalisiert

  • name: RadioButton_38
  • text: Script.execute(38)

.

Labels der Gruppe Videoclip

Label 7

  • name: Label7
  • text: Videoclip (mpeg2): Schneiden und speichern ...

Label 8

  • name: Label8
  • text: Videoclip (mpeg1) speichern ...

.

ExecButton der Gruppe Videoclip

  • name: ExecButton_Start_Video_DVD_3
  • minimumSize: Breite 60, Höhe 60
  • text: Go
  • Kommandertext:
ButtonGroup_Videoclip.text

ButtonGroup der Gruppe Videoclip

  • name: ButtonGroup_Videoclip
  • exclusive: Wahr

Nun fehlt aber doch noch etwas ganz wichtiges, nämlich das Teil, in dem unser Arbeitsscript stehtt:

ScriptObject

  • name: Script
  • text: Script
  • Kommandertext: Der Code des Arbeitsscriptes

Das Zusammenspiel der Elemente

Jetzt wird es interessant. Denn nachdem wir das TabWidget fertiggestellt haben, werden wir nun erfahren, wie das alles auch funktioniert. Also...

Das Prinzip

Durch das Drücken eines RadioButtons wird die im Kommandertext enthaltene Kennzahl an das ScriptObject und damit an das Arbeitsscript weitergeleitet. Dieser Vorgang wird gestartet durch das Drücken auf den Go-Button.

Das Arbeitsscript übernimmt die Kennzahl, wertet sie aus und startet die gewünschten Arbeitsschritte zur Videobearbeitung,

Das schauen wir uns an einem Beispiel etwas genauer an:

So geht's

Der erste RadioButton "Brennen" der Gruppe Video-DVD enthält den Kommandertext:

Script.execute(11)

Da sich es sich hier um Kommandertext für den Zustand checked des RadioButtons handelt, wird der darin enthaltene Befehl nicht direkt ausgeführt, sondern steht für weitere Untaten zur Verfügung und zwar als Inhalt der ButtonGroup, in der sich der RadioButton befindet.

Dieser Inhalt wird vom ExecButton (Go) ausgelesen mit dem Befehl

ButtonGroup_Video_DVD.text

und gleich ausgeführt (Ist ja auch Sinn eines ExecButtons).


Noch einmal:

Durch Drücken von Go wird der Befehl Script.execute(11) ausgeführt. Dieser Befehl startet das im ScriptObject befindliche Arbeitsscript und übergibt ihm dabei als Argument die Kennzahl 11. An Hand dieser Kennzahl werden nun vom Bashscript die einzelnen Arbeitsschritte der Videobearbeitung aufgerufen.

Die Playlist

Der ExecButton

Wie oben schon erwähnt habe ich in der Nähe der "unsichtbaren Widgets" noch einen ExecButton eingebaut, mit dem die Playlist der Videoclips gestartet werden kann.

  • name: ExecButton5 (Da habe ich es doch glatt versäumt, einen anständigen Namen für den Knopf zu vergeben)
  • text: Playlist abspielen
  • Kommandertext:
execBackground(file_read(env("HOME")+"/dvbscript/playlist_starten"))

Das Problem

Die Playlist soll als Hintergrundprozess starten und somit auch dann weiterlaufen, wenn die GUI beendet wird. Das ist in der Bash überhaupt kein Problem: Es genügt ein

nohup xine -P /pfad_zur_playlist/playlist &

Tippen wir diesen Befehl also in das Arbeitsscript ein und starten, wie von den Aktionen gewohnt durch Übergabe einer Kennzahl an das Arbeittsscript:

Script.execute(71)

Wir werden feststellen, daß es nicht funktioniert. Kommander kommt mit dem & im Befehl nicht zurecht. Lassen wir das & weg, dann können wir die Wiedergabeliste starten. Allerdings wird sie beendet, wenn wir die GUI schließen.

Das ist nicht so, wie wir uns das vorgestellt haben.

Macht aber nichts, tricksen wir halt ein bißchen:

execBackground("xine -P /pfad_zur_playlist/playlist")

Dieser Befehl in unserem execButton hinterlegt, würde das Problem lösen, ist aber noch ein bißchen unflexibel, da der im Arbeitsscript ermittelte xine-Pfad nicht übergeben werden kann.

Die Lösung

Macht wiederum nichts. Lassen wir das Arbeitsscript den Befehl, so wie er ausgeführt werden soll, in eine Textdadei zu schreiben:

echo "$xine -P $hauptverzeichnis/playlist -a 1 -l=shuffle" > $hauptverzeichnis/playlist_starten

und lesen diese Datei über den execButton aus:

execBackground(.....)

Führe den Bashbefehl in den Klammern im Hintergrund aus

file_read(....)

Der Befehl Befindet sich in einer Dateo, die mit dieser Anweisung gelesen wird

env("HOME")+"/dvbscript/playlist_starten"

Und das ist der Pfad zu dieser Datei


Nachbemerkung

Das war es dann wohl. Was bleibt noch zu sagen? Layout nicht vergessen! Und zwischendurch mal abspeichern, das Ganze ... oder hatte ich das schon mal erwähnt? ... Ich weiß es nicht mehr.


Einführung: Der Weg zur GUI - Die Funktionen - Screenshots



Zurück zur Programmierung