Checkbutton/Checkbox GUI Python

Fragen zu Tkinter.
Antworten
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

Irgendwie finde ich leider kein einfaches Beispiel, an dem ich das Checkbox-Widget verstehen könnte.
Ich hab mein Programm, mal sehr vereinfacht zu nem Vorname/Nachname Programm. Wie bekomme ich das hin, dass der Nachnahme anfangs ausgeblendet ist und wenn ich den Haken setze der Nachnahme hinzugefügt wird? versteh das Prinzip bei der Checkbox nicht, mit dem True/False setzen.
Weiß jemand Rat? Danke euch

Code: Alles auswählen

import Tkinter as tk
from Tkinter import IntVar

def name(w):

    
    l = tk.Label(w, text = 'Max')
    l.grid(row=1,column=1)

               
def lastname(w):

    l = tk.Label(w, text = 'Mustermann')
    l.grid(row=2,column=1)


def main():


    #build window
    w =tk.Tk()

    #modify window
    w.title('Checkbox-Test')
    w.geometry('300x200')

    #print first name
    name(w)


    #checkbox
    var = IntVar()
    c = tk.Checkbutton(w, text="show last name",variable=var
    , command=lastname(w))
    c.grid(row=0,column=0)

    w.mainloop()

if __name__ == '__main__':
    main()


BlackJack

@MarcNAV: `var` brauchst Du hier gar nicht wenn Du nur das `command` verwenden willst. Und beim `command`-Argument musst Du eine *Funktion* übergeben statt `None`. Das ist nämlich der Rückgabewert von `lastname()` was Du da *aufrufst*.

Eine Checkbox erscheint mir hier aber auch irgendwie unsinnig. Insbesondere wird das `comman()` ja jedes mal aufgerufen wenn man klickt, also werden immer wieder neue `Label`-Objekte erstellt, was nicht nur keinen Sinn macht, sondern auch ein Speicherleck darstellt.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

ah okay thx. Bei mir entscheidet das Häkchen eigentlich ob er die .gz Dateien nach dem entpacken löschen soll. Habs nur fürs Forum hier aufs Wesentliche reduziert.
Hätte noch eine Frage zum Layout. Kann ich einfach wenn ich mit grid() arbeite ihm direkt die Zeile und Spalte angeben ? Weiß Python durch die angegebene Fenstergröße die Grid-Aufteilung automatisch?

Code: Alles auswählen

    Bsp.:
    w =tk.Tk()
    w.geometry('300x200')
    l = tk.Label(w, text = 'Hallo')
    l.grid(row=2,column=3)
BlackJack

@MarcNAV: Für den Fall brauchst Du `command` gar nicht, sondern dann doch `var` und da musst Du halt an der entsprechenden Stelle den aktuellen Wert abfragen.

Das mit dem `grid()` habe ich nicht verstanden? Die angegebene Fenstergrösse hat damit nichts zu tun, und eigentlich sollte man die Fenstergrösse auch überhaupt nicht so vorgeben. Das `grid()` ergibt sich durch die Angaben in den `grid()`-Aufrufen. Wobei ich da keine Zeilen oder Spalten leer lassen würde. Und ich persönlich verwende `grid()` auch nur wenn ich tatsächlich so ein tabellenartiges Layout benötige.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

ah okay. hab nur überall gelesen man solle mit grids arbeiten aber die pack methode gefällt mir persönlich besser.
place scheint mir am unsinnigsten.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

Hab gerade mal rumprobiert aber verstehs ich irgendwie nicht ganz wie ich das alles verknüpfe. Muß ich das mit einer if lastname(w) is TRUE Abfrage machen? Könnt mir das einer kurz abändern? Versteh auch nicht welchen variablen Typ ich da brauche.
BlackJack

@MarcNAV: Du musst den Wert von `var` mittels `get()` abfragen. Als Typen bieten sich für `var` `Tkinter.IntVar` oder `Tkinter.BooleanVar` an.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

Bin glaub schon auf dem richtigen Weg. Was muß ich da noch ändern? Gar nicht so leicht zu verstehen.

Code: Alles auswählen


import Tkinter as tk
from Tkinter import BooleanVar

def name(w):


    l = tk.Label(w, text = 'Max')
    l.grid(row=1,column=1)


def lastname(w, var):

        l = tk.Label(w, text = 'Mustermann')
        l.grid(row=2,column=1)
        var.get()

def main():


    #build window
    w =tk.Tk()

    #modify window
    w.title('Checkbox-Test')
    w.geometry('300x200')

    #print first name
    name(w)


    #checkbox

    var = BooleanVar()
    c = tk.Checkbutton(w, text="show last name",variable=var, command= lastname(w, var))
    c.grid(row=0,column=0)

    w.mainloop()

if __name__ == '__main__':
    main()


BlackJack

