全屏Python TKinter或wxPython窗口,如何“保持在所有窗口底部”?

5 投票
1 回答
1914 浏览
提问于 2025-04-17 08:36

我想创建一个全屏面板,能够在视觉上阻挡屏幕上所有东西的访问(比如桌面、菜单、Unity面板等,适用于Ubuntu 11.10),但这个面板要在其他应用程序打开的窗口下面。

这样做主要是为了让我的笔记本电脑对小孩安全。我希望孩子(4岁)能使用一些特定的应用程序,比如gcompris、childs play、tux math等,但不想让他们接触到其他应用和设置。就像是一个定制的桌面加启动面板,没有任何可以破坏的东西,也无法访问文件等。

我希望这个面板里有一些按钮,可以启动其他应用程序(使用subprocess.call),但面板本身需要保持在从它启动的任何东西下面,或者为了简单起见,保持在任何全屏游戏和所有打开窗口的下面(即使面板获得了焦点)。

Python的tkinter库中的全屏模式overrideredirect(True)非常合适(带有密码保护的关闭按钮),但问题是它不允许其他应用程序出现在它上面,我不确定是否可以让它保持在所有东西的下面。

有没有办法改变这种行为,或者有没有其他工具可以让我在Python中或其他方式实现这个功能?

编辑:附加信息:

我几乎把它弄好了,但overrideredirect(True)还有一个奇怪的行为。我可以在开始时使用lower()把应用程序放低,这样没问题,但当我用overrideredirect(True)时,应用程序会完全消失。下面是非全屏测试代码:

from tkinter import *

def btn1_click():app.quit();app.destroy()
def btn2_click():app.lower()    
def handler():
    if tkinter.messagebox.askyesno("Quit?", "Are you sure you want to quit?"):
        app.quit();app.destroy()

app = Tk()
app.title("Testing...")
app.geometry('300x100+200+100')
#app.overrideredirect(True) 
#app.lower()

b1 = Button(app, text = "Exit!", width = 10, command = btn1_click);b1.pack()
b2 = Button(app, text = "Lower", width = 10, command = btn2_click);b2.pack()
app.protocol("WM_DELETE_WINDOW", handler)
app.mainloop()

当你按原样运行时,它会打开一个新窗口,按下“Lower”按钮会把它送到后面,但如果你取消注释app.overrideredirect(True)这一行,按下按钮后,应用程序仍然在运行,但不再可见。

编辑……好的,我想我明白了:

>>>help(tkinter)
...
     |  overrideredirect = wm_overrideredirect(self, boolean=None)
     |      Instruct the window manager to ignore this widget
     |      if BOOLEAN is given with 1. Return the current value if None
     |      is given.
...

所以,首先我请求窗口管理器忽略我的窗口,但后来我又想让窗口管理器对我的窗口做点什么……真是矛盾 :)

有没有其他方法可以去掉窗口装饰,而不要求窗口管理器忽略这个窗口?

编辑。用不同的工具wxPython重新审视这个问题

这次我尝试简单的方法——使用Boa Constructor。虽然在Tkinter中app.lower()在窗口框架上工作得很好,但现在在wxPython中却遇到了问题。在下面的代码中——按下按钮会在框架上打开一个gedit窗口,然后2秒后框架被带到最上面,再过2秒它应该掉到窗口堆栈的底部,但这并没有发生,至少在我的Ubuntu上是这样。

def OnButton3Button(self, event):
    subprocess.call("gedit") #opens gedit above the Frame
    time.sleep(2) #waits for 2 seconds
    self.Raise() #brings the Frame to the top
    time.sleep(2) #waits for another 2 seconds
    self.Lower() #should Lower the Frame to the bottom, but it doesn't

如果我能让Lower()以某种方式工作,那就简单多了,比如:

def OnFrame1Activate(self, event):
    self.ShowFullScreen(True)

def OnFrame1EnterWindow(self, event):
    self.Lower()

现在我想不出其他办法了,可能我会按照建议使用访客账户。

1 个回答

2

这是我在Windows系统上用pygame设置窗口位置的方法。这样设置后,窗口会覆盖其他所有窗口。如果把-1改成1,窗口就会在其他窗口的后面。我只知道这个方法在Windows上有效。

import pygame, time, datetime, ctypes
from pygame.locals import *
from ctypes import windll

pygame.init()
set_window_pos = windll.user32.SetWindowPos
monitorsize = ctypes.windll.user32
resolution_X = monitorsize.GetSystemMetrics(0)
resolution_Y = monitorsize.GetSystemMetrics(1)

screen = pygame.display.set_mode((255, 242), pygame.NOFRAME)
set_window_pos(pygame.display.get_wm_info()['window'], -1, (resolution_X - 255), 50, 0, 0, 0x0001)

要让窗口全屏,可以使用:

screen = pygame.display.set_mode((800, 350), FULLSCREEN) # this works in linux

撰写回答