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.
Style of the original window is screwed up:
a) Before attaching (the calculator has a menu bar)
b) When attached (the calculator menu bar is gone)
c) When detached (the menu bar hasn't been restored properly)
I've already tried using flags/setFlags qt functions or getWindowLong/setWindowLong but I haven't had luck with all my attempts
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 (i.e. ctrl+break conemu, ctrl+c cmd prompt)... which indicates the code is not doing things correctly when parenting/deparenting
Additional notes:
explorer.exe
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With