Исключение виджета пользовательской записи tkinter - PullRequest
0 голосов
/ 14 июля 2020

Я пытаюсь создать собственный Tkinter Entry widget, который преобразует символы нижнего регистра в верхний регистр до того, как символы будут вставлены в виджет. Я знаю, что есть решения, которые привязывают события отпускания клавиш к виджету с функцией получения текста виджета, а затем конвертируют его в верхний регистр и повторно вставляют текст. Но в этих решениях перед преобразованием отображается символ нижнего регистра, чего я предпочитаю не делать. в текстовый виджет

Этот код отлично подходит для пользовательского Text widget, и я использовал его в других приложениях.

Теперь я пытаюсь использовать тот же подход для создания пользовательский виджет Entry. Вот пример кода, который включает как настраиваемый виджет Text, так и настраиваемый виджет Entry:

from tkinter import *

class CustomText(Text):
    def __init__(self, *args, **kwargs):
        Text.__init__(self, *args, **kwargs)
        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):

        if args[0] == "insert" and args[1] == "insert":
           args =('insert', 'insert', args[2].upper())

        cmd = (self._orig,) + args
        result = self.tk.call(cmd)
        return result

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):

        if args[0] == "insert" and args[1] == "insert":
           args =('insert', 'insert', args[2].upper())

        cmd = (self._orig,) + args
        result = self.tk.call(cmd)
        return result

def get_text():
    print("TEXT widget text = ", mytext.get("1.0", "end"))
    print("ENTRY widget text = " ,entryvar.get())

root = Tk()

entryvar = StringVar()

root.geometry("300x300")
myframe = Frame(root, width = 300, height = 300)
Label(myframe, text="TEXT WIDGET").pack(side = TOP)
myframe.pack(side = TOP)
mytext = CustomText(myframe, width = 30, height=1, wrap="none")
mytext.pack(side = TOP)
Label(myframe, text="ENTRY WIDGET").pack(side = TOP)
myentry = CustomEntry(myframe,  textvariable=entryvar, width = 30)
myentry.pack(side = TOP)

Button(myframe, text="Get Entry Widget Text", command=get_text).pack(side=TOP)

root.mainloop()

Решения работают для виджета CustomText. Как видите, символы преобразуются перед вставкой, и в результате пользователь вводит символы с нажатой клавишей Shift.

Но я получаю исключение при вводе данных в виджет CustomEntry, который я получаю следующее исключение из result = self.tk.call(cmd):

Traceback (most recent call last):
  File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 57, in <module>
    root.mainloop()
  File "C:\Users\rhkea\AppData\Local\Programs\Python\Python37\lib\tkinter\__init__.py", line 1283, in mainloop
    self.tk.mainloop(n)
  File "C:/Users/rhkea/AppData/Roaming/JetBrains/PyCharmCE2020.1/scratches/custom_entry_box.py", line 34, in _proxy
    result = self.tk.call(cmd)
_tkinter.TclError: selection isn't in widget .!frame.!customentry

Есть идеи, почему это может происходить?

1 Ответ

2 голосов
/ 15 июля 2020

Поигравшись с кодом, я обнаружил, что после вставки текста в запись вызывается метод index sel.first. Но выделения нет, поэтому возникает ошибка «выделение отсутствует в виджете.! Frame.! Customentry». Я не знаю, как это обрабатывается в обычном Entry, но вы можете поймать эту ошибку:

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)

        self._orig = self._w + "_orig"
        self.tk.call("rename", self._w, self._orig)
        self.tk.createcommand(self._w, self._proxy)

    def _proxy(self, *args):
        if args[0] == "insert" and args[1] == "insert":
            args = ('insert', 'insert', args[2].upper())
        cmd = (self._orig,) + args

        try:
            return self.tk.call(cmd)
        except TclError as e:
            if args[0] == 'index' and args[1] == 'sel.first':
                pass
            else:
                raise TclError(str(e))

В противном случае вы можете использовать совершенно другой метод, чтобы изменить регистр вставленного текста: используйте трассировка текстовой переменной записи.

class CustomEntry(Entry):
    def __init__(self, *args, **kwargs):
        Entry.__init__(self, *args, **kwargs)
        self._var = StringVar(self)
        self.configure(textvariable=self._var)
        self._var.trace_add('write', self._uppercase)

    def _uppercase(self, *args):
        self._var.set(self._var.get().upper())

С self._var.trace_add('write', self._uppercase) метод _uppercase() вызывается каждый раз, когда изменяется содержимое StringVar.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...