Kommandoaufruf nach Wertänderung eines Radiobuttons bei tkin

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hi,

ich hab mir ein kleines Programm mit drei Radiobuttons geschrieben:

Code: Alles auswählen

import tkinter

def RadioButtonFunction (Variable):
    print ("\n Die Variable des Radiobuttons ist: " + str(Variable))

def start_tkinter ():
    root = tkinter.Tk()
    RadioButtonValue=tkinter.StringVar()
    RadioButtonValue.set("Button3")

    widget1 = tkinter.Radiobutton(root, value="Button1", text="Button 1", variable=RadioButtonValue, pady=100, command=RadioButtonFunction(RadioButtonValue.get()))
    widget1.pack()
    widget2 = tkinter.Radiobutton(root, value="Button2", text="Button 2", variable=RadioButtonValue, command=RadioButtonFunction(RadioButtonValue.get()))
    widget2.pack()
    widget3 = tkinter.Radiobutton(root, value="Button3", text="Button 3", variable=RadioButtonValue, command=RadioButtonFunction(RadioButtonValue.get()))
    widget3.pack()

    root.mainloop()
    return (RadioButtonValue.get())

def main():
    print ("in main")
    backwert = start_tkinter()
    print ("nach tkinter, backwert = " + str(backwert))

if __name__ == '__main__':
    main()
Hier auf dieser Seite steht:
http://www.tutorialspoint.com/python/tk_radiobutton.htm

Eigenschaft command= Routine wird gestartet, wenn Wert des Radiobuttons verändert wird.

Beim Starten des Programms wird 3mal die Routine RadioButtonFunction ausgeführt. Aber wenn ich dann in dem Fenster die Radiobuttons anklicke, dann wird die Funktion nicht nochmal aufgerufen - das verstehe ich nicht, denn ich hab doch extra mit command=RadioButton... definiert, dass dann die Routine ausgeführt werden soll.

Kann mir von Euch vielleicht jemand weiterhelfen?
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo.

Du musst die Funktion an command binden. Momentan führst du jedoch die Funktion aus und bindest dessen Ergebnis an command.
Das Leben ist wie ein Tennisball.
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Danke für die Info. Ich hab das jetzt so gelöst, dass ich die Klammern am Ende der Funktion weggelassen hab, also nicht command=tuwas(), sondern command=tuwas.

Wenn ich dann Werte übergeben will, muss ich das dann mittels globaler Variablen tun, um Daten hin- und herzuschaufeln?
Benutzeravatar
darktrym
User
Beiträge: 785
Registriert: Freitag 24. April 2009, 09:26

Man kann auch die Handles zurückgeben lassen oder löst das mittels Klassen. Global ist immer die schlechteste Lösung.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Danke für die Antwort.

Kannst Du mir einen Tipp geben, was Du mit Klassen meinst? Ich vermute mal, dass ich mir eine Klasse definiere, in der ich den Variablenwert speichere und dann diese Klasse von den verschiedenen Funktionen aufrufe, um Werte zu schreiben oder zu lesen?
Benutzeravatar
darktrym
User
Beiträge: 785
Registriert: Freitag 24. April 2009, 09:26

Wenn du den Zugriff auf widget* brauchst, würde ich die Handles als Klassenattribute sichern. So kann auch jede Klassenmethode nach belieben darauf zugreifen. Alternativ gibts du deine Handles als Tupel zurück und schleifst die durch wo immer sie gebraucht werden.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Papp Nase hat geschrieben:Danke für die Info. Ich hab das jetzt so gelöst, dass ich die Klammern am Ende der Funktion weggelassen hab, also nicht command=tuwas(), sondern command=tuwas.
Richtig. Damit übergist du die Funktion und rufst sie nicht vorher auf. Funktionen sind, wie alles was du in Python an einen Namen binden kannst, ganz normale Objekte. Du kannst sie also beliebig durch die Gegend reichen.
Papp Nase hat geschrieben:Wenn ich dann Werte übergeben will, muss ich das dann mittels globaler Variablen tun, um Daten hin- und herzuschaufeln?
Nein, am besten vergisst du, dass es globale Variablen überhaupt gibt. Die sind nur in sehr sehr seltenen Fällen wirklich sinnvoll. Klassen brauchst du in diesem Fall auch nicht, das kannst du einfacher lösen. Zum Beispiel kannst du der callback-Funktion auch Werte übergeben:

