Qt - 控件坐标转换

屏幕与窗口

****屏幕坐标(绝对坐标) 窗口坐标(相对坐标)****

坐标的概念:

  • 窗口坐标(Window Coordinates):窗口坐标是相对于窗口左上角的坐标。在这个坐标系统中,原点(0,0)位于窗口的左上角,x 轴从左到右增加,y 轴从上到下增加。这意味着,如果你在窗口中的某个位置点击鼠标,那么你得到的鼠标点击事件的坐标就是相对于窗口左上角的坐标。
  • 显示器坐标(Screen Coordinates):显示器坐标是相对于整个显示器的坐标。在这个坐标系统中,原点(0,0)位于显示器的左上角,x 轴从左到右增加,y 轴从上到下增加。这意味着,无论你在哪个窗口或者哪个部分的屏幕上点击鼠标,你得到的鼠标点击事件的坐标都是相对于显示器左上角的坐标。
  • 父窗口坐标(Parent Coordinates):这是相对于父窗口(如果有的话)的坐标系统。原点(0,0)位于父窗口的左上角。这在处理嵌套窗口或控件时非常有用。
  • 场景坐标(Scene Coordinates):这是在 QGraphicsScene 中使用的坐标系统,用于处理图形项的位置和变换。原点(0,0)可以在场景的任何位置,默认在中心 这取决于你如何设置和使用场景。
  • 视图坐标(View Coordinates):这是在 QGraphicsView 中使用的坐标系统,用于处理视图滚动和缩放。原点(0,0)位于视图的左上角。

 

坐标转换:

QPoint QMouseEvent::pos()
//这个只是返回鼠标事件相对这个widget(重载了QMouseEvent的widget)的位置。
    
QPoint QMouseEvent::globalPos()
//窗口坐标,这个是返回鼠标的全局坐标,相对于屏幕的左上角

QPoint QCursor::pos()
//窗口坐标,这个是返回鼠标的全局坐标,相对于屏幕的左上角
    
QPoint QWidget::mapToGlobal(const QPoint & pos) const
//将窗口坐标转换成显示器坐标

QPoint QWidget::mapFromGlobal(const QPoint & pos) const
//将显示器坐标转换成窗口坐标    

QPoint QWidget::mapToParent(const QPoint & pos) const
//将窗口坐标获得的pos转换成父类widget的坐标    

QPoint QWidget::mapFromParent(const QPoint & pos) const
//将父类窗口坐标转换成当前窗口坐标    

QPoint QWidget::mapTo(const QWidget * parent, const QPoint & pos) const
//将当前窗口坐标转换成指定parent坐标。
    
QWidget::pos() : QPoint 
//这个属性获得的是当前目前控件在父窗口中的位置

const QPointF & QMouseEvent::screenPos() const和QPoint QMouseEvent::globalPos() 
//值相同,但是类型更高精度的QPointF    
    

坐标转换:

 补充一些函数:

1QPoint QWidget::mapToGlobal(const QPoint &pos) const
将小部件坐标转换为全局坐标。mapToGlobal(QPoint(0,0))可以得到小部件左上角像素的全局坐标。

2、QPoint QWidget::mapToParent(const QPoint &pos) const
将小部件坐标转换为父部件坐标。如果小部件没有父部件,则效果与mapToGlobal()相同。

3、QPoint QWidget::mapTo(const QWidget *parent, const QPoint &pos) const
将小部件的坐标转换为父部件的坐标系统,parent不能是0,必须是调用小部件的父部件。

4、QPoint QWidget::mapFromGlobal(const QPoint &pos) const
将全局坐标转换为小部件坐标。

5、QPoint QWidget::mapFromParent(const QPoint &pos) const
将父部件坐标转换为小部件坐标。如果小部件没有父部件,则效果与mapFromGlobal()相同。

6、QPoint QWidget::mapFrom(const QWidget *parent, const QPoint &pos) const
将小部件的坐标pos从父部件的坐标系统转换为小部件的坐标系统。parent不能是0,必须是调用小部件的父部件。

7、QPoint QMouseEvent::pos() const
返回鼠标光标相对于接收事件的小部件的位置。

