PyQt5 应用在 TeamViewer 下无法使用全屏模式

PyQt5 应用在 TeamViewer 下无法使用全屏模式

问题描述

使用 PyQt5 (版本为 5.7)中的 QtWebEngineView 构建的桌面应用,部署到远程机器(Windows 7 平台)上以全屏模式运行时,通过 teamviewer 观察到远程桌面没有变化,但是鼠标右键后会弹出菜单选项,与正常打开的 QtWebEngineView 弹出的菜单选项一致。而且直接在远程机器上运行的应用程序在显示器上显示正常,但是无法通过 teamviewer 远程观察。

部分代码:

view = QtWebEngineView()
view.setWindowFlags(Qt.FramelessWindowHint)
view.setUrl(QUrl("http://localhost:{}/".format(port)))
view.show()

分析问题并解决新产生的问题

推测是 teamviewer 无法捕捉到应用全屏后的界面,使用 Print Screen 按键截图后显示的图片也表示该应用的界面无法被捕捉。由于应用的使用场景需要,应用必须全屏,运行时不能漏出 Windows 的任务栏。所以尝试了多种解决方案:

  1. view.showFullScreen() 这种方法尝试过,但很快就发现有问题,并且不仅仅是 PyQt5 构建的应用无法远程监控,包括直接使用 Qt C++ 的代码编译的程序也无法通过远程监控。推测是 QWebEngineView 的原因导致的。
  2. 根据目标机器的屏幕分辨率,调整应用窗口的大小,比如目标机器的分辨率为 1024x768,在高度上减少一个像素,使应用窗口为 1024x767,然后使用 view.show(),即可显示,并能通过 teamviewer 远程观察。

第二种方法是可行的,但它仍然存在一个问题,Windows 桌面底部的任务栏会把应用程序的界面挡住。为了让这个应用程序界面置顶,需要设置窗口的标志位为 Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint

然后程序就可以正常运行了。但是新的问题又出现了,使用了 Qt.WindowStaysOnTopHint 标志位后,程序确实能够置顶,并且不会被任务栏挡住,但是当使用 alt + tab 组合键切换程序时,其他程序也会被该应用遮挡住,导致无法显示。(在实际使用中没有关系,但是在开发过程中有些头疼)

为了保持应用窗口的置顶效果,并使切换应用时,PyQt 应用不再置顶,可以定义一个 QWebEngineView 的子类,重写 changeEvent 方法:

class MyWebView(QWebEngineView):
    def __init__(self, app):
        super(MyWebView, self).__init__()
        self.app = app

    def changeEvent(self, event):
        if event.type() == QEvent.ActivationChange:
            active = self.isActiveWindow()
            if active:
                self.setWindowFlags( self.windowFlags() | Qt.WindowStaysOnTopHint )
                if not self.isVisible():
                    self.show()
                    self.activateWindow()
            else:
                self.setWindowFlags( self.windowFlags() & ~Qt.WindowStaysOnTopHint )
                if not self.isVisible():
                    self.show()

changeEvent 中,处理窗口激活事件,当窗口处于激活状态时,在标志位中增加 Qt.WindowStaysOnTopHint,否则就去除这个标志位。当窗口的标志位改变时,窗口将会处于不可见的状态(可以打印 self.isVisible() 的值查看),所以需要再次调用 self.show() 方法显示窗口。

这里有个很坑的地方,如果不设置窗口的属性,调用 show() 方法后会自动激活窗口,即 self.isActiveWindow() 会返回 True,首次打开应用时这是理所应当的。但是当切换几次后就会发现窗口将会永远置顶(或者没法置顶了)。分析一下 changeEvent 的代码流程就清楚了。

永远置顶的情况是:

  1. 首次打开应用时,窗口处于 visible、active 状态;
  2. 切换应用时,此时将会触发 changeEvent 事件,调用 MyWebView 实例的 changeEvent() 方法,判断当前窗口是非激活状态的,因此修改标志位为 self.windowFlags() & ~Qt.WindowStaysOnTopHint,修改标志位后重新显示窗口,调用 self.show() 方法,显示窗口。
  3. 由于 show() 方法调用后,会自动激活窗口,Qt 的事件循环机制导致 changeEvent() 方法再次被调用,此时窗口处于激活状态,将重新修改标志位为 self.windowFlags() | Qt.WindowStaysOnTopHint,使得切换窗口后,其他程序仍然会被本应用遮挡。

永不置顶的情况是最后不论是哪种状态,标志位都会被改成不含 Qt.WindowStaysOnTopHint 的,因此就永远无法置顶了。

为了解决这个问题,就必须要将 show() 的调用和窗口激活分开,为此需要设置窗口的属性为:

view.setAttribute( Qt.WA_ShowWithoutActivating )

这样就可以实现在激活应用时窗口置顶,切换到其他程序时,应用窗口不置顶(如果其他应用显示的窗口下,可以看到本应用将堆叠在其他程序下面)。

关闭程序

上述代码解决了窗口置顶和显示其他程序时不置顶的需求,但是当你打开任务栏想要关闭程序的时候,发现程序关不掉了。只好重写 closeEvent() 方法:

def closeEvent(self, event):
    self.activateWindow()
    self.destroy()
    self.app.quit()
    from time import sleep
    sleep(1)
    sys.exit(0)

当点击窗口关闭按钮(实际上是没有的,因为会被设置成无边框窗口),或在任务栏中点击右键关闭时,程序将会终止,退出 Python 进程。

其他值得提及的部分

在主函数中,有行代码是特意加上去的:

view.settings().setAttribute( QWebEngineSettings.Accelerated2dCanvasEnabled, False)