Code: Alles auswählen

import functools

def callback(value, event):
    v = value.get()
    ...

widget1 = tkinter.Radiobutton(root, value="Button1", text="Button 1", variable=RadioButtonValue, pady=100, command=functools.partial(RadioButtonFunction, RadioButtonValue))
In diesem Fall ist das aber überflüssig, da der event-Parameter der callback-Funktion bereits das angeklickte Widget als Attribut enthält. Zu dem Widget bekommst du dann auch die dazugehörige Variable raus.

Bei der Gelegenheit solltest du einen Blick in PEP 8 werfen, deine Namensgebung ist etwas unschön. "RadioButtonValue" impliziert, dass es sich hierbei um einen Typ handelt, die übliche Schreibweise lautet "radio_button_value". Selbiges gilt für "RadioButtonFunction".

Auch solltest du dir gar nicht erst angewöhnen Namen zu nummerieren, da solltest du besser geeignete Datenstrukruen wählen. Üblich sind Listen, Tupel oder Dictionaries. "return" ist zudem keine Funktion und sollte deshalb nicht wie eine behandelt werden. Lasse die Klammern um den Rückgabewert weg.

Was du "backwert" nennst, das nennt sich "Rückgabewert". Bei der Gelegenheit so noch angemerkt, dass du dich für eine Sprache entscheiden solltest. Entweder Deutsch oder Englisch. Eine Mischung aus beidem ist etwas gruselig.
Das Leben ist wie ein Tennisball.
BlackJack

@Papp Nase: `tkinter` wird üblicherweise als `tk` importiert, damit das nicht so oft ausgeschrieben im Quelltext stehen muss.

Die Leerzeichensetzung zwischen Funktionsnamen und öffnender Klammer ist inkonsequent. Per Konvention gehört dort kein Leerzeichen hin.

Was die durchnummerierten Namen angeht: Da kann man in diesem Fall auch einfach immer den selben Namen verwenden, denn die `RadioButton`-Exemplare werden danach ja gar nicht mehr benötigt, oder man spaltet den Ausdruck nicht auf und gibt dem Ergebnis einfach gar keinen Namen. Da sich der Code für jeden Radiobutton nahezu identisch wiederholt, böte sich an der Stelle auch eine Schleife an wo die Unterschiede als Daten herausgezogen sind.

Code: Alles auswählen

from __future__ import print_function
try:
    import Tkinter as tk
except ImportError:
    import tkinter as tk
from functools import partial


def radio_button_function(variable):
    print('\n Die Variable des Radiobuttons ist:', variable.get())


def start_tkinter():
    radiobutton_data = [
        ('Button1', 'Button 1'),
        ('Button2', 'Button 2'),
        ('Button3', 'Button 3'),
    ]
    root = tk.Tk()
    variable = tk.StringVar(root, radiobutton_data[-1][0])
 
    for value, text in radiobutton_data:
        tk.Radiobutton(
            root,
            value=value,
            text=text,
            variable=variable,
            command=partial(radio_button_function, variable)
        ).pack()
 
    root.mainloop()
    return variable.get()
 

def main():
    print('in main')
    result = start_tkinter()
    print('nach tkinter, ergebnis =', result)
 

if __name__ == '__main__':
    main()
Falls das ein beliebig einsetzbarer Dialog sein soll, dann ist das Verwenden von `Tk` ungünstig, denn davon darf es in einem Programm immer nur *ein* Exemplar geben. Zumindest zur gleichen Zeit. Man kann diese Funktion also nicht in GUI-Programmen verwenden in denen es schon ein `Tk`-Exemplar gibt. Für modale Dialoge gibt es in `tkinter.simpledialog` Klassen die man als Basis für eigene Dialoge nehmen kann.
Antworten