You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将QWidget放置在指定显示器上(PySide6多屏场景)

问题

基于Python 3.11、PySide6及Windows 10 Enterprise 22H2开发项目,需要创建作为其他应用窗口子窗口的QDialog,并将其置于父应用主窗口内。但在多显示器场景下遇到问题:对话框始终显示在主显示器(左上角坐标为0,0的显示器),当设置的对话框位置超出主显示器范围时,会被自动居中显示在主显示器。

现有代码如下:

from PySide6 import QtWidgets as qw
import win32gui as win32

class DialogApp(qw.QDialog):

    global iRect
        
    def __init__(self, parent=None):
        super(DialogApp, self).__init__(parent)
        self.initUI()
        
    def initUI(self):
    
        layout = qw.QGridLayout()
        layout.setColumnStretch(0,1)
        self.setLayout(layout)
        self.setWindowTitle("Test Dialog")
        self.setGeometry(iRect[0] + 100, iRect[1] + 100, 200, 20)
        self.setSizeGripEnabled(True)     

def mainWindow(): 
    parent_window_ptr = getMainWindow() # 该函数由父应用提供
    return wrapInstance(int(parent_window_ptr), qw.QMainWindow)

iRect = win32.GetWindowRect(parent_window_handle) # 通过Windows API获取父窗口句柄

da = DialogApp(mainWindow()) 
da.show()

上述代码仅在父窗口位于主显示器时,才能让对话框显示在父窗口左上角偏移100像素的位置。想知道是否可通过指定显示器来强制放置QWidget,例如使用类似monitor_info = win32api.GetMonitorInfo(win32api.MonitorFromWindow(other_window_handle, win32con.MONITOR_DEFAULTTOPRIMARY))的方法。

解决方案

可以结合Windows API获取父窗口所在显示器信息,配合PySide6的窗口定位逻辑解决多显示器下的位置问题,具体实现如下:

核心步骤

  • 获取父窗口所在显示器的工作区域(排除任务栏等系统占用区域)
  • 明确对话框的子窗口属性,避免系统将其视为独立窗口调整位置
  • 精准计算对话框位置并完成定位

修改后的代码

from PySide6 import QtWidgets as qw
import win32gui
import win32api
import win32con

class DialogApp(qw.QDialog):
    def __init__(self, parent=None):
        super(DialogApp, self).__init__(parent)
        # 设置窗口标志,明确为父窗口的子窗口,继承显示器上下文
        self.setWindowFlags(qw.Qt.Dialog | qw.Qt.WindowStaysOnTopHint | qw.Qt.SubWindow)
        self.initUI()
        
    def initUI(self):
        layout = qw.QGridLayout()
        layout.setColumnStretch(0, 1)
        self.setLayout(layout)
        self.setWindowTitle("Test Dialog")
        self.resize(200, 20)
        self.setSizeGripEnabled(True)  

def mainWindow(): 
    parent_window_ptr = getMainWindow() # 该函数由父应用提供
    return wrapInstance(int(parent_window_ptr), qw.QMainWindow)

# 获取父窗口句柄与位置
parent_handle = parent_window_handle  # 替换为实际父窗口句柄
parent_rect = win32gui.GetWindowRect(parent_handle)

# 获取父窗口所在显示器的工作区域
monitor_handle = win32api.MonitorFromWindow(parent_handle, win32con.MONITOR_DEFAULTTONEAREST)
monitor_info = win32api.GetMonitorInfo(monitor_handle)
monitor_work_area = monitor_info['Work']  # 格式:(x1, y1, x2, y2)

# 计算对话框目标位置:父窗口左上角偏移100像素
target_x = parent_rect[0] + 100
target_y = parent_rect[1] + 100

# 可选:确保对话框位置不超出显示器工作区域
target_x = max(monitor_work_area[0], min(target_x, monitor_work_area[2] - 200))
target_y = max(monitor_work_area[1], min(target_y, monitor_work_area[3] - 20))

# 创建并显示对话框
parent_win = mainWindow()
da = DialogApp(parent_win)
da.move(target_x, target_y)
da.show()

关键说明

  • 窗口标志设置:添加Qt.SubWindow标志,明确对话框是父窗口的子窗口,继承父窗口的显示器上下文,避免系统强制将其迁移到主显示器。
  • 显示器精准匹配:使用MonitorFromWindow结合MONITOR_DEFAULTTONEAREST参数,确保获取的是父窗口所在的显示器,而非默认主显示器。
  • 位置校验:可选的范围校验逻辑,避免对话框超出显示器可视区域,防止系统自动调整位置。

内容的提问来源于stack exchange,提问作者user2619035

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 20:43:23