Seite 1 von 1

Command Spinbox

Verfasst: Mittwoch 25. Juni 2008, 13:59
von Cobra5
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

Verfasst: Mittwoch 25. Juni 2008, 14:17
von 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.

Verfasst: Mittwoch 25. Juni 2008, 14:19
von numerix
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.

Verfasst: Mittwoch 25. Juni 2008, 14:24
von 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()

Verfasst: Mittwoch 25. Juni 2008, 18:15
von wuf
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:

Verfasst: Mittwoch 25. Juni 2008, 18:23
von numerix
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.

Verfasst: Donnerstag 26. Juni 2008, 00:18
von wuf
@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:

Verfasst: Freitag 27. Juni 2008, 12:59
von Cobra5
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

Verfasst: Sonntag 29. Juni 2008, 16:10
von Cobra5
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

Verfasst: Sonntag 29. Juni 2008, 17:04
von wuf
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:

Verfasst: Sonntag 29. Juni 2008, 17:22
von Cobra5
Nochmals Danke

Gruß Cobra5