@MarcNAV: Du rufst immer noch die Funktion auf statt eine zu übergeben. Beim Erstellen des `Checkbutton()` rufst Du `lastname()` auf und übergibst den Rückgabwert der Funktion als `command`-Argument. Da darfst Du die Funktion nicht aufrufen sondern eine Funktion übergeben die keine Argumente erwartet, und diesie aufgerufen wird, die `lastname()`-Funktion aufruft. Normalerweise erstellt man so eine Funktion mit `functools.partial()` oder als ``lambda``-Ausdruck. Wobei man bei GUIs sowieso eher Klassen verwendet.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

Danke BalckJack jetzt gehts. Super;)
Zuletzt geändert von MarcNAV am Mittwoch 6. August 2014, 11:56, insgesamt 1-mal geändert.
MarcNAV
User
Beiträge: 52
Registriert: Freitag 16. Mai 2014, 11:39

Hier für diejenigen, die das gleiche Problem haben. So funktionierts für meine Zwecke:

Code: Alles auswählen

import Tkinter as tk
from Tkinter import BooleanVar

def name(w):


    l = tk.Label(w, text = 'Max')
    l.grid(row=1,column=1)


def lastname(w, var):


    l = tk.Label(w, text = 'Mustermann')
    l.grid(row=2,column=1)


def main():


    #build window
    w =tk.Tk()

    #modify window
    w.title('Checkbox-Test')
    w.geometry('300x200')

    #print first name
    name(w)


    #checkbox

    var = BooleanVar()

    c = tk.Checkbutton(w, text="show last name",variable=var, command= lambda: lastname(w, var))
    c.grid(row=0,column=0)

    w.mainloop()

if __name__ == '__main__':
    main()


Dusius

Hallo zusammen,

ich werde mein Frage mal hier rein packen....

In meinem kleinen Programm habe ich eine Feld mit Checkbuttons, und daneben ein Canvas Feld. Die Idee war eigentlich, dass ich wenn ich ein bestimmten Checkbutton aktiv habe, eine bestimmte Linie gezeichnet wird, diese soll aber auch wieder weg gehen wenn ich ihn deaktiviere.

Die Checkbuttons und das Canvas Feld sind in unterschiedlichen Klassen untergebracht.

Hat jemand einen Tipp wie ich das am einfachsten realisieren kann?

Grüße
BlackJack

@Dusius: Wo liegt denn das konkrete Problem? Die Fragestellung ist sehr/zu allgemein. Die Klasse mit dem `Canvas`-Exemplar braucht halt eine API mit der man Linien zeichnen/entfernen kann und dann muss man diese API von dem Objekt mit den `Checkbutton`\s aus ansprechen wenn so eine Schaltfläche (de)aktiviert wurde. Wie die Schnittstelle(n) am besten aussehen, wie und wo die Linien verwaltet werden, welches Objekt welchem anderen bekannt gemacht werden sollte und von ”wem”, sind alles Fragen die davon abhängen was genau damit gelöst werden soll.
Dusius

Hey,

also das mit dem Zeichnen ist kein Problem, ich erstelle z.B. 4 verschiedene Linien jeweils mit create_line....
jetzt hätte ich gern, dass wenn ich den checkbutton 1 aktiviere (also das Häckchen setze) diese Linie, die dem checkbutton zugeordnet ist gezeichnet wird. Wenn ich das Häckchen weg mache soll sie wieder weg sein.

Ich möchte verschieden Linien miteinander vergleichen können, aber nur diese, die ich auch sehen möchte.

Eines der Probleme die ich gerade noch habe ist, das Aufrufen einer Funktion (z.B create_line) von einer anderen Klasse aus.

Grüße
BlackJack

@Dusius: Wie schon gesagt, die Klasse die das `Canvas` enthält braucht eine Methode um irgendwie die Linie zu zeichnen. Da fangen dann schon die Fragen an wie man die identifiziert beziehungsweise wo die Daten herkommen. Denn man muss sich das ja in der Klasse mit dem `Canvas` irgendwie merken und die ID von der erzeugten Linie um die dann später wieder löschen zu können.

Und dann muss man dem Objekt mit den Checkbuttons mindestens die Methode(n) zum zeichenen und löschen von Linien bekannt machen. Oder das Objekt mit dem `Canvas`. In dem man es in der `__init__()` übergibt. Oder über eine dafür vorgesehene Methode, oder mit einem Objekt das zwischen diesen beiden Objekten vermittelt, oder…

Also zumindest mir fällt es schwer so eine allgemeine Frage konkret zu beantworten, ohne jetzt eine der vielen Möglichkeiten heraus zu greifen, die aber so überhaupt nicht zum *tatsächlichen* Problem passen muss. Versuch *das* doch mal zu beschreiben, mit Vokabular aus der Problemdomäne und nicht in einer konkreten abstrakten Lösung dessen Problem wir nicht kennen.
Antworten