2019-01-01 17:04:10 +08:00
|
|
|
|
#!/usr/bin/env python
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Created on 2018年3月1日
|
|
|
|
|
@author: Irony
|
2021-07-13 14:52:26 +08:00
|
|
|
|
@site: https://pyqt.site , https://github.com/PyQt5
|
2019-01-01 17:04:10 +08:00
|
|
|
|
@email: 892768447@qq.com
|
|
|
|
|
@file: EmbedWindow
|
|
|
|
|
@description: 嵌入外部窗口
|
|
|
|
|
"""
|
|
|
|
|
|
2018-10-28 16:36:14 +08:00
|
|
|
|
import win32con
|
|
|
|
|
import win32gui
|
2021-07-13 14:52:26 +08:00
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
from PyQt5.QtCore import Qt
|
|
|
|
|
from PyQt5.QtGui import QWindow
|
|
|
|
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QListWidget, \
|
|
|
|
|
QLabel, QApplication
|
|
|
|
|
except ImportError:
|
|
|
|
|
from PySide2.QtCore import Qt
|
|
|
|
|
from PySide2.QtGui import QWindow
|
|
|
|
|
from PySide2.QtWidgets import QWidget, QVBoxLayout, QPushButton, QListWidget, \
|
|
|
|
|
QLabel, QApplication
|
2018-10-28 16:36:14 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Window(QWidget):
|
|
|
|
|
|
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
|
super(Window, self).__init__(*args, **kwargs)
|
|
|
|
|
self.resize(800, 600)
|
|
|
|
|
layout = QVBoxLayout(self)
|
|
|
|
|
|
|
|
|
|
self.myhwnd = int(self.winId()) # 自己的句柄
|
|
|
|
|
|
|
|
|
|
layout.addWidget(QPushButton('获取所有可用、可视窗口', self,
|
|
|
|
|
clicked=self._getWindowList, maximumHeight=30))
|
2021-05-26 17:40:14 +08:00
|
|
|
|
layout.addWidget(QPushButton('释放窗口', clicked=self.releaseWidget, maximumHeight=30))
|
2018-10-28 16:36:14 +08:00
|
|
|
|
layout.addWidget(
|
|
|
|
|
QLabel('双击列表中的项目则进行嵌入目标窗口到下方\n格式为:句柄|父句柄|标题|类名', self, maximumHeight=30))
|
|
|
|
|
self.windowList = QListWidget(
|
|
|
|
|
self, itemDoubleClicked=self.onItemDoubleClicked, maximumHeight=200)
|
|
|
|
|
layout.addWidget(self.windowList)
|
|
|
|
|
|
2021-05-26 17:40:14 +08:00
|
|
|
|
def releaseWidget(self):
|
|
|
|
|
"""释放窗口"""
|
|
|
|
|
if self.layout().count() == 5:
|
|
|
|
|
self.restore()
|
|
|
|
|
self._getWindowList()
|
|
|
|
|
|
2018-10-28 16:36:14 +08:00
|
|
|
|
def closeEvent(self, event):
|
|
|
|
|
"""窗口关闭"""
|
2021-05-26 17:40:14 +08:00
|
|
|
|
self.releaseWidget()
|
2018-10-28 16:36:14 +08:00
|
|
|
|
super(Window, self).closeEvent(event)
|
|
|
|
|
|
|
|
|
|
def _getWindowList(self):
|
|
|
|
|
"""清空原来的列表"""
|
|
|
|
|
self.windowList.clear()
|
|
|
|
|
win32gui.EnumWindows(self._enumWindows, None)
|
|
|
|
|
|
|
|
|
|
def onItemDoubleClicked(self, item):
|
|
|
|
|
"""列表双击选择事件"""
|
|
|
|
|
# 先移除掉item
|
|
|
|
|
self.windowList.takeItem(self.windowList.indexFromItem(item).row())
|
|
|
|
|
hwnd, phwnd, _, _ = item.text().split('|')
|
|
|
|
|
# 开始嵌入
|
2021-05-26 17:40:14 +08:00
|
|
|
|
self.releaseWidget()
|
2018-10-28 16:36:14 +08:00
|
|
|
|
hwnd, phwnd = int(hwnd), int(phwnd)
|
|
|
|
|
# 嵌入之前的属性
|
|
|
|
|
style = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE)
|
|
|
|
|
exstyle = win32gui.GetWindowLong(hwnd, win32con.GWL_EXSTYLE)
|
2021-05-26 17:40:14 +08:00
|
|
|
|
wrect = win32gui.GetWindowRect(hwnd)[:2] + win32gui.GetClientRect(hwnd)[2:]
|
|
|
|
|
print('save', hwnd, style, exstyle, wrect)
|
2018-10-28 16:36:14 +08:00
|
|
|
|
|
|
|
|
|
widget = QWidget.createWindowContainer(QWindow.fromWinId(hwnd))
|
|
|
|
|
widget.hwnd = hwnd # 窗口句柄
|
|
|
|
|
widget.phwnd = phwnd # 父窗口句柄
|
|
|
|
|
widget.style = style # 窗口样式
|
|
|
|
|
widget.exstyle = exstyle # 窗口额外样式
|
2021-05-26 17:40:14 +08:00
|
|
|
|
widget.wrect = wrect # 窗口位置
|
2018-10-28 16:36:14 +08:00
|
|
|
|
self.layout().addWidget(widget)
|
|
|
|
|
|
2021-05-26 17:40:14 +08:00
|
|
|
|
widget.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint)
|
|
|
|
|
win32gui.SetParent(hwnd, int(self.winId()))
|
|
|
|
|
|
2018-10-28 16:36:14 +08:00
|
|
|
|
def restore(self):
|
|
|
|
|
"""归还窗口"""
|
|
|
|
|
# 有bug,归还后窗口没有了WS_VISIBLE样式,不可见
|
2021-05-26 17:40:14 +08:00
|
|
|
|
widget = self.layout().itemAt(4).widget()
|
|
|
|
|
hwnd, phwnd, style, exstyle, wrect = widget.hwnd, widget.phwnd, widget.style, widget.exstyle, widget.wrect
|
|
|
|
|
print('restore', hwnd, phwnd, style, exstyle, wrect)
|
2018-10-28 16:36:14 +08:00
|
|
|
|
widget.close()
|
|
|
|
|
self.layout().removeWidget(widget) # 从布局中移出
|
|
|
|
|
widget.deleteLater()
|
|
|
|
|
|
2021-05-26 17:40:14 +08:00
|
|
|
|
win32gui.SetParent(hwnd, phwnd) # 让它返回它的父窗口
|
|
|
|
|
win32gui.SetWindowLong(hwnd, win32con.GWL_STYLE, style | win32con.WS_VISIBLE) # 恢复样式
|
|
|
|
|
win32gui.SetWindowLong(hwnd, win32con.GWL_EXSTYLE, exstyle) # 恢复样式
|
|
|
|
|
win32gui.ShowWindow(hwnd, win32con.SW_SHOW) # 显示窗口
|
|
|
|
|
win32gui.SetWindowPos(hwnd, 0, wrect[0], wrect[1], wrect[2], wrect[3], win32con.SWP_NOACTIVATE)
|
|
|
|
|
|
2018-10-28 16:36:14 +08:00
|
|
|
|
def _enumWindows(self, hwnd, _):
|
|
|
|
|
"""遍历回调函数"""
|
|
|
|
|
if hwnd == self.myhwnd:
|
|
|
|
|
return # 防止自己嵌入自己
|
|
|
|
|
if win32gui.IsWindow(hwnd) and win32gui.IsWindowVisible(hwnd) and win32gui.IsWindowEnabled(hwnd):
|
|
|
|
|
phwnd = win32gui.GetParent(hwnd)
|
|
|
|
|
title = win32gui.GetWindowText(hwnd)
|
|
|
|
|
name = win32gui.GetClassName(hwnd)
|
|
|
|
|
self.windowList.addItem(
|
|
|
|
|
'{0}|{1}|\t标题:{2}\t|\t类名:{3}'.format(hwnd, phwnd, title, name))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
import sys
|
2021-05-26 17:40:14 +08:00
|
|
|
|
import cgitb
|
|
|
|
|
|
2021-07-13 14:52:26 +08:00
|
|
|
|
cgitb.enable(format='text')
|
2021-05-26 17:40:14 +08:00
|
|
|
|
|
2018-10-28 16:36:14 +08:00
|
|
|
|
app = QApplication(sys.argv)
|
|
|
|
|
w = Window()
|
|
|
|
|
w.show()
|
|
|
|
|
sys.exit(app.exec_())
|