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

问题描述

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

部分代码:

  1. view = QtWebEngineView()
  2. view.setWindowFlags(Qt.FramelessWindowHint)
  3. view.setUrl(QUrl("http://localhost:{}/".format(port)))
  4. 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 方法:

  1. class MyWebView(QWebEngineView):
  2. def __init__(self, app):
  3. super(MyWebView, self).__init__()
  4. self.app = app
  5. def changeEvent(self, event):
  6. if event.type() == QEvent.ActivationChange:
  7. active = self.isActiveWindow()
  8. if active:
  9. self.setWindowFlags( self.windowFlags() | Qt.WindowStaysOnTopHint )
  10. if not self.isVisible():
  11. self.show()
  12. self.activateWindow()
  13. else:
  14. self.setWindowFlags( self.windowFlags() & ~Qt.WindowStaysOnTopHint )
  15. if not self.isVisible():
  16. 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() 的调用和窗口激活分开,为此需要设置窗口的属性为:

  1. view.setAttribute( Qt.WA_ShowWithoutActivating )

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

关闭程序

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

  1. def closeEvent(self, event):
  2. self.activateWindow()
  3. self.destroy()
  4. self.app.quit()
  5. from time import sleep
  6. sleep(1)
  7. sys.exit(0)

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

其他值得提及的部分

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

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

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

小结

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

参考代码可在 github 上获取。

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

  1. centos6下无法使用lsof命令"-bash: lsof: command not found"

    1. 问题描述在centos下, 无法使用命令lsof, 出现以下信息:# lsof -i:3690-bash: lsof: command not found2. 解决方法我们可以通过yum来安装: ...

  2. aspupload ,在winows server 2008 下无法使用

    aspupload ,在winows server 2008 下无法使用.求助解决办法 2014-01-12 13:31 goolean | 浏览 775 次 操作系统 aspupload64位,安装 ...

  3. 解决Windows x64bit环境下无法使用PLSQL Developer连接到Oracle DB中的问题

    本文是原创文章,转载请注明出处: http://blog.csdn.net/msdnchina/article/details/46416455 解决Windows x64bit环境下无法使用PLSQ ...

  4. 关于Markdown下无法使用表格的解决方案

    关于Markdown下无法使用表格的解决方案 写表格,出现如下场景 解决方法.点击左下角M的表示,切换到extra模式 打开了新世界.如果不能点击,估计是你没有激活pro的权限,百度下就可以了. 或者 ...

  5. 解决JSON.stringify()在IE10下无法使用的问题

    今天在IE10下遇到了JSON.stringify()无法使用的问题,错误信息为:'JSON' is undefined . 开始以为是没有添加json2.js引用的原因.后来发现,其他地方也没添加j ...

  6. 解决Oracle在命令行下无法使用del等键问题

    前言: Oracle使用Linux命令行进行编辑? 有PL/SQL development,SQL development等工具,为何用Linux命令行? 但也免不了有用的的时候 以下是解决在Linu ...

  7. PyQt5之使用Qt下的designer工具将.ui文件转换成.py文件后添加什么东西后方可运行

    首先证明我是加了那些鬼东西以后可以成功运行的. 然后来叙述一下我的过程. 这是一个.ui文件生成的.py文件.(把主要的内容省去了,但是没有影响结构) # -*- coding: utf-8 -*- ...

  8. [linux]关于deepin截图软件在KDE桌面下无法使用粘贴的解决方法

    -------更新----- 1.其实不如直接关闭klipper启动程序 # rm -rf /usr/share/plasma/plasmoids/org.kde.plasma.clipboard 2 ...

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

    C#在使用WinIo的驱动开发类似按键精灵一类工具的时候,需要对相关的驱动进行注册才能正常启动,找了下资料,资料来自: http://jingyan.baidu.com/article/642c9d3 ...

随机推荐

  1. linux权限及目录

    [-][rwx][r-x][r--] r:4 - 读  w:2 - 写  x:1 - 执行 1:代表文件类型 2:代表文件所有者的权限 3:代表文件所在组的权限 4:代表其他用户的权限 chgrp:修 ...

  2. Qt学习(二):项目学习

    1. 概述 Qt做UI设计后,通常会生成Form Files文件夹下的ui文件.Generated File文件夹下的ui_xxx等头文件和源文件.Header Files文件夹下的头文件.Sourc ...

  3. 爆款AR游戏如何打造?网易杨鹏以《悠梦》为例详解前沿技术

    本文来自网易云社区. 7月31日,2018云创大会游戏论坛在杭州国际博览中心103B圆满举行.本场游戏论坛聚焦探讨了可能对游戏行业发展有重大推动的新技术.新实践,如AR.区块链.安全.大数据等. 网易 ...

  4. linux 修改主机名 【root@主机名 ~】

    centos 7修改方式: hostnamectl  set-hostname   hostuser reboot 或者直接vi /etc/hostname 添加内容: hostuser 检查修改效果 ...

  5. Sublime Text3 最新版3207 安装及破解

    注:原文地址 https://www.abbeyok.com/archives/337 Sublime Text 3最近更新了新版本,最新版本:3207,之前的license无效了,新版破解方法如下: ...

  6. STR[#6]

    photo 小明在旅游的路上看到了一条美丽的河,河上有许多船只,有的船只向左航行,有的船只向右航行.小明希望拍下这一美丽的风景,并且把尽可能多的船只都完整地拍到一张照片中. 小明位于河的边上,并且可以 ...

  7. Linux系统如何迁移至LVM磁盘

    今天遇到一个问题,算是比较严重的把.就是要把当前系统转移到 LVM 卷里面去,下面有一些发生过程介绍. 不感兴趣可以直接跳过,看实战部分<如何迁移系统至LVM卷> 朋友今天突然找我,说是要 ...

  8. 极光大数据告诉你,程序员们都在"愁"些啥?

    有言道:隔行如隔山.面对不甚熟悉的人群和岗位,我们很容易在固有印象的干扰下,作出一些偏离实际的解读.比如在很多外行人眼中,程序员群体的固有形象是性格木讷,生活方式通常也比较宅.他们最大的爱好就是玩游戏 ...

  9. 【转】【C++专题】C++ sizeof 使用规则及陷阱分析

    提示:下文例子都经过Visual C++ 6.0验证,平台为win32 Windows. 一.什么是sizeof 首先看一下sizeof在msdn上的定义: The sizeof keyword gi ...

  10. 基础篇:6.9)GD&T较线性尺寸公差的优缺点

    本章目的:理解GD&T标注对比线性/传统/坐标尺寸公差的优势,但也不要忘记其使用限制. 1.线性尺寸公差   1.1 定义 线性尺寸公差=传统尺寸公差=坐标尺寸公差. 传统尺寸公差(Tradi ...