Dropdown Box mit Tkinter // Listbox Problem

Fragen zu Tkinter.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Wenn ich jedes lb mit'n self.lb ersetz und bei read natürlich noch das Argument self hinzukommt

Code: Alles auswählen

def read(self, event): 
    text = self.lb.get(lb.curselection()) 
    print text 
Jedoch gibts dann noch Probleme mit dem Eventbinding und außerdem benutzt du einen außerordentlich bösen Sternimport. Mit self globalisierst du auch nicht, sondern bindest die Variable an die Instanz der Klasse.

(Ich würd' dir ja jetzt'n funktionierendes Beispiel geben, aber von Tkinter hab ich recht wenig Ahnung)
Benutzeravatar
sorgenlos
User
Beiträge: 69
Registriert: Donnerstag 15. Februar 2007, 00:52

Was ist am Sternimport denn böse? :)

und deinen Lösungsansatz hatte ich auch schon eingeschlagen, aber:

Code: Alles auswählen

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 1403, in __call__
    return self.func(*args)
TypeError: read() takes exactly 2 arguments (1 given)
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Man überschreibt Schlüsselwörter, die Übersichtlichkeit geht flöten und der Quellcode wird unübersichtlicher. Hab'n bissel rumgespielt, ist sicherlich total schlechter tkinter Stil, jedoch funktioniert die Version...

(UM NOCHMAL DARAUF HINZUWEISEN!!! Ich bin kein Tkinter Programmierer. Der Quelltext stellt keine Referenz dar!)

Code: Alles auswählen

import Tkinter as tk

class test_GUI: 
    def __init__(self): 
        
        fenster = tk.Tk() 
        fenster.geometry("110x75") 
    
        #Die Listbox    
        self.lb = tk.Listbox(fenster, selectmode=tk.EXTENDED) 
        self.lb.pack() 
        self.lb.place(x=18, y=10, width=80, height=35) 
        self.lb.insert(tk.END, "Peter") 
        self.lb.insert(tk.END, "Hans") 
    
        #Der Button    
        test_button = tk.Button(fenster, text="test", command=self.read) 
        test_button.place(x=6, y=50, width=100, height=20) 

    #die Methode        
    def read(self): 
        for i in self.lb.curselection():
            text = self.lb.get(i) 
            print text 
        
__name__ == '__main__' 
dasFenster = test_GUI() 
tk.mainloop()
BlackJack

Vielleicht solltest Du Dich erst einmal nur mit Klassen, ohne GUI beschäftigen. Das erste Argument bei Methoden ist immer die Instanz auf der die Methode aufgerufen wird. Dein `event` ist also eigentlich `self` und beim Druck auf den den Button wird an die `command`-Funktion gar nichts übergeben.

Code: Alles auswählen

import Tkinter as tk

class TestGUI: 
    def __init__(self): 
        fenster = tk.Tk()
    
        self.listbox = tk.Listbox(fenster,
                                  selectmode=tk.EXTENDED,
                                  width=10,
                                  height=2)
        for name in ('Peter', 'Hans'):
            self.listbox.insert(tk.END, name)
        self.listbox.pack()
    
        test_button = tk.Button(fenster, text='test', command=self.read)
        test_button.pack()
    
    def read(self):
        print self.listbox.get(self.listbox.curselection())


if __name__ == '__main__':
    das_fenster = TestGUI()
    tk.mainloop()
Da sind so gut wie alle manuelle Grössenangaben herausgenommen, das kann der Layout-Manager im allgemeinen besser als der Programmierer, weil der ja gar nicht alle möglichen Schrifteinstellungen, Schriftgrössen und Windowmanager testen kann.

Die Grösse der `Listbox` sollte man auch dort beim Konstrukturaufruf angeben, weil die Höhe da z.B. in Zeilen/Einträgen angegeben wird. Das passt dann immer, im Gegensatz zu dem `place()` wo bei mir in der Anzeige der untere Rand vom zweiten Eintrag nicht mehr dargestellt wurde.
Benutzeravatar
sorgenlos
User
Beiträge: 69
Registriert: Donnerstag 15. Februar 2007, 00:52

Gut, das Globlisieren funktioniert jetzt einwandfrei :wink: vielen Dank nochmal an euch, das hat noch paar andere Fehler behoben.

Das einzige was jetzt noch fehlt ist der "Fokus" ich weiß nicht wie das sonst nennen soll :D Ich will einfach nur das die Auswahl in den Boxen bleibt und nicht verschwindet.

hier ein flash-Filmchen, damit ihr versteht was ich meine :lol: :

Klick mich zum Anschaun

ich find dazu auch nichts in keinem der offiziellen Tutorials :?
pyStyler
User
Beiträge: 311
Registriert: Montag 12. Juni 2006, 14:24

selectmode könnte die Lösung sein?

Code: Alles auswählen

tk.Listbox(hp, selectmode=tk.MULTIPLE)
Benutzeravatar
sorgenlos
User
Beiträge: 69
Registriert: Donnerstag 15. Februar 2007, 00:52

PROBLEM GELÖST

Selectmode bestimmt aber nur das Verhalten innerhalb einer Listbox.

Um zwei unabhängige Listboxen zu bekommen die sich nicht gegenseitig deselektiern nimmt man noch als zusatz:

Code: Alles auswählen

 tk.Listbox(hp, selectmode=tk.MULTIPLE, exportselection=0)
Benutzeravatar
sorgenlos
User
Beiträge: 69
Registriert: Donnerstag 15. Februar 2007, 00:52

Ich habe ein Problem, Beispiel:

Ich habe eine Listbox mit drei Einträgen (ja, nein, vlcht)
für jedes Objekt wurde vorher die auswahl für das Objekt in einer Liste gespeichtert (andere Informationen auch, spielt aber keine Rolle)

