PyQt5技术问题:如何将QDialog居中于QMainWindow的centralwidget内
QDialog与QMainWindow中央部件的尺寸匹配及居中同步问题
问题描述
我的QMainWindow结构如下:
- 顶部是Windows默认标题栏(包含程序图标、最小化、最大化及关闭按钮)
- 下方依次为菜单栏、工具栏
- 中间是仅包含stackedwidget子控件的centralwidget
- 底部是状态栏
调用.exec()打开新QDialog时,需要实现以下需求:
- QDialog尺寸为centralwidget尺寸的0.98倍
- QDialog居中,使其中心与centralwidget中心重合
- QMainWindow尺寸变化时,QDialog位置同步调整
目前尺寸设置正确,但坐标位置不符合预期,我的尝试代码如下:
title_bar_height = QtWidgets.QApplication.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight) central_widget_width = int(self.main_self.ui.centralwidget.frameSize().width()) central_widget_height = int(self.main_self.ui.centralwidget.frameSize().height()) self.setFixedSize(int(0.95*central_widget_width),int(1.0*(central_widget_height-title_bar_height))) central_widget_top_x = int(self.main_self.ui.centralwidget.frameGeometry().x()) central_widget_top_y = int(self.main_self.ui.centralwidget.frameGeometry().y()) central_widget_width = int(self.main_self.ui.centralwidget.frameGeometry().width()) central_widget_height = int(self.main_self.ui.centralwidget.frameGeometry().height()) qdialog_width = self.frameGeometry().width() qdialog_height = self.frameGeometry().height() print(central_widget_top_y)#->75 qdialog_new_x = central_widget_top_x + (central_widget_width-qdialog_width)/2 qdialog_new_y = central_widget_top_y + (central_widget_height-qdialog_height)/2 self.move(int(qdialog_new_x),int(qdialog_new_y)) print(self.frameGeometry().y()) #->75
解决方案
核心问题
代码中坐标计算错误的原因是:frameGeometry()返回的是centralwidget相对于父部件的局部坐标,但move()方法使用的是全局屏幕坐标,两者坐标系不匹配。此外要实现响应式同步,需要监听主窗口的尺寸变化。
步骤1:正确计算尺寸与居中位置
改用mapToGlobal()将centralwidget的区域转换为全局屏幕坐标,再计算QDialog的位置:
# 获取centralwidget的全局屏幕矩形 central_top_left = self.main_self.ui.centralwidget.mapToGlobal(self.main_self.ui.centralwidget.rect().topLeft()) central_width = self.main_self.ui.centralwidget.width() central_height = self.main_self.ui.centralwidget.height() # 设置QDialog尺寸为centralwidget的0.98倍 dlg_width = int(central_width * 0.98) dlg_height = int(central_height * 0.98) self.setFixedSize(dlg_width, dlg_height) # 计算中心对齐的位置 dlg_x = central_top_left.x() + (central_width - dlg_width) // 2 dlg_y = central_top_left.y() + (central_height - dlg_height) // 2 self.move(dlg_x, dlg_y)
步骤2:实现响应式同步
监听主窗口的resize信号,在窗口尺寸变化时重新计算QDialog的位置:
- 在QDialog初始化时绑定信号:
# 绑定主窗口resize信号到自定义槽函数 self.main_self.resize.connect(self.adjust_position)
- 实现槽函数复用位置计算逻辑:
def adjust_position(self): # 重复步骤1的计算逻辑 central_top_left = self.main_self.ui.centralwidget.mapToGlobal(self.main_self.ui.centralwidget.rect().topLeft()) central_width = self.main_self.ui.centralwidget.width() central_height = self.main_self.ui.centralwidget.height() dlg_width = int(central_width * 0.98) dlg_height = int(central_height * 0.98) self.setFixedSize(dlg_width, dlg_height) dlg_x = central_top_left.x() + (central_width - dlg_width) // 2 dlg_y = central_top_left.y() + (central_height - dlg_height) // 2 self.move(dlg_x, dlg_y)
注意事项
- 无需手动扣除标题栏高度:centralwidget的尺寸已经自动排除了标题栏、菜单栏和工具栏的占用区域。
- 使用
width()/height()而非frameSize():前者返回部件内部可用尺寸,更贴合需求。
内容的提问来源于stack exchange,提问作者Chris P
相关产品推荐
相关产品推荐

