Python 绑定回调以最小化和最大化顶级窗口中的事件
我已经通读了相关的答案,似乎可以接受的方法是将回调绑定到顶级小部件中的Python 绑定回调以最小化和最大化顶级窗口中的事件,python,linux,tkinter,Python,Linux,Tkinter,我已经通读了相关的答案,似乎可以接受的方法是将回调绑定到顶级小部件中的和事件。我尝试了以下方法,但没有效果: from Tkinter import * tk = Tk() def visible(event): print 'visible' def invisible(event): print 'invisible' tk.bind('<Map>', visible) tk.bind('<Unmap>', invisible) tk.mai
和
事件。我尝试了以下方法,但没有效果:
from Tkinter import *
tk = Tk()
def visible(event):
print 'visible'
def invisible(event):
print 'invisible'
tk.bind('<Map>', visible)
tk.bind('<Unmap>', invisible)
tk.mainloop()
从Tkinter导入*
tk=tk()
def可见(事件):
打印“可见”
def不可见(事件):
打印“不可见”
tk.bind(“”,可见)
tk.bind(“”,不可见)
tk.mainloop()
我正在Linux上运行python 2.7。这可能与不同操作系统中的窗口管理器代码有关吗
在
tk.mainloop()
之前调用tk.iconify()
也没有效果。事实上,产生正确行为的唯一命令是tk.draw()
,这与最小化窗口肯定不是一回事。另外,如果调用
和
事件是通过调用pack()
、grid()
或place()
触发的,那么为什么在Windows和/或Mac上最小化应用程序窗口时会触发
,如和答案所示。为什么在Linux上调用draw()
和deiconify()
时会触发它们呢?对于我来说,在Win10上,您的代码工作得很好,但需要注意的是,中间的框架按钮会产生“可见”,无论是“最大化”还是“还原”。因此,最大化后再进行恢复将导致2个新的“可见”变为可见
我并没有特别预料到这一点,因为我说地图是在
正在映射一个小部件,即使其在应用程序中可见。例如,当您调用小部件的.grid()方法时,就会发生这种情况
顶层不由几何图形管理。权威人士说
地图,取消地图
只要窗口的映射状态发生更改,就会生成映射和取消映射事件
窗口是在未映射状态下创建的。顶级窗口在转换到正常状态时将被映射,而在撤消和图标状态下将被取消映射
尝试在mainloop调用之前添加tk.iconify()
。这应该与最小化按钮的操作相同。如果它没有导致“不可见”,那么Linux上似乎存在tcl/tk错误。在Linux上取消映射
术语Unmap
在Linux上的含义与在Windows上的含义完全不同。在Linux上,取消窗口映射意味着使其(几乎)无法跟踪;它不会出现在应用程序的图标中,也不会再在wmctrl-l
的输出中列出。我们可以通过以下命令取消映射/映射窗口:
xdotool windowunmap <window_id>
无论是否最小化,线程始终打印:
normal
变通办法
幸运的是,如果您必须能够检测窗口的最小化状态,那么在Linux上,我们有类似xprop
和wmctrl
的替代工具。尽管它非常脏,但它在应用程序内部非常可靠地可以编写脚本
根据注释中的要求,下面是一个使用外部工具创建自己版本的绑定的简化示例
工作原理
- 当窗口出现时(应用程序启动),我们使用
通过检查名称和pid来获取窗口的wmctrl-lp
(id
窗口的pid为0)tkinter
- 一旦我们有了
,我们就可以检查窗口id
的输出中是否有字符串xprop-id
。如果是这样,窗口将最小化\u NET\u WM\u STATE\u HIDDEN
tkinter
,包括定期检查。在下面的例子中,这些评论应该能说明问题
我们需要什么
我们需要同时安装和。基于Dedian的系统:
sudo apt-get install wmctrl xprop
代码示例
导入子流程
导入时间
从Tkinter进口*
类测试窗口:
定义初始(自我,主):
self.master=master
self.wintitle=“Testwindow”
self.checked=False
self.state=None
按钮=按钮(self.master,text=“按我”)
button.pack()
self.master.after(0,self.get_状态)
self.master.title(self.wintitle)
def get_窗口(自):
"""
通过标题和pid获取窗口(tkinter窗口的pid为0)
"""
在subprocess.check\u输出中为w返回[w.split()(
[“wmctrl”,“-lp”]
).decode(“utf-8”).splitlines()如果self.wintitle在w][1][0]中
def get_状态(自身):
"""
通过检查_NET_WM_state_HIDDEN是否在
xprop-id的输出
"""
尝试:
"""
checked=False是为了防止重复获取窗口id
(在回路中节省燃油)。确定窗口后,将通过进一步检查。
"""
self.match=self.get_window()如果self.checked==False,则self.match
self.checked=True
除索引器外:
通过
其他:
win_data=子进程。检查_输出([“xprop”,“-id”,self.match])。解码(“utf-8”)
如果win\u数据中有“\u NET\u WM\u STATE\u HIDDEN”:
newstate=“最小化”
其他:
newstate=“正常”
#仅当状态发生变化时才采取行动
如果是newstate!=自我状态:
印刷新闻状态
self.state=newstate
#每半秒钟检查一次
self.master.after(500,self.get_状态)
def main():
root=Tk()
app=TestWindow(根)
root.mainloop()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
我自己实现了Jacob建议的
from Tkinter import Tk, Toplevel
import subprocess
class CustomWindow(Toplevel):
class State(object):
NORMAL = 'normal'
MINIMIZED = 'minimized'
def __init__(self, parent, **kwargs):
Toplevel.__init__(self, parent, **kwargs)
self._state = CustomWindow.State.NORMAL
self.protocol('WM_DELETE_WINDOW', self.quit)
self.after(50, self._poll_window_state)
def _poll_window_state(self):
id = self.winfo_id() + 1
winfo = subprocess.check_output(
['xprop', '-id', str(id)]).decode('utf-8')
if '_NET_WM_STATE_HIDDEN' in winfo:
state = CustomWindow.State.MINIMIZED
else:
state = CustomWindow.State.NORMAL
if state != self._state:
sequence = {
CustomWindow.State.NORMAL: '<<Restore>>',
CustomWindow.State.MINIMIZED: '<<Minimize>>'
}[state]
self.event_generate(sequence)
self._state = state
self.after(50, self._poll_window_state)
if __name__ == '__main__':
root = Tk()
root.withdraw()
window = CustomWindow(root)
def on_restore(event):
print 'restore'
def on_minimize(event):
print 'minimize'
window.bind('<<Restore>>', on_restore)
window.bind('<<Minimize>>', on_minimize)
root.mainloop()
从Tkinter导入Tk,顶级
导入子流程
类自定义窗口(顶级):
类状态(对象):
正常=‘正常’
最小化='MINIMIZED'
定义初始值(自、父、**kwargs):
顶层.uuuu初始化(自、父、**kwargs)
self.\u state=CustomWindow.state.NORMAL
self.protocol('WM\u DELETE\u WINDOW',self.quit)
自我后(50,自我调查,窗口,状态)
def_poll_w
sudo apt-get install wmctrl xprop
import subprocess
import time
from Tkinter import *
class TestWindow:
def __init__(self, master):
self.master = master
self.wintitle = "Testwindow"
self.checked = False
self.state = None
button = Button(self.master, text = "Press me")
button.pack()
self.master.after(0, self.get_state)
self.master.title(self.wintitle)
def get_window(self):
"""
get the window by title and pid (tkinter windows have pid 0)
"""
return [w.split() for w in subprocess.check_output(
["wmctrl", "-lp"]
).decode("utf-8").splitlines() if self.wintitle in w][-1][0]
def get_state(self):
"""
get the window state by checking if _NET_WM_STATE_HIDDEN is in the
output of xprop -id <window_id>
"""
try:
"""
checked = False is to prevent repeatedly fetching the window id
(saving fuel in the loop). after window is determined, it passes further checks.
"""
self.match = self.get_window() if self.checked == False else self.match
self.checked = True
except IndexError:
pass
else:
win_data = subprocess.check_output(["xprop", "-id", self.match]).decode("utf-8")
if "_NET_WM_STATE_HIDDEN" in win_data:
newstate = "minimized"
else:
newstate = "normal"
# only take action if state changes
if newstate != self.state:
print newstate
self.state = newstate
# check once per half a second
self.master.after(500, self.get_state)
def main():
root = Tk()
app = TestWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
from Tkinter import Tk, Toplevel
import subprocess
class CustomWindow(Toplevel):
class State(object):
NORMAL = 'normal'
MINIMIZED = 'minimized'
def __init__(self, parent, **kwargs):
Toplevel.__init__(self, parent, **kwargs)
self._state = CustomWindow.State.NORMAL
self.protocol('WM_DELETE_WINDOW', self.quit)
self.after(50, self._poll_window_state)
def _poll_window_state(self):
id = self.winfo_id() + 1
winfo = subprocess.check_output(
['xprop', '-id', str(id)]).decode('utf-8')
if '_NET_WM_STATE_HIDDEN' in winfo:
state = CustomWindow.State.MINIMIZED
else:
state = CustomWindow.State.NORMAL
if state != self._state:
sequence = {
CustomWindow.State.NORMAL: '<<Restore>>',
CustomWindow.State.MINIMIZED: '<<Minimize>>'
}[state]
self.event_generate(sequence)
self._state = state
self.after(50, self._poll_window_state)
if __name__ == '__main__':
root = Tk()
root.withdraw()
window = CustomWindow(root)
def on_restore(event):
print 'restore'
def on_minimize(event):
print 'minimize'
window.bind('<<Restore>>', on_restore)
window.bind('<<Minimize>>', on_minimize)
root.mainloop()