从 QDockWidget 附加和分离外部应用程序时的问题 [英] Issues when attaching and detaching external app from QDockWidget

查看:48
本文介绍了从 QDockWidget 附加和分离外部应用程序时的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑一下这段代码:

import subprocess
import win32gui
import win32con
import time
import sys
from PyQt5.Qt import *  # noqa


class Mcve(QMainWindow):

    def __init__(self, path_exe):
        super().__init__()

        menu = self.menuBar()

        attach_action = QAction('Attach', self)
        attach_action.triggered.connect(self.attach)
        menu.addAction(attach_action)

        detach_action = QAction('Detach', self)
        detach_action.triggered.connect(self.detach)
        menu.addAction(detach_action)

        self.dock = QDockWidget("Attach window", self)
        self.addDockWidget(Qt.RightDockWidgetArea, self.dock)

        p = subprocess.Popen(path_exe)
        time.sleep(0.5)  # Give enough time so FindWindowEx won't return 0
        self.hwnd = win32gui.FindWindowEx(0, 0, "CalcFrame", None)
        if self.hwnd == 0:
            raise Exception("Process not found")

    def detach(self):
        try:
            self._window.setParent(None)
            # win32gui.SetWindowLong(self.hwnd, win32con.GWL_EXSTYLE, self._style)
            self._window.show()
            self.dock.setWidget(None)
            self._widget = None
            self._window = None
        except Exception as e:
            import traceback
            traceback.print_exc()

    def attach(self):
        # self._style = win32gui.GetWindowLong(self.hwnd, win32con.GWL_EXSTYLE)
        self._window = QWindow.fromWinId(self.hwnd)
        self._widget = self.createWindowContainer(self._window)
        self.dock.setWidget(self._widget)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Mcve("C:\\Windows\\system32\\calc.exe")
    w.show()
    sys.exit(app.exec_())

这里的目标是修复代码,以便正确地将窗口附加/分离到 QDockWidget.目前,代码有两个重要问题.

The goal here is to fix the code so the window attaching/detaching into a QDockWidget will be made properly. Right now, the code has 2 important issues.

原来窗口的样式搞砸了:

Style of the original window is screwed up:

a) 附加前(计算器有菜单栏)

a) Before attaching (the calculator has a menu bar)

b) 附加后(计算器菜单栏不见了)

b) When attached (the calculator menu bar is gone)

c) 分离时(菜单栏没有正确恢复)

c) When detached (the menu bar hasn't been restored properly)

我已经尝试过使用 flags/setFlags qt 函数或 getWindowLong/setWindowLong 但我的所有尝试都没有成功

I've already tried using flags/setFlags qt functions or getWindowLong/setWindowLong but I haven't had luck with all my attempts

如果您已经将计算器附加和分离到主窗口,然后您决定关闭主窗口,那么您肯定希望所有内容(pyqt 进程)都被正确关闭和清理.现在,情况并非如此,为什么?

If you have attached and detached the calculator to the mainwindow, and then you decide to close the mainwindow, you definitely want everything (pyqt process) to be closed and cleaned properly. Right now, that won't be the case, why?

实际上,当您将计算器附加/分离到主窗口时,python 进程将保持,您需要手动强制终止进程(即 ctrl+break conmu,ctrl+c cmd 提示符)...这表明代码在为人父母/去父母时没有正确做事

In fact, when you've attached/detached the calculator to the mainwindow, the python process will hold and you'll need to force the termination of the process manually (i.e. ctrl+break conemu, ctrl+c cmd prompt)... which indicates the code is not doing things correctly when parenting/deparenting

附加说明:

推荐答案

我发现部分问题需要关闭.因此,当您在 attach 函数中创建 self._window 并关闭 MainWindow 时,该其他窗口(线程)仍处于静止状态.因此,如果您在 __init__ 函数中添加 self._window = None 并添加如下 __del__ 函数,则该部分是固定的.仍然不确定缺少菜单.我还建议使用 self.__p 保持子进程句柄,而不是放手.也将其包含在 __del__ 中.

I found part of the issue wrt to closing. So when you are creating the self._window in the attach function and you close the MainWindow, that other window (thread) is sitting around still. So if you add a self._window = None in the __init__ function and add a __del__ function as below, that part is fixed. Still not sure about the lack of menu. I'd also recommend holding onto the subprocess handle with self.__p instead of just letting that go. Include that in the __del__ as well.

    def __del__(self):
        self.__p.terminate()
        if self._window:
            print('terminating window')
            self._window.close

可能更好的是包含一个 closeEvent

Probably better yet would be to include a closeEvent

    def closeEvent(self, event):
        print('Closing time')
        self.__p.terminate()
        if self._window is not None:
            print('terminating window')
            self._window.close

这篇关于从 QDockWidget 附加和分离外部应用程序时的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