Toplevel Window: merkwüridige Text-Formatierung

Fragen zu Tkinter.
Antworten
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Hallo,

ich habe in einer Applikation ein Toplevel Window mit einem Text erstellt. Merkwürdigerweise formatiert Python den Text reichlich komisch, er wird nach spätestens zwei Wörtern umgebrochen. Kann mir jemand sagen, was die Ursache ist?

Code: Alles auswählen

def file_exists(f_name):
    global err_msg
    err_msg = Toplevel(main_frame)
    err_msg["height"] = 300
    err_msg["width"] = 500
    err_msg.resizable(0, 0)
    err_msg.wm_title("File already exists")
    err_text = Message(err_msg, text="Unzipping files: the file '" + f_name + "' already exists!")
    err_text.place(x=5, y=20)
BlackJack

@Grendel: Welcher Text? Was ist `Message`? Wenn Du an anderen Stellen auch Grössen und Positionen hart vorgibst, wird es wahrscheinlich daran liegen. Lass Tk das Layout machen und setze keine festen Grössen und vergiss `place()`. Und wenn Du schon am vergessen bist: ``global`` hat in einem sauberen Programm auch nichts zu suchen. Ebensowenig wie Sternchen-Importe.

Für Nachrichtendialoge gibt es übrigens schon etwas: das `tkMessagebox`-Modul.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Hallo BlackJack,

naja, es soll der Text im Toplevel Window angezeigt werden, der in "err_text = Message" definiert ist. Das die "hart" codierten Fenstergrößen Ursache für die komische Formatierung sind, halte ich für unwahrscheinlich. Es gibt nur ein einziges Parent Window und das Toplevel Window ist eigentlich davon unabhängig, jedenfalls was die Größe angeht. Oder irre ich mich hier? EDIT: Das Toplevel Window ist groß genug, um den Text in einer Zeile darzustellen. Generell hast du recht, man sollte nicht mit place() arbeiten. Das Problem ist nur, ich müsste mein ganzes Programm umstricken und außerdem ist ein fixes Layout oder zumindest das Verhindern eines "resize" in diesem Fall von Vorteil.

Zum global Statement: es werden weitere Buttons hinzugefügt werden, die bei Klick jeweils Unterprogramme ausführen. Verwende ich global nicht, dann erzeugt meine IDE einen "Unresolved Reference" Fehler. Das Programm lässt sich allerdings trotzdem starten. Hm ...

tkMessagebox reicht nicht, wegen der oben erwähnten, zusätzlichen Buttons.

Danke,
Andreas
BlackJack

@Grendel: Ja aber was ist denn nun `Message`? Da drin vermute ich mal Code der eine weitere, harte Grössenvorgabe macht.

Das harte Grössen und Positionen für komische Formatierungen zuständig sind, ist ja gerade der Grund warum man die nicht verwendet. Auf anderen Systemen als dem auf dem die GUI so entworfen wurde, kann das alles komisch aussehen, bis hin zu unbenutzbar werden, wenn die Inhalte nicht in den hart begrenzten Platz passen.

Wenn man ein Programm komplett “falsch“ aufzieht, muss man es halt auch komplett umstricken wenn man es richtig machen will. Auch bei den dynamischen Layoutmanagern kann man eine Grössenänderung verhindern. Muss man aber auch nicht.

Die Erklärung zu ``global`` verstehe ich nicht. Wenn da noch etwas hinzugefügt werden soll, dann gibt man das Widget halt am Ende an den Aufrufer zurück, damit der noch etwas damit machen kann. Oder man übergibt die Daten für zusätzliche Schaltflächen als Argumente an die Funktion. Das da noch GUI-Elemente dazu kommen spricht auch wieder gegen `place()`, weil man sich dann ja wieder selbst um Position und Grösse kümmern muss, und die Gefahr besteht, dass der fixe Platz nicht ausreicht.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Ich verwendete hart codierte Größen und Positionen, da mein Parent Window relativ viele Checkbuttons enthält, die teilweise auch noch voneinander abhängig sind. Um das auch visuell zu verdeutlichen, habe ich mit Einrückungen gearbeitet und mein Layout entsprechend gestaltet.

Die zusätzlichen Schaltflächen werden im gleichen Unterprogramm definiert, aber sie lösen beim Anklicken Aktionen aus, die in anderen Unterprogrammen definiert sind. Daher meine Idee, das global Statement zu nutzen.

Die Frage ist, ob ein flexibles oder vom Grid Manager gesteuertes Layout dies nicht zerstört. Unter Windows sieht mein Programm übrigens, bis auf Kleinigkeiten, identisch aus.

Zu "Message" im Toplevel Window, ja, das ist ein Fehler, das gehört da nicht rein.
BlackJack

@Grendel: Relativ viele Widgets (hier `Checkbutton`\s) und manuelles Layout klingt ja noch gruseliger. Ich sehe jetzt nicht warum das mit einem Layoutmanager nicht gehen soll‽ Einrücken kann man leicht durch Padding erreichen.

Keine Ahnung was Du hier mit ”Unterprogrammen” meinst, so als Begriff gibt es das nicht bei Python, aber ``global`` hat in einem sauberen Programm immer noch nichts zu suchen. Da man spätestens bei GUI-Programmierung sowieso nicht mehr um objektorientierte Programmierung herum kommt, gibt es keine Ausrede das Schlüsselwort zu verwenden.

