【问题标题】:Have Win32 MessageBox appear over other programs让 Win32 MessageBox 出现在其他程序之上
【发布时间】:2012-07-30 16:59:20
【问题描述】:

我最近开始学习 Python,并编写了一个小脚本,当某个网站更改内容时会通知我。然后我将它作为计划任务添加到 Windows,以便它可以每 10 分钟运行一次。我想立即收到有关网站更改的通知,因此我添加了一个 win32ui 消息框,如果脚本检测到网站已更改,则会弹出该消息框。这是我用于 MessageBox 的小代码 sn-p(我知道,富有想象力的文字):

win32ui.MessageBox("The website has changed.", "Website Change", 0)

我的问题是,我大部分时间都在使用远程桌面,所以当 MessageBox 弹出时它位于远程桌面会话后面,有没有办法强制 MessageBox 出现在它上面?

在类似的注释中,当脚本运行时,命令行会在我不想要的远程桌面会话中非常短暂地打开,有没有办法阻止这种行为?

我对 Windows 特定的解决方案很满意,因为我知道这可能意味着与窗口管理器打交道,或者可能是另一种通知我的方式,而不是使用 MessageBox。

【问题讨论】:

    标签: python windows user-interface


    【解决方案1】:

    当您从任务计划程序启动任何操作时,Windows 会阻止任何“简单”将您的窗口或对话框置于顶部的方式。

    1. 第一种方式 - 使用MB_SYSTEMMODAL(4096 值)标志。根据我的经验,它使 Msg 对话框“始终在最前面”。

      win32ui.MessageBox("The website has changed.", "Website Change", MB_SYSTEMMODAL)
      
    2. 第二种方式 - 尝试通过以下调用将您的控制台/窗口/对话框置于最前面。当然,如果你使用MessageBox,你必须在调用MessageBox之前这样做(对于你自己创建的窗口)。

      SetForegroundWindow(Wnd);
      BringWindowToTop(Wnd);
      SetForegroundWindow(Wnd);
      

    至于控制台窗口闪烁,您可以尝试在隐藏状态下启动Python。例如,使用ConEmu、“HidCon”或cmdow。参考他们的参数,比如:

    ConEmu -basic -MinTSA -cmd C:\Python27\python.exe C:\pythonScript.py
        or
    CMDOW /RUN /MIN C:\Python27\python.exe C:\pythonScript.py
    

    【讨论】:

    • 如果可行,那就太好了,谢谢,我明天才能尝试,但到时会回复你。关于防止命令窗口在 RDP 会话中弹出的任何想法,还是我必须忍受它?每 10 分钟弹出一次,这只是一个轻微的烦恼,而不是一个大问题。
    • 在任务调度程序中,我正在调用类似“C:\Python27\python.exe C:\pythonScript.py”的东西,它运行脚本并导致命令行弹出一秒钟在关闭之前。
    【解决方案2】:

    通过使用pyw 扩展名而不是简单的py 命名脚本来避免命令窗口闪烁。您也可以使用pythonw.exe 而不是python.exe,这真的取决于您的要求。

    http://onlamp.com/pub/a/python/excerpts/chpt20/index.html?page=2

    【讨论】:

    • 啊好主意,我想知道不同版本的用途。
    【解决方案3】:

    使用ctypes它显示一个windows错误消息框非常好用,

    import ctypes
    if condition:
        ctypes.windll.user32.MessageBoxW(0, u"Error", u"Error", 0)
    

    【讨论】:

      【解决方案4】:

      这对我有用:

      from ctypes import *
      def MessageBox(title, text, style):
          sty = int(style) + 4096
          return windll.user32.MessageBoxW(0, text, title, sty) #MB_SYSTEMMODAL==4096
          ## Button Styles:
          ###  0:OK  --  1:OK|Cancel -- 2:Abort|Retry|Ignore -- 3:Yes|No|Cancel -- 4:Yes|No -- 5:Retry|No -- 6:Cancel|Try Again|Continue
          ## To also change icon, add these values to previous number
          ### 16 Stop-sign  ### 32 Question-mark  ### 48 Exclamation-point  ### 64 Information-sign ('i' in a circle)
      

      用法:

      MessageBox('Here is my Title', 'Message to be displayed', 64)
      

      【讨论】:

      • 在您确认问题出在您这边后,请删除上述评论。
      【解决方案5】:

      使消息框系统模式化将导致它在每个应用程序上弹出,但在它被关闭之前无法与之交互。考虑创建一个可以放在前面的自定义对话框窗口,或者改用通知气泡。

      【讨论】:

      • “但在它被解除之前无法与之交互”实际上是不正确的。 MB_SYSTEMMODAL 意味着 MessageBox 将“始终在顶部”。就是这样。
      • 有没有办法打开一个强制与之交互的消息框?我只是在想,如果我在远程桌面上工作,我会点击很多,如果它出现在我的另一台显示器上并且很快被最小化,很可能会错过弹出窗口。
      • 您可以根据需要让气泡保持打开状态。
      【解决方案6】:

      Windows 试图使在活动应用程序上弹出窗口变得困难。用户觉得这很烦人,尤其是因为中断窗口通常会窃取键盘焦点。

      Windows 发出此类通知的方式是在通知区域中使用气球而不是消息框。通知气球不会窃取焦点,并且(据说)不会分散注意力。

      我不确定 python Windows UI 库是否为 notification balloons 提供包装器。

      【讨论】:

      • 我认为即使 Python 确实提供了通知包装器,这也行不通,通知会出现在远程桌面会话后面,不是吗?尽管 Outlook 设法让通知以某种方式出现在 RDP 会话的左上方..
      【解决方案7】:

      借助 Python 和 MSG 命令非常简单的模态异步消息框(在 Win10 上工作):

      # In CMD (you may use Username logged on target machine instead of * to send message to particular user):
      msg /server:IP_or_ComputerName * /v /time:appearance_in_secs Message_up_to_255_chars 
      # I.e. send "Hello everybody!" to all users on 192.168.0.110 disappearing after 5 mins 
      msg /server:192.168.0.110 * /v /time:300 "Hello everybody!"
      

      在 Python 中,我一直使用 subprocess 发送 CMD 命令,允许我读取和处理输出,查找错误等。

      import subprocess as sp
      
      name = 'Lucas'
      message = f'Express yourself {name} in 255 characters ;)'
      command = f'msg /server:192.168.0.110 * /v /time:360 "{message}"'
      output = str(sp.run(command, stdout=subprocess.PIPE, stderr=subprocess.STDOUT))
      
      if 'returncode=0' in output:
          pint('Message sent')
      else:
          print('Error occurred. Details:\n')
          print(output[output.index('stdout=b'):])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-03
        • 1970-01-01
        • 2011-09-10
        • 2010-09-05
        • 2022-11-10
        • 1970-01-01
        • 1970-01-01
        • 2013-08-15
        相关资源
        最近更新 更多