ComboBox - Aktualisierung im Ausgabefeld

Fragen zu Tkinter.
Schorlem
User
Beiträge: 40
Registriert: Dienstag 3. Juni 2014, 16:37

Das Verwirrendste wird wohl der sich nicht bewegende Cursor sein. Tkinter bietet entsprechende Funktionen an, um diesen zu bewegen, allerdings habe ich diese der Einfachheit halber weggelassen.

Als Hilfe: Füg mal "print(self.user_input)" als erste Zeile der Methode validate() ein. Merkst du was? ;)

Wenn du beispielsweise mehrmals "a" drückst, besteht die Zeichenfolge aus "aaaaa". Gibst du jetzt z.B. "b" ein, ergibt sich "aaaaab". Da jedoch keiner deiner Listeneinträge damit startet, wird das "b" ignoriert und es steht weiterhin "aaaaaa" als Ausgabe. Nicht vorgesehene Zeichen sind quasi komplett unsichtbar, wobei es anscheinend noch schwerer wird, da sich der Cursor nicht bewegt. Könnte man reinmachen, wollte jetzt aber erstmal nur das Teil erklären ;)
Diese Nachricht wurde maschinell erstellt und ist daher ohne Unterschrift gültig.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ja, das mit dem nichtbewegenden Cursor ist sehr verwirrend.
Ich probiere Deinen Vorschlag mit "print(self.user_input)" aus.

Bei "aaaaa" und der Eingabe von ' b', daß dann die ganze Reihe gelöscht wird und 'b' als Anfangsbuchstabe in einer neuen Suche fortgeführt wird, ist nicht wie ich es mir vorstelle.
Es kann zur Folge "aaaaa" weitere Möglichkeiten geben, daher finde ich daß die Ausgabe von 'self.cobo.get()' unterbrochen wird und nur auf die letzte Möglichkeit von "aaaaa" der Cursor zurück geht. Als Benutzer ist mir dann klar, daß es mit "aaaaab" kein Resultat gibt.

Die ComboBox muß letztendlich benutzerfreundlich und nicht verwirrend sein.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,
habe in den letzten zwei Tagen, die Empfehlung von Hyperion versucht umzusetzen.
Habe das Ganze auf den Kopf gestellt und nichts gelassen, wie es war.
Meiner Meinung, ist die Funktionsweise, benutzerfreundlich und logisch aufgebaut.

Die Funktionen:
- keysym_input
- drift_event
- nosign_event
- input_work
- control_output
habe ich so ausgearbeitet, um diese mit einer eigenen Klasse in einem externen Modul betreiben zu können.
Mit diesem Modul, ist dann nicht nur eine ComboBox zu steuern, sondern auch ein Entry-Feld ohne ComboBox.

Hier mal mein Code, mit der Bitte um Input! :wink:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x
 
from tkinter import ttk
 