8、QPoint QMouseEvent::globalPos() const
返回事件发生时鼠标光标的全局位置。

9、const QPointF &QMouseEvent::screenPos() const
以QPointF的形式返回鼠标光标相对于接收事件的屏幕的位置。这个函数是在Qt 5.0中引入的。

 

代码示例1:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QLabel>
#include <QPushButton>
#include <QMainWindow>
#include <QMouseEvent>


QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class DraggableButton;
class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    void mouseMoveEvent(QMouseEvent *event) override;

private slots:
    void updateBtnLocation();

private:
    Ui::MainWindow *ui;

    QLabel* cursorPosLabel = nullptr;
    QLabel* cursorGlobalLabel  = nullptr;
    QLabel* currentViewLabel = nullptr;
    QLabel* btnPosLabel = nullptr;
    QLabel* btnMapFromParentLabel = nullptr;
    QLabel* btnMapToParentLabel = nullptr;
    QLabel* btnMapToGlobalLabel = nullptr;
    QLabel* btnMapFromGlobalLabel = nullptr;
    DraggableButton* dragBtn = nullptr;
};

class DraggableButton : public QPushButton
{
    Q_OBJECT
public:
    DraggableButton(QWidget *parent = nullptr)
        : QPushButton(parent), m_dragging(false) {}

protected:
    void mousePressEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            m_dragging = true;
            m_startPosition = event->pos();
        }
    }

    void mouseMoveEvent(QMouseEvent *event) override
    {
        if (m_dragging)
        {
            move(mapToParent(event->pos() - m_startPosition));
            emit btnMoving();
        }
    }

    void mouseReleaseEvent(QMouseEvent *event) override
    {
        if (event->button() == Qt::LeftButton) {
            m_dragging = false;
        }
    }

signals:
    void btnMoving();
private:
    bool m_dragging;
    QPoint m_startPosition;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QPushButton"
#include "QLabel"
#include "QMouseEvent"
#include "QVBoxLayout"
#include "qdebug.h"
#include "QWidget"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    this->setObjectName("mianwin");
    this->setStyleSheet("#mianwin { border: 5px solid yellow; }");
    ui->setupUi(this);
    auto widget = new QWidget(this);
    widget->setObjectName("view");
    widget->setStyleSheet("#view { border: 2px solid red; }");

    cursorPosLabel = new QLabel(widget);
    cursorGlobalLabel = new QLabel(widget);
    currentViewLabel = new QLabel(widget);
    btnPosLabel = new QLabel(widget);
    btnMapFromParentLabel = new QLabel(widget);
    btnMapToParentLabel = new QLabel(widget);
    btnMapToGlobalLabel = new QLabel(widget);
    btnMapFromGlobalLabel = new QLabel(widget);

    dragBtn = new DraggableButton(this);
    dragBtn->setText("Drag me!");
    dragBtn->setFixedSize(80,40);

    QVBoxLayout* vL = new QVBoxLayout(widget);
    vL->setSpacing(20);
    vL->addWidget(cursorPosLabel);
    vL->addWidget(cursorGlobalLabel);
    vL->addWidget(currentViewLabel);
    vL->addSpacing(50);
    vL->addWidget(btnPosLabel);
    vL->addWidget(btnMapFromParentLabel);
    vL->addWidget(btnMapToParentLabel);
    vL->addWidget(btnMapToGlobalLabel);
    vL->addWidget(btnMapFromGlobalLabel);
    vL->addStretch();
    setMouseTracking(true);
    setCentralWidget(widget);

    connect(dragBtn,&DraggableButton::btnMoving,this,&MainWindow::updateBtnLocation);
}

void MainWindow::mouseMoveEvent(QMouseEvent *event)
{
    auto cursorPos = QCursor::pos();
    auto cursorGlobal = event->globalPos();
    cursorPosLabel->setText(QString("鼠标的全局位置:(x:%1,y:%2)").arg(cursorPos.x()).arg(cursorPos.y()));
    cursorGlobalLabel->setText(QString("QMouseEvent事件的globalPos全局位置:(x:%1,y:%2)").arg(cursorGlobal.x()).arg(cursorGlobal.y()));
    currentViewLabel->setText(QString("QMouseEvent事件的pos()相对于当前窗口位置:(x:%1,y:%2)").arg(event->pos().x()).arg(event->pos().y()));
}

