mirror of
https://github.com/3minbe/DBC_Converter.git
synced 2026-05-17 09:33:59 +09:00
144 lines
5.2 KiB
Python
144 lines
5.2 KiB
Python
"""
|
|
Authors: Mitja Martini and Russell Adams
|
|
License: "Licensed same as original by Mitja Martini or public domain, whichever is less restrictive"
|
|
Source: https://mail.python.org/pipermail/tkinter-discuss/2012-January/003041.html
|
|
|
|
Edited by RedFantom for ttk and Python 2 and 3 cross-compatibility and <Enter> binding
|
|
"""
|
|
import tkinter as tk
|
|
from tkinter import ttk
|
|
|
|
tk_umlauts = ['odiaeresis', 'adiaeresis', 'udiaeresis', 'Odiaeresis', 'Adiaeresis', 'Udiaeresis', 'ssharp']
|
|
|
|
|
|
class AutocompleteEntry(ttk.Entry):
|
|
"""
|
|
Subclass of :class:`ttk.Entry` that features autocompletion.
|
|
|
|
To enable autocompletion use :meth:`set_completion_list` to define
|
|
a list of possible strings to hit.
|
|
To cycle through hits use down and up arrow keys.
|
|
"""
|
|
def __init__(self, master=None, completevalues=None, **kwargs):
|
|
"""
|
|
Create an AutocompleteEntry.
|
|
|
|
:param master: master widget
|
|
:type master: widget
|
|
:param completevalues: autocompletion values
|
|
:type completevalues: list
|
|
:param kwargs: keyword arguments passed to the :class:`ttk.Entry` initializer
|
|
"""
|
|
ttk.Entry.__init__(self, master, **kwargs)
|
|
self._completion_list = completevalues
|
|
self.set_completion_list(completevalues)
|
|
self._hits = []
|
|
self._hit_index = 0
|
|
self.position = 0
|
|
|
|
def set_completion_list(self, completion_list):
|
|
"""
|
|
Set a new auto completion list
|
|
|
|
:param completion_list: completion values
|
|
:type completion_list: list
|
|
"""
|
|
self._completion_list = sorted(completion_list, key=str.lower) # Work with a sorted list
|
|
self._hits = []
|
|
self._hit_index = 0
|
|
self.position = 0
|
|
self.bind('<KeyRelease>', self.handle_keyrelease)
|
|
|
|
def autocomplete(self, delta=0):
|
|
"""
|
|
Autocomplete the Entry.
|
|
|
|
:param delta: 0, 1 or -1: how to cycle through possible hits
|
|
:type delta: int
|
|
"""
|
|
if delta: # need to delete selection otherwise we would fix the current position
|
|
self.delete(self.position, tk.END)
|
|
else: # set position to end so selection starts where textentry ended
|
|
self.position = len(self.get())
|
|
# collect hits
|
|
_hits = []
|
|
for element in self._completion_list:
|
|
if element.lower().startswith(self.get().lower()): # Match case-insensitively
|
|
_hits.append(element)
|
|
# if we have a new hit list, keep this in mind
|
|
if _hits != self._hits:
|
|
self._hit_index = 0
|
|
self._hits = _hits
|
|
# only allow cycling if we are in a known hit list
|
|
if _hits == self._hits and self._hits:
|
|
self._hit_index = (self._hit_index + delta) % len(self._hits)
|
|
# now finally perform the auto completion
|
|
if self._hits:
|
|
self.delete(0, tk.END)
|
|
self.insert(0, self._hits[self._hit_index])
|
|
self.select_range(self.position, tk.END)
|
|
|
|
def handle_keyrelease(self, event):
|
|
"""
|
|
Event handler for the keyrelease event on this widget.
|
|
|
|
:param event: Tkinter event
|
|
"""
|
|
if event.keysym == "BackSpace":
|
|
self.delete(self.index(tk.INSERT), tk.END)
|
|
self.position = self.index(tk.END)
|
|
if event.keysym == "Left":
|
|
if self.position < self.index(tk.END): # delete the selection
|
|
self.delete(self.position, tk.END)
|
|
else:
|
|
self.position -= 1 # delete one character
|
|
self.delete(self.position, tk.END)
|
|
if event.keysym == "Right":
|
|
self.position = self.index(tk.END) # go to end (no selection)
|
|
if event.keysym == "Down":
|
|
self.autocomplete(1) # cycle to next hit
|
|
if event.keysym == "Up":
|
|
self.autocomplete(-1) # cycle to previous hit
|
|
if event.keysym == "Return":
|
|
self.handle_return(None)
|
|
return
|
|
if len(event.keysym) == 1 or event.keysym in tk_umlauts:
|
|
self.autocomplete()
|
|
|
|
def handle_return(self, event):
|
|
"""
|
|
Function to bind to the Enter/Return key so if Enter is pressed the selection is cleared.
|
|
|
|
:param event: Tkinter event
|
|
"""
|
|
self.icursor(tk.END)
|
|
self.selection_clear()
|
|
|
|
def config(self, **kwargs):
|
|
"""Alias for configure"""
|
|
self.configure(**kwargs)
|
|
|
|
def configure(self, **kwargs):
|
|
"""Configure widget specific keyword arguments in addition to :class:`ttk.Entry` keyword arguments."""
|
|
if "completevalues" in kwargs:
|
|
self.set_completion_list(kwargs.pop("completevalues"))
|
|
return ttk.Entry.configure(self, **kwargs)
|
|
|
|
def cget(self, key):
|
|
"""Return value for widget specific keyword arguments"""
|
|
if key == "completevalues":
|
|
return self._completion_list
|
|
return ttk.Entry.cget(self, key)
|
|
|
|
def keys(self):
|
|
"""Return a list of all resource names of this widget."""
|
|
keys = ttk.Entry.keys(self)
|
|
keys.append("completevalues")
|
|
return keys
|
|
|
|
def __setitem__(self, key, value):
|
|
self.configure(**{key: value})
|
|
|
|
def __getitem__(self, item):
|
|
return self.cget(item)
|