Hoch Runter Button für eine Listbox

Fragen zu Tkinter.
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

Ich habe bis jetzt erfolgreich eine Listbox erstellt, will durch diese aber nicht mit der Tastatur oder einer Maus Navigieren sondern mit einem Tochdisplay.
Dafür will ich 2 Buttons erstellen mit deren Hilfe ich den Aktiven Balken hoch und runter bewege, -> mit .curselection() dann die Position ermitteln, und einem dritten Button diesen dann auswählen.

Wie erstelle ich solche "NavigationsButtons"?

Danke schonmal
BlackJack

@PappaBär83: Wo liegt denn das konkrete Problem dabei? Du musst halt Schaltflächen erstellen bei denen als `command` jeweils Funktionen/Methoden übergeben werden welche die entsprechenden Aktionen durchführen. Also beispielsweise für ”Selektion runter” die aktuelle Selektion ermitteln, löschen, und das darauffolgende Element auswählen. Ähnlich für ”Selektion rauf”. Dabei auch auf die Randfälle achten wie: Es war nichts ausgewählt, oder die Auswahl ist bereits am jeweiligen Rand (oben/unten). Man könnte so ein kombiniertes Bedienelement in einer eigenen Klasse kapseln.
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

Hey.
Ich kenne kein Kommando oder keine Methode mit der ich das machen kann.
Habe Probiert mit (Listboxname).curselection() versucht die aktuelle Markierte Position zu ermitteln, bei Drücken eines Buttons diesen Wert um 1 zu erhöhen oder herabzusetzen und diesen dann per (Listenname).select_set(Wert) zurückzugeben.
Das hat aber nicht funktioniert.
Nach Nachlesen fand ich heraus das .curselection() ein Tupel zurückgiebt und mit den kann man nicht rechnen,
Tupel in eine Zahl umwandeln hat auch nicht Funkioniert. (<- bei mir jedenfalls nicht).
BlackJack

@PappaBär83: Ein Tupel in eine Zahl umwandeln funktioniert natürlich nicht, was sollte denn da auch als Zahl heraus kommen? Du kannst aber die Zahl die in dem Tupel als Element steckt, heraus holen. Und das solltest Du wissen und können bevor Du Dich mit objektorientierter Programmierung und GUIs beschäftigst, denn Tupel ist einer der Grunddatentypen von Python mit denen man umgehen können muss, die laufen einem oft über den Weg.

Hast Du das Tutorial in der Python-Dokumentation schon einmal durchgearbeitet?
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

learning by doing
Ich will, und ich gebe mir Mühe.
Auch wenn ich viele Bücher und To-Do's durcharbeite sind das Wichtige Kleinigkeiten die allein vom lesen nicht im Kopf bleiben wollen.

@BlackJack: wie bekomm ich das element aus dem Tupel? Mit .pop() funktioniert's nicht (hab ich gerade ausprobiert).

Hier mal ein Beispiel wie ich mir das Vorstelle und wo ich nicht weiterkomme

Code: Alles auswählen

# Hoch-Runter Button Test

import tkinter	
import sys

#def hoch():
    #???#
    #???#

#def runter():
    #???#
    #???#

def ende ():						
    sys.exit(0)

main = tkinter.Tk()
main.geometry("450x200") 

Liste = tkinter.Listbox(main)
Liste.insert("end", "Zeile 1")
Liste.insert("end", "Zeile 2")
Liste.insert("end", "Zeile 3")
Liste.insert("end", "Zeile 3")
Liste.insert("end", "Zeile 4")
Liste.insert("end", "Zeile 5")
Liste.insert("end", "Zeile 6")             
Liste["height"] = 7                           		# Höhe des Textfeldes
Liste["width"] = 29                            		# Breite des Textfeldes
Liste["font"] = "MS 12"                        		# Schriftart und Schriftgröße
Liste.select_set('0')
Liste.place(x=110, y=0, anchor="nw") 


hButton = tkinter.Button(main)			# Button für liste Hoch
hButton["text"] = "Hoch"
#hButton["command"] =  hoch
hButton.place(x=0, y=00, anchor="nw")

rButton = tkinter.Button(main)			# Button für liste Runter
rButton["text"] = "Runter"
#rButton["command"] =  runter
rButton.place(x=0, y=30, anchor="nw")

# SchlussButton

eButton = tkinter.Button(main)			# Button zum Fensster beenden
eButton["text"] = "Fenster aus"
eButton["command"] = ende
eButton.place(x=0, y=80, anchor="nw")		


