最新大型开源项目-云游戏,云桌面系统,欢迎关注
本项目代码地址
播放控制区
总共4个部分
1.最左边圆形logo区域,可自动旋转
2.播放进度条
3.暂停,开始按钮
4.音量控制
1.旋转的Logo
主要步骤如下
1.将图片绘制成圆形
2.边上绘制一个暗色的圆环,圆心绘制一个白色的小圆圈
3.启动定时器,使图片按一定速度旋转
绘制这个控件相对简单,唯一需要注意的是,绘制的起始点在左上角,要想让圆形图片绕中心旋转,需要对坐标有所偏移
首先要移动绘制中心,从蓝色点移动到红色点,移动前,蓝色点的坐标为(0,0),移动之后,红色点为(0,0),在此时,蓝色点将变为(-宽度/2,-高度/2).
class RotateCover : public QWidget
{
Q_OBJECT
public:
// size: 设置当前控件的大小
// url: 设置图片的资源地址
explicit RotateCover(int size, const QString& url, QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) override;
private:
// 保存图片
QPixmap pixmap_;
// 定时器,用来更新旋转角度
QTimer* rotate_timer_ = nullptr;
// 当前的旋转角度
float rotate_angel_ = 0;
};
RotateCover::RotateCover(int size, const QString& url, QWidget *parent) : QWidget(parent) {
// 设置widget大小
setFixedSize(QSize(size, size));
// 加载图片并缩放到widget相同的尺寸
QImage image;
image.load(url);
pixmap_ = QPixmap::fromImage(image);
pixmap_ = pixmap_.scaled(size, size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
// 启动定时器,每隔17ms增加0.8度
rotate_timer_ = new QTimer(this);
connect(rotate_timer_, &QTimer::timeout, this, [=]() {
rotate_angel_ += 0.8f;
repaint();
});
rotate_timer_->start(17);
}
void RotateCover::paintEvent(QPaintEvent *event) {
QPainter painter(this);
int pen_width = 4;
QPen pen;
pen.setWidth(pen_width);
pen.setColor(QColor(0x334466));
painter.setPen(pen);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
painter.save();
// 移动到中心
painter.translate(this->width()/2, this->height()/2);
// 旋转一定的角度
painter.rotate(rotate_angel_);
QPainterPath path;
QRect circle_image_rect;
//注意此时的X Y坐标,
circle_image_rect.setX(-this->width()/2);
circle_image_rect.setY(-this->width()/2);
circle_image_rect.setWidth(this->width());
circle_image_rect.setHeight(this->height());
path.addRoundedRect(circle_image_rect, this->width()/2, this->height()/2);
painter.setClipPath(path);
// 绘制图片,注意此时的X Y坐标
painter.drawPixmap(-this->width()/2, -this->width()/2, pixmap_);
// 执行restore之后,绘制原点就变回左上角了,接下来按普通绘制即可。
painter.restore();
// 绘制一个圆形的边框
QRect border_rect(pen_width/2, pen_width/2, this->width()-pen_width, this->height()-pen_width);
painter.drawRoundedRect(border_rect, border_rect.width()/2, border_rect.height()/2);
// 中心绘制一个小的圆形
int inner_circle_width = 12;
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(QColor(0xffffff)));
painter.drawEllipse(QPointF(this->width()/2, this->height()/2), inner_circle_width, inner_circle_width);
}
2.播放进度
主要步骤如下
1.绘制横向的长条,颜色是未激活的底色
2.绘制已经走过的区域,长条变为激活的颜色
3.绘制可以拖动的圆形按钮,颜色为激活的颜色
paintEvent和各种鼠标事件已经多次使用,不在赘述
class Slider : public QWidget
{
Q_OBJECT
public:
// nc 未激活的颜色
// ac 已经激活的颜色
Slider(int nc, int ac, QWidget *parent = nullptr);
void paintEvent(QPaintEvent *event) override;
void enterEvent(QEvent *event) override;
void leaveEvent(QEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
//设置当前的进度,0~100
void SetCurrentProgress(int percent);
private:
int normal_color_;
int active_color_;
bool enter_ = false;
bool mouse_pressed_ = false;
// 存储当前圆形按钮的位置,鼠标点击,拖动后会更新
int circle_handle_x_offset_ = 0;
};
Slider::Slider(int nc, int ac, QWidget *parent) : QWidget(parent) {
this->normal_color_ = nc;
this->active_color_ = ac;
setMouseTracking(true);
}
void Slider::paintEvent(QPaintEvent *event) {
QPainter painter(this);
painter.setRenderHint(QPainter::RenderHint::Antialiasing);
int circle_handle_radius = 6;
int slider_height = 2;
painter.setPen(Qt::NoPen);
painter.setBrush(QBrush(QColor(normal_color_)));
int slider_x_offset = 0;
int slider_y_offset = (this->height() - slider_height)/2;
// 绘制一条横向的长条,占满整个widget的宽度,颜色是未激活的底色
painter.drawRect(slider_x_offset, slider_y_offset, this->width(), slider_height);
// 绘制一个从0到circle_handle_x_offset_的长条,为激活的颜色,覆盖一部分未激活的区域,代表已经走过了这段距离
painter.setBrush(QBrush(QColor(active_color_)));
painter.drawRect(slider_x_offset, slider_y_offset, circle_handle_x_offset_, slider_height);
QPen pen;
pen.setColor(QColor(0xcccccc));
pen.setWidth(1);
painter.setPen(pen);
// 绘制一个圆形的按钮,刚好在当前的进度所在的位置
painter.drawEllipse(QPointF(circle_handle_x_offset_, this->height()/2), circle_handle_radius, circle_handle_radius);
}
void Slider::enterEvent(QEvent *event) {
enter_ = true;
repaint();
}
void Slider::leaveEvent(QEvent *event) {
enter_ = false;
repaint();
}
//鼠标按下,更新按钮当前的坐标
void Slider::mousePressEvent(QMouseEvent *event) {
mouse_pressed_ = true;
circle_handle_x_offset_ = event->pos().x();
repaint();
}
//鼠标按下且正在移动,更新按钮当前的坐标
void Slider::mouseMoveEvent(QMouseEvent *event) {
if (mouse_pressed_) {
circle_handle_x_offset_ = event->pos().x();
repaint();
}
}
void Slider::mouseReleaseEvent(QMouseEvent *event) {
mouse_pressed_ = false;
repaint();
}
// 将百分比,映射到x坐标上,然后绘制
void Slider::SetCurrentProgress(int percent) {
percent = std::min(100, percent);
circle_handle_x_offset_ = percent * 1.0f / 100.0f * this->width();
repaint();
}
3.统一管理这个区域的控件
定义一个PlayerController类,用来同一存放这几个控件
class PlayController : public QWidget
{
Q_OBJECT
public:
explicit PlayController(QWidget *parent = nullptr);
private:
// 旋转的Logo
RotateCover* rotate_cover_ = nullptr;
// 标题
QLabel* title_ = nullptr;
// 播放进度控制
Slider* slider_ = nullptr;
};
这个就比较简单了,直接添加到布局中即可。
PlayController::PlayController(QWidget *parent) : QWidget(parent) {
auto root_layout = new QHBoxLayout();
LayoutHelper::ClearMarginSpacing(root_layout);
root_layout->addSpacing(2);
{
auto item_layout = new QVBoxLayout();
LayoutHelper::ClearMarginSpacing(item_layout);
rotate_cover_ = new RotateCover(60, ":/images/resources/preset_1.jpg", this);
item_layout->addStretch();
item_layout->addWidget(rotate_cover_);
item_layout->addStretch();
root_layout->addSpacing(20);
root_layout->addLayout(item_layout);
}
{
auto item_layout = new QVBoxLayout();
LayoutHelper::ClearMarginSpacing(item_layout);
title_ = new QLabel();
title_->setText("海浪之声");
title_->setStyleSheet("font-family:Microsoft YaHei; font-size: 15px; font-weight: bold;");
item_layout->addSpacing(15);
item_layout->addWidget(title_);
slider_ = new Slider(0xbbbbbb, 0x334466, this);
slider_->setFixedHeight(30);
slider_->setMinimumWidth(450);
slider_->SetCurrentProgress(50);
item_layout->addSpacing(10);
item_layout->addWidget(slider_);
item_layout->addStretch();
root_layout->addSpacing(20);
root_layout->addLayout(item_layout);
}
root_layout->addStretch();
setLayout(root_layout);
}
4.添加到MainWindow中,放在声音素材展示区下面
MainWindow::MainWindow(QWidget *parent)
: QWidget(parent) {
...
title_bar_ = new TitleBar(this);
side_bar_ = new SideBar(this);
// 生成
play_controller_ = new PlayController();
auto right_content_layout = new QVBoxLayout();
LayoutHelper::ClearMarginSpacing(right_content_layout);
content_area_ = new QScrollArea();
right_content_layout->addWidget(content_area_);
//添加进去
play_controller_->setFixedHeight(90);
right_content_layout->addWidget(play_controller_);
right_content_layout->addStretch();
...
}
最后运行