【Qt开发】常用控件(三) -> geometry
目录
1 -> 控件的位置和尺寸
2 -> 相关 API
3 -> 代码示例
3.1 -> 控制按钮的位置
3.2 -> 表白程序
1 -> 控件的位置和尺寸
位置和尺寸。其实是四个属性的统称:
- x 横坐标
- y 纵坐标
- width 宽度
- height 高度
但是在实际开发中,并不会直接使用这几个属性,而是通过一系列封装的方法来获取/修改。
对于 Qt 的坐标系,使用的是 “左手坐标系”,其中坐标系的原点是当前元素的父元素的左上角。
API | 说明 |
geometry() | 获取到控件的位置和尺寸,返回结果是一个 QRect,包含了x,y,width,height。其中x,y 是左上角的坐标 |
setGeometry(QRect) setGeometry(int x, int y, int widrh, int height) | 设置控件的位置和尺寸,可以直接设置一个 QRect,也可以分四个属性单独设置 |
2 -> 相关 API
API | 说明 |
x() | 获取横坐标 计算时包含 window frame |
y() | 获取纵坐标 计算时包含 window frame |
pos() | 返回 QPoint 对象,里面包含 x(),y(),setX(),setY() 等方法 计算时包含 window frame |
frameSize() | 返回 QSize 对象,里面包含 width(),height(),setWidth(),setHeight() 等方法 计算时包含 window frame |
frameGeometry() | 返回 QRect 对象。QRect 相当于 QPoint 和 QSize 的结合体,可以获取 x,y,width,size 计算时包含 window frame 对象 |
width() | 获取宽度 计算时不包含 window frame |
height() | 获取高度 计算时不包含 window frame |
size() | 返回 QSize 对象,里面包含 width(),height(),setWidth(),setHeight() 等方法 计算时不包含 window frame |
rect() | 返回 QRect 对象,QRect 相当于 QPoint 和 QSize 的结合体,可以获取并设置 x,y,width,size 计算时不包含 window frame 对象 |
geometry() | 返回 QRect 对象,QRect 相当于 QPoint 和 QSize 的结合体,可以获取并设置 x,y,width,size 计算时不包含 window frame 对象 |
setGeometry() | 直接设置窗口的位置和尺寸,可以设置 x,y,width,height,或者 QRect 对象 计算时不包含 window frame 对象 |
通过观察可以发现,其实这里的 API 有 frameGeometry 和 geometry 两个就足够完成所有需求了。为什么还要提供那么多功能重复的 API 呢?
这就涉及到 Qt API 的设计理念了:尽量符合人的直觉。
举个例子感受 geometry 和 frameGeometry 的区别
1. 在界面上放置一个按钮
2. 在按钮的 slot 函数中,编写代码
void Widget::on_pushButton_clicked()
{QRect rect1 = this->geometry();QRect rect2 = this->frameGeometry();qDebug() << rect1;qDebug() << rect2;
}
3. 在构造函数中,也添加同样的代码
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);QRect rect1 = this->geometry();QRect rect2 = this->frameGeometry();qDebug() << rect1;qDebug() << rect2;
}
执行程序,可以看到,在构造函数中,打印出的 geometry 和 frameGeometry 是相同的。
但是在点击按钮时,打印的 geometry 和 frameGeometry 则存在差异。
注意:
在构造方法中,Widget 刚刚创建出来,还没有加入到对象树中,此时也就不具备 Window frame。
在按钮的 slot 函数中,由于用户点击的时候,对象树已经构造好了,此时 Widget 已经具备了 Window frame,因此在位置和尺寸上均出现了差异。
如果把上述代码修改成打印 pushButton 的 geometry 和 frameGeometry,结果就是完全相同的。因为 pushButton 并非是一个窗口。
3 -> 代码示例
3.1 -> 控制按钮的位置
1. 在界面上拖动五个按钮
五个按钮的 objectName 分别是 pushButton_target,pushButton_up,pushButton_down,pushButton_left,pushButton_right。
五个按钮的初始位置和大小自行设计。
2. 在 widget.cpp 中编写四个按钮的 slot 函数
修改QRect对象的x和y,使QRect的高度宽度发生变化
void Widget::on_pushButton_up_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setY(rect.y() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_down_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setY(rect.y() + 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_left_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setX(rect.x() - 5);ui->pushButton_target->setGeometry(rect);
}void Widget::on_pushButton_right_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;rect.setX(rect.x() + 5);ui->pushButton_target->setGeometry(rect);
}
运行程序可以看到,按下下方的按钮,就会控制 target 的左上角的位置。对应的按钮整个尺寸也会发生改变。
上述代码中是直接设置的 QRect 中的 x,y。实际上 QRect 内部是存储了左上和右下两个点的坐标,再通过这两个点的坐标差值计算长宽。
单纯修改左上坐标就会引起整个矩形的长宽发生改变。
如果想让整个按钮都移动,可以改成下列代码
// 平移target
void Widget::on_pushButton_up_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;
// rect.setY(rect.y() - 5);
// ui->pushButton_target->setGeometry(rect);ui->pushButton_target->setGeometry(rect.x(), rect.y()-5, rect.width(), rect.height());}void Widget::on_pushButton_down_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;
// rect.setY(rect.y() + 5);
// ui->pushButton_target->setGeometry(rect);ui->pushButton_target->setGeometry(rect.x(), rect.y() + 5, rect.width(), rect.height());}void Widget::on_pushButton_left_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;
// rect.setX(rect.x() - 5);
// ui->pushButton_target->setGeometry(rect);ui->pushButton_target->setGeometry(rect.x() - 5, rect.y(), rect.width(), rect.height());}void Widget::on_pushButton_right_clicked()
{// 获取到target本身的geometryQRect rect = ui->pushButton_target->geometry();qDebug() << rect;
// rect.setX(rect.x() + 5);
// ui->pushButton_target->setGeometry(rect);ui->pushButton_target->setGeometry(rect.x() + 5, rect.y(), rect.width(), rect.height());}
3.2 -> 表白程序
1. 往界面上拖拽两个按钮和一个 Label。
Label 的 objectName 为 pushButton_true 和 pushButton_false,label 的 objectName 为 label
2. 在 widget.cpp 中添加 slot 函数
void Widget::on_pushButton_true_clicked()
{ui->label->setText("好耶么么(*  ̄3)(ε ̄ *)");
}void Widget::on_pushButton_false_clicked()
{// 如果点击,就把按钮挪走// 可以通过随机数,来确定按钮新的位置int width = this->geometry().width();int height = this->geometry().height();// 重新生成按钮位置// 使用rand函数之前要设置随机种子int x = rand() % width;int y = rand() % height;// 移动按钮位置ui->pushButton_false->move(x, y);
}
运行程序可以看到,当点击 “否” 时,按钮就跑了。
上述代码使用的是 pressed,鼠标按下事件。如果使用 mouseMoveEvent,只要鼠标移动过来,按钮就跑了。
window frame 的影响
如果 widget 作为一个窗口(带有标题栏、最小化、最大化、关闭按钮),那么在计算尺寸和坐标的时候就有两种算法,包含 window frame 和不包含 window frame。
其中 x(),y(),frameGeometry(),pos(),move() 都是按照包含 window frame 的方式来计算的。
其中 geometry(),width(),height(),rect(),size() 则是按照不包含 window frame 的方式来计算的。
如果一个不是作为窗口的 widget,上述两类方式得到的结果是一致的。
感谢各位大佬支持!!!
互三啦!!!