Buttons disablen

Fragen zu Tkinter.
Antworten
woto
User
Beiträge: 9
Registriert: Mittwoch 15. Juni 2022, 12:55

Hallo zusammen,

ich habe folgenden TestCode:

Code: Alles auswählen

import tkinter

class MyView(tkinter.Frame):
    def __init__(self, master=None):
        super().__init__(master)

        # LabelFrame für den Rahmen um den Namen und die Buttons
        frame = tkinter.LabelFrame(root, text="", padx=5, pady=5, bg="green")
        frame.grid(row=3, column=2, padx=2, pady=5, sticky="nsew")

        # Hinzufügen der Buttons
        bt_down = tkinter.Button(frame, text="runter", relief="raised", bd=5, width=7, height=1)
        bt_down.grid(row=1, column=0, padx=5, pady=5)

        bt_up = tkinter.Button(frame, text="rauf", relief="raised", bd=5, width=7, height=1)
        bt_up.grid(row=1, column=1, padx=5, pady=5)

        # Hinzufügen der Buttons
        bt_down_stop = tkinter.Button(frame, text="runter stop", relief="raised", bd=5, width=7, height=1)
        bt_down_stop.grid(row=2, column=0, padx=5, pady=5)

        bt_up_stop = tkinter.Button(frame, text="rauf stop", relief="raised", bd=5, width=7, height=1)
        bt_up_stop.grid(row=2, column=1, padx=5, pady=5)
    
# Beispiel für die Verwendung der Klasse
if __name__ == "__main__":
    root = tkinter.Tk()
    root.title("Datenkacheln")
    app = MyView(master=root)
    root.mainloop()
Nun möchte ich, wenn ich den Button "rauf" betätige, dass der Button "runter" disabled wird und umgekehrt.
Mit den Buttons "runter_stop" und "rauf_stop" sollen die beiden Buttons wieder enabled werden.

Da ich hier eine Klasse verwende, komme ich nicht auf die Lösung.
Kann mir da jemand auf die Sprünge helfen?
VG woto
woto
User
Beiträge: 9
Registriert: Mittwoch 15. Juni 2022, 12:55

ok, konnte es doch lösen:

Code: Alles auswählen

import tkinter

class MyView(tkinter.Frame):
    def __init__(self, master=None):
        super().__init__(master)
        self.master = master
        self.create_widgets()

    def create_widgets(self):
        # LabelFrame für den Rahmen um den Namen und die Buttons
        frame = tkinter.LabelFrame(self.master, text="", padx=5, pady=5, bg="green")
        frame.grid(row=3, column=2, padx=2, pady=5, sticky="nsew")

        # Hinzufügen der Buttons
        self.bt_down = tkinter.Button(frame, text="runter", relief="raised", bd=5, width=7, height=1, command=self.disable_up)
        self.bt_down.grid(row=1, column=0, padx=5, pady=5)

        self.bt_up = tkinter.Button(frame, text="rauf", relief="raised", bd=5, width=7, height=1, command=self.disable_down)
        self.bt_up.grid(row=1, column=1, padx=5, pady=5)

        # Hinzufügen der Stop-Buttons
        self.bt_down_stop = tkinter.Button(frame, text="runter stop", relief="raised", bd=5, width=7, height=1, command=self.enable_buttons)
        self.bt_down_stop.grid(row=2, column=0, padx=5, pady=5)

        self.bt_up_stop = tkinter.Button(frame, text="rauf stop", relief="raised", bd=5, width=7, height=1, command=self.enable_buttons)
        self.bt_up_stop.grid(row=2, column=1, padx=5, pady=5)

    def disable_up(self):
        self.bt_up.config(state="disabled")
        self.bt_down.config(state="normal")

    def disable_down(self):
        self.bt_down.config(state="disabled")
        self.bt_up.config(state="normal")

    def enable_buttons(self):
        self.bt_down.config(state="normal")
        self.bt_up.config(state="normal")

# Beispiel für die Verwendung der Klasse
if __name__ == "__main__":
    root = tkinter.Tk()
    root.title("Datenkacheln")
    app = MyView(master=root)
    root.mainloop()
Benutzeravatar
__blackjack__
User
Beiträge: 13919
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@woto: Das Hauptprogramm sollte in einer Funktion stehen. Die heisst üblicherweise `main()`. Dann fällt auf, dass in der `__init__()` auf das globale `root` zugegriffen wird, was nicht sein darf. Damit ist so ein `MyView`-Objekt ja auch gar nicht mehr flexibel nutzbar weil es dann Probleme gäbe wenn `master` und `root` nicht das selber Objekt sind.

