python - FocusOut 事件触发两个回调而不是 Python/Tkinter 中的预期一个
问题描述
我正在使用我发现的一些代码为 tkinter 创建一个 timepicker 小部件,该小部件由两个 Spinboxes 组成(一个用于小时值,另一个用于分钟值),但是当我在两个 spinbox 上添加事件的行为时,两者都被触发只有一个FocusOut 事件仅在一个 Spinbox 中。
预期的行为将是只有来自失去焦点的微调框的回调应该被触发,而不是两者都被触发。
编辑:在 acw1668 发表评论后,现在我知道问题在于消息框对话框从下一个 Spinbox 中窃取了焦点,所以现在我正在寻找一个合适的解决方案或好的做法来解决这个问题。
这是代码:
import tkinter as tk
from tkinter import messagebox
class Timepicker(tk.Frame):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.hourstr = tk.StringVar(self, '10')
self.hour = tk.Spinbox(self, from_=0, to=23, wrap=True, name='hourspin',
textvariable=self.hourstr, width=4)
vcmd = (parent.register(self._validate_hour), '%P')
self.hour.configure(validate='key', validatecommand=vcmd)
self.hour.bind('<FocusOut>', self._focus_hour)
self.minstr = tk.StringVar(self, '30')
self.minstr.trace("w", self.trace_var)
self.last_value = ""
self.min = tk.Spinbox(self, from_=0, to=59, wrap=True, name='minspin',
textvariable=self.minstr, width=4, )
vcmd = (parent.register(self._validate_minutes), '%P')
self.min.configure(validate='key', validatecommand=vcmd)
self.min.bind('<FocusOut>', self._focus_minutes)
self.hour.grid()
self.min.grid(row=0, column=1)
def trace_var(self, *args):
if self.last_value == "59" and self.minstr.get() == "0":
self.hourstr.set(int(self.hourstr.get()) + 1 if self.hourstr.get() != "23" else 0)
self.last_value = self.minstr.get()
def _focus_hour(self, event):
result = self._validate_generic(self.hourstr.get(), 23)
if (not result or self.hourstr.get() == '') \
and self.parent.focus_get() != '.!timepicker.hourspin':
messagebox.showerror('Invalid value', f'{self.hourstr.get()} is not a valid input')
def _focus_minutes(self, event):
result = self._validate_generic(self.minstr.get(), 23)
if (not result or self.minstr.get() == '') \
and self.parent.focus_get() != '.!timepicker.minspin':
messagebox.showerror('Invalid value', f'{self.minstr.get()} is not a valid input')
def _validate_hour(self, new_value):
# Returning True allows the edit to happen, False prevents it.
if new_value == '':
return True
result = self._validate_generic(new_value, 23)
return result
def _validate_minutes(self, new_value):
# Returning True allows the edit to happen, False prevents it.
if new_value == '':
return True
result = self._validate_generic(new_value, 59)
return result
def _validate_generic(self, new_value, maxvalue):
if not new_value.isdigit():
return False
return len(new_value) <= 2 \
and int(new_value) <= maxvalue
root = tk.Tk()
Timepicker(root).pack()
root.mainloop()
解决方案
推荐阅读
- c# - 如何在按下按钮时从文本输入中搜索此树视图中的特定节点?
- wso2 - WSO2 - 不支持的请求方法
- sql - 动态拆分字符串
- ios - UINavigationController 堆栈中的阴影
- intervention - 在 Laravel 5.7 中上传 gif 图像
- rust - 如何返回对存储在结构成员中的可选盒装特征的可变引用
- c# - 统一脚本可以简单地成为公共变量吗
- ruby-on-rails - 设置从 rails 生成 PDF 的动态页眉和页脚数据(Grover gem)
- python - 他们是创建列表列表而不是逐行检查的更好方法吗
- elasticsearch - 弹性搜索 - 过滤匹配值和数据类型的数据