Was heisst ”unter Windows” sieht das Programm identisch aus? Im Vergleich zu was? Zu einem anderen Windows-Rechner? Auch wenn der eine andere Bildschirmauflösung, ein anderes Theme, und zum Beispiel andere Schriftarten- und grössen eingestellt hat‽
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Unter Linux und Windows sieht es nahezu identisch auch. Von OOP halte ich nicht sonderlich viel. Viel zusätzliche Tipp-Arbeit ohne erkennbaren Nutzen. Bei großen Projekten hat OOP sicherlich seine Berechtigung, aber bei einem kleinen Ein-Fenster Programm - okay, mit vielen Optionen - möchte ich mich eher nicht damit beschäftigen. Ich müsste das komplett neu lernen. Mir ist der ganze Ansatz fremd und mein kleines Progrämmchen muss ja auch mal fertig werden.

Unterprogramme ... okay, gemeint waren Funktionen. Ein Klick auf die Buttons ruft Funktionen auf, also z.B.

Code: Alles auswählen

err_msg = Toplevel(main_frame):
...
skip_button = Button(err_msg, text="Skip", command=file_exists_skip)
...


def file_exists_skip():
    ...
    ...
    ...
    err_msg.destroy()
In diesem Fall beschwert sich die IDE mit "Unresolved Reference"
BlackJack

@Grendel: Es sieht nur nahezu identisch aus weil sich die konkreten Systeme bei denen Du es angeschaut hast sich nicht zu stark unterscheiden. Das muss aber nicht so sein.

Wenn Du von OOP nichts hältst, dann ist Python wohl die falsche Sprache und GUIs das falsche Thema. Selbst in Sprachen ohne spezielle OOP-Unterstützung sind GUI-Rahmenwerke trotzdem objektorientiert. Sieht man bei C und Gtk beispielsweise, oder auch die SDL-Bibliothek für Spieleprogrammierung.

Funktionen kannst Du nicht gemeint haben denn Funktionen benutzen kein ``global`` sondern bekommen Argumente und haben Rückgabewerte und operieren nicht auf globalen Variablen. Dann sind es keine Funktionen mehr.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

So dogmatisch sehe ich das nicht. Wenn ich mich nicht irre, kann jedes Problem, das mit einer Programmiersprache zu lösen ist, sowohl mit dem OOP Ansatz, als auch funktional / prozedural gelöst werden. Python unterstützt ausdrücklich mehrere dieser Ansätze. Auch eine GUI ist unter Verzicht von OOP natürlich umsetzbar und verletzt, was Python angeht, keineswegs irgendein inhärentes Paradigma. Insofern ist Python durchaus die richtige Sprache und GUIs auch das "richtige Thema".
BlackJack

@Grendel: Ob man das nun mit OOP oder funktional löst kommt letztendlich auf's selbe hinaus: Kein ``global``! Eins von beidem sollte man verstanden haben und dann auch tatsächlich umsetzen, und an der Stelle hat Python dann beim funktionalen Ansatz Defizite was Closures und das neu binden von ”eingefangenen” Namen angeht. Wenn man dann noch dazu nimmt das Python zwar viel erlaubt und unterstützt, letztlich aber doch sehr dogmatisch ist, bleibt für solche Lösungen am Ende nur OOP, denn selbst wenn beide Wege gleich gut unterstützt würden: „There should be one-- and preferably only one --obvious way to do it.“ Dieser *offensichtliche* Weg ist in Python OOP. In Python ist *jeder* Wert ein Objekt. Das würde ich also schon irgendwie als inheräntes Paradigma bezeichnen.

Auch wenn man GUIs prozedural umsetzen kann — wer macht das denn? Kein verbreitetes GUI-Rahmenwerk ist nicht OOP. GUIs sind der Bereich in dem OOP richtig glänzen kann, denn das passt an der Stelle wirklich richtig gut. Wie schon gesagt: Selbst in Sprachen die keine besondere Unterstützung für OOP haben, sind die GUI-Rahmenwerke objektorientiert.

Viele andere Bibliotheken für traditionelle prozedurale nicht-OOP-Sprachen sind auch mindestens im Ansatz objektorientiert.

Ganz davon abgesehen ist in keinem Ansatz ``global`` ein Mittel um guten Code zu schreiben. Globaler Zustand zieht in jeder Sprache (die so etwas zulässt) die gleichen Probleme mit sich. Schlecht nachvollziebarer, testbarer, wartbarer, wiederverwendbarer, refaktorisierbarer Code wegen Abhängigkeiten die man erst kennt wenn man wirklich den gesamten Code durchgegangen ist und wirklich alles im Kopf hat.
Grendel
User
Beiträge: 50
Registriert: Samstag 19. Dezember 2015, 16:06

Die Deklarierung globaler Variablen versuche ich gerade aus meinem Programm zu verbannen. Was OOP angeht, ich komme bei meinem kleinen Programm (am Ende vermutlich weniger als 650 Zeilen Code inkl. Leerzeilen und Kommentare) ganz gut ohne aus. Es ist auch eine Frage der "Kosten-Nutzen-Relation". Wenn ich mir überlege, mich mittels Büchern durch ein komplett neues, mir nicht wirklich verständliches Konzept zu arbeiten, um dann mein Programm von vorn zu beginnen, nur im sagen zu können: seht her, OOP! Also nöö. Ich sehe gerade, ich habe sogar ein eBook zum Thema, aber trotzdem nur begrenzt Zeit.

Ich bin mir nichtmal sicher, ob ich den Geometrie-Manager tauschen soll, obwohl mir in diesem Fall tatsächlich klar ist, dass die Wahl von place() eher, sagen wir mal, suboptimal war. :)
Antworten