最新大型开源项目-云游戏,云桌面系统,欢迎关注
本项目代码地址
1.播放按钮
包括一个圆形的背景和一个图片,以及点击后的事件回调
using OnButtonClickCallback = std::function<void()>;
class CircleButton : public QWidget
{
Q_OBJECT
public:
// icon_url: 正常状态下,鼠标未点击或者未进入控件区域时的图片
// active_icon_url: 鼠标进入控件区域或者点击时的图片
CircleButton(const QString& icon_url, const QString& active_icon_url = "", QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) override;
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
// 设置回调函数
void SetOnClickCallback(OnButtonClickCallback&& cbk);
// 切换图片,播放和暂定是2套不同的图片
void ChangeIcon(const QString& icon_url, const QString& active_icon_url = "");
signals:
private:
bool enter_ = false;
// 2个状态下的图片
QPixmap pixmap_;
QPixmap pixmap_active_;
// 保存回调函数
OnButtonClickCallback callback_;
};
CircleButton::CircleButton(const QString& icon_url, const QString& active_icon_url, QWidget *parent) : QWidget(parent) {
// 加载图片并缩放到合适的比例
this->ChangeIcon(icon_url, active_icon_url);
}
void CircleButton::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
int pen_width = 1;
QPen pen;
pen.setWidth(1);
// 鼠标进入和离开时,分别设置不同的画笔和画刷
if (enter_) {
pen.setColor(QColor(0x334466));
painter.setBrush(QBrush(QColor(0x334466)));
}
else {
pen.setColor(QColor(0xcccccc));
painter.setBrush(Qt::NoBrush);
}
painter.setPen(pen);
// 绘制一个圆形的背景
int radius = (this->width()-2*pen_width)/2;
painter.drawEllipse(QPointF(this->width()/2, this->height()/2), radius, radius);
//鼠标进入和离开时,绘制不同的图片
if (enter_ && !pixmap_active_.isNull()) {
painter.drawPixmap((this->width() - pixmap_.width())/2, (this->height() - pixmap_.height())/2, pixmap_);
} else {
painter.drawPixmap((this->width() - pixmap_active_.width())/2, (this->height() - pixmap_active_.height())/2, pixmap_active_);
}
}
void CircleButton::enterEvent(QEvent *event) {
enter_ = true;
repaint();
}
void CircleButton::leaveEvent(QEvent *event) {
enter_ = false;
repaint();
}
void CircleButton::mouseReleaseEvent(QMouseEvent *event) {
if (callback_) {
callback_();
}
repaint();
}
void CircleButton::SetOnClickCallback(OnButtonClickCallback&& cbk) {
this->callback_ = std::move(cbk);
}
// 加载图片,并缩放到合适的比例
void CircleButton::ChangeIcon(const QString& icon_url, const QString& active_icon_url) {
QImage image;
image.load(icon_url);
pixmap_ = QPixmap::fromImage(image);
pixmap_ = pixmap_.scaled(24, 24, Qt::KeepAspectRatio, Qt::SmoothTransformation);
if (!active_icon_url.isEmpty()) {
QImage image;
image.load(active_icon_url);
pixmap_active_ = QPixmap::fromImage(image);
pixmap_active_ = pixmap_active_.scaled(24, 24, Qt::KeepAspectRatio, Qt::SmoothTransformation);
}
repaint();
}
2.音量控制
绘制一个三角形,唯一需要注意的是,绘制方向是从上向下,从左到右,而我们的三角形是从下往上,越来越高的。因此计算斜率时,需要注意,我们计算得到的是蓝色三角形上,两个红圈代表的点之间的距离,因此上面红圈的坐标就是:高度-2个红圈之间的距离 = x轴到第一个红圈的距离
class VolumeController : public QWidget
{
Q_OBJECT
public:
explicit VolumeController(QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
// 设置当前音量,0~100
void SetCurrentVolume(int volume);
private:
int current_volume_ = 30;
};
void VolumeController::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
QPen pen;
pen.setWidth(1);
pen.setColor(QColor(0x334466));
painter.setPen(pen);
painter.setBrush(Qt::NoBrush);
// 绘制一个三角形,仅有边框
QPainterPath path;
path.moveTo(0, this->height()-1);
path.lineTo(this->width()-1, this->height()-1);
path.lineTo(this->width()-1, 0);
path.lineTo(0, this->height()-1);
painter.drawPath(path);
// 绘制填充区域
painter.setBrush(QBrush(QColor(0x334466)));
{
// 计算斜率,注意此时时数学上的方向
float k = this->height() * 1.0f / this->width();
// 计算当前音量下,x轴上的长度
int target_width = current_volume_*1.0f / 100.0f * this->width();
// 计算当前斜率下,y轴上的大小
int target_y = k * target_width;
QPainterPath path;
path.moveTo(0, this->height()-1);
// 高度-2个红圈之间的距离 = x轴到第一个红圈的距离
path.lineTo(target_width, this->height() - target_y);
path.lineTo(target_width, this->height() - 0);
path.lineTo(0, this->height()-1);
painter.drawPath(path);
}
}
void VolumeController::mousePressEvent(QMouseEvent *event) {
}
void VolumeController::mouseReleaseEvent(QMouseEvent *event) {
int percent = event->pos().x() * 1.0f / this->width() * 100;
SetCurrentVolume(percent);
repaint();
}
void VolumeController::SetCurrentVolume(int volume) {
this->current_volume_ = volume;
repaint();
}
3.添加到PlayController中
PlayController::PlayController(QWidget *parent) : QWidget(parent) {
auto root_layout = new QHBoxLayout();
...
{
auto item_layout = new QVBoxLayout();
LayoutHelper::ClearMarginSpacing(item_layout);
play_btn_ = new CircleButton(":/images/resources/play_arrow.svg", ":/images/resources/play_arrow_active.svg");
play_btn_->setFixedSize(QSize(30, 30));
play_btn_->SetOnClickCallback([=]() {
// 不同的状态,切换不同的图片
if (is_playing_) {
is_playing_ = false;
play_btn_->ChangeIcon(":/images/resources/play_arrow.svg", ":/images/resources/play_arrow_active.svg");
}
else {
is_playing_ = true;
play_btn_->ChangeIcon(":/images/resources/pause.svg", ":/images/resources/pause_active.svg");
}
});
item_layout->addStretch();
item_layout->addWidget(play_btn_);
item_layout->addStretch();
root_layout->addSpacing(25);
root_layout->addLayout(item_layout);
}
{
auto item_layout = new QVBoxLayout();
LayoutHelper::ClearMarginSpacing(item_layout);
volume_controller_ = new VolumeController(this);
volume_controller_->setFixedSize(QSize(100, 25));
item_layout->addSpacing(32);
item_layout->addWidget(volume_controller_);
item_layout->addStretch();
root_layout->addSpacing(25);
root_layout->addLayout(item_layout);
}
root_layout->addStretch();
setLayout(root_layout);
}
运行后,所有UI即可正常工作