最新大型开源项目-云游戏,云桌面系统,欢迎关注
本项目代码地址
1.绘制控制按钮小圆圈
实现一个类,继承自QWidget,然后实现paintEvent方法,在此方法内进行绘制。
鼠标进入,离开后,按钮有不同的颜色,因此需要实现进入和离开的事件监听
enterEvent 鼠标进入
leaveEvent 鼠标离开
因为是绘制圆形的按钮,所以需要一个半径,同时需要鼠标进入时的颜色和正常无鼠标进入的颜色。
class OperationIcon : public QWidget {
public:
// 绘制半径,普通状态下颜色,鼠标进入时颜色
OperationIcon(int radius, int normal_color, int enter_color, QWidget* parent = nullptr);
// 绘制事件
void paintEvent(QPaintEvent *event) override;
// 鼠标进入事件
void enterEvent(QEvent *event) override;
// 鼠标离开事件
void leaveEvent(QEvent* event) override;
private:
int radius_ = 10;
int normal_color_ = 0xff0099;
int enter_color_ = 0xff000000;
};
绘制圆形可以使用绘制椭圆或者圆角矩形的方式,在paintEvent中,我们使用绘制圆角矩形的方式。
OperationIcon::OperationIcon(int radius, int normal_color, int enter_color, QWidget* parent) : QWidget(parent) {
this->radius_ = radius;
this->normal_color_ = normal_color;
this->enter_color_ = enter_color;
}
void OperationIcon::paintEvent(QPaintEvent *event) {
QPainter painter(this);
// 开启抗锯齿,绘制的图形更加细腻
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
// 不需要描边,只需填充颜色即可
painter.setPen(Qt::NoPen);
// 进入和离开(普通状态),分别设置颜色画刷
if (enter_) {
painter.setBrush(QBrush(QColor(this->enter_color_)));
}
else {
painter.setBrush(QBrush(QColor(this->normal_color_)));
}
// 绘制圆角矩形
painter.drawRoundedRect(this->rect(), this->width()/2, this->height()/2);
}
void OperationIcon::enterEvent(QEvent *event) {
//进入时,设置状态重绘
enter_ = true;
repaint();
}
void OperationIcon::leaveEvent(QEvent* event) {
//离开时,设置状态重绘
enter_ = false;
repaint();
}
2.添加到TitleBar中
添加2个按钮到一个水平的Layout中,然后将Layout添加到TitleBar中,并添加合适的空隙。
TitleBar::TitleBar(QWidget* parent) : QWidget(parent) {
setFixedHeight(Settings::kTitleBarHeight);
setFixedWidth(Settings::kWindowWidth);
// 生成一个垂直布局,是为了让TitleBar的内容,上下调整更方便
auto root_layout = new QVBoxLayout();
// 生成一个水平布局,按钮添加在这个布局里
auto item_layout = new QHBoxLayout();
// 给按钮所在的布局,添加一个弹簧,将按钮挤压到右边
item_layout->addStretch();
auto btn_size = Settings::kOperationBtnRadius;
// 生成最小化按钮
{
min_btn_ = new OperationIcon(btn_size,
Settings::kOperationBtnMinNomralColor,
Settings::kOperationBtnMinEnterColor,
this);
// 设置大小
min_btn_->setFixedSize(QSize(btn_size, btn_size));
// 添加到水平Layout中
item_layout->addWidget(min_btn_);
}
// 添加一个空隙
item_layout->addSpacing(6);
// 同理添加一个关闭按钮
{
close_btn_ = new OperationIcon(btn_size,
Settings::kOperationBtnCloseNomralColor,
Settings::kOperationBtnCloseEnterColor,
this);
close_btn_->setFixedSize(QSize(btn_size, btn_size));
item_layout->addWidget(close_btn_);
}
item_layout->addSpacing(6);
root_layout->addLayout(item_layout);
setLayout(root_layout);
}
运行后,得到的效果如下
3.增加点击事件
鼠标点击事件是通过以下两个方法获得的
mousePressEvent 鼠标按下
mouseReleaseEvent 鼠标抬起
3.1 定义一个回调函数
当鼠标点击时,通过回调函数通知。
当然,也可以使用Qt的信号和槽实现,但C++11之后,可以方便使用Lambda表达式,故此使用functional函数(仿函数)。
using ClickCallback = std::function<void()>;
3.2 实现鼠标事件和回调函数的设置
class OperationIcon : public QWidget {
public:
...
//鼠标按下
void mousePressEvent(QMouseEvent *event) override;
// 鼠标抬起
void mouseReleaseEvent(QMouseEvent *event) override;
// 设置点击回调函数
// 注意这里用的是右值参数
void SetOnClickCallback(ClickCallback&& cbk);
private:
...
// 按下状态
bool pressed_ = false;
// 回调函数
ClickCallback click_cbk_;
};
实现很简单,只需要在鼠标抬起的时候,调用一下回调函数即可。
自定义Widget在这里也体现了一定的灵活度,因为有的需求在按下立刻触发,如果使用Qt的clicked信号,则无法实现了。
void OperationIcon::mousePressEvent(QMouseEvent *event) {
pressed_ = true;
repaint();
}
void OperationIcon::mouseReleaseEvent(QMouseEvent *event) {
pressed_ = false;
repaint();
if (click_cbk_) {
click_cbk_();
}
}
void OperationIcon::SetOnClickCallback(ClickCallback&& cbk) {
// 注意这里是move,因为回调函数只有一个,直接move过来保存到click_cbk_这个变量里
click_cbk_ = std::move(cbk);
}
3.3 处理逻辑
我们的按钮添加在了TitleBar的Layout里,添加了一个最小化,一个关闭。
有2个位置可以处理这两个事件:
1.在TitleBar中直接处理
2.TitleBar暴露接口,给外面处理
我们选择暴露接口,给外面处理,以获取更大的灵活性
class TitleBar : public QWidget
{
public:
void SetMinClickCallback(ClickCallback&& cbk);
void SetCloseClickCallback(ClickCallback&& cbk);
}
直接把回调函数设置给按钮即可:
void TitleBar::SetMinClickCallback(ClickCallback&& cbk) {
min_btn_->SetOnClickCallback(std::move(cbk));
}
void TitleBar::SetCloseClickCallback(ClickCallback&& cbk) {
close_btn_->SetOnClickCallback(std::move(cbk));
}
在MainWindow中,我们处理这2个事件
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent) {
...
// 最小化
title_bar_->SetMinClickCallback([=]() {
this->showMinimized();
});
//直接退出应用
title_bar_->SetCloseClickCallback([=]() {
qApp->exit(0);
});
}