PyQt5中如何正确获取QFrame控件的屏幕绝对坐标
问题原因
你遇到的问题由两个错误共同导致:
- 坐标获取时机错误
你在setupUi执行阶段就打印坐标,此时Qt布局管理器还未完成所有控件的尺寸、位置计算,窗口也未完成屏幕渲染映射,所有控件的位置都是初始化的默认局部坐标,mapToGlobal自然无法返回正确的全局坐标。 - 坐标转换传参错误
mapToGlobal()方法接收的参数是当前控件自身坐标系下的点,而geometry().bottomLeft()返回的是控件在父级坐标系下的左下角坐标,传入后会导致计算逻辑错误。正确的参数应该用rect().bottomLeft(),返回的是控件自身坐标系下的左下角点(原点为控件自身左上角)。
解决方法
根据你的使用场景选择对应方案即可:
方案1:点击日期编辑框时触发弹窗(最适配你的开发场景)
你的需求是点击日期编辑框弹出日历,直接在点击事件的回调函数中获取坐标即可,此时窗口已完成渲染,坐标完全准确:
# 日期编辑框点击槽函数示例 def on_date_edit_clicked(self): # 获取QFrame左下角的全局坐标 frame_global_bottom_left = self.dateEditFrame.mapToGlobal(self.dateEditFrame.rect().bottomLeft()) # 将弹窗左上角对齐到QFrame左下角,刚好悬浮在编辑框下方 self.calendar_dialog.move(frame_global_bottom_left) self.calendar_dialog.show()
方案2:窗口初始化完成后立刻获取坐标
如果需要在窗口刚显示时就拿到坐标,可以把坐标获取逻辑放到showEvent中,或者用QTimer.singleShot延迟执行,等待布局计算完成:
from PyQt5 import QtWidgets, QtCore import sys class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.resize(600, 400) self.centralwidget = QtWidgets.QWidget(MainWindow) self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.gridLayout.addWidget(self.groupBox, 0, 1, 1, 1) self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget) self.gridLayout.addWidget(self.groupBox_2, 0, 0, 4, 1) self.frame = QtWidgets.QFrame(self.centralwidget) self.gridLayout.addWidget(self.frame, 1, 1, 1, 1) MainWindow.setCentralWidget(self.centralwidget) # 延迟10ms执行,等待布局和窗口渲染完成 QtCore.QTimer.singleShot(10, self.print_frame_pos) def print_frame_pos(self): # 正确的坐标转换写法 print(self.frame.mapToGlobal(self.frame.rect().bottomLeft())) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.showMaximized() sys.exit(app.exec_())
内容的提问来源于stack exchange,提问作者Mark Petrov
相关产品推荐
相关产品推荐

