经过多日摸鱼,我终于摆脱了前端的泥淖,今天是时候开始重拾我心爱的C艹了。
One
呃,学长给的这demo看起来有一点点简陋。但至少可以播放。
算了,先来看看他的代码实现吧。
显然,mainwindow里面放的是主界面,playerlist是导歌的组件
playerlist
PlayerList
类定义了信号/槽函数如下:
1 | signals: |
从名字看是点击打开文件按钮之后的事件。
不妨进入源码:
首先是PlayerList
类的构造函数:(这里我自行添加了注释)
1 | PlayerList::PlayerList(QWidget *parent) : QWidget(parent) |
然后是openFileButtonClicked
:
1 | void PlayerList::openFileButtonClicked(){ |
mainwindow
MainWindow
构造函数:
1 | MainWindow::MainWindow(QWidget *parent) |
好的,源码分析就到这里。
定个小目标,今天弄成这样:
过会就开工!
Two Records
过会(指摸了三天然后通关了宝可梦再开始。
我发现QT的examples里就有musicplayer的样例,非常好啊!
准备先阅读一番。
QT_FORWARD_DECALARE_CLASS()
一个QT的预处理宏,
1用来前向声明,避免不需要的include。
Q_PROPERTY(“property”, #arg)
Example:
1
2
3 /* 对于一个属性volume,靠volume函数获取其值,靠setVolume改变其值,
并且和槽函数volumeChanged连接 */
Q_PROPERTY(int volume READ volume WRITE setVolume NOTIFY volumeChanged)
QToolButton的PopupMode
一般分为三种:
- QToolButton::DelayedPopup 点击一定时间和单击立刻松开的效果有别。
- QToolButton::MenuButtonPopup 按钮上会有一个箭头指示有弹出菜单存在。
- QToolButton::InstantPopup 一经点击,立刻弹出。
QOverload<>::of()
当某函数有多个重载版本时,可以用该函数来指定调用哪个版本的重载函数。
多用于信号槽的连接。
例如:
1 connect(slider, &QAbstractSlider::valueChanged, label, QOverload<int>::of(&QLabel::setNum));将Slider值改变的事件与setNum以int为参数的版本连接。
QBoxLayout
用于布局的类。
其有两个子类。
QHBoxLayout,用于水平方向布局。QVBoxLayout,用于竖直方向布局。
QStandardPaths::standardLocations()
获取系统标准中某一类型文件的存储路径列表(QStringList)。
1 fileDialog.setDirectory(QStandardPaths::standardLocations(QStandardPaths::MusicLocation).value(0, QDir::homePath()));上面这段代码的意思是,将fileDialog的初始位置设置在标准音乐路径的索引0处(一般系统标准下只会有这一个路径),若该列表为空,则进入$HOME返回的路径。
value函数继承自QList,有两个重载版本:
- template<class T> T QList<T>:value(int index) 返回列表中第i个元素;
- template<class T> T QList<T>:value(int index, const T &default) 返回列表第i个元素,若列表无第i个元素,则返回default的引用
QWidget::setToolTip(const QString&)
设置Widget对象的悬停显示文本。
我们常常看到setToolTip与tr同用。这里的tr全称是translate,是用于国际化的一个函数。
More Details See This
Inside Sample Object Tree
这个样例播放器的布局,完全依赖与QBoxLayout这个类。不妨让我们看看它的层级结构。
MusicPlayer: public QWidget
- controlLayout(
QHBoxLayout
)
openButton
(QToolButton *
, has a ToolTip “Open a file…”, connected withopenFile
)playButton
(QToolButton *
, has a ToolTip “Play” or “Pause”, connected withtogglePlayBack
)positionSlider
(QSlider, Qt::Horizontal
, has a ToolTip “Seek”)volumeButton
(QToolButton *
, has a ToolTip “Adjust Volume”, a menu popping up after user clicking the button)
menu
(QMenu
, has an QWidgetActionaction
)popup
(QWidget *
, set as the DefaultWidget ofaction
)popupLayout
(QHBoxLayout
)
slider
(QSlider, Qt::Horizontal, triggeringvolumeChanged
when its value changed)label
(QLabel, explicitly shows the volume, num changed as the slider’s value changing)
set icon of buttons
btn->setIcon(QPixmap(“:/rsc/filename”))
Pass parameters from signals to slots
信号函数的参数数量和类型注意要与槽函数的一致. 这个问题我也花了好久解决. 写这个QT真是踩一堆坑, 难受.
Into MusicPlayer::setPosition
今天解决了一个之前的疑惑.
直接上代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 void MusicPlayer::init()
{
...
/** 这里的valueChanged为什么不直接和player的setPosition connect呢? 是个好问题:
* 因为这样会造成卡顿.
* 只要sliderBar的值改变都会触发player的setPosition
* 但我们需要的是什么呢? 是手动调整sliderBar时才触发这一事件.
* 故MusicPlayer::setPosition中设置了if条件, 就是为了避免这一错误.
*/
connect(sliderBar, &QSlider::valueChanged, this, &MusicPlayer::setPosition);
...
}
void MusicPlayer::setPosition(int pos)
{
if(qAbs(player->position() - pos) > 99)
player->setPosition(pos);
}
Three 2021/2/5 Updation
看起来有点样子了. 开心.
Four
因为有恶性bug把前一个版本改成了后一个 出来混早晚要还的.
明天早上起来改改, 准备准备收工了.
Five
解决方法:
重写paintEvent
方法.
Six
暂时不改了, 这是仓库地址: View Source Code Here