""" Calling QWidget.move() is not idempotent Repro setup Two monitors, both set to 200% scaling, so that they are side-by-side 1) Run app. With window entirely on left screen, press the button more than once. Note that the position of the small popup widget does not change after the first press. Expected: popup stays on upper left corner of window. Actual == expected 2) Now place window entirely on right screen, and repeat. Expected: popup stays on upper left corner of window. Actual == expected 3) Now place window roughly in the middle, but mostly on the RHS. You will be able to tell if you are in the right spot because the window geometry's left will be out of screen 0's geometry range, e.g. 3654. Try putting the "D" in "Dump" in the middle of the screen (so it is on both screens). Now click the button multiple times. Expected: popup stays on upper left corner of window. Actual: popup goes back and forth between its proper position and the same(?) relative position on the other screen """ import sys # import win32gui from PySide2.QtCore import ( QCoreApplication, qVersion, QLibraryInfo, QRect, QSize, Qt, Slot, ) from PySide2.QtGui import (QWindow, QScreen) from PySide2.QtWidgets import ( QApplication, QPushButton, QVBoxLayout, QWidget, ) class PopupWindow(QWidget): def __init__(self, parent=None): window_flags = Qt.CustomizeWindowHint | Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint super().__init__(parent, window_flags) self.setFixedSize(QSize(100, 100)) class MainWindow(QWidget): """ Repro steps: Ensure that all active monitors """ def __init__(self, parent=None): super().__init__(parent) self.setMinimumSize(QSize(400, 300)) vbox = QVBoxLayout() self.setLayout(vbox) button = QPushButton('Position popup') button.pressed.connect(self.click) vbox.addWidget(button) button = QPushButton('Quit') button.pressed.connect(qApp.quit) vbox.addWidget(button) vbox.addStretch() self._popup = PopupWindow() self._popup.show() def dump_screens(self): def rect_to_str(rect): return "{},{},{},{}".format(rect.left(), rect.top(), rect.right(), rect.bottom()) for index, screen in enumerate(QApplication.instance().primaryScreen().virtualSiblings()): print('screen {} ratio {} geometry {} size {},{} virtualGeometry {}'.format( index, screen.devicePixelRatio(), rect_to_str(screen.geometry()), screen.size().width(), screen.size().height(), rect_to_str(screen.virtualGeometry()) )) def click(self): self.dump_screens() print('\nwindow geometry', self.geometry(), self.screenName()) print('before', self._popup.pos()) x = self.geometry().left() - 50 y = self.geometry().top() - 50 print('move to', x, y) self._popup.move(x, y) print('after', self._popup.pos()) def updateTitle(self): self.setWindowTitle(qVersion() + ' ' + self.screenName()) def screenName(self): wh = self.windowHandle() return wh.screen().name() if wh else '' class QTest(): def __init__(self): print("Initializing ", QLibraryInfo.build()) QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) win = MainWindow() win.show() win.updateTitle() win.windowHandle().screenChanged.connect(win.updateTitle) app.exec_() def main(): QTest() if __name__ == '__main__': main()