Command Spinbox

Fragen zu Tkinter.
Antworten
Cobra5
User
Beiträge: 22
Registriert: Sonntag 25. Mai 2008, 10:44

Hallo allerseits,

hab folgendes Problem:

Code: Alles auswählen

from Tkinter import * 

T = Tk()

for i in range(5):

    S = Spinbox(T,values=('A','B','C'),command=lambda: show(S.get()))
    S.grid(row=i)

def show(A):

    print A
Ich erstelle mit einer for Schleife mehere Spinboxen mit den Werten a,b,c. Wenn ich eine Spinbox benutzte soll der aktuelle Wert gezeigt werden (Funktion: show). Mache ich dies, gibt die Funktion aber immer den Wert der letzten Spinbox zurück, auch wenn ich eigentlich andere benutze. Er gibt bei command (S.get()) also der Funktion immer den Inhalt der letzten Spinbox weiter. Gibt es eine Möglichkeit das zu verhindern? Oder muss ich jede Spinbox einzeln erstellen (ohne for Schleife, sondern S_1 =... , S_2 = ... , ...).

Danke im Voraus.

Gruß Cobra5
BlackJack

Du musst dafür sorgen, dass `S` in der ``lambda``-Funktion zu dem Zeitpunkt gebunden wird, zu dem die Funktion erzeugt wird. So wie's jetzt ist, wird `S` erst bei einer Veränderung der `Spinbox` aufgelöst und das ist dann eben der Wert an den `S` zuletzt gebunden war.

Also erst die Spinbox erzeugen und an einen Namen binden, und dann das `command` setzen und dabei die eben erzeugte Spinbox über ein Default-Argument binden.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dein Code hat fast keine Zeile, die nicht gegen die gängigen Python-Konventionen verstößt!

http://www.python.org/dev/peps/pep-0008/
(Hat neulich jemand hier im Forum auch auf Deutsch übersetzt - lässt sich sicher schnell finden).

Daran solltest du zunächst arbeiten, weil es dann anderen auch leichter fällt, deinen Code nachzuvollziehen.
BlackJack

Beispiel mit `functools.partial()`:

Code: Alles auswählen

import Tkinter as tk
from functools import partial

def show(number, spinbox):
    print '%d = %s' % (number, spinbox.get())

def main():
    root = tk.Tk()
    for i in xrange(5):
        spinbox = tk.Spinbox(root, values=('A', 'B', 'C'))
        spinbox.configure(command=partial(show, i, spinbox))
        spinbox.pack()
    root.mainloop()

if __name__ == '__main__':
    main()
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo BlackJack

Das Modul `functools.partial()` ist eine Neuigkeit für mich. Ich habe dein Code-Snippet ausprobiert. Es hinterlies den folgenden Traceback:

Traceback (most recent call last):
File "spinbox_01.py", line 2, in ?
from functools import partial
ImportError: cannot import name partial

Ich suchte mit Google nach dem Modul 'functools' und fand unter:
http://pypi.python.org/pypi/functools/0.5 eine Archiv-Datei mit dem namen functools-05.tar.gz. Ich entpackte diese Archiv-Datei im Linux-Verzeichnis /tmp. Habe die installation mit dem Befehl python setup.py install durchgeführt. Nach der Installation kontrollierte ich im Python-Verzeichnis ...../site_packages ob die neu installierten Dateien vorhanden sind. Ich fand folgende Dateien:

a) functools.py
b) unctools.pyc
c) _functools.so

So wie ich einschätzen kann ist die Installation korrekt durchgeführt worden. Ich startete das Code-Snippet neu. Es wirft immer noch den gleichen Traceback ab. Es gib scheinbar Probleme beim Import von 'partial'. Was meinst du was könnte das sein?

Was bewirkt dies Modul genau?

Mein Setup hier ist:

Linux SuSE 10.0
Python 2.4

Danke für deine Bemühung Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

wuf hat geschrieben:Was meinst du was könnte das sein?
Zitat aus der Library Reference:
6.6 functools -- Higher order functions and operations on callable objects.

New in version 2.5.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

@pütone: Danke für den Tipp

Hallo Cobra5

Hier ist noch der konservative Lösungsansatz:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Skriptname spinbox_02.py (26.06.2008 wuf)

import Tkinter as tk


