Установить текст по умолчанию для автозаполнения виджета ввода в Tkinter - PullRequest
0 голосов
/ 05 февраля 2020

Я создаю GUI, используя tkinter, который имеет несколько простых полей. Я выяснил, как использовать значения по умолчанию для них (я загружаю эти значения из файла .pickle в словарь), используя параметр textvariable виджета Entry, но я построил одно из полей, чтобы использовать автозаполнение, когда пользователь вводит значение , Это отдельный класс, и я использовал код, который нашел здесь .

Я пробовал несколько вещей, чтобы загрузить значение в этом виджете при запуске приложения, например, возвращая значение и используя метод set (), но я потерпел неудачу. Я либо получаю ошибки, либо ничего не происходит. Значения, которые я ввожу в виджет, успешно сохраняются в моем файле выбора.

Я все еще изучаю объектно-ориентированное программирование с python, поэтому, пожалуйста, будьте осторожны со мной. Итак, как я могу изменить приведенный ниже код для отображения значения по умолчанию?

from Tkinter import *
import re

lista = ['a', 'actions', 'additional', 'also', 'an', 'and', 'angle', 'are', 'as', 'be', 'bind','bracket', 'brackets', 'button', 'can', 'cases', 'configure', 'course', 'detail', 'enter', 'event', 'events', 'example', 'field', 'fields', 'for', 'give', 'important', 'in', 'information', 'is', 'it', 'just', 'key', 'keyboard', 'kind', 'leave', 'left', 'like', 'manager', 'many', 'match', 'modifier', 'most', 'of', 'or', 'others', 'out', 'part', 'simplify', 'space', 'specifier', 'specifies', 'string;', 'that', 'the', 'there', 'to', 'type', 'unless', 'use', 'used', 'user', 'various', 'ways', 'we', 'window', 'wish', 'you']


class AutocompleteEntry(Entry):
    def __init__(self, lista, *args, **kwargs):

        Entry.__init__(self, *args, **kwargs)
        self.lista = lista        
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()

        self.var.trace('w', self.changed)
        self.bind("<Right>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)

        self.lb_up = False

    def changed(self, name, index, mode):  

        if self.var.get() == '':
            self.lb.destroy()
            self.lb_up = False
        else:
            words = self.comparison()
            if words:            
                if not self.lb_up:
                    self.lb = Listbox()
                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Right>", self.selection)
                    self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END,w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

    def selection(self, event):

        if self.lb_up:
            self.var.set(self.lb.get(ACTIVE))
            self.lb.destroy()
            self.lb_up = False
            self.icursor(END)

    def up(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != '0':                
                self.lb.selection_clear(first=index)
                index = str(int(index)-1)                
                self.lb.selection_set(first=index)
                self.lb.activate(index) 

    def down(self, event):

        if self.lb_up:
            if self.lb.curselection() == ():
                index = '0'
            else:
                index = self.lb.curselection()[0]
            if index != END:                        
                self.lb.selection_clear(first=index)
                index = str(int(index)+1)        
                self.lb.selection_set(first=index)
                self.lb.activate(index) 

    def comparison(self):
        pattern = re.compile('.*' + self.var.get() + '.*')
        return [w for w in self.lista if re.match(pattern, w)]

if __name__ == '__main__':
root = Tk()

entry = AutocompleteEntry(lista, root)
entry.grid(row=0, column=0)
Button(text='nothing').grid(row=1, column=0)
Button(text='nothing').grid(row=2, column=0)
Button(text='nothing').grid(row=3, column=0)

root.mainloop()

1 Ответ

0 голосов
/ 06 февраля 2020

Хорошо, поэтому, проанализировав этот код в течение пары часов, я выяснил, как получить значение по умолчанию с помощью метода insert(). Моей первой проблемой после этого было то, что список также активен по умолчанию при запуске приложения. При добавлении другого условия if в функцию changed она не будет открывать список, пока значение не будет очищено. Когда я добавляю условный оператор, строка self.lb.destroy() выдает ошибку при очистке поля:

AttributeError: объект 'AutocompleteEntry' не имеет атрибута 'lb'

Я не уверен, почему эта ошибка выдается, поскольку она работала до того, как я добавил условие. Однако lb не определен нигде в классе или функции. Удаление строки исправило ошибку, и все, кажется, работает как ожидалось. Вот изменения, которые я сделал. Если у кого-то есть лучшее решение, пожалуйста, дайте мне знать.

class AutocompleteEntry(Entry):
    # add settings argument which is True or False    
    def __init__(self, lista, settings, *args, **kwargs):

        Entry.__init__(self, *args, **kwargs)
        self.lista = lista
        # define the self.settings object
        self.settings = settings
        self.var = self["textvariable"]
        if self.var == '':
            self.var = self["textvariable"] = StringVar()
        self.var.trace('w', self.changed)
        self.bind("<Return>", self.selection)
        self.bind("<Up>", self.up)
        self.bind("<Down>", self.down)

        self.lb_up = False

    def changed(self, name, index, mode):

        if self.var.get() == '':
            # self.lb.destroy() - removed this line
            self.lb_up = False
            # change this variable to False once the field is cleared
            self.settings = False 
        # add if condition - field is not empty and settings is True
        elif self.var.get() != '' and self.settings == True:
            self.lb_up = False
        else:
            words = self.comparison()
            if words:
                if not self.lb_up:
                    self.lb = Listbox()
                    self.lb.bind("<Double-Button-1>", self.selection)
                    self.lb.bind("<Return>", self.selection)
                    self.lb.place(x=self.winfo_x(), y=self.winfo_y()+self.winfo_height())
                    self.lb_up = True

                self.lb.delete(0, END)
                for w in words:
                    self.lb.insert(END,w)
            else:
                if self.lb_up:
                    self.lb.destroy()
                    self.lb_up = False

И последняя часть:

if __name__ == '__main__':
    root = Tk()
    # define settings variable and add to AutoCompleteEntry arguments
    settings = True
    entry = AutocompleteEntry(lista, settings, root)
    entry.insert(END, "this is the default value")
    entry.grid(row=0, column=0)
    Button(text='nothing').grid(row=1, column=0)
    Button(text='nothing').grid(row=2, column=0)
    Button(text='nothing').grid(row=3, column=0)

    root.mainloop()
...