main.mainloop()
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

PappaBär83 hat geschrieben:Mit .pop() funktioniert's nicht (hab ich gerade ausprobiert).
@PappaBär83: Hast Du das Tutorial in der Python-Dokumentation schon einmal durchgearbeitet? Vor allem das Kapitel zu Indexzugriff?
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

@Sirius3: ma kurz drüber geschlafen (mittagsschlaft) und auf manches kommt man dann selber.
wie ich an das Element komme hab ich jetzt.
Nun is ein neues Problem aufgetaucht: ich muss die Markierung (Liste.select_set()) zurücksetzten bevor ich sie neu setzte sonnst wird alles druchmarkiert.

Code: Alles auswählen

# Hoch-Runter Button Test

import tkinter	
import sys

def hoch():
    Poho = Liste.curselection()    #Position hoch
    print (Poho)
    Poho1 = Poho[0]
    print (Poho1)    
    Poho2 = Poho1 - 1
    print (Poho2)
    Liste.select_set(Poho2)

def runter():
    Poru = Liste.curselection()    #Position runter
    print (Poru)
    Poru1 = Poru[0]
    print (Poru1)    
    Poru2 = Poru1 + 1
    print (Poru2)
    Liste.select_set(Poru2)



def ende ():						# Funktion zum Fenster beenden
    sys.exit(0)

main = tkinter.Tk()
main.geometry("450x200") 

Liste = tkinter.Listbox(main)
Liste.insert("end", "Zeile 1")
Liste.insert("end", "Zeile 2")
Liste.insert("end", "Zeile 3")
Liste.insert("end", "Zeile 4")
Liste.insert("end", "Zeile 5")
Liste.insert("end", "Zeile 6")
Liste.insert("end", "Zeile 7")
Liste["selectmode"] = "singel"             
Liste["height"] = 7                           		# Höhe des Textfeldes
Liste["width"] = 29                            		# Breite des Textfeldes
Liste["font"] = "MS 12"                        		# Schriftart und Schriftgröße
Liste.select_set(first = 4)
Liste.place(x=110, y=0, anchor="nw") 


hButton = tkinter.Button(main)			# Button für liste Hoch
hButton["text"] = "Hoch"
hButton["command"] =  hoch
hButton.place(x=0, y=00, anchor="nw")

rButton = tkinter.Button(main)			# Button für liste Runter
rButton["text"] = "Runter"
rButton["command"] =  runter
rButton.place(x=0, y=30, anchor="nw")

# SchlussButton

eButton = tkinter.Button(main)			# Button zum Fensster beenden
eButton["text"] = "Fenster aus"
eButton["command"] = ende
eButton.place(x=0, y=80, anchor="nw")		# Button bei Pixel X=1 Y=600 Plazieren


main.mainloop()
BlackJack

@PappaBär83: Ich sehe da noch viel drängendere Probleme die man vorher angehen sollte. Zum Beispiel das Du Dich erst einmal mit objektorientierter Programmierung vertraut machen solltest statt ein Programm zu schreiben bei dem alles global auf Modulebene existiert. Das wird sehr schnell sehr unübersichtlich und fehleranfällig. Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm gehört in eine Funktion, die heisst üblicherweise `main()`. Und Werte (ausser Konstanten) sollten Funktionen und Methoden als Argumente betreten und nicht auf magische Weise einfach so in der Umgebung/auf Modulebene existieren.

Die Namensgebung ist teilweise sehr schlecht und hält sich in der Schreibweise nicht an den
Style Guide for Python Code. Namen sollen dem Leser vermitteln was der Wert der hinter dem Namen steckt im Kontext des Programms bedeutet. Namen wie `Poho`, `Poho1`, `Poho2`, `Poru`, `Poru1`, oder `Poru2` sind alles andere als selbsterklärend.

Anzeigeelemente mit `place()` absolut zu positionieren ist keine gute Idee. Das sieht dann nur auf Rechnern mit ähnlichen Einstellung wie dem auf dem es entwickelt wurde vernünftig aus und kann bei anderen Displays, Auflösungen, Grundeinstellungen des Systems, schlecht aussehen, oder sogar unbenutzbar werden.
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

Vielen dank für deine ausführliche Erläuterung warum ich hier nicht richtig bin.
Neben Beruf, Frau, Kindern und dem alltäglichen Schwachsinn des Alltags hatte ich vor mal was anders zu machen um den Kopf vom Normalstress abzulenken.
Hier bekommen anscheinend nur Studierte und Gelernte Programmiere direkte Antworten die zur Fragestellung passen.
Danke für eure Bemühungen.

