WA_TranslucentBackground Frameless windows problem with WIN32 API SetParent
-
Hello,
Here is video: https://streamable.com/0a6q8r
When I use my custom Frameless and rounded form (I must use Qt.WA_TranslucentBackground for rounded form), WIN32API SetParent doesn't work.
But when normal window (no custom form or custom form WITHOUT WA_TranslucentBackground), SetParent API works fine.
I'm waiting for your help, Thanks!Here is my code:
import sys,os, subprocess, psutil, time import win32gui from win32con import * from PySide6 import QtCore, QtWidgets from PySide6.QtWidgets import * from PySide6.QtCore import * from PySide6.QtGui import * BORDERLESS_CUSTOM_FORM = True class MACTema(QDialog): def __init__(self, w, parent=None): QDialog.__init__(self, parent) self.parent = parent self._w = w self.setupUi() contentLayout = QHBoxLayout() contentLayout.setContentsMargins(0, 3, 0, 3) contentLayout.addWidget(w) self.windowContent.setLayout(contentLayout) self.setWindowTitle(w.windowTitle()) self.setGeometry(w.geometry()) self._w.setAttribute(Qt.WA_DeleteOnClose, True) self._w.destroyed.connect(self.__child_was_closed) def setupUi(self): self.vboxWindow = QtWidgets.QVBoxLayout(self) self.vboxWindow.setContentsMargins(0, 0, 0, 0) self.windowFrame = QWidget(self) self.windowFrame.setObjectName('windowFrame') self.vboxFrame = QtWidgets.QVBoxLayout(self.windowFrame) self.vboxFrame.setContentsMargins(0, 0, 0, 0) self.titleBar = QWidget() self.titleBar.setContentsMargins(0, 0, 0, 0) self.titleBar.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)) self.hboxTitle = QHBoxLayout(self.titleBar) self.hboxTitle.setContentsMargins(0, 0, 4, 0) self.hboxTitle.setSpacing(0) self.lblIcon = QLabel() if not self._w.windowIcon().isNull(): self.lblIcon.setPixmap(self._w.windowIcon().pixmap(QSize(64, 64))) self.lblIcon.setAlignment(Qt.AlignLeft | Qt.AlignVCenter) self.lblIcon.setFixedSize(QSize(64 + 16, 32 + 2)) self.lblIcon.setContentsMargins(5, 5, 0, 0) self.lblTitle = QLabel('Title') self.lblTitle.setObjectName('lblTitle') self.lblTitle.setAlignment(Qt.AlignBottom | Qt.AlignHCenter) self.lblTitle.setAttribute(Qt.WA_TransparentForMouseEvents, True) spButtons = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.btnMaximize = QPushButton() # clicked pyqtSlot => on_btnMaximize_clicked self.btnMaximize.setObjectName('btnMaximize') self.btnMaximize.setSizePolicy(spButtons) self.btnClose = QPushButton() # clicked pyqtSlot => on_btnClose_clicked self.btnClose.setObjectName("btnClose") self.btnClose.setContentsMargins(0, 0, 0, 0) self.btnClose.setSizePolicy(spButtons) self.btnMinimize = QPushButton() # click => on_btnMinimize_clicked self.btnMinimize.setObjectName("btnMinimize") self.btnMinimize.setSizePolicy(spButtons) self.vboxFrame.addWidget(self.titleBar) self.windowContent = QWidget(self.windowFrame) self.vboxFrame.addWidget(self.windowContent) self.vboxWindow.addWidget(self.windowFrame) self.hboxTitle.addWidget(self.lblIcon) self.hboxTitle.addWidget(self.lblTitle) self.hboxTitle.addWidget(self.btnMinimize) self.hboxTitle.addWidget(self.btnMaximize) self.hboxTitle.addWidget(self.btnClose) self.CONTROLBOX_WIDTH = self.btnClose.width() self.setWindowFlags(Qt.WindowType.Window | Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint) if True: # Problem here self.setAttribute(Qt.WA_TranslucentBackground) COLOR_ACIK_MINIMIZE, COLOR_KAPALI_MINIMIZE = "rgb(0, 120, 0)", "rgb(0,200,0)" COLOR_ACIK_CLOSE, COLOR_KAPALI_CLOSE = "rgb(255, 0, 0)", "rgb(255, 50, 50)" COLOR_MINIMIZE = COLOR_ACIK_MINIMIZE COLOR_CLOSE = COLOR_ACIK_CLOSE CONTROL_BOX_MAC = f""" #windowFrame {{ border-top-left-radius:10px;border-top-right-radius:10px; border-bottom-left-radius:5px;border-bottom-right-radius:5px; background-color: palette(Window);}} #btnClose, #btnMaximize, #btnMinimize {{ margin: 4px; border: none; border-radius: 8px; width:17px; height:17px; max-height:17px; max-width:17px; }} #btnMaximize {{ border: none; border-radius: 8px; background-color: rgb(255, 170, 0); }} #btnMaximize::hover {{ background-color: rgba(255, 170, 0, 175); }} #btnMinimize {{ border: none; border-radius: 8px; background-color: {COLOR_MINIMIZE}; }} #btnMinimize::hover {{ background-color: rgba(0, 120, 0, 175); }} #btnClose {{ border: none; border-radius: 8px; background-color: {COLOR_CLOSE}; }} #btnClose::hover {{ background-color: rgba(255, 0, 0, 175); }} #btnClose::disabled, #btnMaximize::disabled, #btnMinimize::disabled {{ background-color: palette(midlight); }} """ self.setStyleSheet(CONTROL_BOX_MAC) QtCore.QMetaObject.connectSlotsByName(self) self.effect = QtWidgets.QGraphicsDropShadowEffect() self.effect.setBlurRadius(10) self.effect.setXOffset(0) self.effect.setYOffset(0) self.effect.setColor(QColor(0, 0, 0, 150)) self.windowFrame.setGraphicsEffect(self.effect) self.setContentsMargins(8, 8, 8,8) @Slot() def on_btnClose_clicked(self): self.close() def __child_was_closed(self): self._w = None # The child was deleted, remove the reference to it and close the parent window self.close() def setWindowTitle(self, title): super(MACTema, self).setWindowTitle(title) self.lblTitle.setText(title) class MyForm(QMainWindow): def __init__(self): super(MyForm, self).__init__() self.setupUi() if BORDERLESS_CUSTOM_FORM: self.mac = MACTema(w=self) self.mac.setGeometry(QRect(350,200,1280,720)) self.mac.show() else: self.setGeometry(QRect(350, 200, 1280, 720)) self.show() QApplication.processEvents() self.CalcSetParentFunction() def setupUi(self): widCenter = QWidget() qv= QVBoxLayout(widCenter) self.frame = QFrame() qv.addWidget(self.frame) self.setCentralWidget(widCenter) def CalcSetParentFunction(self): psutil.Popen("notepad.exe", stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, shell=True) # starts notepad time.sleep(2) self.hwnd = win32gui.FindWindow(None, "Untitled - Notepad") # Untitled - Notepad print("Notepad Hwnd: 0x%X"% self.hwnd) if not self.hwnd: return lStyle = win32gui.GetWindowLong(self.hwnd, GWL_STYLE); lStyle &= ~(WS_POPUP | WS_CHILD) #lStyle |= WS_CHILD win32gui.SetWindowLong(self.hwnd, GWL_STYLE, lStyle); win32gui.SetParent(self.hwnd, self.frame.winId()) self.tmr = QTimer(self) self.tmr.timeout.connect(self.UpdateGUI) self.tmr.setInterval(100) self.tmr.start() def UpdateGUI(self): win32gui.RedrawWindow(self.hwnd, None, None, RDW_INVALIDATE | RDW_FRAME | RDW_ERASE | RDW_ALLCHILDREN) if __name__ == "__main__": app = QApplication(sys.argv) os.system("taskkill /f /im notepad.exe") Form = MyForm() sys.exit(app.exec_())
Thank you very much!
-
Hi,
@Emrecp said in WA_TranslucentBackground Frameless windows problem with WIN32 API SetParent:
self.parent = parent
You are nuking the original property with this one. I am not saying that this is the cause of your issue but it may have some influence.
Why are you mixing super calls and base class method invocation ?
That said, when calling winId, your widget will get a native handle like explained in the method documentation. So I wonder if this triggers the effect you are seeing.
Try reordering that stuff, and start by making the parenting and only then finish the custom setup.