class ComboBox:
    def __init__(self, mylist):

        self.mylist = mylist
        self.combo_check = {'??' : '??'}
        self.drift = {'Right' : +1, 'Left' : -1}
        self.none_check = {'Return' : 'Return', 'Delete' : 'Delete',
            'KP_Enter' : 'KP_Enter', 'KP_Delete' : 'KP_Delete',
            'BackSpace' : 'BackSpace'}
        self.key2utf = {'adiaeresis' : 'ä', 'Adiaeresis' : 'Ä',
            'odiaeresis' : 'ö', 'Odiaeresis' : 'Ö', 'udiaeresis' : 'ü',
            'Udiaeresis' : 'Ü', 'ssharp' : 'ß', 'space' : ' '}
        self.len_imput = 0
        self.len_combo = 0
        self.key_input = ''
        self.selected = False
         
        # create the self.combo box
        self.combo = ttk.Combobox()
        self.combo.bind('<<ComboboxSelected>>', self.control)
        self.combo.bind('<KeyRelease>', self.control)
        self.combo.bind('<Button-1>', self.control)
        self.combo.focus_set()
         
        # load the self.combo box with the list
        self.combo['values'] = self.mylist
         
        # pack the widgets vertically in this order
        self.combo.pack()

        self.combo.mainloop()
 

    def keysym_input(self, wert, key_input, combo_get):
        """
        Verarbeite den Tastenwert aus event.keysym.
        - Dictionary key2utf, wandelt bei den Selbstlauten 'ÄäÖöÜüß',
            den Ausgabewert von event.keysym in ein UTF-Zeichen um.
        - Dictionary combo_check, vergleicht bei selektierten Wert der
            ComboBox, den Ausgabewert von event.keysym.
        """

        if len(wert) == 1:
            return wert
        result = self.key2utf.get(wert)
        if result:
            return result
        result = self.combo_check.get(wert)
        if result:
            if key_input != combo_get:
                return combo_get
            else:
                return key_input
        result = self.none_check.get(wert)
        if result:
            return combo_get
        return None
 

    def drift_event(self, event, key_input, combo_get):
        """
        Überprüfe die Cursor-Richtung mit event.keysym durch
        Dictionary self.drift.
        - Verarbeite die Cursor-Bewegung (Right, Left)
            und aktualisiere keyinput.
        """

        check = self.drift.get(event)
        if not check:
            return None
        if len(combo_get) > len(key_input):
            start = key_input[:len(key_input)+check]
            end = combo_get[len(start):len(start)+1]
            key_input = start + end
            return key_input
 

    def nosign_event(self, event, key_input, len_input, combo_get,
            len_combo):
        """
        Überprüfe event.keysym mit Dictionary self.none_check.
        - Verarbeite Delete, KP_Delete, BackSpace
        """

        check = self.none_check.get(event)
        if not check:
            return None
        if check == 'BackSpace':
            if len(key_input) > 1:
                key_input = key_input[:len(key_input)-1]
            else:
                key_input = ''
            return key_input
        elif check == 'Delete' or check == 'KP_Delete':
            if len(key_input) > 1:
                key_input = key_input[:len(key_input)+1]
            else:
                key_input = key_input[:1]
        return key_input

 
    def input_work(self, wert, key_input, selected):
        """
        Überprüfe Eingabewert mit der Auswahlliste
        - Postiver Eingabewert, Übergabe des Eingabewertes
        - Negativer Eingabewert, letzter Eingabewert wird gelöscht
        Rückgabewert:
        - Ergebnis, <ComboboxSelected> == True
        """

        try:
            if len(wert) == 1:
                if selected:
                    return wert, False
                else:
                    return (key_input + wert), False
            else:
                return wert, True
        except TypeError:
            if key_input:
                return key_input[:-1], False
            else:
                return ''
 

    def control_output(self, key_input):
        """
        Vergleiche die Eingabewerte mit der Auswahlliste.
        - Postiver Eingabewert, Ausgabe des Listenergebnisses
        - Negativer Eingabewert, letzter Eingabewert wird gelöscht
        """

        try:
            check = [item for item in self.mylist
                if item.upper().startswith(key_input.upper())][0]
            return check, key_input
        except IndexError:
            return '', key_input[:-1]
 

    def control(self, event):
        """
        Überwache die Eingabewerte durch Tastatur und Maus.
        Funktionen:
        - keysym_input
        - drift_event
        - nosign_event
        - input_work
        - control_output
        """

        if self.key_input != '':
            self.len_imput = len(self.key_input)
        if self.combo.get() != '':
            self.len_combo = len(self.combo.get())
        result = self.keysym_input(event.keysym, self.key_input,
            self.combo.get())
        drift = self.drift_event(event.keysym, self.key_input,
            self.combo.get())
        if drift:
            self.key_input = drift
        eventcheck = self.nosign_event(event.keysym, self.key_input,
            self.len_imput, self.combo.get(), self.len_combo)
        if eventcheck:
            self.key_input = eventcheck
            self.combo.set(eventcheck)
            return
        if not result:
            return
        self.key_input, self.selected = self.input_work(result,
            self.key_input, self.selected)
        self.combo.set(self.combo.get().strip())
        combo, self.key_input = self.control_output(self.key_input)
        self.combo.set(self.key_input)
        if combo != '':
            self.combo.set(combo)
 
 
def main():
    L = ['aaaaaa', 'abbbbb', 'aaabbb', 'acabbb', 'bbbbbb', 'cccccc',
        'vvvvvv', 'wwwwww', 'xxxxxx', 'yyyyyy', 'yywyyy', 'zzzzzz', ]
    ComboBox(L)
 
if __name__ == "__main__":
    main()
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

``self.none_check`` ist ein wenig seltsam. Hier würde eine einfache Menge genügen.

Edit: In Zeile 129 sollte wohl ein Tupel stehen.
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Meinst Du bei 'self.none_check', den Namen?
Verstehe nicht was Du unter einer einfacher Menge verstehst, vielleicht ein kurzes Beispiel!