Bücher können nur zeigen wie es aussehen sollte, aber keine Antworten geben wenn es mal nicht läuft.
BlackJack

@PappaBär83: Was war denn die konkrete Fragestellung im letzten Beitrag? Was Du machen musst hast Du ja selbst erkannt.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi PappaBär83

Hier ein Prototyp zum herumexperimentieren:

Code: Alles auswählen

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

from functools import partial

try:
    # Tkinter for Python 2.xx
    import Tkinter as tk
except:
    # Tkinter for Python 3.xx
    import tkinter as tk

LISTBOX_HEIGHT = 10
LISTBOX_WIDTH = 29
LISTBOX_FONT = ('Helvetica', 12, 'normal')
LISTBOX_ITEMS = (
    "Zeile 1",
    "Zeile 2",
    "Zeile 3",
    "Zeile 4",
    "Zeile 5",
    "Zeile 6",
    "Zeile 7",
    "Zeile 8"
    )
NUM_OF_ITEMS = len(LISTBOX_ITEMS)

BUTTON_UP = "Hoch"
BUTTON_DOWN = "Runter"
BUTTON_SELECT = "Selektiere"
BUTTON_READ_SELECTION = "Zeige Selektion"
BUTTON_CLEAR_SELECTION = "Lösche Selektion"
BUTTON_END = "Beenden"
BUTTON_CLOSE = "Schliessen"
BUTTONS = (BUTTON_UP, BUTTON_DOWN, BUTTON_SELECT, BUTTON_READ_SELECTION,
    BUTTON_CLEAR_SELECTION, BUTTON_END)

DISPLAY_FONT = ('Helvetica', 14, 'bold')
DISPLAY_FG = 'steelblue'

        
class MyListbox(tk.Listbox):
     
    def __init__(self, parent, **options):
        self.parent = parent
        tk.Listbox.__init__(self, parent, **options)
        self.cursor_index = 0
        
    def cursor_up(self):
        if self.cursor_index > 0:
            self.cursor_index -= 1
            self.set_cursor(self.cursor_index)
    
    def cursor_down(self):
        if self.cursor_index < NUM_OF_ITEMS - 1:
            self.cursor_index += 1
            self.set_cursor(self.cursor_index)
    
    def set_cursor(self, index):
        self.focus_set()
        self.activate(index)
        self.cursor_index = index
        
    def select_item(self):
        self.select_set(self.cursor_index)
    
    def clear_selection(self):
        self.selection_clear(0, 'end')
 
            
class Application(object):

    def __init__(self, title=''):
        self.main = tk.Tk()
        self.main.title(title)
        self.main.protocol("WM_DELETE_WINDOW", self.close)
        
        main_frame = tk.Frame(self.main)
        main_frame.pack(expand=True, padx=6, pady=6)

        button_frame = tk.Frame(main_frame)
        button_frame.pack(side='left', expand=True, padx=(0, 4))

        listbox_frame = tk.Frame(main_frame, bd=0, relief='sunken')
        listbox_frame.pack(side='left', expand=True, padx=(0, 4))
        
        display_frame = tk.Frame(main_frame, bd=0, relief='sunken')
        display_frame.pack(side='left', expand=True)
        
        for button in BUTTONS:
            tk.Button(button_frame, text=button, command=partial(
                self.buttons_callback, button)).pack(fill='x')        

        self.my_listbox = MyListbox(listbox_frame, height=LISTBOX_HEIGHT,
            width=LISTBOX_WIDTH, font=LISTBOX_FONT, highlightthickness=0,
            bd=0)
        self.my_listbox.pack(padx=4, pady=4)
        listbox_frame.config(bg=self.my_listbox['bg'])
        
        self.my_listbox.insert(0, *LISTBOX_ITEMS)
        self.my_listbox.set_cursor(4)

        self.display_var = tk.StringVar()
        self.display_label = tk.Label(display_frame, height=LISTBOX_HEIGHT,
            width=LISTBOX_WIDTH, textvariable=self.display_var, bd=0,
            font=DISPLAY_FONT)
        self.display_label.pack(padx=4, pady=4)
        
    def buttons_callback(self, button):
        print(button)
        
        if button == BUTTON_END:
            self.close()
            
        if button == BUTTON_UP:
            self.my_listbox.cursor_up()
            
        if button == BUTTON_DOWN:
            self.my_listbox.cursor_down()

        if button == BUTTON_SELECT:
            self.my_listbox.select_item()
            
        if button == BUTTON_CLEAR_SELECTION:
            self.my_listbox.selection_clear(0, 'end')
            
        if button == BUTTON_READ_SELECTION:
            selected_items = ''
            for index in self.my_listbox.curselection():
                selected_items += "{}\n".format(self.my_listbox.get(index))
                #print(selected_items)
            
            if selected_items != '':
                self.display_var.set(selected_items)
                
    def run(self):
        self.main.mainloop()
        
    def close(self):
        # Here you can do something before shutdown!
        self.main.destroy()
                