def show(obj,index):
    """Der Wert einer Spinbox wurde verändert"""

    print 'Spinbox.Nr = %d Wert = %s ' % (index,obj.get())

#~~ Erstellt das Tk-Hauptfenster
root = tk.Tk()
root['bg'] = 'khaki'
root.title('Spinbox')

for i in range(5):

    #~~ Erstellt das Spinbox-Objekt
    spinbox_obj = tk.Spinbox(root,
        values  = ('A','B','C'),
        bd = 1,
        bg = 'white',
        fg = 'blue'
        )

    #~~ Die Option 'command' kann erst hier mit der Methode 'configure'
    #   konfiguriert werden, da die lambda-Funktion für den Funktions-
    #   Aufruf 'show' das Spinbox-Objekt benötigt.
    spinbox_obj.configure(
        command = lambda obj=spinbox_obj,index=i: show(obj,index)
        )

    #~~ Bindet das Spinbox-Objekt an den Grid-Layout-Manager
    spinbox_obj.grid(row=i,column=0,padx=4,pady=4)

root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Cobra5
User
Beiträge: 22
Registriert: Sonntag 25. Mai 2008, 10:44

Es funktioniert jetzt. Danke sehr für die Hilfe. :D

P.S: Habe die Überstezung (PEP 8 ) gefunden. Werde es mir mal anschauen. Habe noch nicht so viel Erfahrung mit Python-Programmierung und wusste daher noch nicht mal, dass es solche Konventionen gibt. Aber danke für die Info.

Gruß Cobra5
Cobra5
User
Beiträge: 22
Registriert: Sonntag 25. Mai 2008, 10:44

Ich hätte noch eine Frage zur Spinbox.

Gibt es einen Befehl, mit dem ich den aktuellen Wert einer Spinbox ändern kann. Habe bereits mit Google gesucht, aber leider auf den angezeigten Seiten nichts gefunden.

Danke im voraus.

Gruß Cobra5
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hallo Cobra5

Hier ein Beispiel:

a) Es wird ein neuer Wert in die erste Spinbox geschrieben
b) Es wird eine neues Zeichen in die fünfte Spinbox eingefügt

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Skriptname spinbox_03.py (29.06.2008 wuf)

import Tkinter as tk


def show(obj,index):
    """Der Wert einer Spinbox wurde verändert"""

    print 'Spinbox.Nr = %d Wert = %s ' % (index,obj.get())

#~~ Erstellt das Tk-Hauptfenster
root = tk.Tk()
root['bg'] = 'khaki'
root.title('Spinbox')

#~~ Sammel-Liste für Spinbox-Objekte
spinbox_obj_list = []

for i in range(5):

    #~~ Erstellt das Spinbox-Objekt
    spinbox_obj = tk.Spinbox(root,
        values  = ('A','B','C'),
        bd = 1,
        bg = 'white',
        fg = 'blue'
        )

    #~~ Die Option 'command' kann erst hier mit der Methode 'configure'
    #   konfiguriert werden, da die lambda-Funktion für den Funktions-
    #   Aufruf 'show' das Spinbox-Objekt benötigt.
    spinbox_obj.configure(
        command = lambda obj=spinbox_obj,index=i: show(obj,index)
        )

    #~~ Bindet das Spinbox-Objekt an den Grid-Layout-Manager
    spinbox_obj.grid(row=i,column=0,padx=4,pady=4)

    #~~ Füge das Spinbox-Objekt der Spinbox-Objektliste hinzu
    spinbox_obj_list.append(spinbox_obj)

#~~ Den Inhalt der ersten Spinbox mit dem Wert 10 überschreiben
spinbox_obj_list[0].delete(0,'end')
spinbox_obj_list[0].insert(0,10)

#~~ Einen neuen Wert in die letzte Spinbox einfügen (5. Spinbox)
#   Der Wert heisst X und wird an der ersten Position eingefügt
spinbox_obj_list[4].insert(0,'X')

root.mainloop()
Hier findest du weitere Informationen:
http://effbot.org/tkinterbook/spinbox.htm

Gruss wuf :wink:
Take it easy Mates!
Cobra5
User
Beiträge: 22
Registriert: Sonntag 25. Mai 2008, 10:44

Nochmals Danke

Gruß Cobra5
Antworten