绑定回调以最小化和最大化顶级窗口中的事件 [英] Binding callbacks to minimize and maximize events in Toplevel windows

查看:162
本文介绍了绑定回调以最小化和最大化顶级窗口中的事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经阅读了相关的答案,并且似乎可以接受的方法是通过将回调绑定到Toplevel小部件中的<Map><Unmap>事件.我尝试了以下操作,但没有效果:

I've read through related answers and it seems that the accepted way to do this is by binding callbacks to <Map> and <Unmap> events in the Toplevel widget. I've tried the following but to no effect:

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()

我正在Linux上运行python 2.7.难道这与不同操作系统中的窗口管理器代码有关?

I'm running python 2.7 on Linux. Could this be related to window manager code in different operating systems?

tk.mainloop()之前调用tk.iconify()也不起作用.实际上,唯一产生正确行为的命令是tk.withdraw(),这与最小化窗口当然不是同一回事.此外,如果<Map><Unmap>事件是通过调用pack()grid()place()触发的,为什么在Windows和/或Mac上将应用程序窗口最小化时,触发<Map>的原因是答案建议.为什么在Linux上调用withdraw()deiconify()时会触发它们?

Calling tk.iconify() before tk.mainloop() has no effect either. In fact, the only command that produces the correct behavior is tk.withdraw() which is certainly not the same thing as minimizing the window. Additionally, if <Map> and <Unmap> events are triggered by calling pack(), grid(), or place(), why is <Map> triggered when the application window is minimized on Windows and/or Mac, as this and this answer suggest. And why would they be triggered when calling withdraw() and deiconify() on Linux?

推荐答案

在Linux上取消映射

Linux上的术语Unmap与Windows上的含义完全不同.在Linux上,取消映射是指使窗口(几乎)不可追踪;它不会出现在应用程序的图标中,也不会在wmctrl -l的输出中列出.我们可以通过以下命令取消映射/映射窗口:

Unmapping on Linux

The term Unmap has a quite different meaning on Linux than it has on Windows. On Linux, Unmapping a window means making it (nearly) untraceable; It does not appear in the application's icon, nor is it listed anymore in the output of wmctrl -l. We can unmap / map a window by the commands:

xdotool windowunmap <window_id>

和:

xdotool windowmap <window_id>

要查看是否甚至可以让tkinter检测窗口的状态为 minimized ,我在基本窗口中添加了一个线程,使用以下命令每秒打印一次窗口的状态:

To see if we can even possibly make tkinter detect the window's state minimized, I added a thread to your basic window, printing the window's state once per second, using:

root.state()

是否已最小化线程,始终会打印该线程:

Minimized or not, the thread always printed:

normal

解决方法

幸运的是,如果您必须能够检测到窗口的最小化状态,那么在Linux上,我们可以使用xpropwmctrl之类的替代工具.尽管很脏,但是可以在应用程序内部可靠地编写脚本.

Workaround

Luckily, if you must be able to detect the window's minimized state, on Linux we have alternative tools like xprop and wmctrl. Although as dirty as it gets, it is very well scriptable reliably inside your application.

根据注释中的要求,在一个简化的示例下面,使用外部工具创建您自己的绑定版本.

As requested in a comment, below a simplified example to create your own version of the bindings with external tools.

  • 当窗口出现(应用程序启动)时,我们使用wmctrl -lp通过检查 name pid (tkinter窗口)来获取窗口的id.具有pid 0).
  • 一旦有了window id,我们就可以检查字符串_NET_WM_STATE_HIDDEN是否在xprop -id <window_id>的输出中.如果是这样,则将窗口最小化.
  • When the window appears (the application starts), We use wmctrl -lp to get the window's id by checking both name and pid (tkinter windows have pid 0).
  • Once we have the window id, we can check if the string _NET_WM_STATE_HIDDEN is in output of xprop -id <window_id>. If so, the window is minimized.

然后,我们可以轻松地使用tkinter after()方法进行定期检查.在下面的示例中,评论应能说明一切.

Then we can easily use tkinter's after() method to include a periodic check. In the example below, the comments should speak for themselves.

我们同时需要 wmctrl

We need both wmctrl and xprop to be installed. On Dedian based systems:

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()

这篇关于绑定回调以最小化和最大化顶级窗口中的事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