tkinter - widget - Bezeichnungen aus dem Element ziehen

Fragen zu Tkinter.
Antworten
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hallo,

ich habe mir ein kleines Programm ausgedacht, mit dem ich in einer Funktion Checkboxen erstelle. Die Funktion liefert ein mehrdimensionales Array zurück, bei dem jede Zeile aus den Werten "widgethandler, variablehandler und bezeichner" besteht. Diese drei Informationen brauchte ich in meinem nachfolgenden Programm, um verschiedene Aktionen damit durchzuführen.

Code: Alles auswählen

import tkinter
from functools import partial

def create_buttons (window_handler, entries=[], **options):
    return_value=[]
    for entry in entries:
        print (entry)
        widget_var=tkinter.BooleanVar()
        widget=tkinter.Checkbutton (window_handler,
                                    variable=widget_var,
                                    text=entry,

                                    **options)
        return_array=[widget, widget_var, entry]
        return_value.append (return_array)
    return return_value

def set_all (handlerlist, state):
    for handler in handlerlist:
        handler[1].set (state)

def main():
    root = tkinter.Tk()
#    root.

    entry_buttons = ["Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"]

    button_array = create_buttons(root,
                                  entry_buttons
                                  )

    abort_button = tkinter.Button (root, text="Beenden", command=root.quit )
    abort_button.pack()

    all_button = tkinter.Button (root, text="Alle", command=partial(set_all, button_array, True))
    all_button.pack()
    no_button = tkinter.Button (root, text="Keine", command=partial(set_all, button_array, False))
    no_button.pack()

    for element in button_array:
        print ("Elementbezeichner: %s " % str(element[2]) )
        element[0].pack()


    root.mainloop()

if __name__ == '__main__':
    main()
Ich finde es irgendwie "unpraktisch", ein mehrdimensionales Array zurückzugeben, um z.B. an den Variablenbezeichner heranzukommen. Der einzelne Button wird durch "widgethandler" angesprochen. Besteht die Möglichkeit, dass ich nur mit diesem einen Bezeichner auf die anderen Elemente wieder zurückgreifen kann, die ich vorher beim Erstellen

Code: Alles auswählen

        widget=tkinter.Checkbutton (window_handler,
                                    variable=widget_var,
                                    text=entry,

                                    **options)
zugewiesen habe - also dass ich nicht Checkbutton-Variable als zweites Element aus dem Array auslesen muss, sondern irgendwie mit widget.XXX.get()/set() die Information kriege?
Schorlem
User
Beiträge: 40
Registriert: Dienstag 3. Juni 2014, 16:37

Du kannst die Konfiguration eines Widgets mit .cget() abrufen. Beispiel:

Code: Alles auswählen

for button in buttons:
    print(button.cget('text'))
Noch praktischer wäre es, wenn du die ganze GUI in eine Klasse steckst, dann musst du keine umständliche Liste hin und her schicken.
Zusätzlich solltest du bei deinem Beenden-Button die "command"-Option auf eine Funktion zeigen lassen, die ungefähr so aussieht (die Klasse setze ich jetzt voraus, ansonsten musst du "root" halt als Parameter übergeben:

Code: Alles auswählen

def quit():
    self.root.destroy()
    self.root.quit()
Damit beendest du nicht nur das Programm, sondern schließt auch das Fenster.
Diese Nachricht wurde maschinell erstellt und ist daher ohne Unterschrift gültig.
BlackJack

@Papp Nase: Veränderbare Objekte als Defaultwerte sind in der Regel keine gute Idee. Wobei bei `create_buttons()` das `entries`-Argument IMHO sowieso kein Defaultwert haben sollte.

Du benutzt den Begriff `handler` soweit ich das sehe falsch. Da wo Du das für Widgets verwendest, ist in anderen Sprachen/GUI-Rahmenwerken der Begriff `handle` üblich. Das ist aber in der Regel eine Zahl die als Stellvertreter für ein Objekt steht, also man hat ein Handle was für ein Widget steht. In Python hat man aber die Objekte direkt in der Hand und muss dafür keine Zahlen als Alias in der Gegend herum reichen, darum ist Handle eigentlich falsch als Bezeichnung. Dazu kommt noch, dass es bei Tkinter tatsächlich so etwas wie Handles gibt, denn man kann von einem `Checkbutton` zum Beispiel die leider nicht das `BooleanVar`-Objekt abfragen, aber ein Handle dafür das man mit der `setvar()`-Methode verwenden kann.

Konkrete Typen sollte man in Namen vermeiden, also so etwas wie `list` oder `array` was auch noch falsch ist, weil es die Erwartung weckt man hätte ein Array vor sich, wo man eigentlich eine Liste hat.

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 create_checkbuttons(master, texts, **options):
    return [
        tk.Checkbutton(master, variable=tk.BooleanVar(), text=text, **options)
        for text in texts
    ]


def set_all(checkbuttons, state):
    for checkbutton in checkbuttons:
        checkbutton.setvar(checkbutton['variable'], state)


def main():
    root = tk.Tk()
    checkbutton_texts = [
        'Button 1', 'Button 2', 'Button 3', 'Button 4', 'Button 5', 'Button 6'
    ]

    checkbuttons = create_checkbuttons(root, checkbutton_texts)

    tk.Button(root, text='Beenden', command=root.quit).pack()
    tk.Button(
        root, text='Alle', command=partial(set_all, checkbuttons, True)
    ).pack()
    tk.Button(
        root, text='Keine', command=partial(set_all, checkbuttons, False)
    ).pack()

    for checkbutton in checkbuttons:
        print('Elementbezeichner:', checkbutton['text'])
        checkbutton.pack()

    root.mainloop()


if __name__ == '__main__':
    main()
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Vielen Dank für Eure Antworten.

Könnt ihr mir vielleicht dieses Konstrukt erklären:

Code: Alles auswählen

    return [
        tk.Checkbutton(master, variable=tk.BooleanVar(), text=text, **options)
        for text in texts
    ] 
Ich verstehe das mit der for-Schleife noch nicht, warum man die dahinter setzen kann - und ohne Doppelpunkt. Ich hab analog dazu mal das hier ausprobiert, was aber nicht klappt:

Code: Alles auswählen

liste = [1,2,3,4,6,7,8,9,10]
print (element)
for element in liste
Zuletzt geändert von Papp Nase am Mittwoch 16. Juli 2014, 08:49, insgesamt 2-mal geändert.
BlackJack

@Papp Nase: Das ist eine „list comprehension” (LC). Die eckigen Klammern sind da wichtig. Und Dein Versuch mit `print()` wäre da kein gutes Beispiel denn die Syntax ist dafür da Listen zu erzeugen. Das `print()` wäre dann dafür da um ein einzelnes Element zu erzeugen, nur hat das den Rückgabewert `None`, was nicht sehr sinnvoll wäre.

Edit: Die kommen natürlich auch im Tutorial vor: https://docs.python.org/2.7/tutorial/da ... rehensions
Papp Nase
User
Beiträge: 139
Registriert: Dienstag 11. März 2014, 15:12

Hallo Blackjack.

vielen Dank, dass Du mir das mit der list comprehension erklärt und den Link zugestellt hast, ich habe mich sehr darüber gefreut.
Antworten