Application("Meine Auswahlliste").run()
An Stelle des Place-Layoutmanagers würde ich nur den Pack- oder Grid-Layoutmanager verwenden.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Hierbei habe ich versucht das Kernproblem von dir, Papabär83, zu erfassen und die Lösung auf das notwendige Minimum zu reduzieren (wufs Zeilenzahl halbiert). Allerdings bleibt eine Kernaussage bestehen, welche Du in beiden Beispielen findest: Um die Verwendung von Klassen (Objektorientierte Programmierung, Vererbung) kommst Du nicht herum, wenn Du mit Tkinter (und allen anderen GUI-Toolkits) die Übersicht behalten willst.

Darüber hinaus existiert bis auf die Bedingung im "Main-Idiom" kein Code auf Modulebene. Das "Skript" ließe sich so zum Testen einzelner Funktionen aber auch zum Wiederverwerten ohne Seiteneffekte importieren. Das Grundgerüst für Deine Programme sollte in Zukunft so aussehen:

Code: Alles auswählen

#!/usr/bin/env python3

# Constants(!) go here
# Class and function-definitions go here

def main():
    pass # Usefull code goes here

if __name__ == '__main__':
    main()
Ich weiß, dass viele tkinter-Beispiele, welche man im Netz finden kann, hierauf aus Gründen der "Einfachheit" verzichten. Aber wie gesagt, man erhält die Möglichkeit des interaktiven Testens (im Interpreter). Im folgenden Beispiel ließe sich die ints-Funktion im Interpreter testen, ohne dass ein Fenster erzeugt wird oder man das Programm im Ganzen starten müsste.

Im Komplettbeispiel wirst Du neben der Verwendung von Klassen, Dinge finden, welche neu für Dich wären:
  1. Einen Generatorausdruck (ließe sich auch durch eine so genannte List-Comprehension (LC) formulieren) beim Einfügen der Beispielelement in die Listbox.
  2. Listenoperation map. Da Listen elementarer Sprachbestandteil von Python sind, bist Du gut beraten Dich eher früher als später mit ihnen zu beschäftigen. Sie erleichtern das Programmiererleben ungemein.

Code: Alles auswählen

#!/usr/bin/env python3
import sys
import tkinter as tk


class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.listbox = None # tk.Listbox
        self._init_widgets()
        
    def _init_widgets(self):
        # Listbox
        self.listbox = tk.Listbox(self, selectmode=tk.SINGLE)
        self.listbox.insert('end', *('Zeile {}'.format(e) for e in range(7)))
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.select_set(0)
        # Buttons
        up = tk.Button(self, text='nach oben', command=self.selection_up)
        up.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        down = tk.Button(self, text='nach unten', command=self.selection_down)
        down.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        quit = tk.Button(self, text='Beenden', command=self.quit)
        quit.pack(side=tk.TOP, fill=tk.BOTH, expand=True)
        
    def selection_up(self):
        index = first_selection(self.listbox)
        if not index:
            # No selection (None) or index == 0 (evaluate to False)
            return
        self.listbox.select_clear(index)
        self.listbox.select_set(index - 1)
        
    def selection_down(self):
        index = first_selection(self.listbox)
        if index is None or index >= (self.listbox.size() - 1):
            # No selection (None) or selected item is last item.
            return
        self.listbox.select_clear(index)
        self.listbox.select_set(index + 1)

    def quit(self):
        sys.exit(0)


# -----------------------------------------------------------------------------
# Utility functions
# -----------------------------------------------------------------------------
def ints(xs):
    """Converts the values from ``xs`` into a list of integers (if possible)."""
    return list(map(int, xs))

