Wednesday, 30 January 2019

Issues when attaching and detaching external app from QDockWidget

Consider this little piece of code:

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_())

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.

Issue1

Style of the original window is screwed up:

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

enter image description here

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

enter image description here

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

enter image description here

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

Issue2

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?

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 (ie: ctrl+break conemu, ctrl+c cmd prompt)... which indicates the code is not doing things correctly when parenting/deparenting

Additional notes:



from Issues when attaching and detaching external app from QDockWidget

No comments:

Post a Comment