void MainWindow::updateBtnLocation()
{
    btnPosLabel->setText(QString("btn事件的pos()相对于当前父控件位置:(x:%1,y:%2)").arg(dragBtn->pos().x()).arg(dragBtn->pos().y()));
    auto dragBtnmapFromParent = dragBtn->mapFromParent(QPoint(0,0));
    btnMapFromParentLabel->setText(QString("父窗口QPoint(0,0)位置转为btn的位置:(x:%1,y:%2)").arg(dragBtnmapFromParent.x()).arg(dragBtnmapFromParent.y()));
    auto dragBtnmapToParent = dragBtn->mapToParent(QPoint(0,0)+QPoint(dragBtn->width(),dragBtn->height()));
    btnMapToParentLabel->setText(QString("btn的QPoint(80,40)相对于当前父控件位置:(x:%1,y:%2)").arg(dragBtnmapToParent.x()).arg(dragBtnmapToParent.y()));
    auto dragBtnmapToGlobal = dragBtn->mapToGlobal(QPoint(0,0));
    btnMapToGlobalLabel->setText(QString("btn的QPoint(0,0)相对于当前全局位置:(x:%1,y:%2)").arg(dragBtnmapToGlobal.x()).arg(dragBtnmapToGlobal.y()));
    auto dragBtnmapFromGlobal = dragBtn->mapFromGlobal(QPoint(0,0));
    btnMapFromGlobalLabel->setText(QString("全局QPoint(0,0)位置转为btn的位置:(x:%1,y:%2)").arg(dragBtnmapFromGlobal.x()).arg(dragBtnmapFromGlobal.y()));
}
MainWindow::~MainWindow()
{
    delete ui;
}

运行效果:

 

代码示例2:

widget.cpp

#include "widget.h"
#include "ui_widget.h"


#include <QDebug>
#include <QMoveEvent>

Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{
    ui->setupUi(this);

    button = new QPushButton("Click me", this);
    button->setGeometry(50, 50, 100, 50);

}

Widget::~Widget()
{
    delete ui;
}

//窗口移动事件
void Widget::moveEvent(QMoveEvent *event)
{
     qDebug()<<"原来的pos"<<event->oldPos()<<"现在的pos"<<event->pos();

     // 转换到全局坐标
     QPoint globalPoint = button->mapToGlobal(QPoint(0, 0));
     qDebug() << "Global Point:" << globalPoint;

     // 转换到父控件坐标
     QPoint parentPoint = button->mapToParent(QPoint(0, 0));
     qDebug() << "Parent Point:" << parentPoint;

     // 从全局坐标转换回控件内部坐标
     QPoint mappedGlobalPoint = button->mapFromGlobal(globalPoint);
     qDebug() << "Mapped Global Point:" << mappedGlobalPoint;

     //button左上角在Widget的坐标
     QPoint topLeftPoint = button->geometry().topLeft(); //topLeft返回矩形左上角的位置
     qDebug() <<"topLeftPoint: "<<topLeftPoint;
     //button右上角在Widget的坐标
     QPoint topRightPoint = button->geometry().topRight();//topRight返回矩形右上角的位置
     qDebug() <<"topRightPoint: "<<topRightPoint;


     QRect geometryRect = this->geometry();//去了标题栏的几何坐标
     qDebug()<<"geometryRect: "<<geometryRect;
     QRect frameGeometryRect = this->frameGeometry();//加上了标题栏的几何坐标
     qDebug()<<"frameGeometryRect: "<<frameGeometryRect;

     QRect btn_geometryRect = button->geometry();
     qDebug()<<"btn_geometryRect: "<<btn_geometryRect;
     QRect btn_frameGeometryRect = button->frameGeometry();
     qDebug()<<"btn_frameGeometryRect: "<<btn_frameGeometryRect;
}

运行效果:

 

————————————————

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_45882303/article/details/136892019

posted @   [BORUTO]  阅读(528)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示