def first_selection(listbox):
    """Returns the index of the first selected item of a listbox or None."""
    indices = ints(listbox.curselection())
    if not indices: # Nothing selected
        return
    return indices[0]
    
# -----------------------------------------------------------------------------
# Main idiom
# -----------------------------------------------------------------------------
def main():
    root = tk.Tk()
    frame = Application(root)
    frame.pack(fill=tk.BOTH, expand=True)
    root.mainloop()
    
if __name__ == '__main__':
    main()
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

Hi Papabär83

Hierbei habe ich bwbg's Lösung auf das notwendige Minimum reduziert (bwg's Zeilenzahl 70 wuf's 45):

Code: Alles auswählen

#!/usr/bin/env python3
import sys
import tkinter as tk
from functools import partial
 
BUTTONS = ('nach oben', 'nach unten', 'Beenden')
ITEMS = ('Zeile {}'.format(e) for e in range(7))
BUT_PROPS = dict(side=tk.TOP, fill=tk.BOTH, expand=True)


class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
       
        self.listbox = tk.Listbox(self, selectmode=tk.SINGLE)
        self.listbox.insert('end', *ITEMS)
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.select_set(0)
        [tk.Button(self, text=button, command=partial(self.callback, button)
            ).pack(BUT_PROPS) for button in BUTTONS]
   
    def callback(self, button):
        if button == 'Beenden': sys.exit(0)
        else:
            self.selection(button)
            
    def selection(self, direction):
        indices = self.listbox.curselection()
        if not indices: return
        index = indices[0]
        if direction == 'nach oben':
            if index == 0: return
            self.listbox.select_clear(index)
            self.listbox.select_set(index - 1)
        if direction == 'nach unten':
            if index >= self.listbox.size() - 1: return
            self.listbox.select_clear(index)
            self.listbox.select_set(index + 1)

def main():
    root = tk.Tk()
    frame = Application(root).pack(fill=tk.BOTH, expand=True)
    root.mainloop()
   
if __name__ == '__main__': main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
bwbg
User
Beiträge: 407
Registriert: Mittwoch 23. Januar 2008, 13:35

Dass das mal nicht in code-golfing ausartet ;)

Auf partial hatte ich ganz bewusst verzichtet. Aber lassen wir das jetzt mal so stehen, bevor die Verwirrung zu groß wird.
"Du bist der Messias! Und ich muss es wissen, denn ich bin schon einigen gefolgt!"
BlackJack

@wuf: Etwas kürzer ohne ”schmutzige” Tricks wie LCs als Schleifenersatz und von der Formatierung her auch mehr nach dem Styleguide, also nicht auf biegen und brechen auf kurz getrimmt :-) :

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial


class Application(tk.Frame):

    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.listbox = tk.Listbox(self, selectmode=tk.SINGLE)
        self.listbox.insert(tk.END, *('Zeile {}'.format(i) for i in range(7)))
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.select_set(0)
        pack_arguments = dict(side=tk.TOP, fill=tk.BOTH, expand=True)
        tk.Button(
            self, text='nach oben', command=partial(self.move_selection, -1)
        ).pack(pack_arguments)
        tk.Button(
            self, text='nach unten', command=partial(self.move_selection, 1)
        ).pack(pack_arguments)
        tk.Button(self, text='Beenden', command=self.quit).pack(pack_arguments)

    def move_selection(self, amount):
        try:
            index = int(self.listbox.curselection()[0])
        except IndexError:
            index = 0
        self.listbox.select_clear(index)
        self.listbox.select_set(
            max(0, min(index + amount, self.listbox.size() - 1))
        )


def main():
    root = tk.Tk()
    frame = Application(root)
    frame.pack(fill=tk.BOTH, expand=True)
    root.mainloop()


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

Hi BlackJack

Super Code!
bwbg hat geschrieben:code-golfing
Willkommen im Club der Golfer :)

Hier mein Skript ohne die eher "schmutzige" LC als Schleifenersatz. Habe mein Skript noch einmal überarbeitet aber ohne den Einsatz deiner try:... except: Variante:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial

 
class Application(object):

    def __init__(self, root):
        self.listbox = tk.Listbox(root, selectmode=tk.SINGLE)
        self.listbox.insert(tk.END, *('Zeile {}'.format(i) for i in range(7)))
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.select_set(0)
        for button in ('nach oben', 'nach unten', 'Beenden'):
            tk.Button(root, text=button, command=partial(self.callback, button)
                ).pack(side=tk.TOP, fill=tk.BOTH, expand=True)

    def callback(self, button):
        if button == 'Beenden': quit()
        if button == 'nach oben': self.move_selection(-1)
        if button == 'nach unten': self.move_selection(1)

    def move_selection(self, displacement):
        indices = self.listbox.curselection()
        if not indices: return
        index = indices[0]
        if 0 <= index + displacement < self.listbox.size():
            self.listbox.select_clear(index)
            if displacement: self.listbox.select_set(index + displacement)
            if not displacement: self.listbox.select_set(index + 1) 

 