`My` ist in 99% der Fälle ein unsinniger Namenszusatz. Wenn es nicht auch ein `OurView` oder `TheirView` gibt, hat das `my` überhaupt keine Bedeutung. Und warum heisst das Objekt dann `app`?

Namen sollten auch keine kryptischen Prä- oder Suffixe haben. Wenn man `button` meint, sollte man nicht nur `bt` schreiben. Und solange man nicht Yoda heisst, sollte man auch nicht anfangen Worte komisch umzustellen. Das ist ein `down_button` und kein `button_down`.

Ein `LabelFrame` ohne Text macht nicht wirklich Sinn, dann ist das ja einfach nur ein `Frame`. Ich sehe auch nicht warum man in den `View`, der ja auch ein `Frame` ist, noch mal einen `Frame` setzen muss. Zumal der `View` als `Frame` in dem Code auch überhaupt nicht benutzt wird, denn da fehlt der Aufruf der das layoutet. Während es keinen Sinn macht den inneren Frame als einziges Objekt in einem Grid an eine andere Stelle zu setzen als Zeile 0 und Spalte 0.

Auch die Schaltflächen sollten in Zeile 0 anfangen und nicht in Zeile 1 wenn Zeile 0 sonst nichts weiter enthält.

Wenn es im `tkinter`-Modul für Werte mit einer speziellen Bedeutung eine Konstante gibt, sollte man die auch verwenden, statt fehleranfällig diesen Wert als Zeichenkette anzugeben.

Schaltflächen haben schon von Haus aus das angegebene `relief`. Und selbst wenn sie ein anderes hätten, sollte man das nicht ändern, denn das ist ja der Wert, den der Benutzer optisch bei Schaltflächen erwartet.

Höhe und Breite von Schaltflächen sollte man nicht selbst angeben, die ergeben sich auch dem Inhalt. Und auch wenn die Breite nicht in Pixeln, sondern in Zeichen angegeben wird, ist hier nicht garantiert, dass der tatsächliche Text auch da rein passt. Die Breite ist hier mit 7 Zeichen angegeben, der längste Text hat aber 11 Zeichen. Das kann passen, muss es aber nicht.

Wenn man etwas beim Druck auf eine Schaltfläche machen will, dann muss man eine Rückruffunktion oder -methode angeben. Und die muss dann Zugriff auf die Objekte haben, die dann gebraucht werden. Also müssen mindesten die beiden Schaltflächen deren Zustand geändert werden soll, an das Objekt gebunden werden.

Zwischenstand:

Code: Alles auswählen

import tkinter


class View(tkinter.Frame):
    def __init__(self, master=None):
        super().__init__(
            master, padx=5, pady=5, background="green", relief=tkinter.RIDGE
        )
        grid_options = {"padx": 5, "pady": 5, "sticky": tkinter.NSEW}

        self.down_button = tkinter.Button(
            self, text="runter", border=5, command=self.on_down
        )
        self.down_button.grid(row=0, column=0, **grid_options)

        self.up_button = tkinter.Button(
            self, text="rauf", border=5, command=self.on_up
        )
        self.up_button.grid(row=0, column=1, **grid_options)

        tkinter.Button(
            self, text="runter stop", border=5, command=self.on_stop
        ).grid(row=1, column=0, **grid_options)

        tkinter.Button(
            self, text="rauf stop", border=5, command=self.on_stop
        ).grid(row=1, column=1, **grid_options)

        for i in range(2):
            self.grid_columnconfigure(i, uniform="a")

    def on_down(self):
        self.up_button["state"] = tkinter.DISABLED

    def on_up(self):
        self.down_button["state"] = tkinter.DISABLED

    def on_stop(self):
        self.down_button["state"] = self.up_button["state"] = tkinter.NORMAL


def main():
    root = tkinter.Tk()
    root.title("Datenkacheln")
    view = View(root)
    view.pack(padx=2, pady=5)
    root.mainloop()


if __name__ == "__main__":
    main()
Wobei ich nicht so ganz sehe warum es zwei Stopp-Buttons geben muss.

Edit: Zum letzten Beitrag: Es macht keinen Sinn die `__init__()` in eine weitere Methode zu verschieben. `master` gibt es bereits, das braucht man nicht selbst binden. Aber das sollte man auch gar nicht benutzen, denn wie gesagt umgeht man damit das `View`-Objekt selbst als Frame *und* man layoutet Zeugs in ein übergeordnetes Widget, was man nicht macht. Am `master` hat ein Kindwidget nichts zu basteln.
“I am Dyslexic of Borg, Your Ass will be Laminated” — unknown
Antworten