对于绑定,我在python焦点方面做错了什么?
我试图将按钮小部件绑定到键盘enter,但是没有发生任何事情,或者焦点结束在要加载的类的最后一个实例上。
我在self.bind('<Return>', lambda e: self.convert)
之后将button.nothing添加到基本代码中。试过container.bind('<Return>', lambda e: self.convert)
什么都没做。我不明白为什么代码没有绑定除了焦点之外的关键事件在错误的位置(焦点总是在类的最后一个实例上)。这是我在https://github.com/photodude/Tkconverter工作的代码
在修改代码成为更多OOP之前,在自述文件中链接到源非OOP教程和所有文件到源教程。
如何将焦点放在类的"active“用户可见实例上?
上面提供了一个指向代码的链接,这是一个最小的、可重复的例子。
< code >G 212
当您打开"F到C“并按enter键时,您会得到一个弹出错误”无法将字符串转换为浮动“,但是当您使用"C到F”时,就会发生正确的操作(温度转换)。在"F到C“上弹出的”错误“与单击”转换“按钮时相同,而输入字段为空白或有数值以外的其他内容。这个弹出错误发生在"C到F“上,然后按enter键,输入一个空白条目或非数字值。如果您在"F到C“或"C到F”上,请在输入框中输入一个数字值(如98或100),然后单击“转换”按钮,一切都按预期工作。
预期的绑定行为是指对用户可见的活动实例具有键绑定的活动焦点,如“转换”按钮所具有的。
按社区要求张贴的代码。有关当前代码和尝试修复的历史记录,请参见Github。App.py
# source https://www.pythontutorial.net/tkinter/tkraise/
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
from ControlFrame import ControlFrame
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title('Temperature Converter')
self.geometry('300x120')
self.resizable(False, False)
if __name__ == "__main__":
app = App()
ControlFrame(app)
app.mainloop()
ControFrame.py
# source https://www.pythontutorial.net/tkinter/tkraise/
import tkinter as tk
from tkinter import ttk
from ConverterFrame import ConverterFrame
from TemperatureConverter import TemperatureConverter
class ControlFrame(ttk.LabelFrame):
def __init__(self, container):
super().__init__(container)
self['text'] = 'Options'
# radio buttons
self.selected_value = tk.IntVar()
ttk.Radiobutton(
self,
text='F to C',
value=0,
variable=self.selected_value,
command=self.change_frame).grid(column=0, row=0, padx=5, pady=5)
ttk.Radiobutton(
self,
text='C to F',
value=1,
variable=self.selected_value,
command=self.change_frame).grid(column=1, row=0, padx=5, pady=5)
self.grid(column=0, row=1, padx=5, pady=5, sticky='ew')
# initialize frames
self.frames = {}
self.frames[0] = ConverterFrame(
container,
'Fahrenheit',
TemperatureConverter.fahrenheit_to_celsius
)
self.frames[1] = ConverterFrame(
container,
'Celsius',
TemperatureConverter.celsius_to_fahrenheit
)
self.change_frame()
def change_frame(self):
for frame in self.frames.values():
frame.reset()
frame.grid_remove()
frame = self.frames[self.selected_value.get()]
frame.reset()
frame.tkraise()
frame.grid()
frame.focus_set()
ConverterFrame.py
# source https://www.pythontutorial.net/tkinter/tkraise/
import tkinter as tk
from tkinter import ttk
from tkinter.messagebox import showerror
class ConverterFrame(ttk.Frame):
def __init__(self, container, unit_from, converter):
super().__init__(container)
self.unit_from = unit_from
self.converter = converter
self.master.bind('<Return>', lambda event=None: self.enter_key())
# field options
options = {'padx': 5, 'pady': 0}
# temperature label
self.temperature_label = ttk.Label(self, text=self.unit_from)
self.temperature_label.grid(column=0, row=0, sticky='w', **options)
# temperature entry
self.temperature = tk.StringVar()
self.temperature_entry = ttk.Entry(self, textvariable=self.temperature)
self.temperature_entry.grid(column=1, row=0, sticky='w', **options)
self.temperature_entry.focus()
# button
self.convert_button = ttk.Button(self, text='Convert')
self.convert_button.grid(column=2, row=0, sticky='w', **options)
self.convert_button.configure(command=self.convert)
# self.convert_button.bind('<Return>', lambda event=None: self.convert)
# result label
self.result_label = ttk.Label(self)
self.result_label.grid(row=1, columnspan=3, **options)
# add padding to the frame and show it
self.grid(column=0, row=0, padx=5, pady=5, sticky="nsew")
def convert(self, event=None):
""" Handle button click event
"""
try:
input_value = float(self.temperature.get())
result = self.converter(input_value)
self.result_label.config(text=result)
except ValueError as error:
showerror(title='Error', message=error)
def reset(self):
self.temperature_entry.delete(0, "end")
self.result_label.text = ''
def enter_key(self):
self.convert()
TemperatureConverter.py
# source https://www.pythontutorial.net/tkinter/tkraise/
class TemperatureConverter:
@staticmethod
def fahrenheit_to_celsius(f, format=True):
result = (f - 32) * 5/9
if format:
return f'{f} Fahrenheit = {result:.2f} Celsius'
return result
@staticmethod
def celsius_to_fahrenheit(c, format=True):
result = c * 9/5 + 32
if format:
return f'{c} Celsius = {result:.2f} Fahrenheit'
return result
尝试了来自Python Tkinter: Binding Keypress Event to Active Tab in ttk.Notebook的解决方案,如下所示,但没有成功
class ConverterFrame(ttk.Frame):
def __init__(...):
...
tag = str(self)
self._add_bindtag(self, tag)
self.bind_class(tag, '<Return>', lambda event=None: self.convert())
def _add_bindtag(self, widget, tag):
bindtags = widget.bindtags()
if tag not in bindtags:
widget.bindtags((tag,) + bindtags)
for child in widget.winfo_children():
self._add_bindtag(child, tag)
发布于 2022-09-16 03:37:16
这里的解决方案是更正ControlFrame.py,以初始化change_frame()
上每个框架的实例。源教程中的原始错误实例化了ConverterFrame()
类,最后一个类将替换以前所有与焦点和绑定相关的错误。
移动self.frames[0] = ConverterFrame(...)
..。转换成特定的函数并调用change_frame()
上的函数,纠正了帧替换问题。
完全修改的代码在GitHub https://github.com/photodude/Tkconverter上
https://stackoverflow.com/questions/73074571
复制相似问题