def main():
    root = tk.Tk()
    Application(root)
    root.mainloop()
 
 
if __name__ == '__main__':
    main()
N.B: Hoffen wir, dass unser Mittspieler PappaBär83 wieder in das Golf-Clubhaus zurückkehrt.

Gruss wuf :wink:
Take it easy Mates!
BlackJack

@wuf: So eine Dispatch-Methode mit vielen ``if``\s ist aus OOP-Sicht eher unschön. Das ist eine unnötige Indirektion über Zeichenketten statt direkt Funktionen/Methoden oder allgemeiner ausgedrückt passende aufrufbare Objekte als `command` zu verwenden. Wenn man bei der Schleife bleiben möchte kann man da ja über (Schaltflächenbeschriftung, `command`-Wert)-Paare iterieren und sich damit den Umweg über `callback()` sparen.

Du verwendest übrigens das ”falsche” `quit()`, nämlich das auf Modulebene aus den eingebauten Funktionen was es ausserhalb einer interaktiven Python-Shell eigentlich gar nicht geben dürfte. Passender wäre das auf dem Widget das den Abbruch der Tk-Hauptschleife und damit die Rückkehr vom `mainloop()`-Aufruf bewirkt.
Benutzeravatar
wuf
User
Beiträge: 1529
Registriert: Sonntag 8. Juni 2003, 09:50

OK BlackJack

Besten Dank für deine Anregungen. Habe mein Skript noch ein weiteres mal angepasst:

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from functools import partial

 
class Application(tk.Frame):

    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.listbox = tk.Listbox(self, selectmode=tk.SINGLE)
        self.listbox.insert(tk.END, *('Zeile {}'.format(i) for i in range(7)))
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.listbox.select_set(0)
        for button, callback in (('nach oben', partial(self.move_sel, -1)), 
            ('nach unten', partial(self.move_sel, 1)), ('Beenden', self.quit)):
            tk.Button(self, text=button, command=callback).pack(
                side=tk.TOP, fill=tk.BOTH, expand=True)

    def move_sel(self, displacement):
        indices = self.listbox.curselection()
        if not indices: return
        index = indices[0]
        if 0 <= index + displacement < self.listbox.size():
            self.listbox.select_clear(index)
            self.listbox.select_set(index + displacement) 

 
def main():
    root = tk.Tk()
    frame = Application(root)
    frame.pack(fill=tk.BOTH, expand=True)
    root.mainloop()
 
 
if __name__ == '__main__':
    main()
Gruss wuf :wink:
Take it easy Mates!
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

So. Urlaub zu ende.
kam ja doch noch was zusammen ;) .
Ich glaub das was ich gesucht habe haben bwbg und wuf gefunden.
"
def cursor_up(self):
if self.cursor_index > 0:
self.cursor_index -= 1
self.set_cursor(self.cursor_index)

def cursor_down(self):
if self.cursor_index < NUM_OF_ITEMS - 1:
self.cursor_index += 1
self.set
"
"
def selection_up(self):
index = first_selection(self.listbox)
if not index:
# No selection (None) or index == 0 (evaluate to False)
return
self.listbox.select_clear(index)
self.listbox.select_set(index - 1)

def selection_down(self):
index = first_selection(self.listbox)
if index is None or index >= (self.listbox.size() - 1):
# No selection (None) or selected item is last item.
return
self.listbox.select_clear(index)
self.listbox.select_set(index + 1)
"

Das werde ich bei nächstbietender Gelegenheit mal ausprobieren.
Fettes Mercy
PappaBär83
User
Beiträge: 21
Registriert: Freitag 5. September 2014, 09:16

Jap
Da kann ich definitiv noch von lernen.
Wo komm ich eigentlich am besten weiter wenn ich mich über die Möglichkeiten (Argumente) von Funktionen belesen möchte?
Irgendwo müssen ja die vordefinierten Funktionen (wie Listbox) Dokumentiert sein!?!?
Antworten