英文:
Customtkinter: why does this event.widget lose the proper grid information?
问题
在一个用户界面中,我尝试创建一个交互式矩阵,用户可以输入一些数据。除了数据值的输入,每列和每行都有一个带有占位文本的输入框,用户应该在其中输入列的名称(例如,价格)和行的名称(例如,公司)。为了生成矩阵,我有这个类方法。
import customtkinter as ctk
from tkinter import messagebox
class AK_Matrix_Frame(ctk.CTkFrame):
def __init__(self, root):
# 初始化框架类
super().__init__(root)
# 设置框架属性
self.width = 200
self.height = 400
self.grid(row=1, column=0, padx=10, pady=5)
# 参数
self.m = 2
self.n = 3
# 初始化和设置引用字典
self.AK_Widget_Matrix_dict = {}
self.gen_matrix()
# 基本按钮
read_button = ctk.CTkButton(self, text="Read", command=self.read_matrix)
read_button.pack(pady=12, padx=10)
root.mainloop()
def gen_matrix(self):
matrix_label = ctk.CTkLabel(self, text="Anbieter-Kategorien Matrix", font=('Ariel', 18))
matrix_label.pack(pady=12, padx=10)
self.matrix_frame = ctk.CTkFrame(self, width=200, height=200)
self.matrix_frame.pack( padx=10, pady=5, expand=True)
self.AK_Widget_Matrix_dict[(0,0)] = ctk.CTkLabel(self.matrix_frame, text="A\K", font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(0,0)].grid(row=0, column=0, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
for i in range(self.m):
self.AK_Widget_Matrix_dict[(i+1,0)] = ctk.CTkEntry(self.matrix_frame, placeholder_text="Anbieter{a}".format(a=i+1), font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(i+1,0)].grid(row=i+1, column=0, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
self.AK_Widget_Matrix_dict[(i+1,0)].bind("<Return>", self.replace_matrix_entry_w_label)
for j in range(self.n):
if i == 0:
self.AK_Widget_Matrix_dict[(0,j+1)] = ctk.CTkEntry(self.matrix_frame, placeholder_text="Kategorie{k}".format(k=j+1), font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(0,j+1)].grid(row=0, column=j+1, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
self.AK_Widget_Matrix_dict[(0,j+1)].bind("<Return>", self.replace_matrix_entry_w_label)
self.AK_Widget_Matrix_dict[(i+1,j+1)] = ctk.CTkEntry(self.matrix_frame, font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(i+1,j+1)].grid(row=i+1, column=j+1, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
def read_matrix(self):
pass
def replace_matrix_entry_w_label(self, event):
print(event.widget.grid_info())
i = event.widget.grid_info()["row"]
j = event.widget.grid_info()["column"]
print(event.widget)
print("Row, Column:", i, j)
txt = event.widget.get()
print("Event widget contains:", txt)
event.widget.destroy()
self.AK_Widget_Matrix_dict[(i , j)] = ctk.CTkLabel(self.matrix_frame, text=txt, font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(i , j)].grid(row=i, column=j, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
AK_Matrix_Frame(ctk.CTk())
矩阵可以正常显示,所有输入框和标签都被正确放置。但是,当调用self.replace_matrix_entry_w_label
类方法时,网格信息被错误传递。
对于我输入文本并按回车的任何边缘列或行输入,以下是输出:
{'in': <customtkinter.windows.widgets.ctk_entry.CTkEntry object .!ak_matrix_frame.!ctkframe.!ctkentry2>, 'column': 0, 'row': 0, 'columnspan': 1, 'rowspan': 1, 'ipadx': 0, 'ipady': 0, 'padx': 6, 'pady': (2, 3), 'sticky': 'nesw'}
Row, Column: 0 0
Event widget contains: 23def
因此,正确读取了写入的文本,但行和列是错误的(无论小部件位于矩阵的哪个位置,它们始终是0,0)。我几乎完全相同的代码在使用 tkinter 而不是 customtkinter 时有效。
为什么grid_info()
中的行和列不正确?
我尝试访问绑定的小部件event.widget.grid_info()
以获取行和列位置,并使用它来替换输入框为标签。实际发生的是,行和列的值始终为0,0,无论我选择矩阵中的哪个输入框。由于输入框中的文本实际上是正确的,我不明白问题出在哪里。
英文:
In an UI I'm trying to make I want to make an interactive matrix where some data should be entered by the user. Apart from the data value Entries, each column and row has an Entry with a placeholder text where the user should enter the name of the column (e.g. price) and row (e.g. a company). In order to generate the matrix I have this class method
import customtkinter as ctk
from tkinter import messagebox
class AK_Matrix_Frame(ctk.CTkFrame):
def __init__(self, root):
#initialize the frame class-------------------
super().__init__(root)
#Set frame properties-------------------------
self.width = 200
self.height = 400
self.grid(row=1, column=0, padx=10, pady=5)
#Parameters-----------------------------------
self.m = 2
self.n = 3
#initialize and set up reference dict----------
self.AK_Widget_Matrix_dict ={}
self.gen_matrix()
#Base Button-----------------------------------
read_button = ctk.CTkButton(self, text = "Read", command = self.read_matrix)
read_button.pack(pady=12, padx = 10)
root.mainloop()
def gen_matrix(self):
matrix_label = ctk.CTkLabel(self, text = "Anbieter-Kategorien Matrix", font= ('Ariel', 18))
matrix_label.pack(pady=12, padx = 10)
self.matrix_frame = ctk.CTkFrame(self, width=200, height=200)
self.matrix_frame.pack( padx=10, pady=5, expand=True)
self.AK_Widget_Matrix_dict[(0,0)] = ctk.CTkLabel(self.matrix_frame, text = "A\K", font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(0,0)].grid(row = 0, column = 0, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
for i in range(self.m):
self.AK_Widget_Matrix_dict[(i+1,0)] = ctk.CTkEntry(self.matrix_frame, placeholder_text = "Anbieter{a}".format(a = i+1), font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(i+1,0)].grid(row = i+1, column = 0, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
self.AK_Widget_Matrix_dict[(i+1,0)].bind("<Return>", self.replace_matrix_entry_w_label)
for j in range(self.n):
if i == 0:
self.AK_Widget_Matrix_dict[(0,j+1)] = ctk.CTkEntry(self.matrix_frame, placeholder_text = "Kategorie{k}".format(k = j+1), font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(0,j+1)].grid(row = 0, column = j+1, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
self.AK_Widget_Matrix_dict[(0,j+1)].bind("<Return>", self.replace_matrix_entry_w_label)
self.AK_Widget_Matrix_dict[(i+1,j+1)] = ctk.CTkEntry(self.matrix_frame, font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(i+1,j+1)].grid(row = i+1, column = j+1, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
def read_matrix(self):
pass
def replace_matrix_entry_w_label(self, event):
print(event.widget.grid_info())
i = event.widget.grid_info()["row"]
j = event.widget.grid_info()["column"]
print(event.widget)
print("Row, Column:",i,j)
txt = event.widget.get()
print("Event widget contains:",txt)
event.widget.destroy()
self.AK_Widget_Matrix_dict[(i , j)] = ctk.CTkLabel(self.matrix_frame, text = txt, font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(i , j)].grid(row = i, column = j, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
AK_Matrix_Frame(ctk.CTk())
The matrix displays without problem and all entries and labels are placed in the correct location. But when the class method self.replace_matrix_entry_w_label is called, the grid information is transmitted falsely.
And this is the output for any fringe column or row entry I enter text and press return:
{'in': <customtkinter.windows.widgets.ctk_entry.CTkEntry object .!ak_matrix_frame.!ctkframe.!ctkentry2>, 'column': 0, 'row': 0, 'columnspan': 1, 'rowspan': 1, 'ipadx': 0, 'ipady': 0, 'padx': 6, 'pady': (2, 3), 'sticky': 'nesw'}
Row, Column: 0 0
Event widget contains: 23def
So the text one writes in is read correctly, but the row and column are wrong (always 0,0 no matter where the widget is located).
I had the code almost identically with tkinter instead off customtkinter, and then it worked.
Why is the row and column in grid_info() not correct?
I tried accessing the bound widgets event.widget.grid_info()
in order to get row and column position and use that to replace the Entry with a Label. What actually happens is that the row and column values are always 0,0, no matter which entry in the matrix I select. Since the text written in the Entry is actually correct I don't understand where the problem is.
答案1
得分: 0
问题出在customtkinter的CTkEntry
部件内部创建了一个名为Entry
的tkinter部件作为自身的属性。
event.widget
不是指代你网格中具有行和列编号的CTkEntry
,而是指代了这个CTkEntry
内部包含的Entry
。
在replace_matrix_entry_w_label
函数中的代码要求获取Entry
在其父级中的位置。但父级是一个CTkEntry
部件,唯一的位置是(0,0)
。如果你请求Entry
的grid_info()
,那是CTkEntry
的主部件,代码会运行正常,如下所示:
def replace_matrix_entry_w_label(self, event):
i = event.widget.master.grid_info()["row"]
j = event.widget.master.grid_info()["column"]
print("Row, Column:", i, j)
txt = event.widget.get()
event.widget.master.destroy()
self.AK_Widget_Matrix_dict[(i , j)] = ctk.CTkLabel(self.matrix_frame, text=txt, font=('Ariel', 14))
self.AK_Widget_Matrix_dict[(i , j)].grid(row=i, column=j, padx=5, pady=5, sticky='w'+'e'+'n'+'s')
出于上述相同的原因,如果你不销毁event.widget.master
,你仍然会在你的UI上拥有一个CTkEntry
的空外壳,只是内部的Entry
被销毁了,但对象仍然存在。
英文:
The problem arises because customtkinter's CTkEntry
widget internally creates a tkinter Entry
as an attribute of itself.
event.widget
does not refer to the CTkEntry
that has a row and column number in your grid, but instead refers to the Entry
that this CTkEntry
contains.
Your code in the function replace_matrix_entry_w_label
asks for the position of Entry
in its parent. But the parent is a CTkEntry
widget and the only location is (0,0)
. The code works if you ask for the grid_info()
of the master of Entry
, that is of CTkEntry
. Like this:
def replace_matrix_entry_w_label(self, event):
i = event.widget.master.grid_info()["row"]
j = event.widget.master.grid_info()["column"]
print("Row, Column:",i,j)
txt = event.widget.get()
event.widget.master.destroy()
self.AK_Widget_Matrix_dict[(i , j)] = ctk.CTkLabel(self.matrix_frame, text = txt, font= ('Ariel', 14))
self.AK_Widget_Matrix_dict[(i , j)].grid(row = i, column = j, padx = 5, pady = 5, sticky='w'+'e'+'n'+'s')
For the same reason as described above, if you don't destroy event.widget.master
you will still have an empty shell of CTkEntry
where just the internal Entry
is destroyed, but the object still lives on your UI.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论