哈尔滨的网站建设公司,网站建设方案总结语,wordpress 首页栏目,河北高端网站设计公司上篇文章#xff1a;RK3568源码编译与交叉编译环境搭建#xff0c;进行了OK3568开发板软件开发环境搭建#xff0c;通过编译RK3568的源码#xff0c;可以得到Qt开发的交叉编译相关工具。
本篇#xff0c;就来在搭建好的软件开发中#xff0c;进行Qt软件的开发测试。由于…上篇文章RK3568源码编译与交叉编译环境搭建进行了OK3568开发板软件开发环境搭建通过编译RK3568的源码可以得到Qt开发的交叉编译相关工具。
本篇就来在搭建好的软件开发中进行Qt软件的开发测试。由于Qt是支持跨平台的因此本篇的音乐播放器先在Windows上编写调试功能调好后再通过交叉编译在Linux板子上测试。
在第一篇的开箱介绍中体验了OK3568板子自带的Qt界面有视频播放器、音乐播放器等这些都实现了基本的播放功能但没有对操作界面做更加丰富的开发所以本篇来实现一个界面更加优美操作更新方便的音乐播放器软件可以实现音乐列表的显示与选择播放、歌词显示等先来看下最终的效果 本篇的Qt代码从野火Linux开发板的例程中移植修改而来下面分析下程序的代码结构。
1 音乐播放器开发总体结构
整个Qt音乐播放器项目的代码结构如下
主代码中是音乐播放器相关的代码包括 音乐播放器主界面唱片动画界面在音乐播放时显示一个唱片转动的动画效果操作按钮界面实现播放、暂停、继续、上一首、下一首、进度调节音量调节歌词显示界面当有对应的歌词时显示歌词歌词加载与计算 Ui代码中使用一些Qt的基本功能包括 一个Qt界面基类滑条功能类图标按钮显示类列表功能类 Skin中是一些图片资源和字体/皮肤定义最后是编译的中间文件和编译结果存储的目录 先看下程序的主要代码实现。
首先是整体的主界面部分进行各项功能的初始化显示主要包括
唱片界面初始化歌词界面初始化按钮界面初始化播放列表初始化
void MusicPlayer::InitWidget()
{QtWidgetTitleBar *widgetTitle new QtWidgetTitleBar(this);widgetTitle-SetScalSize(Skin::m_nScreenWidth, 60);widgetTitle-SetBackground(Qt::transparent);widgetTitle-setFont(QFont(Skin::m_strAppFontNormal));widgetTitle-SetTitle(tr(音乐播放器), #ffffff, 24);connect(widgetTitle, SIGNAL(signalBackHome()), this, SIGNAL(signalBackHome()));QHBoxLayout *horLayoutCentor new QHBoxLayout();horLayoutCentor-setContentsMargins(0, 0, 0, 0);horLayoutCentor-setSpacing(0);//唱片界面m_recorder new WidgetRecord(this);horLayoutCentor-addWidget(m_recorder, 1);//歌词界面m_lyricWidget new LyricWidget(this);horLayoutCentor-addWidget(m_lyricWidget, 1);//按钮界面m_playerToolBar new WidgetToolBar(this);connect(m_playerToolBar, SIGNAL(play()), this, SLOT(SltMusicPlay()));connect(m_playerToolBar, SIGNAL(pause()), this, SLOT(SltMusicPause()));connect(m_playerToolBar, SIGNAL(toolBarClicked(int)), this, SLOT(SltToolbarClicked(int)));QVBoxLayout *verLayoutAll new QVBoxLayout(this);verLayoutAll-setContentsMargins(0, 0, 0, 0);verLayoutAll-setSpacing(0);verLayoutAll-addWidget(widgetTitle, 1);verLayoutAll-addLayout(horLayoutCentor, 6);verLayoutAll-addWidget(m_playerToolBar);// 播放列表m_widgetMusicList new MusicPlayListWidget(this);connect(m_widgetMusicList, SIGNAL(signalMediaChanged(QString, QString)), this, SLOT(SltCurrentSongChanged(QString, QString)));m_widgetMusicList-hide();connect(m_playerToolBar, SIGNAL(next()), m_widgetMusicList-playList(), SLOT(next()));connect(m_playerToolBar, SIGNAL(previous()), m_widgetMusicList-playList(), SLOT(previous()));connect(m_playerToolBar, SIGNAL(currentPostionChanged(int)), this, SLOT(SltChangePostion(int)));
}初始化各个界面后还要连接对应的槽函数如点击操作按钮后的处理、切换播放列表中的音乐时的处理等。
2 自定义控件的代码
在介绍音乐播放器代码之前需要先介绍一些Qt自定义控件的代码这些代码属于公共代码写好了之后不仅音乐播放器可以用后续开发其它功能也可以复用这部分代码。
2.1 qtwidgetbase
这个cpp文件中定义了3个类
2.1.1 QtWidgetBase
窗口基类该类的一个主要功能是可以向窗口内添加图片形式的按钮并且通过鼠标事件给出哪个按钮被按下
void QtWidgetBase::addBtn(int index, QtPixmapButton *btn)
{m_btns.insert(index, btn);this-update();
}
void QtWidgetBase::mousePressEvent(QMouseEvent *e)
{QRect rect;foreach (QtPixmapButton *btn, m_btns){ScaleRect(rect, btn-rect());if (rect.contains(e-pos())){if (btn-isCheckAble()){btn-setChecked(!btn-isChecked());emit signalBtnClicked(btn-id());}else{btn-setPressed(true);}this-update();break;}}if (rect.contains(e-pos())){this-update();}QWidget::mousePressEvent(e);
}2.1.2 QtWidgetTitleBar
窗口的标题栏用于绘制窗口上方的标题如显示“音乐播放器”这几个字另外标题栏右侧还支持一个应用退出(返回)的图标按钮
void QtWidgetTitleBar::SetTitle(const QString title, const QColor textClr, const int fontSize)
{this-m_strTitle title;this-m_colorText textClr;this-m_nFontSize fontSize;this-update();
}void QtWidgetTitleBar::paintEvent(QPaintEvent *)
{QPainter painter(this);painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::TextAntialiasing);painter.scale(m_scaleX, m_scaleY);QRect rect(0, 0, m_nBaseWidth, m_nBaseHeight);if (m_pixmapBackground.isNull()){painter.fillRect(rect, m_colorBackground);}else{painter.drawPixmap(rect, m_pixmapBackground);}// 绘制文字QFont font painter.font();font.setPixelSize(m_nFontSize);painter.setFont(font);painter.setPen(m_colorText);painter.drawText(rect, Qt::AlignCenter, m_strTitle);
}2.1.3 QtAnimationWidget
属性动画移动窗体该类用于在窗口中实现一些简单的动画效果如音乐播放器会有一个唱片转动和唱针抬起放下的动作。 该类通过调用Qt的QPropertyAnimation属性动画类实现相关的功能:
QtAnimationWidget::QtAnimationWidget(QWidget *parent) : QtWidgetBase(parent)
{m_bShow false;m_animation new QPropertyAnimation(this, pos);m_colorBackground QColor(#ffffff);connect(m_animation, SIGNAL(finished()), this, SLOT(SltAnimationFinished()));connect(m_animation, SIGNAL(finished()), this, SIGNAL(signalAnimationFinished()));
}void QtAnimationWidget::StartAnimation(const QPoint startPos, const QPoint endPos, int duration, bool bShow)
{if (m_animation-state() ! QPropertyAnimation::Stopped){m_animation-stop();}if (!this-isVisible())this-setVisible(true);m_animation-setDuration(duration);m_animation-setStartValue(startPos);m_animation-setEndValue(endPos);m_bShow bShow;m_animation-start();
}QPropertyAnimation类的主要API接口
setStartValue指定动作的初始状态setEndValue指定动作的最终状态setDuration指定动画时长单位为毫秒start进行动画播放
2.2 qtsliderbar
用于实现自定义滑条控件分为水平滑条与竖直滑条音乐播放器的播放进度需要用到水平滑条音乐播放器的音量调节需要用到竖直滑条。滑条的基本形状是一个具有一定粗细的直线代表滑条上面一个圆形代表滑块可以是两个颜色不同的同心圆。 画水平滑条的主要代码如下
//画水平滑条
void QtSliderBar::drawHorizontalBar(QPainter *painter)
{painter-save();QPen pen(m_colorSlider, m_nSliderSize, Qt::SolidLine, Qt::RoundCap);painter-setPen(pen);int nY this-height() / 2;int radius m_nHandleSize / 2;painter-drawLine(radius, nY, this-width() - radius, nY);// 先绘制那个大圆QRect rect(m_nOffset - radius, nY - radius, m_nHandleSize, m_nHandleSize);painter-setPen(Qt::NoPen);painter-setBrush(m_bShowHandleBg ? m_colorHandleBg : m_colorHandle);painter-drawEllipse(rect.left(), rect.top(), m_nHandleSize, m_nHandleSize);QPainterPath path;path.moveTo(radius, nY);path.lineTo((m_nOffset m_nHandleSize) ? m_nOffset - radius : radius, nY);path.addEllipse(rect.left() radius / 2, nY - radius / 2, radius, radius);pen.setColor(m_colorHandle);painter-setPen(pen);painter-setBrush(m_colorHandle);painter-drawPath(path);painter-restore();
}2.3 qtpixmapbutton
图片按钮顾名思义就是(小)图片形式的按钮支持未按下和按下后的两种样式的图片显示。如音乐播放器的这些操作按钮都是图片形式的按钮 该类在构造函数时将按钮的id图片按钮要显示的位置未按下时和按下时要展示的图片通过参数传入即可
QtPixmapButton::QtPixmapButton(int id, QRect rect, QPixmap pixmapNormal, QPixmap pixmapPressed) :m_nId(id),m_rect(rect),m_strText(),m_pixmapNormal(pixmapNormal),m_pixmapPressed(pixmapPressed),m_bPressed(false),m_bVisible(true),m_bCheckAble(false),m_bChecked(false),m_bEnable(true)
{}QPixmap QtPixmapButton::pixmap()
{return (m_bPressed || m_bChecked) ? m_pixmapPressed : m_pixmapNormal;
}2.4 qtlistwidget
这个cpp文件中定义了2个类
QtListWidgetItemQtListWidget
2.4.1 QtListWidgetItem
该类用于表示列表中的每一个项可以是字符并且可以带有图片(图标)
class QtListWidgetItem
{
public:QtListWidgetItem(int id, const QStringList args);QtListWidgetItem(int id, const QString name);QtListWidgetItem(int id, const QString name, const QPixmap icon);QtListWidgetItem(int id, const QString path, const QString name, const QPixmap icon);int m_nId;QString m_strText;QPixmap m_pixmapIcon;QString m_strBaseName;QString m_strPath;QRect m_rect;QStringList m_strMultiParameters;bool m_bPressed;
};2.4.2 QtListWidget
项目的显示可以按列显示也可以按行显示并且支持鼠标的滑动显示音乐播放器的音乐列表就是按列显示的 该组件的类定义如下
class QtListWidget : public QtWidgetBase
{Q_OBJECT
public:typedef enum{None,LeftDirection,RightDirection,UpDirection,DownDirection} MoveDirection;Q_PROPERTY(int xPos READ movePos WRITE setMovePos)explicit QtListWidget(QWidget *parent 0);~QtListWidget();QtListWidgetItem *currentItem();void AddItem(int id, QtListWidgetItem *item);void SetItems(const QMapint, QtListWidgetItem * items);void SetBackground(const QPixmap pixmap);void SetBackground(const QColor color);void setItemSize(int size);void setHoriazontal(bool bOk);void setAlignment(Qt::Alignment aligns);void setScaleSize(int w, int h);public slots:void setPrevIndex();void setCurrentIndex(int index);void setNexIndex();signals:void currentItemClicked(QtListWidgetItem *item);void currentIndexClicked(int index);private:void setMovePos(int nValue);int movePos() { return m_nStartPos; }void ClearItems();private:bool m_bPressed;QPoint m_startPos;int m_nStartPos;int m_nMoveEndValue;bool m_bRecovery;protected:QMapint, QtListWidgetItem * m_listItems;int m_alignment;QColor m_backgroundColor;QPixmap m_pixmapWallpaper;QColor m_colorText;int m_nStartIndex;int m_nCurrentIndex;int m_nMargin;int m_nSpace;int m_nItemShowCnt;int m_nItemSize;bool m_bHorizontal;QPropertyAnimation *m_animationMove;int m_nDirection;protected:QSize sizeHint() const;void resizeEvent(QResizeEvent *e);void mousePressEvent(QMouseEvent *e);void mouseReleaseEvent(QMouseEvent *);void mouseMoveEvent(QMouseEvent *e);void paintEvent(QPaintEvent *);void drawHorizontalItem(QPainter *painter);void drawVerticalItem(QPainter *painter);virtual void drawItemInfo(QPainter *painter, QtListWidgetItem *item);
};3 音乐播放器代码
上面介绍了一些公用的自定义组件下面就是利用这些自定义组件以及Qt的各种功能实现一个音乐播放器。
3.1 音乐播放
音乐播放部分主要有三部分功能
音频解码播放使用Qt自带的媒体播放器组件QMediaPlayer进行音频播放播放时的按钮操作上一首、暂停/继续、下一首、播放进度调节、音量调节、音乐列表按钮唱片动画界面在音乐播放时显示一个唱片转动的动画效果以及唱针放下抬起的动作 3.1.1 QMediaPlayer播放音频
这里使用Qt自带的QMediaPlayer组件进行音频的播放QMediaPlayer播放音频的基本步骤为
创建一个QMediaPlayer连接播放位置变化的槽函数设置播放的音乐文件设置音量开始播放
player new QMediaPlayer;
connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(positionChanged(qint64)));
player-setMedia(QUrl::fromLocalFile(./Music/test.mp3));
player-setVolume(50);
player-play();本项目的音频播放初始化部分
void MusicPlayer::InitPlayer()
{m_player new QMediaPlayer(this);m_player-setPlaylist(m_widgetMusicList-playList());connect(m_player, SIGNAL(durationChanged(qint64)), this, SLOT(SltDurationChanged(qint64)));connect(m_player, SIGNAL(positionChanged(qint64)), this, SLOT(SltPostionChanged(qint64)));connect(m_player, SIGNAL(error(QMediaPlayer::Error)), this, SLOT(SltMediaError(QMediaPlayer::Error)));m_volumeSlider new QtSliderBar(this);m_volumeSlider-SetHorizontal(false);m_volumeSlider-SetValue(100);m_volumeSlider-hide();connect(m_volumeSlider, SIGNAL(currentValueChanged(int)), m_player, SLOT(setVolume(int)));
}3.1.2 播放操作按钮
音乐播放时需要用到播放、暂停、继续、上一首、下一首、进度调节、音量调节等操作按钮这里的对应按钮使用图标显示为对应的按钮通过加载QPixmap来实现
void MusicToolBar::InitWidget()
{// 按钮m_btns.insert(0, new QtPixmapButton(0, QRect(12, 4, 60, 60), QPixmap(:/images/music/ic_prev.png), QPixmap(:/images/music/ic_prev_pre.png)));m_btns.insert(1, new QtPixmapButton(1, QRect(64, 4, 60, 60), QPixmap(:/images/music/ic_play.png), QPixmap(:/images/music/ic_pause.png)));m_btns.insert(2, new QtPixmapButton(2, QRect(128, 4, 60, 60), QPixmap(:/images/music/ic_next.png), QPixmap(:/images/music/ic_next_pre.png)));m_btns.insert(3, new QtPixmapButton(3, QRect(680, 4, 60, 60), QPixmap(:/images/music/ic_volume.png), QPixmap(:/images/music/ic_volume_pre.png)));m_btns.insert(4, new QtPixmapButton(4, QRect(740, 4, 60, 60), QPixmap(:/images/music/ic_list.png), QPixmap(:/images/music/ic_list_pre.png)));m_btns.value(1)-setCheckAble(true);connect(this, SIGNAL(signalBtnClicked(int)), this, SLOT(SltBtnClicket(int)));// 进度条m_progressBar new QtSliderBar(this);m_progressBar-SetHorizontal(true);m_progressBar-SetMaxValue(0);m_progressBar-SetValue(0);// 进度条的值改变, 转变为MusicToolBar的信号currentPostionChanged()connect(m_progressBar, SIGNAL(currentValueChanged(int)), this, SIGNAL(currentPostionChanged(int)));
}3.1.3 播放时的动画界面
为了在播放时能有视觉上的动态效果这里加了一个唱片转动的动画效果当音乐播放时唱针移动到唱片上唱片开始转动。
MusicRecord::MusicRecord(QWidget *parent) : QtWidgetBase(parent)
{m_nRotateCD 0;m_nRotateHandle 0;m_bPlay false;m_nBaseWidth 400;m_nBaseHeight 350;m_handlePixmap new PixmapItem(QPixmap(:/images/music/ic_handle.png), this);m_pixmapRecord QPixmap(:/images/music/ic_blackrecord.png);m_pixmapArtist QPixmap(:/images/music/ic_cd.png);m_timer new QTimer(this);m_timer-setInterval(100);connect(m_timer, SIGNAL(timeout()), this, SLOT(SltCicleRun()));m_animationHandle new QPropertyAnimation(m_handlePixmap, ratote);m_animationHandle-setDuration(300);m_animationHandle-setEasingCurve(QEasingCurve::Linear);connect(m_animationHandle, SIGNAL(valueChanged(QVariant)), this, SLOT(SltHandleMove(QVariant)));
}
void MusicRecord::Start()
{m_bPlay true;m_timer-start();m_animationHandle-setStartValue(0);m_animationHandle-setEndValue(30);m_animationHandle-start();this-update();
}void MusicRecord::Stop()
{m_bPlay false;m_timer-stop();m_animationHandle-setStartValue(30);m_animationHandle-setEndValue(0);m_animationHandle-start();this-update();
}3.2 播放列表
播放列表功能用来实现音频文件的显示以及手动指定切换要播放的音乐。 3.2.1 读取音乐文件
这里使用Qt的QMediaPlaylist组件来实现音乐列表的管理。QMediaPlaylist是一个列表它可以保存媒体文件包括媒体路径等信息它具有着列表的性质比如添加删除插入等但它能做的比单纯的储存要多得多。设置播放顺序对播放的控制保存到本地从本地读取都可以很方便地实现。
void MusicPlayListWidget::ScanDirMedias(const QString path)
{QDir dir(path);if (!dir.exists())return;dir.setFilter(QDir::Dirs | QDir::Files);dir.setSorting(QDir::DirsFirst);QFileInfoList list dir.entryInfoList();int index m_mapItems.size();for (int i 0; i list.size(); i){QFileInfo fileInfo list.at(i);if (fileInfo.fileName() . || fileInfo.fileName() ..){continue;}if (fileInfo.isDir()){ScanDirMedias(fileInfo.filePath());}else if (fileInfo.suffix() mp3){QString strName fileInfo.baseName().toLocal8Bit().constData();QString strPath fileInfo.absoluteFilePath().toLocal8Bit().constData();m_playList-addMedia(QUrl::fromLocalFile(strPath));m_mapItems.insert(index, new QtListWidgetItem(index, strPath, strName, QPixmap()));index;}}
}3.2.2 音乐列表界面
音乐列表的具体界面实现主要是在对应的矩形位置显示各个音乐文件的名称
MusicPlayListWidget::MusicPlayListWidget(QWidget *parent) : QtAnimationWidget(parent)
{this-setAttribute(Qt::WA_TranslucentBackground);m_colorBackground QColor(#5362b5);m_nBaseWidth 405;m_nBaseHeight 350;m_nYPos 60;m_listWidget new PlayListWidget(this);QVBoxLayout *verLayout new QVBoxLayout(this);verLayout-setContentsMargins(0, 10, 0, 10);verLayout-setSpacing(0);verLayout-addStretch(1);verLayout-addWidget(m_listWidget, 9);// 播放列表(创建一个QMediaPlaylist))m_playList new QMediaPlaylist(this);m_playList-setPlaybackMode(QMediaPlaylist::Loop);connect(m_playList, SIGNAL(currentIndexChanged(int)), this, SLOT(SltCurrMediaChanged(int)));connect(m_listWidget, SIGNAL(currentIndexClicked(int)), m_playList, SLOT(setCurrentIndex(int)));
}3.3 歌词显示
歌词显示功能需要在音乐播放的时候能根据播放的进度显示对应的歌词。 3.3.1 歌词显示界面
歌词界面的具体界面实现主要是在对应的矩形位置显示当前音乐播放位置前后的音乐歌词并高亮当前播放的那句歌词
void LyricWidget::drawLyricLines(QPainter *painter)
{painter-save();QTextOption option;option.setWrapMode(QTextOption::WordWrap);option.setAlignment(Qt::AlignCenter);QRect rect(0, 0, m_nBaseWidth, 52);int index 0;for (int i 0; i m_nShowCount; i){rect QRect(rect.left(), rect.bottom(), rect.width(), LYRIC_LINE_HEIGHT);index m_nStartIndex i;QString strText index m_strLyricLines.size() ? m_strLyricLines.at(index) : ;painter-setPen(index m_nCurrentIndex ? Qt::white : Qt::black);painter-drawText(rect, strText, option);}painter-restore();
}3.3.2 歌词显示时间计算
通过下面这个函数计算当前音乐播放的位置
void LyricWidget::SetLyricPostion(int postion)
{if (!m_bLyricLoad)return;m_lyricFactory-findIndex(postion);
}4 交叉编译与测试
如果是在Windows上编写的程序并且支持Windows上运行在Qt程序编写好后可以先在Windows查看运行效果。
通过交叉编译来测试音乐播放器在OK3568-C板子上的播放效果。
为了方便每次的编译我这里编写一个my3568build.sh的编译脚本
#! /bin/bashmkdir -p build
cd buildexport PATH/home/xxpcb/myTest/OK3568/sourcecode/OK3568-linux-source/buildroot/output/OK3568/host/bin:$PATHqmake .. make然后执行该脚本即可编译:
./my3568build.sh 将编译成功的可执行文件MusicPlayer复制到OK3568-C板子中然后在其同目录下创建一个music文件夹里面放入若干个mp3音乐文件和对应的歌词文件然后就可以测试了 文件复制到板子我这里使用的ADB无线传输的方式比较方便具体ADB操作演示可参考上篇文章最后的Qt交叉编译与测试部分
需注意的是板子里的这个Linux系统不支持中文的显示所以我把歌名都先改成了字母后再复制到板子中进行测试。
5 总结
本篇介绍了使用Qt开发一个音乐播放器首先是一个Qt自定义控件的介绍包括滑条、图标按钮、列表等然后使用这些自定义组件以及Qt的各种功能实现一个音乐播放器具有基础的音乐播放、暂停继续、歌曲列表显示歌曲切换等功能。代码可以在Windows上运行通过交叉编译可以在OK-3568这块Linux板子上运行。