这是因为远程机器没有显卡,因此无法使用显卡加速功能,但 QWebEngineView 如果默认会启用 QWebEngineSettings.Accelerated2dCanvasEnabled 这个属性,导致程序在远程机器上运行的时候,图表显示的功能会出现异常。因此需要显式关闭该属性。

小结

Qt 的界面为 Python 桌面应用开发带来了很多方便,但是由于环境的差异导致程序会出现一些不可名状的异常。在资料比较少的情况下,自己尝试摸索出代码的执行流程并且给出解决方案其实是挺耗时间的。不过好在最终成功解决了问题。

参考代码可在 github 上获取。

原文地址:https://www.cnblogs.com/brifuture/p/10225560.html

时间: 2024-08-05 00:23:01

PyQt5 应用在 TeamViewer 下无法使用全屏模式的相关文章

火狐浏览器下连接a下无法使用select下拉菜单

火狐浏览器下连接a下无法使用select下拉菜单:如果select下拉菜单包裹在链接a中,则无法实现选中效果,当然如此使用在实际应用中也是很少见的,不过下面还是做一下简单介绍,如何避免此种问题的出现,寄希望能够给需要者带来一定的帮助.代码实例如下: <!DOCTYPE html> <html> <head> <meta charset=" utf-8"> <meta name="author" content=&

centos6下无法使用lsof命令&quot;-bash: lsof: command not found&quot;

1. 问题描述 在centos下, 无法使用命令lsof, 出现以下信息: # lsof -i:3690 -bash: lsof: command not found 2. 解决方法 我们可以通过yum来安装: # yum install lsof 本人操作如下: # yum install lsof Loaded plugins: fastestmirror Setting up Install Process Loading mirror speeds from cached hostfil

aspupload ,在winows server 2008 下无法使用

aspupload ,在winows server 2008 下无法使用.求助解决办法 2014-01-12 13:31 goolean | 浏览 775 次 操作系统 aspupload64位,安装后,用探针能检测出,是 V3.1 64位,但无论怎么样都不能正常执行,提示Invalid key length. Should be 76 characters.主要是为了上传大一些的文件,无组件的根本没办法,若真不能用aspupload, 有其它解决办法也可以 2014-01-13 15:31 提

命令在root用户下无法使用

有些命令在自己的用户下可以用,但是在root用户下不能用是因为环境变量设置问题. 自己个人目录下的bashrc文件是个人的环境变量. etc下的proflie和enviroment是公共环境变量. 如果确实设置了公共环境变量,root用户下还是无法使用命令,则是因为环境变量路径设置有问题. 比如-用来代替/home/用户名 就会出现这样的问题,所以环境变量中不推荐使用-. 把环境变量中的-变更成/home/用户名,问题就解决了.

pyqt5 VS tk python2 下比较

最近看了下pyqt5,介于页面比较美观,画界面的工具也比较好用,做了相同的界面,分别用pyinstaller打包成exe来做个对比 1界面风格,美观度 左边是qt,右边是tk 可以看出风格完全是2个类型,qt风格比较win7,tk风格xp经典 当然tk也有主题库ttk,能开发出和qt差不多的界面,不过这里就不再讨论了 2界面开发难度 qt有designer来画图,只要拖拽就能完成界面设计 tk有vb的插件,可以在vb里面拖拽完成界面设计 不过从组件丰富度来说,tk是不如qt的 两者都可以生成界面

Winio驱动在64位windows下无法使用的解决方法

C#在使用WinIo的驱动开发类似按键精灵一类工具的时候,需要对相关的驱动进行注册才能正常启动,找了下资料,资料来自: http://jingyan.baidu.com/article/642c9d34e55bd9644b46f74e.html 我在这里进行转载: Winio驱动在64位windows下无法正常安装驱动,只能重启后禁用签名强制才能安装,用了网上的方法还是必须重启禁用签名强制才能正常使用,既然一定要这样才行,那就顺着它来. 从网上下载Bootice V1.3.3或以上版本,注意要下

sqlplus的session下无法使用退格键的问题处理

可能用过sqlplus的人都知道,在sqlplus连接上Oracle后的session界面中是无法正常使用方向键和退格键的,这个是一个比较麻烦的一点,往往有一句sql写错了,不能修改还要重新开始十分的麻烦,用过MySQL的人一定不习惯这样,不过好在Linux系统下有提供2个很好用的工具能解决这个问题,它们就是rlwrap和readline,通过这两个工具启动sqlplus就能解决在session中编辑的问题和添加类似于系统的history的功能,当然安装的时候建议配置好yum源,记得要配置epe

解决phpMyAdmin在nginx+php-fpm模式下无法使用的问题

昨天接到一个网友的问题,说yum安装nginx+php-fpm+mysql+phpMyAdmin后,发现phpMyAdmin无法打开,一直报502错误已经抓狂半天了,本着帮助别人快乐自己的原则,远程帮他看了一下, 现记录和总结如下,问题解决思路的总结放在文章最后,问题解决思路总结也是本文的重点. 问题环境:CentOS6通过yum安装的nginx+php-fpm+mysql+phpMyAdmin 问题描述:安装完成后发现nginx没有问题,而phpMyAdmin无法打开,提示502错误 问题解决

Vbox虚拟机装CentOS,在桥接模式下无法使用yum的问题解决

执行yum操作,报错: YumRepo Error: All mirror URLs are not using ftp, http[s] or file. Eg. $releasever is not a valid release or hasnt been released yet/removing mirrorlist with no valid mirrors: /var/cache/yum/base/mirrorlist.txtError: Cannot retrieve repos