Ok, habe es zuerst nicht gesehen, Danke für das Info zu Zeile 129! :wink:
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Das mit dem set, ist mir noch nicht klar?

Ich habe jetzt ein Modul zum ansteuern der ComboBox erstellt:

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# For Python3.x
 
class List2Result(object):
    def __init__(self):

        self.combo_check = {'??' : '??'}
        self.drift = {'Right' : +1, 'Left' : -1}
        self.none_check = {'Return' : 'Return', 'Delete' : 'Delete',
            'KP_Enter' : 'KP_Enter', 'KP_Delete' : 'KP_Delete',
            'BackSpace' : 'BackSpace'}
        self.key2utf = {'adiaeresis' : 'ä', 'Adiaeresis' : 'Ä',
            'odiaeresis' : 'ö', 'Odiaeresis' : 'Ö', 'udiaeresis' : 'ü',
            'Udiaeresis' : 'Ü', 'ssharp' : 'ß', 'space' : ' '}
        self.len_imput = 0
        self.len_combo = 0
        self.key_input = ''
        self.selected = False
 

    def keysym_input(self, wert, key_input, combo_get):
        """
        Verarbeite den Tastenwert aus event.keysym.
        - Dictionary key2utf, wandelt bei den Selbstlauten 'ÄäÖöÜüß',
            den Ausgabewert von event.keysym in ein UTF-Zeichen um.
        - Dictionary combo_check, vergleicht bei selektierten Wert der
            ComboBox, den Ausgabewert von event.keysym.
        """

        if len(wert) == 1:
            return wert
        result = self.key2utf.get(wert)
        if result:
            return result
        result = self.combo_check.get(wert)
        if result:
            if key_input != combo_get:
                return combo_get
            else:
                return key_input
        result = self.none_check.get(wert)
        if result:
            return combo_get
        return None
 

    def drift_event(self, event, key_input, combo_get):
        """
        Überprüfe die Cursor-Richtung mit event.keysym durch
        Dictionary self.drift.
        - Verarbeite die Cursor-Bewegung (Right, Left)
            und aktualisiere keyinput.
        """

        check = self.drift.get(event)
        if not check:
            return None
        if len(combo_get) > len(key_input):
            start = key_input[:len(key_input)+check]
            end = combo_get[len(start):len(start)+1]
            key_input = start + end
            return key_input
 

    def nosign_event(self, event, key_input, len_input, combo_get,
            len_combo):
        """
        Überprüfe event.keysym mit Dictionary self.none_check.
        - Verarbeite Delete, KP_Delete, BackSpace
        """

        check = self.none_check.get(event)
        if not check:
            return None
        if check == 'BackSpace':
            if len(key_input) > 1:
                key_input = key_input[:len(key_input)-1]
            else:
                key_input = ''
            return key_input
        elif check == 'Delete' or check == 'KP_Delete':
            if len(key_input) > 1:
                key_input = key_input[:len(key_input)+1]
            else:
                key_input = key_input[:1]
        return key_input

 
    def input_work(self, wert, key_input, selected):
        """
        Überprüfe Eingabewert mit der Auswahlliste
        - Postiver Eingabewert, Übergabe des Eingabewertes
        - Negativer Eingabewert, letzter Eingabewert wird gelöscht
        Rückgabewert:
        - Ergebnis, <ComboboxSelected> == True
        """

        try:
            if len(wert) == 1:
                if selected:
                    return wert, False
                else:
                    return (key_input + wert), False
            else:
                return wert, True
        except TypeError:
            if key_input:
                return key_input[:-1], False
            else:
                return ('', False)
 

    def control_output(self, key_input):
        """
        Vergleiche die Eingabewerte mit der Auswahlliste.
        - Postiver Eingabewert, Ausgabe des Listenergebnisses
        - Negativer Eingabewert, letzter Eingabewert wird gelöscht
        """

        try:
            check = [item for item in self.mylist
                if item.upper().startswith(key_input.upper())][0]
            return check, key_input
        except IndexError:
            return '', key_input[:-1]
 
 
def main():
    return
    wert = 'a'
    key_input = 'abc'
    combo_get = ''
    result = List2Result().keysym_input(wert, key_input, combo_get)
    print(result)
 
if __name__ == "__main__":
    main()
Was dann noch im Modul ComboBox übrigbleibt ist dies:

Code: Alles auswählen

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

from help2listresult import List2Result
 
class ComboBox:
    def __init__(self, mylist):

        self.mylist = mylist
        self.len_imput = 0
        self.len_combo = 0
        self.key_input = ''
        self.selected = False
         
        # create the self.combo box
        self.combo = ttk.Combobox()
        self.combo.bind('<<ComboboxSelected>>', self.control)
        self.combo.bind('<KeyRelease>', self.control)
        self.combo.bind('<Button-1>', self.control)
        self.combo.focus_set()
         
        # load the self.combo box with the list
        self.combo['values'] = self.mylist
         
        # pack the widgets vertically in this order
        self.combo.pack()

        self.combo.mainloop()
 

    def control(self, event):
        """
        Überwache die Eingabewerte durch Tastatur und Maus.
        Funktionen aus Modul help2listresult (Class: List2Result):
        - keysym_input
        - drift_event
        - nosign_event
        - input_work
        """

        if self.key_input != '':
            self.len_imput = len(self.key_input)
        if self.combo.get() != '':
            self.len_combo = len(self.combo.get())
        # keysym_input
        result = List2Result().keysym_input(event.keysym, self.key_input,
            self.combo.get())
        # drift_event
        drift = List2Result().drift_event(event.keysym, self.key_input,
            self.combo.get())
        if drift:
            self.key_input = drift
        # nosign_event
        eventcheck = List2Result().nosign_event(event.keysym, self.key_input,
            self.len_imput, self.combo.get(), self.len_combo)
        if eventcheck:
            self.key_input = eventcheck
            self.combo.set(eventcheck)
            return
        if not result:
            return
        # input_work
        self.key_input, self.selected = List2Result().input_work(result,
            self.key_input, self.selected)
        self.combo.set(self.combo.get().strip())
        # control_output

        try:
            check = [item for item in self.mylist
                if item.upper().startswith(self.key_input.upper())][0]
            return self.combo.set(check), self.key_input
        except IndexError:
            self.key_input = self.key_input[:-1]
            return self.combo.set(self.key_input), self.key_input
 
 
def main():
    L = ['aaaaaa', 'abbbbb', 'aaabbb', 'acabbb', 'bbbbbb', 'cccccc',
        'vvvvvv', 'wwwwww', 'xxxxxx', 'yyyyyy', 'yywyyy', 'zzzzzz', ]
    ComboBox(L)
 
if __name__ == "__main__":
    main()
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nobuddy hat geschrieben:Das mit dem set, ist mir noch nicht klar?
Du solltest eine Menge verwenden, weil du das Dictionary wie eine Menge verwendest. Wenn der Wert zu einem Schlüssel immer identisch ist (oder alle Werte des Dictionary), dann sind die Werte überflüssig und du brauchst nur die Schlüssel. Und ein Dictionary nur mit Schlüsseln ist eine Menge.
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Hallo EyDu,

meinst Du so etwas in der Art?

Code: Alles auswählen

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

a = {'4711' : ['abc', 'asd', '10', 'löä'],
    '4612' : ['abc', 'asd', '5', 'löä'],
    '4513' : ['abc', 'asd', '7', 'löä']}

key_input = input()
try:
    print([a.get(x) for x in set(a) if x.startswith(key_input)][0])
except IndexError:
    print('Kein Ergebnis für diese Zeichenfolge!')
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Nein, du verwendest doch nicht einmal eine Menge. Ich meine das:

Code: Alles auswählen

self.none_check = set(['Return', 'Delete' : 'Delete', 'KP_Enter', 'KP_Delete', 'BackSpace'])
Und statt

Code: Alles auswählen

result = self.none_check.get(wert)
if result:
    return combo_get
return None
dann eben einfach

Code: Alles auswählen

if wert in self.none_check:
    return combo_get
return None
Da fällt mir auf: "result" ist ein sehr seltsamer Name, wenn es sich nicht um ein Ergebnis handelt.

Bzw. statt

Code: Alles auswählen

check = self.none_check.get(event)
if not check:
    return None
dann

Code: Alles auswählen

if event not in self.none_check:
    return None
#else:
#    check = event
Das Leben ist wie ein Tennisball.
Nobuddy
User
Beiträge: 994
Registriert: Montag 30. Januar 2012, 16:38

Ok, jetzt habe ich es verstanden, Danke für Deinen Input! :wink:
Antworten