Wenn ich in der Liste nun hin und her switche zwichen den Objekten,

soll er die Auswahl in der Listbox aktualisieren um zu zeigen welche Auswahl für das Objekt in der Vergangenheit getätigt wurde.

Ich hab diverse Sachen schon ausprobiert wie zb. set.curseletion aber es funktioniert nicht.

Hat jemand von euch eine Idee wie ich das lösen könnte?
schlangenbeschwörer
User
Beiträge: 419
Registriert: Sonntag 3. September 2006, 15:11
Wohnort: in den weiten von NRW
Kontaktdaten:

könntest du dein problem etwas genauer formulieren? Vlt auch ein bisschen code oder so? Abstahieren hilft auch oft.
Benutzeravatar
sorgenlos
User
Beiträge: 69
Registriert: Donnerstag 15. Februar 2007, 00:52

hat sich von selbst gelöst das problem, lösung folgt morgen..

Aber ich hänge nun an folgendem Problem, ich will eine Listbox wieder deselektieren um veränderung vornehmen zu können.

Der Befehl funktionierte auch,

Code: Alles auswählen

self.listbox.selection_clear(self.listbox.curselection())
jedoch bekomme ich nun diesen Fehler:

Code: Alles auswählen

 File "C:gui.py", line 707, in neu
    self.listbox.selection_clear(self.listbox.curselection())
  File "C:\Python25\lib\lib-tk\Tkinter.py", line 2530, in selection_clear
    'selection', 'clear', first, last)
TclError: bad listbox index "": must be active, anchor, end, @x,y, or a number
EDIT

ich habs auch selbst geschafft :D

Code: Alles auswählen

self.listbox.selection_clear(0,x)
x = elemente in der liste -1
hsv_seiwert
User
Beiträge: 1
Registriert: Samstag 14. Juni 2008, 15:52

Mein Vorschlag für eine Dropdown-box wäre folgender:

Code: Alles auswählen

global klick
klick=0
def ausgabe():
    global klick
    klick+=1
    if klick % 2 != 0:
        global textfenster
        textfenster= Text(fenster,width=29,height=10)
        textfenster.grid(row=1,columnspan=2)
    else:
        textfenster.grid_forget()
        
from Tkinter import*  
fenster = Tk()
entry=Entry(fenster)
entry.grid(row=0)
fenster.button = Button(fenster,text ="klick mich", command=ausgabe) 
fenster.button.grid(row=0,column=1) 
# Fenster anzeigen 
fenster.mainloop()
Zuletzt geändert von hsv_seiwert am Montag 16. Juni 2008, 12:40, insgesamt 1-mal geändert.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Hallo, zunächst einmal: "Willkommen im Forum."

Wenn du dir dein Posting ansiehst, stellst du sicher fest, dass man den Code nicht besonders gut lesen kann. Das lässt sich verbessern, indem du ihn in Code-Tags setzt. Dazu gibt es in der Eingabemaske extra einen Button.

Das kannst du - via edit - auch nachträglich noch machen. Solltest du mal tun, dann gibt es vielleicht auch Reaktionen auf deine "Lösung".
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen

Ich habe das Beispiel von BlackJack verwendet und es soweit abgeändert, daß der Button überflüssig ist.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

class TestGUI:
    def __init__(self):
        fenster = tk.Tk()

        self.mylist = {0 : 'Hans', 1 : 'Peter', 2 : 'Thomas'}

        self.listbox = tk.Listbox(fenster,
                                  selectmode=tk.EXTENDED,
                                  width=10,
                                  height=len(self.mylist))
        for name in sorted(self.mylist):
            self.listbox.insert(tk.END, self.mylist[name])
            self.listbox.bind('<<ListboxSelect>>', self.check_select)
        self.listbox.pack()

    def check_select(self, event):
        """Überprüfe das Ereignis und führe den Auftrag aus"""
        indices = list(map(int, self.listbox.curselection()))
        result = ''.join([self.mylist[row]
            for row in sorted(self.mylist) if row == indices[0]])
        print(result)
        return result


if __name__ == '__main__':
    das_fenster = TestGUI()
    tk.mainloop()
Und in einem weiteren Beispiel, wird die Auswahl an das Entry-Feld übergeben.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x

import tkinter as tk

class TestGUI:
    def __init__(self):
        fenster = tk.Tk()
        self.entry=tk.Entry(fenster)
        self.entry.pack()

        self.mylist = {0 : 'Hans', 1 : 'Peter', 2 : 'Thomas'}

        self.listbox = tk.Listbox(fenster,
                                  selectmode=tk.EXTENDED,
                                  width=10,
                                  height=len(self.mylist))
        for name in sorted(self.mylist):
            self.listbox.insert(tk.END, self.mylist[name])
            self.listbox.bind('<<ListboxSelect>>', self.check_select)
        self.listbox.pack()

    def check_select(self, event):
        """Überprüfe das Ereignis und führe den Auftrag aus"""
        indices = list(map(int, self.listbox.curselection()))
        result = ''.join([self.mylist[row]
            for row in sorted(self.mylist) if row == indices[0]])
        self.entry.delete(0, tk.END)
        return self.entry.insert(tk.END, result)


if __name__ == '__main__':
    das_fenster = TestGUI()
    tk.mainloop()
muffin
User
Beiträge: 19
Registriert: Dienstag 19. Februar 2013, 10:43

sorgenlos hat geschrieben:Hallo Leute, ich such schon seit einiger Zeit die Möglichkeit mit Tkinter eine Dropdownbox zu erstellen, in etwa so:
... und warum versuchst du es nicht mit einer ttk.combobox?
Antworten