GUI-Architektur für interaktive Datenanalyse
This is a modal window.
The media could not be loaded, either because the server or network failed or because the format is not supported.
Formal Metadata
Title |
| |
Title of Series | ||
Number of Parts | 60 | |
Author | ||
Contributors | ||
License | CC Attribution 3.0 Germany: You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor. | |
Identifiers | 10.5446/42499 (DOI) | |
Publisher | ||
Release Date | ||
Language |
Content Metadata
Subject Area | ||
Genre | ||
Abstract |
|
6
13
21
25
41
53
00:00
Motion captureArchitectureGraphical user interfaceComputer animation
00:23
Motion captureGraphical user interfaceArchitectureRaw image formatString (computer science)Computer hardwareHausdorff spaceSoftwareComputer programmingComputer animation
02:06
Route of administrationDemosceneSoftwareDiagramLecture/Conference
02:34
EmulationThresholding (image processing)Execution unitComputer fontAngleHistogramReal-time operating systemSurfaceMetreParticle detectorComputer animation
03:29
Parameter (computer programming)Plane (geometry)Direction (geometry)Frequency distributionChemical polarityPROBE <Programm>Hausdorff spaceMittelungsverfahrenComputer animation
04:12
Term (mathematics)Maxima and minimaCurve fittingLeakHistogramTwo-dimensional spaceMittelungsverfahrenNumberParameter (computer programming)DemoscenePositionHausdorff spacePROBE <Programm>SoftwareCurve fittingSpannungsanalyseComputer animation
05:59
Motion captureArchitectureGraphical user interfaceGoogolData modelComputer-generated imageryDisk read-and-write headGame controllerModel View ControllerPresentation of a groupView (database)Social classFile viewerPattern languageData modelSocial classC++Table (information)Set (mathematics)XMLComputer animationProgram flowchart
07:48
View (database)Data modelCodeFile viewerMonster groupTable (information)Data modelDiagramProgram flowchart
08:22
View (database)Core dumpService (economics)Parameter (computer programming)Electronic mailing listGeometryGUI widgetGraphical user interfaceMenu (computing)Reduction of orderComputer-generated imagerySystem callVariable (mathematics)Equivalence relationFunction (mathematics)RootParameter (computer programming)SignalScripting languageChain ruleService (economics)Beam (structure)Function (mathematics)DisplayVariable (mathematics)Block (periodic table)Computer fileRoute of administrationCodePlane (geometry)Single-precision floating-point formatRaw image formatEncapsulation (object-oriented programming)Computer trespassMilitary operationComputer programmingObject-oriented programmingAlgorithmMathematical optimizationSoftwareDatabaseDatabaseEnergy levelFluxData modelApple KeynoteFile viewerCodeObjektorientierungPattern languageGraphical user interfaceEngineering drawing
16:24
Parameter (computer programming)Menu (computing)GUI widgetGraphical user interfaceSheaf (mathematics)Motion captureUser profileSoftware testingFunctional (mathematics)LoginKeyboard shortcutEvent horizonInterrupt <Informatik>Group actionSystem callBerechnungRow (database)Plane (geometry)Mechanism designDesire pathBlock (periodic table)Recursive languageElectronic data processingSoftwareComputing platformText editorParameter (computer programming)FunktionalitätSoftware testingRoute of administrationCrash (computing)EditorVideo cardAktion <Informatik>Graphical user interfaceDirection (geometry)CalculationSocial classApple KeynoteMilitary operationDebuggerInterrupt <Informatik>FlagArt 2Computer animation
24:26
Menu (computing)MeasurementCurve fittingTask (computing)Line (geometry)StatisticsThresholding (image processing)Virtual memoryDot productRight angleComputer animation
25:24
Ende <Graphentheorie>Computer animationEngineering drawing
Transcript: German(auto-generated)
00:00
Ja, guten Morgen. Das Forschungszentrum Jülich betreibt diese Außenstelle in Garching bei München, um den Forschungsreaktor mitzubenutzen. Ein Forschungsreaktor dient nicht der Erforschung von Reaktortechnologie, sondern benutzt etablierte Reaktortechnik, um Spalteneutronen freizusetzen, die als Sonden in der Materialforschung benutzt werden.
00:21
Der Reaktor beliefert an die 30 Messplätze mit Neutronenstrahlen und dort stehen dann Instrumente für Diffraktion, Reflektometrie, Spektroskopie, Aktivierungsanalyse, Tomographie und einiges mehr. Diese Instrumente sind zugänglich über Ausschreibung, Antrag, Begutachtung
00:43
für Forscher aus Bayern, Deutschland, Europa, der ganzen Welt. Die kommen dann zu uns an, jedes einzelne Instrument, für einen Tag, für drei Tage, für zwei Wochen. Wir haben also ständig wechselnde Gäste und die erwarten nicht nur Hardware,
01:05
die möchten nicht Rohdaten nach Hause nehmen, sondern die möchten letztlich Antwort auf wissenschaftliche Fragen und dabei helfen wir ihnen mehr und mehr auch durch Softwareentwicklung.
01:21
Und zu den gerechtfertigten Erwartungen eines Nutzers gehört heutzutage auch, dass er nicht obskure Zeichenketten in Konfigurationsdateien in eine bestimmte Zeile und Spalte eintragen möchte, sondern eine zeitgemäße Nutzeroberfläche hat.
01:42
Und was ich im Folgenden an allgemeinen Überlegungen bringen werde zur Architektur von Nutzeroberflächen ist abstrahiert von einer konkreten Software, die ich in den letzten zwei Jahren überarbeitet habe, die ich übernommen habe aus der Instrumentengruppe,
02:00
funktional, aber in prekarem Zustand. Und wie weit das, was ich davon abstrahiert habe, für eure möglichen Anwendungen übertragbar und anwendbar ist, beurteilt ihr am besten selber, indem ihr seht, was meine Software konkret tut.
02:23
Und deshalb eine kurze praktische Demo. Und ich glaube, das geht, ach, der ohne Mikrofon geht nicht von wegen der Aufzeichnung, oder? Da muss ich jetzt versuchen, das einhändig zu tun.
02:40
Wir laden die Daten. Es sind hier in diesem Fall Daten von, auch mit Brille geht es auch nicht auf die Nähe. Es gibt so viele Gründe, Echtzeit-Demos in Vorträgen zu vermeiden. Also, wir laden Daten von einem Diffraktometer für die Materialforschung.
03:05
Ganz einfacher Aufbau. Neutronenstahl wird fokussiert auf die Probe. Und Neutronen, die unter einem bestimmten Raumwinkel rausgestreut werden, landen in einem Flächendetektor, der ortsauflösend Histogramme aufnimmt. Ein solches Histogramm sehen wir. Wir sehen zwei Ringe. Diese Ringe sind Neutronen, die unter einem bestimmten Winkel gestreut werden,
03:27
durch konstruktive Interferenz an hintereinander liegenden Gitterebenen. Und nun scannen wir ein paar dieser Bilder durch. Wenn man hier unten auf den Parameter schaut, sieht man diese verschiedenen Bilder
03:40
entsprechend verschiedenen Polarwinkeln in der Probenorientierung. Und dann sieht man, dass die Intensität sehr, sehr unterschiedlich ist. Das liegt daran, dass diese Gitterebenen Vorzugsrichtungen haben in einem Kristall, der aus vielen kleinen Kristalliten zusammengesetzt ist. Und diese Orientierungshäufigkeitsverteilung will der Experimentator
04:01
letztlich mit nach Hause nehmen. Die ist von Interesse in der Materialforschung oder in der Geologie. Diese reichen, aber verrauschten Detektordaten sind nur ein Mittel zum Zweck. Der Nutzer will die Daten reduzieren auf ein paar wenige aussagekräftige Zahlen.
04:23
Der erste Schritt ist, er projiziert aus diesem zweidimensionalen Histogramm einzelne Schnitte hinunter in das eindimensionale Histogramm, das unten gezeigt ist. Und in einem zweiten Schritt interessiert er sich eigentlich nur noch
04:43
für die Intensität in dem Peak. Wenn er Spannungsanalyse macht, interessiert er sich auch noch, wie die Position dieses Peaks leicht verschoben wird. Und dazu macht er einen Fit. Dazu definiert er zunächst einmal den Untergrund
05:01
und dann definiert er den Bereich, wo der Peak angefitted werden soll. Und dann kann man hier die Parameter entnehmen und dann geht man von einem zum nächsten Bild und hat die jeweiligen Parameter. Und am Ende interessiert man sich für die Intensität als Funktion der Probenorientierung.
05:25
Und das lässt man sich dann in diesem Fach typischerweise als Polfigur anzeigen. Da wird jetzt gerechnet, es werden alle Daten herunterprojiziert, alle Daten angefittert und dann werden die Intensitäten als mehr oder weniger große Kreise in dieser Polfigur angezeigt.
05:47
Dann kann man die Daten abspeichern und mit nach Hause nehmen, mit welcher Software auch immer weiterverarbeiten. Soweit die praktische Demo und nun zur Architektur dahinter.
06:06
Empfehlung allgemein ist, eine grafische Oberfläche wird nach dem Model View Pattern organisiert. Dann sucht man mal, wie das empfohlen wird und findet jede Menge Variationen.
06:24
Model View Control, Model View Presenter. Man zoomt in so einen einzelnen Vorschlag rein und sieht, welche Variationen von diesem Pattern es alle gibt. Das deutet sich schon an, so ganz eindeutig sind die Empfehlungen nicht.
06:45
Wir programmieren in C++ und Qt, Qt ist das große Framework, um open source grafische Oberflächen zu programmieren. Gibt es auch mit kommerzieller Lizenz, wird in der Automobilindustrie sehr viel benutzt.
07:04
Ein modernes Armaturenbrett ist ein Flachbildschirm mit Qt dahinter. Und Qt hat hunderte Klassen und speziell Model View Klassen um sich.
07:21
Eine Tabelle mit Sortierfunktionen im Header, auf die oder die Spalte klicken. Mit allen möglichen schönen Zutaten anzeigen zu lassen, baut man in seine GUI die Table View Klasse ein und verknüpft die mit einem Table Model,
07:41
was erbt von einem vorgegebenen Abstract Table Model. Ja, soweit ganz klar. Nur hat man ja verschiedene Ansichten auf seine Daten und wie setzt man die in Beziehung, wenn man das nicht im Voraus bedenkt, dann sieht es bald so aus und dann kommt das Spaghetti Monster
08:05
und übernimmt die Herrschaft über den Code. Also, Model View schön und gut im Kleinen, um die Ansicht für eine einzelne Tabelle zu zeigen. Aber wie baut man das in den Code im Großen ein?
08:25
Wahrscheinlich so. Eine andere Variation von dem Model View Pattern ist View Model Model. Und was die hier jetzt View Model nennen, ist das, was Qt Model nennt. Und was wir zuvor besprochen haben, Qt Abstract Table Model ist das View Model,
08:47
was Qt vorgibt, wie man so etwas organisiert betrifft, also nur die oberen zwei Ebenen und man ist selbst dafür verantwortlich, wie das View Model auf die eigentlichen Daten zugreift.
09:01
Ich habe eine Vermutung, warum es dazu relativ wenig Literatur gibt, warum das wenig diskutiert wird, weil die meisten Anwendungen auf Datenbanken zugreifen und dann greift man aus dem View Model, da im View Model steht dann ein SQL-Aufruf drin und die Datenbank organisiert alles weitere,
09:22
ist nur für unsere wissenschaftlichen Anwendungen nicht die Art und Weise, wie wir unsere Daten organisieren und unsere Daten verändern. Und daher müssen wir uns selbst überlegen, wie wir das gestalten. Dieses Modell hier bringt schon einmal mit sich, dass wir den Code organisieren können
09:41
in eine Core-Bibliothek, wo unsere Daten drinstehen und unsere Algorithmen, die die eigentlichen physikalischen Operationen an den Daten machen und eine GUI-Ebene oben drüber. Dann liegt vielleicht noch eine Ebene unten drunter, zum Beispiel für einen Logger.
10:04
Und ganz speziell für wissenschaftliche Anwendungen, wir können die Core-Bibliothek über eine Python API den fortgeschrittenen Nutzern verfügbar machen, die dann über Skripte die gleichen Operationen an den Daten vornehmen,
10:21
wie der naive Nutzer aus seiner GUI. Und in einer anderen Software bieten wir den Service, dass man aus der GUI ein in der GUI zusammengeklicktes Modell in ein Pythonskript exportieren kann, um den Nutzer den Übergang von GUI-Operation zu Skriptoperation zu erleichtern.
10:47
Jetzt zur Organisation innerhalb von Core-Daten und Operationen an den Daten von der GUI aus ansteuerbar. Gerade wenn man ein fremdes Projekt übernimmt, habe ich es sehr nützlich gefunden,
11:05
eine Doxygen drüber laufen zu lassen, statische Code-Analyse, eigentlich ein Dokumentationstool, man geht dann auf Files, man geht auf Hauptdirektorie-Ebene und bekommt, wenn man Doxygen
11:21
seinerseits richtig parametriert hat, eine Ansicht, aus welchen Unterordnern Dateien aus welchen anderen Unterordnern inkludiert werden. Und auch das ist eine Form von Spaghetti, die das Verständnis des Codes erschwert. Das ist auch eine sehr lustvolle Arbeit darin aufzuräumen,
11:42
wenn man in ein fremdes Projekt kommt und dann erst einmal oberflächlich versucht, was hängt von was ab, wo kann ich das auseinandersortieren, wie schiebe ich Files in andere Ordner, um dann letztlich in einer solchen Struktur anzukommen, wo die Pfeile nur noch von oben nach unten gehen,
12:04
das heißt, ich kann unten elementare Dienste bereitstellen, die kann ich für sich testen, die müssen für sich funktionieren und wenn die einmal funktionieren, muss ich nicht mehr drüber nachdenken, wie die von irgendwas oben drüber abhängen und von oben drüber kann ich sie einfach benutzen. Nur ganz ohne Trick geht es nicht
12:26
und der Trick in diesem Fall ist, ich brauche globale Variablen, denn letztlich muss ich doch von den verschiedensten Stellen auf meine Fenster in der GUI, auf meine Knöpfe, meine Trigger,
12:43
meine Toggles zugreifen und muss auf die Daten zugreifen. Es gibt Empfehlungen, dass globale Variablen zu vermeiden sind, wenn man die Begründungen nachliest, finde ich nicht einschlägig hier.
13:01
Qt liefert von vornherein sowieso eine globale Variable in der Wurzel der ganzen Hierarchie und genauso machen wir es auch für unsere Daten. Über diesen einen Pointer können wir dann auf die Sitzungsdaten, auf die Rohdaten, auf die experimentellen Daten zugreifen,
13:21
die Rohdaten und im Laufe der Sitzung wandeln wir die Rohdaten dann in reduzierte Daten um. Alle mal eleganter, ehrlich zu seiner globalen Variable zu stehen als die hinter irgendeinem Singleton zu verstecken.
13:40
Ein anderes Prinzip, was empfohlen wird für die saubere objektorientierte Programmierung, Kapselung und jede Funktion muss nur das wissen, was sie unbedingt wissen muss. Nein, wir reichen Funktionsaufrufe durch eine Funktion, eine andere Funktion aufruft, eine andere Funktion aufruft, jede hängt von einem gewissen Parametersatz ab,
14:02
die ruft dann zwei verschiedene Funktionen auf mit verschiedenen Parametersatz und jetzt ändert sich unten irgendwas. Also müssen wir von oben an eine andere Kette an Parametern mit durchreichen. Ist viel eleganter. Wir rufen von unten unsere globale Variable auf und suchen uns unten das, was wir wirklich verwenden wollen.
14:23
Muss man viel weniger dann in den ganzen Aufrufen ändern. Ja, und damit zur Kernfrage. Wie halten wir ein solches Display aktuell, wenn der Nutzer einen Parameter ändert, wenn der Nutzer beschließt,
14:43
ein einzelner Pfeil ist fehlerhaft, den möchte er ausblenden. Dann muss einiges neu berechnet werden. Es soll aber nur das Nötigste neu berechnet werden. Qt bietet als grundlegende Lösung Signals und Slots an.
15:05
Wenn ein Parameter geändert wird, wird ein Signal gesendet und vorher hat man alle nötigen Verbindungen gesetzt. Wenn dieses Signal kommt, dann reagiere hier, dann reagiere dort, aktualisiere dieses Fenster, aktualisiere jenes Fenster.
15:24
Das führt zu ganz schlimmen Spaghetti. Man muss schon froh sein, wenn es nicht zu zyklischen Signalflüssen kommt. Es kommt jedenfalls sehr leicht dazu, dass auf ein Signal in einzelne Rechnungen über verschiedene Ketten mehrmals aktiviert werden und das muss geändert und verbessert werden.
15:47
Am Anfang steht die Einsicht, warum eigentlich diese punktgenauen Verknüpfungen, wenn ich hier einen Parameter ändere, dann da und da und da meine Rechnungen wiederholen, meine Ansichten ändern.
16:03
Das ist ein Versuch der Optimierung, nämlich wir versuchen nur zu berechnen, was sich geändert hat. Wir versuchen nur Fenster neu zu zeichnen, wo sich Datenpunkte geändert haben. Und ganz allgemein ist der Ratschlag, vor eilige Optimierung zu vermeiden,
16:23
verursacht unnötige Komplikationen. Und so auch hier, wir müssen uns nicht darum sorgen, dass die GUI Zeit damit verbringt, einzelne Fenster neu zu zeichnen. Nein, wir können auf jede Useraktion hin einfach die ganze GUI neu zeichnen.
16:41
Da kümmert sich Q drum oder da kümmert sich unsere Grafikkarte drum. Ich weiß noch nicht mal, auf welchem Niveau es geschieht, aber es geschieht. Es wird letztlich nur das neu gezeichnet, wo sich was geändert hat, muss nicht unsere Sorge sein. Schwieriger ist es mit den Berechnungen und das ist nun typische
17:03
Problematik der wissenschaftlichen Datenverarbeitung, die in vielen anderen Anwendungen so nicht auftritt. Das Problem, dass auf eine Parameteränderung hin Daten mehrfach neu berechnet werden, weil irgendwelche reduzierten Daten zweiter Art von reduzierten Daten erster Art abhängen,
17:23
die ihrerseits von den Parameter abhängen und das auf verschiedenen Faden. Und wenn man nun einfach von unten das Kommando gibt, berechnen, neu berechnen, neue und Rekursion, und dann landet man eben mehrfach bei Data One, Data Two. Geht es andersrum?
17:42
Parameter sagt, der GUI, bitte alles neu zeichnen und dafür alles nötige neu berechnen. Nein, man hat auch diese Mehrfachabhängigkeiten. Das gleiche Problem, es werden Sachen mehrfach berechnet und das kann dann echt in die Zeit gehen. Da wartet der Nutzer dann.
18:01
Lösung, man muss das neu berechnen entkoppeln von der Logik, mit der man sagt, es muss neu berechnet werden. Und das kann man mit einem einzigen Bit tun, indem man zu den entsprechenden Datensätzen,
18:22
deren Berechnung Zeit kostet, eine Flag setzt, aktuell oder veraltet. Parameterwert ändert sich, es wird von unten nach oben durchgereicht. Du bist veraltet, du bist veraltet, du bist veraltet. Dann Kommando an die GUI, zeichne alles neu.
18:41
Die GUI sagt, gib mir deine Daten und wenn du veraltet bist, dann bring dich erst mal auf den aktuellen Stand. Mit diesem Mechanismus ist sichergestellt, dass alles nötig nur einmal berechnet wird. Und im vorigen Bild, der eine Verzeichnisbaum für die GUI,
19:02
der andere für CoR, für unsere Sitzungsdaten, ist das eine Interaktion in jede Richtung. Settings, ein Parameter hat sich geändert. GUI muss neu zeichnen. Dann geht GUI durch alle Fenster durch und holt sich die nötigen Daten.
19:29
Ja, es ist noch Zeit für ein Kapitel über das Loggen. Warum möchte man seine Daten, seine Abläufe loggen?
19:43
Verschiedenste Anwendungen zum Debuggen, das Klassische. Ich drucke mir hier und da eine Zeile aus. Profiling, ich möchte wissen, wo die meiste Zeit mit Rechnen verbracht wird. Klar, dafür gibt es auch andere Tools, dafür gibt es spezialisierte Tools.
20:03
Muss man wieder lernen, damit umzugehen. Wenn man eh einen Log-File schreibt, dann kann man das eigentlich alles in einem Aufwasch dokumentieren. Und der Nutzer kann den Log-File mit seinen reduzierten Daten ablegen und dann später nachvollziehen, wo sie hergekommen sind.
20:21
Und dann kriegt man Bonus-Funktionalität, wenn man es erst mal dahin bringt, dass der Log-File auch vom Programm wieder eingelesen und wieder abgespielt werden kann. Das ist extrem nützlich, während man an der GUI entwickelt. Denn zum Entwickeln gehört immer wieder irgendwas Kleines ändern, immer wieder testen.
20:41
Und da muss man sich immer wieder durch Datenladen parametrieren, Bild aussuchen, durchklicken, um an die Stelle zu kommen, wo man gerade geändert hat. Wenn man einmal in der Lage ist, einen Log-File abzuspielen, dann ist dieser ganze Arbeitsgang automatisiert. Dann kann man das als funktionale Tests verwenden.
21:03
Also immer, wenn sich irgendwas an der Software geändert hat, dann simuliere mir all diese Nutzersitzungen, die ich da als Test-Suite abgelegt habe und schaue, ob noch das Gleiche durchläuft, ob noch das Gleiche rauskommt. Und der Nutzer kann uns einen Log-File schicken,
21:22
wenn es ihm gecrasht ist oder er sonst meint, einen Bug gefunden zu haben. Und wir können idealerweise, wenn es dann nicht als so plattformabhängig geworden ist, wir können idealerweise das Ganze nachspielen, an die gleiche Stelle kommen, den gleichen Crash bei uns kriegen. Und eine weitere Anwendung, was wir jetzt noch nicht ausprobiert haben, aber wo ich vermute, dass es da auch relativ zügig
21:43
zu einer Lösung käme, wenn wir es brauchen würden bei der einen oder anderen Anwendung, ist Andurido Funktionalität, die für sich auch schon alles andere als trivial zu implementieren ist. Wie schreibt man einen solchen Log-File? Das kann man auf verschiedenen Ebenen tun.
22:02
Man könnte, und da gibt es Praktiken, das so zu tun, da gibt es, man könnte einfach die Mausbewegung aufzeichnen und dann registrieren, wo geklickt wird. Und alle Tastatureingaben aufzeichnen. Dann gibt es einen Ansatz. Interrupts ist nicht das richtige Wort, glaube ich.
22:22
Auf Systemebene gibt es eine Möglichkeit, auf jeden einzelnen Funktionsaufruf zuzugreifen. Völlig agnostisch. Was für eine Art Anwendung das ist, das ist im Prinzip die Ebene, auf der ein Debugger in ein laufendes Programm reingeht und aufzeichnet, was von wo aufgerufen wurde.
22:42
Da gibt es ein kommerzielles Tool, speziell für Qt, wo man auf diese Art und Weise aufzeichnen kann, was der Nutzer tut. Andere Möglichkeit wäre, auf unserer Core-Ebene alle Funktionsaufrufe, die von oben kommen, zu registrieren.
23:00
Aber was ich jetzt vorstellen möchte, ist, auf Widget-Ebene die Nutzeraktionen zu registrieren. Und dazu erweitern wir die Qt-Widget-Klassen geringfügig,
23:20
um Funktionalität um einzelne Nutzeraktionen aufzuzeichnen und die entsprechenden Kommandos abzuspielen. Und damit haben wir dann eine solche Architektur, wo der Nutzer nach wie vor über die GUI auf die Control-Widgets zugreift.
23:41
Die einzelnen physikalischen Operationen im Core durchgeführt werden. Nebenher ein Log-File geschrieben wird. Nebenher ein Command-Stack gehalten wird, der für Andoridu verwendet werden kann. Diesen Log-File, das ist ASCII, kann man im Texteditor nachbearbeiten.
24:01
Man kann viele solche Sitzungen sammeln oder aus dem Texteditor heraus verschiedene Variationen erzeugen, wie eine Test-Suite erzeugen, die dann Teil der Entwicklungsumgebung wird. Und der Tester kann damit spielen, das ins Programm reinfüttern und GUI-Sitzungen simulieren.
24:24
Und damit zurück zur praktischen Demonstration. Ich habe vorhin einen Log-File erzeugt.
24:45
Aus irgendeinem Grund muss ich den umbenennen. Dann schauen wir mal rein. Ja, kommt perfekt hin, danke. Also, es ist ausgezeichnet worden, was von wo aufgerufen wurde,
25:02
wie lange gerechnet hat. Und am Ende steht Quit. Das nehmen wir raus, weil ihr sonst beim Abspielen nicht viel sehen würdet.
25:26
Und da sind wir bei der Darstellung, die wir vorhin hatten. Der Untergrund, der Fit-Bereich, alles genau so gesetzt, wie ich das vorhin von Hand gemacht habe. Ja, danke schön.
25:48
Herzlichen Dank, Joachim. Fragen?
26:09
Wo ihr doch eh über Python die API exportieren wollt, habt ihr darüber nachgedacht, dass GUI direkt auch in Python zu machen? Letzten Endes Geschmacks- und Gewohnheitssache.
26:22
Ich sehe nicht, warum ich auf den Vorteil einer streng typprüfenden Sprache verzichten soll. Aber ich sehe schon auch, dass es die Tendenz gibt.