Problem: tk.Listbox() Auswahl bekommen...

Fragen zu Tkinter.
Antworten
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Dienstag 11. November 2008, 18:37

Möchte das Ergebnis einer tk.Listbox Selektion abfragen, doch listbox.curselection() spuckt einen Fehler aus. Was mache ich falsch?

Code: Alles auswählen

import sys
import Tkinter as tk

streams_txt = ["eins", "zwei", "drei"]


root = tk.Tk()

listbox = tk.Listbox(
    root, selectmode=tk.MULTIPLE, height=len(streams_txt)
)
listbox.pack()

for txt in sorted(streams_txt):
    listbox.insert(tk.END, txt)

tk.Button(root, text = "OK", command=root.destroy).pack(side=tk.RIGHT)
tk.Button(root, text = "Abort", command=sys.exit).pack(side=tk.RIGHT)
tk.mainloop()


print listbox.curselection()
Problem:

Code: Alles auswählen

Traceback (most recent call last):
  File "test.py", line 21, in <module>
    print listbox.curselection()
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 2489, in curselection
    self._w, 'curselection'))
_tkinter.TclError: invalid command name ".41189504"

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Dienstag 11. November 2008, 18:54

Es dürfte daran liegen, dass du die tk-Instanz beim Klick auf [OK] zerstörst, bevor du die Methode curselection() aufrufst.

So funktioniert es:

Code: Alles auswählen

import sys
import Tkinter as tk

streams_txt = ["eins", "zwei", "drei"]

def output():
    print listbox.curselection()

root = tk.Tk()
listbox = tk.Listbox(root, selectmode=tk.MULTIPLE, height=len(streams_txt))
listbox.pack()

for txt in sorted(streams_txt):
    listbox.insert(tk.END, txt)

tk.Button(root, text = "OK", command=output).pack(side=tk.RIGHT)
tk.Button(root, text = "Abort", command=sys.exit).pack(side=tk.RIGHT)

tk.mainloop()
abgdf

Dienstag 11. November 2008, 21:18

Hallo jens,

da bei Events wie Klicks auf Buttons Funktionen aufgerufen werden, in denen man in der Regel wieder auf die Fensterelemente zugreifen möchte, formuliert man Tkinter-GUIs auch am besten in einer Klasse. Das kann dann z.B. so aussehen:

Code: Alles auswählen

#!/usr/bin/env python

import Tkinter as tk
from Tkconstants import *

class MyApp:

    def __init__(self):

        self.streams_txt = ["eins", "zwei", "drei"]

        self.root = tk.Tk()

        self.listbox = tk.Listbox(self.root,
                                  selectmode = tk.MULTIPLE,
                                  height = len(self.streams_txt))
        self.listbox.pack()

        for txt in sorted(self.streams_txt):
            self.listbox.insert(tk.END, txt)

        self.but1 = tk.Button(self.root,
                              text = "OK",
                              command = self.showit)
        self.but1.pack(side = RIGHT)

        self.but2 = tk.Button(self.root,
                             text = "Abort",
                             command = self.root.destroy)
        self.but2.pack(side = RIGHT)

        # "RIGHT" kommt aus dem Modul "Tkconstants".

        self.root.mainloop()

    def showit(self):
        print self.listbox.curselection()

if __name__ == "__main__":
    app = MyApp()
Zum Beenden nimmt man lieber die ".destroy()"-Methode des Hauptfensterwidgets (hier self.root) als "sys.exit()", da dadurch Aufräumarbeiten besser erledigt werden.

Viele Grüße
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 12. November 2008, 09:47

Das ist ja doof ;)

Im Grunde möchte ich keine echte GUI Anwendung bauen, sondern viel mehr ein kleines Konsolenskript erweitern. Denn per Konsole kann man schlecht einem User ein Menü bauen, bei dem ehr mehrere Punkte auswählen kann. (Zumindest nicht unter Windows).

Aber danke für die Hinweise. Ich denke dann werde ich eine kleine Klasse bauen ;)

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
abgdf

Mittwoch 12. November 2008, 16:29

Ach so, sowas wie "Kommander" unter Linux? Vielleicht was Windows-spezifisches benutzen,

http://martin.hinner.info/apicmndr/

Aber es wäre vielleicht auch mit Tkinter möglich: In der Methode mit einem "os.system()" das Programm aufrufen, und dann ".destroy()" aufrufen.

Gruß

Edit: Oder geht es nicht um zu öffnende Programme, sondern um Werte, die im .bat-Skript weiterverarbeitet werden sollen?
Benutzeravatar
jens
Moderator
Beiträge: 8483
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Freitag 14. November 2008, 13:06

Meine Lösung schaut nun so aus:

Code: Alles auswählen

# -*- coding: utf-8 -*-

import sys
import Tkinter as tk

class TkListebox(object):
    def __init__(self, title, lable, items, selectmode=tk.MULTIPLE, width=100):
        self.selection = []
        self.items = items

        self.root = tk.Tk()
        self.root.title(title)
        tk.Label(self.root, text=lable, font = "Tahoma 9 bold").pack()

        self.listbox = tk.Listbox(
            self.root, selectmode=selectmode, height=len(items), width=width
        )
        self.listbox.pack()

        vars = []
        for txt in self.items:
            self.listbox.insert(tk.END, txt)

        b = tk.Button(self.root, text = "OK", command=self.save_selection)
        b.pack(side=tk.RIGHT)
        b = tk.Button(self.root, text = "Abort", command=sys.exit)
        b.pack(side=tk.RIGHT)

        tk.mainloop()

    def save_selection(self):
        self.selection = []
        for index in self.listbox.curselection():
            self.selection.append(self.items[int(index)])

        self.root.destroy()


# Bsp:
streams_txt = ["eins", "zwei", "drei"]

selection = TkListebox(
    title = "Please select",
    lable = "Please select streams:",
    items = streams_txt
).selection

print "Selection:", selection

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten