我正在尝试使用Python为第三方应用程序编写HUD。
我已经能够确保我的HUD在第三方应用程序移动时跟随第三方应用程序,但我很难确保HUD始终显示在第三方应用程序的顶部,并在最小化或其他应用程序转到前台时消失。
我已经尝试了Window的一些函数(SetWindowPos、BringWindowToTop和SetForegroundWindow),但这些函数都没有给出预期的结果: HUD始终位于第三方应用程序之后。
下面是一个简单的代码示例来说明我的问题:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import ctypes
import ctypes.wintypes
user32 = ctypes.windll.user32
HUD_WIDTH = 100
HUD_HEIGHT = 50
WINDOW_NAME = "Window name" #Replace this by the name of an opened window
EVENT_OBJECT_LOCATIONCHANGE = 0x800B
EVENT_SYSTEM_FOREGROUND = 0x0003
WINEVENT_OUTOFCONTEXT = 0x0000
EVENT_SYSTEM_MINIMIZEEND = 0x0017
class Hud(QLabel):
def __init__(self,window_handle):
super().__init__()
self.initUI()
self.window_handle = window_handle
rect = ctypes.wintypes.RECT()
user32.GetWindowRect(window_handle,ctypes.byref(rect))
self.window_x = rect.left
self.window_y = rect.top
self.setFollowWindow()
def initUI(self):
self.setWindowFlags(Qt.Window | Qt.FramelessWindowHint)
self.resize(HUD_WIDTH,HUD_HEIGHT)
p = self.palette()
p.setColor(self.backgroundRole(), Qt.black)
p.setColor(self.foregroundRole(),Qt.white)
self.setPalette(p)
self.setWindowOpacity(0.7)
self.setText("Hello")
self.setAlignment(Qt.AlignCenter)
self.show()
def mousePressEvent(self,event):
self.click_x_coordinate = event.x()
self.click_y_coordinate = event.y()
def mouseMoveEvent(self,event):
self.move(event.globalX()-self.click_x_coordinate,event.globalY()-self.click_y_coordinate)
def setFollowWindow(self):
WinEventProcType = ctypes.WINFUNCTYPE(
None,
ctypes.wintypes.HANDLE,
ctypes.wintypes.DWORD,
ctypes.wintypes.HWND,
ctypes.wintypes.LONG,
ctypes.wintypes.LONG,
ctypes.wintypes.DWORD,
ctypes.wintypes.DWORD
)
def callback(hWinEventHook, event, hwnd, idObject, idChild, dwEventThread, dwmsEventTime):
if idObject != -9: #Avoids mouse events
if event == EVENT_OBJECT_LOCATIONCHANGE and hwnd == self.window_handle:
rect = ctypes.wintypes.RECT()
user32.GetWindowRect(hwnd,ctypes.byref(rect))
self.move(self.x() + rect.left - self.window_x,self.y() + rect.top - self.window_y)
self.window_x = rect.left
self.window_y = rect.top
elif event == EVENT_SYSTEM_FOREGROUND or event == EVENT_SYSTEM_MINIMIZEEND:
if hwnd == self.window_handle:
user32.SetWindowPos(self.winId().__int__(),-1,self.x(),self.y(),self.width(),
self.height())
self.WinEventProc = WinEventProcType(callback)
user32.SetWinEventHook.restype = ctypes.wintypes.HANDLE
self.hook = user32.SetWinEventHook(
EVENT_SYSTEM_FOREGROUND,
EVENT_OBJECT_LOCATIONCHANGE,
0,
self.WinEventProc,
0,
0,
WINEVENT_OUTOFCONTEXT
)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
self.initUI()
def initUI(self):
self.launch_hud_button = QPushButton("Launch HUD",self)
self.launch_hud_button.clicked.connect(self.launchHud)
self.show()
def launchHud(self):
window_handle = user32.FindWindowW(0,WINDOW_NAME)
if window_handle != 0 :
self.hud = Hud(window_handle)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_())我还尝试使用SetParent将第三方应用程序设置为我的HUD的父应用程序,但当我这样做时,我的HUD根本不显示。
你有什么建议让它使用Window或其他什么东西来工作吗?
发布于 2019-07-16 21:31:38
通过将HUD父类设置为QMainWindow而不是QLabel,并删除对setWindowOpacity的调用,我最终设法确保我的HUD始终位于给定的第三方应用程序的顶部。以下代码适用于我:
import sys
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import ctypes
import ctypes.wintypes
user32 = ctypes.windll.user32
HUD_WIDTH = 100
HUD_HEIGHT = 50
WINDOW_NAME = "Window name" #Replace this by the name of an opened window
class Hud(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
self.hwnd = self.winId().__int__()
def initUI(self):
self.setWindowFlags(Qt.FramelessWindowHint)
self.resize(HUD_WIDTH,HUD_HEIGHT)
self.textArea = QLabel()
self.setCentralWidget(self.textArea);
self.setStyleSheet("background-color: rgb(0, 0, 0);color: rgb(255,255,255);")
self.textArea.setText("Hello")
self.textArea.setAlignment(Qt.AlignCenter)
self.show()
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow,self).__init__()
self.initUI()
def initUI(self):
self.launch_hud_button = QPushButton("Launch HUD",self)
self.launch_hud_button.clicked.connect(self.launchHud)
self.show()
def launchHud(self):
window_handle = user32.FindWindowW(0,WINDOW_NAME)
if window_handle != 0 :
self.hud = Hud()
user32.SetParent(self.hud.hwnd,window_handle)
if __name__ == '__main__':
app = QApplication(sys.argv)
main_window = MainWindow()
sys.exit(app.exec_()) 如果有人知道为什么QMainWindow适用于SetParent而不是像QLabel这样的其他Qt类,或者为什么修改窗口不透明度会导致不可见的HUD (对SetParent的调用不会返回0,所以我假设HUD实际上被设置为我的第三方应用程序的子类,但被绘制为完全透明),我会非常感兴趣。
发布于 2019-03-04 06:21:37
试试看:
# ...
def launchHud(self):
window_handle = user32.FindWindowW(0,WINDOW_NAME)
if window_handle != 0 :
self.hud = Hud(window_handle)
self.hud.setWindowFlags(self.windowFlags() | # <---
Qt.FramelessWindowHint | # <---
Qt.WindowStaysOnTopHint) # <---
self.hud.show() # <--- !!!
# ...https://stackoverflow.com/questions/54973359
复制相似问题