Tkinter Checkbutton Auswertung funktioniert nicht wie erwartet

Fragen zu Tkinter.
Antworten
Eiszapfen
User
Beiträge: 1
Registriert: Sonntag 7. Februar 2016, 15:31

Hallo zusammen,

Ich habe vor einigen Tagen begonnen, mich intensiver mit Python auseinander zu setzen, da ich mein plattformübergreifenden Skripte/Tools/Apps (nennt es, wie ihr wollt) eben damit umsetzen wollte. Windows-spezifische Dinge setze ich hauptsächlich mit AutoIt um und ich verfüge über einige Jahre Erfahrung mit C++ in Verbindung mit Qt. An generellen Programmier-Fähigkeiten, sollte es also nicht scheitern. :)

Allerdings habe ich vielleicht für den Anfang etwas hoch gegriffen, denn ich möchte direkt ein Tool mit grafischem Interface umsetzen. Und vermutlich fehlt auch noch das eine oder andere Häppchen Verständis in Python.

Zum Problem:
Die Datei main.py erzeugt ein Fenster mit einem Button. Dieser Button löst eine Funktion aus dia_compose_message.py aus, welche ein weiteres Fenster erzeugen soll. In diesem weiteren Fenster soll ein Checkbutton ausgewertet werden.

Das Problem:
  1. Führe ich dia_compose_message.py direkt aus, funktioniert alles wie es soll, der Status wird korrekt erkannt.
  2. Führe ich main.py aus, erscheint das zweite Fenster ohne dass ich vorher den Button drücken müssen. In diesem Zustand funktioniert die Auswertung des Checkbutton allerdings auch. Ich nehme an, dass das Erscheinen des Fensters durch den import in main.py und die letzte Zeile in dia_compose_message.py (Klasse wird aufgerufen) ausgelöst wird.
  3. Kommentiere ich besagte letzte Zeile aus, erscheint das Fenster tatsächlich erst, wenn ich in main.py den Button gedrückt habe. Allerdings funktioniert dann die Auswertung des Status des Checkbutton nicht. Hier wird dann immer 0 (Null) zurückgegeben.
Es wäre schön, wenn ihr mir erklären könntet, ob ich bei Punkt 2 mit meiner Vermutung richtig liege und warum dort die Auswertung funktioniert.
Wenn mir dann noch jemand erklären könnte, woran es liegt, dass Punkt 3 nicht richtig funktioniert, wäre ich extrem dankbar.


dia_compose_message.py:

Code: Alles auswählen

from tkinter import *

class ComposeMessage:
    def __init__(self):
        gui = Tk()
        gui.title('Another title')

        var1 = IntVar()

        def cb_state():
            print('variable is: ' + str(var1.get()))

        che_administrative_message = Checkbutton(gui, text='Test',
                                                 variable=var1, command=cb_state)
        che_administrative_message.place(x=5, y=55)

        mainloop()

ComposeMessage()
main.py:

Code: Alles auswählen

from tkinter import *
from tkinter import ttk

from dialogs import dia_compose_message

def compose_message():
    dia_compose_message.ComposeMessage()

gui = Tk()
gui.minsize(width=800, height=600)
gui.maxsize(width=800, height=600)
gui.title('TITLE')
but_compose_message = Button(gui, text='Compose', command=compose_message)
but_compose_message.configure(width=110)
but_compose_message.place(x=5, y=35)
gui.mainloop()
BlackJack

@Eiszapfen: Module werden beim importieren ausgeführt. Wenn auf Modulebene also steht das ein Exemplar von `ComposeMessage` erstellt werden soll, dann wird das auch gemacht. Unter anderem damit Module sinnvoll verwendet werden können, sollte deshalb nichts passieren was über die Definition von Konstanten, Funktionen, und Klassen hinaus geht. Alles andere gehört in Funktionen, die man dann aufrufen kann oder halt auch nicht. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst, und die durch folgendes Idiom aufgerufen wird:

Code: Alles auswählen

if __name__ == '__main__':
    main()
Der Name `__name__` wird von der Laufzeitumgebung immer auf den Namen des Moduls gesetzt, ausser bei dem Modul mit dem das Programm gestartet wurde, da ist der Name `__main__` egal wie das Modul heisst. So kann man so ein Modul dann als Programm ausführen und auch als Modul importieren *ohne* das dadurch die `main()`-Funktion ausgeführt wird.

Zu Punkt 3: Es darf im Programm nur *ein* Tk-Exemplar geben. Das ist *das* Hauptfenster, da hängt der Tk/Tcl-Interpreter dran, und der darf nur einmal gleichzeitig laufen. Wenn man davon mehrere gleichzeitig hat, können sehr komische Dinge passieren. Für zusätzliche Fenster kann man `Toplevel` verwenden.

Sonstige Anmerkungen: Gewöhn Dir *-Importe am besten gar nicht erst an. Damit holt man sich alle Namen aus dem Modul in das importierende Modul und es wird schwer zu erkennen wo welcher Name her kommt, und es besteht auch die Gefahr von Namenskollisionen mit Namen aus anderen Modulen oder eingebauten Funktionen. Das `tkinter`-Modul wird oft als `tk` importiert, damit man nicht so viel tippen muss, aber auch nicht alle einzelnen Namen importieren muss, die man verwenden möchte.

Die `ComposeMessage`-Klasse ist keine Klasse sondern nur eine umständliche Art eine Funktion zu schreiben.

Namen durchnummerieren deutet entweder auf schlechte Namen hin, weil man sich keine Mühe gemacht hat einen sinnvollen Namen zu wählen, oder das man eine Datenstruktur verwenden möchte statt einzelner Namen.

Vermeide Abkürzungen die nicht allgemein bekannt sind. Falls Du jetzt anfangen wolltest jedem Namen ein dreibuchstabiges Kürzel für den Widgettyp voran zu stellen: Das ist keine gute Idee. Das lädt nur zum Rätselraten ein was das denn bedeuten möge. Bei dem `dia_*`-Präfix für ein Modul das in einem `dialogs`-Package steckt wird es ausserdem reichlich redundant. Übrigens ist es in Python unüblich pro Klasse ein Modul zu schreiben.

`place()` und absolute Grössen vorgeben ist in Tk genau so eine schlechte Idee wie in Qt. Grössen und Positionen sollten vom Inhalt der Widgets abhängen und vom GUI-Rahmenwerk passend gewählt werden.

Eine Anbindung an Qt gibt es für Python übrigens auch.
Antworten