Hallo zusammen,
ich bin grade dabei, ein kleines Tool zusammenzufrickeln (wenns dann mal läuft wird der Code noch aufgehübscht, aber im Moment bin ich noch sehr mit Trial-and-Error beschäftigt).
zu meinen Vorkenntnissen: ich kann gut (bis sehr gut) C, und seit einigen Wochen befasse ich mich auch mit objektorientierter Programmierung (gezwungenermaßen C#, aber es wird auf C++ hinauslaufen). Python ROCKT einfach mal, wie schnell man damit lauffähige Programme hinbekommt ist der Wahnsinn.
Nun zu meinem Problem: ich habe eine Liste von Strings (Städtenamen) und ein Entry-Widget in meinem Tkinter-Programm. Ich möchte, dass diese nun bei der Eingabe automatisch vorgeschlagen werden. Wenn man z.B. ein [A] tippt, wird "Aachen" vorgeschlagen, wenn ein [S] folgt "Aschaffenburg" usw. Dazu müsste ich ja so etwas wie ein "keypressed-event" von dem Entry-Widget abfragen können.
Geht sowas? Das wäre nämlich die optimale Lösung. Alternativ habe ich es auch schon einmal mit einer Art Combobox versucht, aber die war leider nicht mit der Tastatur durchsuchbar.
Weiß jemand Rat?
Autovervollständigung von Entry-Widgets
Hallo ayJay
Kannst du das einmal ausprobieren:
Gruss wuf 
Kannst du das einmal ausprobieren:
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import Tkinter as tk
def entry_keypress(event):
""" Ausgabe der aktivierten Taste """
print 'Key',event.keysym
root = tk.Tk()
root.geometry('200x100')
entry = tk.Entry(root,
width = 20,
bg = 'white',
bd = 1,
highlightthickness = 0
)
entry.place(x=20,y=20)
entry.bind('<KeyPress>',entry_keypress)
entry.focus_set()
root.mainloop()

Take it easy Mates!
*thumbsup*
[edith]Hochmut kommt vor dem Fall[/edith]
Mein Problem nun: das eingegebene Zeichen wird hinten an den automatisch eingefügten Ort drangehängt. Wie es scheint, wird die mit bind angegebene Funktion aufgerufen, bevor das Zeichen eingetragen wird.
Wie kann ich das überflüssige Zeichen loswerden?
[edith]Hochmut kommt vor dem Fall[/edith]
Code: Alles auswählen
def autocomplete(namepart, obj):
for ort in orte:
if ort.upper().startswith(namepart.upper()):
obj.delete(0,END)
obj.insert(0, ort)
break
Wie kann ich das überflüssige Zeichen loswerden?
Wars don't determine who's right - only who's left
*push*
Ich habe im Moment:
Dieser Handler macht aber Probleme, wenn z.B. in dem Entry-Widget was markiert war. Ich könnte natürlich alles per Hand handlen, aber im Grunde würde es reichen, wenn der Handler erst nach der Aktualisierung des Textes aufgerufen wird.
Ich habe im Moment:
Code: Alles auswählen
if len(event.keysym)==1:
start.insert(INSERT, event.keysym)
autocomplete(start.get(),startAutocomplete)
start.selection_range(start.index(INSERT)-1,start.index(INSERT))
Wars don't determine who's right - only who's left
Hallo ayJay
Hier ist eine von vielen Lösungen für dein Problem. Es ist alles optimierbar und erweiterbar. Hoffe dich richtig verstanden zu haben. Eine Text-Ergänzung muss für mich aus einer Auswahl-Listbox erfolgen. Es gibt näturlich noch Lösungen die auf Text-Rechtschreibung basieren. Es gibt sicher noch Forum-Freunde mit besseren Ideen.
Viel Spass beim Programmieren
Gruss wuf
Hier ist eine von vielen Lösungen für dein Problem. Es ist alles optimierbar und erweiterbar. Hoffe dich richtig verstanden zu haben. Eine Text-Ergänzung muss für mich aus einer Auswahl-Listbox erfolgen. Es gibt näturlich noch Lösungen die auf Text-Rechtschreibung basieren. Es gibt sicher noch Forum-Freunde mit besseren Ideen.
Code: Alles auswählen
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
# Erstellt : wuf 03.06.2008
# Geändert : wuf 03.06.2008
# Funktion: Bei einem Entry-Widget wird während
# der Eingabe der eingegebene Text laufend
# mit einer Wortliste verglichen. Befinden
# sich übereinstimmende Wörter in der Wort-
# liste werden diese in einer Auswahl-Listbox
# angezeigt. Besteht keine Übereinstimmung,
# oder wird die Eingabe mit der Taste 'Enter'
# beendet, bewirkt dies eine Schliessung der
# Auswahl-Listbox.
# Eine Wort-Selektion in der Auswahl-Listbox
# mit der linken Maustaste bewirkt ein Über-
# trag des selektierten Wortes in das Entry-
# Widget. Mit dem Übertrag wird die Auswahl-
# Listbox geschlossen.
#
# Pendenzen: a) Die Auswahl-Listbox muss beim Einsatz
# einer langen Wortliste und breiteren
# Wörtern noch mit Scrollbars ergänzt werden.
#
# b) Die Auswahl-Listbox sollte bei einer
# realen Anwendung in einem Popup-Fenster
# (Toplevel-Fenster) eingebettet sein, damit
# unterhalb des Entry-Widgets weitere Widgets
# platziert werden können. Somit können diese
# beim sichbar werden der Auswahl-Listbox
# problemlos zugedeckt werden
# Status: Prototype
import Tkinter as tk
def entry_keypress(event):
""" Ausgabe der aktivierten Taste """
global listbox_show_flag,listbox #,listbox_place_info
#~~ Taste
key = event.keysym
# print 'Debug:Key',key
if key == 'Return':
#~~ Es wurde die 'Enter-Taste aktiviert
# Mache die Auswahl-Listbox unsichtbar
show_listbox(tk.FALSE)
entry_value = entry.get()
print 'Debug:Entry-Value',entry_value
return entry_value
show_listbox(tk.TRUE)
#~~ Lade den Eingabetext
entry_text = event.widget.get()
# print 'Debug:Entry-Text',entry_text,len(entry_text)
update_complete_box(entry_text)
def update_complete_box(entry_text):
"""Aktualisiere Auswahl-Listbox"""
global listbox_show_flag,listbox #,listbox_place_info
#~~ Länge des Eingabtextes
len_entry_text = len(entry_text)
#~~ Durchsuche die City-Wortliste
choice_list = []
for index,city in enumerate(city_list):
# Kontrolle: Übersteigt die Anzahl Zeichen des Eingabetextes
# die Anzahl Zeichen der City-Bezeichnung
if len_entry_text <= len(city):
#~~ Nein
# Trenne die Anzahl Zeichen vom City-Wort ab. Die
# Anzahl abzutrennenden Zeichen entspricht der
# Länge des Eingabetextes
city_fraction = city[0:len_entry_text]
# print 'Dibug:Fraktion',city_fraction
#~~ Vergleiche den vom City-Wort abgetrennten Text
# mit der Texteingabe
if city_fraction == entry_text:
#~~ Es gibt eine Übereinstimmung zwischen
# der Texteingabe und dem City-Wort aus
# der City-Liste
print 'Debug:City',city_fraction
#~~ Füge das gefundene City-Wort der
# Auswahllist hinzu
choice_list.append(city_list[index])
#~~ Lösche den Inhalt der Auswahl-Listbox
listbox.delete(0,'end')
#~~ Fülle die Auswahl-Listbox mit den auswählbaren
# City-Wörtern. Skaliere die Höhe der Auswahl-Listbox
num_cities = len(choice_list)
# print 'Debug:Anzahl-Cities',num_cities
if not num_cities:
#~~ Die Auswahlliste enthält keine Einträge
show_listbox(tk.FALSE)
return
#~~ Justiere die Höhe der Auswahl-Listbox
listbox.configure(height=num_cities)
for city in choice_list:
#~~ Lade das Auswahlwort in die Auswahl-Listbox
listbox.insert(0,city)
def show_listbox(show_flag):
"""Steuert die Sichtbarkeit der Auswahl-Listbox"""
global listbox_show_flag,listbox
if show_flag:
#~~ Mache die Auswahl-Listbox sichtbar
if not listbox_show_flag:
listbox_show_flag = show_flag
listbox.place_configure(listbox_place_info)
else:
#~~ Mache die Auswahl-Listbox unsichtbar
if listbox_show_flag:
listbox_show_flag = show_flag
listbox.place_forget()
def choice(event):
"""Wahl aus der Auswahl-Listbox"""
global listbox,entry
#~~ Listbox: Lade den index der Auswahl
list_index = listbox.curselection()[0]
#~~ Listbox: Lade den selektierten Namen
selection = listbox.get(list_index)
#~~ Entry: Lösche den Eingabetext
entry.delete(0)
#~~ Entry: Übertrage den aus der Auswahl-Listbox
# selektierten Namen in das Entryfeld
entry.insert(0,selection)
#~~ Mache die Auswahl-Listbox unsichtbar
show_listbox(tk.FALSE)
# print 'Debug:Listbox-Selektion',selection
#**** Start des Hauptprogrammes ****
root = tk.Tk()
root.geometry('220x150')
root['bg'] = 'steelblue'
root.title('wuf:choice')
#~~ Ortschaften-Liste
city_list = ['Basel','Bern','Burgdorf','Altdorf','Luzern','Genf','Zürich']
#~~ Listbox Sichbar-Flag
listbox_show_flag = tk.FALSE
#~~ Erstelle ein Entry-Widget
entry = tk.Entry(root,
width = 28,
bg = 'white',
bd = 1,
font = ('helvetica','8'),
highlightthickness = 0
)
entry.place(x=20,y=20)
entry.bind('<KeyRelease>',entry_keypress)
#~~ Erstelle ein Listbox-Widget
listbox = tk.Listbox(root,
width = 28,
bg = 'lightblue',
fg = 'blue',
bd = 0,
font = ('helvetica','8'),
selectmode = 'single',
highlightthickness = 0
)
listbox.place(x=21,y=40)
listbox.bind('<ButtonRelease>',choice)
#~~ Mache die Auswahl-Listbox unsichtbar
listbox_place_info = listbox.place_info()
listbox.place_forget()
#~~ Setze den Fokus auf das Eingab-Widget
entry.focus_set()
root.mainloop()

Gruss wuf

Take it easy Mates!
Vielen Dank für deine Mühe!
Wenn ich den Code richtig überblicke reicht es, wenn ich bei mir <KeyPress> mit <KeyRelease> ersetze, weil dann das widget beim event schon den aktualisierten Inhalt hat. Das Vervollständigen soll dann vollständig in dem Entry-widget erfolgen, ohne dass man zur Maus greifen muss.
Wenn ich den Code richtig überblicke reicht es, wenn ich bei mir <KeyPress> mit <KeyRelease> ersetze, weil dann das widget beim event schon den aktualisierten Inhalt hat. Das Vervollständigen soll dann vollständig in dem Entry-widget erfolgen, ohne dass man zur Maus greifen muss.
Wars don't determine who's right - only who's left