项目描述:QT开发的一个MP3播放器。基本实现功能包括:上一首、播放/暂停、停止、下一首、文件打开、歌词同步显示、播放列表的显示、显示到托盘等功能。
项目代码如下:
widget.h
1 #ifndef WIDGET_H 2 #define WIDGET_H 3 4 #include <QWidget> 5 #include <phonon> 6 #include <QTimer> 7 8 #include <QTextEdit> 9 #include <QSystemTrayIcon> 10 #include <QMenu> 11 12 namespace Ui { 13 class Widget; 14 } 15 16 class Widget : public QWidget 17 { 18 Q_OBJECT 19 20 public: 21 explicit Widget(QWidget *parent = 0); 22 ~Widget(); 23 void creatActions();//创建动作 24 25 private slots: 26 void on_toolButton_previous_clicked();//上一首 27 void on_toolButton_playpause_clicked();//播放/暂停 28 void on_toolButton_stop_clicked();//停止播放 29 void on_toolButton_next_clicked();//下一首 30 void on_toolButton_open_clicked();//打开 31 32 private: 33 Ui::Widget *ui; 34 Phonon::MediaObject *mediaObject;//管理媒体源 35 Phonon::MediaObject *musicInformationMediaObject;// 36 Phonon::VideoWidget *videoWidget;// 37 Phonon::AudioOutput *audioOutput;//连接物理设备 38 Phonon::SeekSlider *seekSlider;//实现进度条 39 Phonon::VolumeSlider *volumeSlider;//音量调节 40 QList<Phonon::MediaSource> musicSourceList;//播放列表 41 42 QTimer *timer; 43 44 QIcon *iconplay; 45 QIcon *iconpause; 46 47 QAction *play; 48 QAction *stop; 49 QAction *open; 50 QAction *exit; 51 52 public: 53 void setCurrentLrc();//设置歌词显示 54 55 private slots: 56 void listWidget_cellDoubleClicked(QModelIndex);//双击选歌 57 void showTime(qint64);//时间更新显示 58 void mediaObjectStateChanged(Phonon::State,Phonon::State); 59 void musicAboutToFinish();//歌曲快结束时 60 void currentMusicSourceChanged(Phonon::MediaSource); 61 void musicInformationStateChanged(Phonon::State,Phonon::State); 62 void exitSlot(); 63 void iconActivated(QSystemTrayIcon::ActivationReason); 64 65 private: 66 QTextEdit *text;//解析歌词 67 QSystemTrayIcon *trayicon; 68 QMenu *trayiconMenu; 69 70 protected: 71 void keyPressEvent(QKeyEvent *); 72 void dragEnterEvent(QDragEnterEvent *); 73 void dropEvent(QDropEvent *);//拖放歌曲 74 }; 75 76 #endif // WIDGET_H
wdget.cpp
1 #include <QFileDialog> 2 #include <QtGlobal> 3 #include <QDesktopServices> 4 #include <QKeyEvent> 5 #include <QMouseEvent> 6 #include <QtGui> 7 8 #include "widget.h" 9 #include "ui_widget.h" 10 11 Widget::Widget(QWidget *parent) : 12 QWidget(parent), 13 ui(new Ui::Widget) 14 { 15 ui->setupUi(this); 16 17 this->setWindowTitle(tr("MP3播放器"));//设置标题 18 this->setMouseTracking(true);//启用widget的鼠标跟踪。 19 20 /**初始化媒体**/ 21 mediaObject =new Phonon::MediaObject();//媒体对象 22 mediaObject->setTickInterval(1); 23 audioOutput = new Phonon::AudioOutput(Phonon::VideoCategory);//音频输出 24 Phonon::createPath(mediaObject,audioOutput);//连接媒体对象与音频输出 25 26 musicInformationMediaObject = new Phonon::MediaObject(this); //音乐信息对象 27 28 volumeSlider = new Phonon::VolumeSlider(audioOutput,this); //音量滑动条 29 volumeSlider->move(220,70); 30 volumeSlider->resize(50,20); 31 volumeSlider->setStyleSheet("background-color:rgb(255,255,255,100)"); 32 volumeSlider->setFixedWidth(100);//固定音量条大小 33 34 seekSlider = new Phonon::SeekSlider(mediaObject,this); //进度滑动条 35 seekSlider->move(10,35); 36 seekSlider->resize(170,20); 37 seekSlider->setStyleSheet("background-color:rgb(255,255,255,100)"); 38 39 creatActions(); 40 41 connect(mediaObject,SIGNAL(tick(qint64)),this,SLOT(showTime(qint64))); 42 //时间显示与歌词的更新,tick发射媒体对象流的时间参数,单位毫秒 43 connect(mediaObject,SIGNAL(stateChanged(Phonon::State,Phonon::State)),this,SLOT(mediaObjectStateChanged(Phonon::State,Phonon::State))); 44 45 text = new QTextEdit(this); 46 text->hide();//用于查找下句歌词以计算时间间隔 47 ui->textEdit->setVisible(false);//文本编辑框不可见,(解析歌词) 48 connect(ui->listWidget,SIGNAL(doubleClicked(QModelIndex)),SLOT(listWidget_cellDoubleClicked(QModelIndex))); 49 //双击播放歌曲 50 connect(musicInformationMediaObject, SIGNAL(stateChanged(Phonon::State,Phonon::State)),this, SLOT(musicInformationStateChanged(Phonon::State,Phonon::State))); 51 //当加入新音乐时执行 52 //自动播放下一首 53 connect(mediaObject,SIGNAL(aboutToFinish()),this,SLOT(musicAboutToFinish()));//本首音乐快结束时 54 connect(mediaObject,SIGNAL(currentSourceChanged(Phonon::MediaSource)),this,SLOT(currentMusicSourceChanged(Phonon::MediaSource))); 55 56 QPalette palette = ui->label_lrc->palette();//设置窗体内歌词颜色 57 palette.setColor(QPalette::WindowText,Qt::darkBlue); 58 ui->label_lrc->setPalette(palette); 59 60 setWindowIcon(QIcon(":/images/blank.png")); 61 setAutoFillBackground(true); 62 63 ui->listWidget->setStyleSheet("background:rgb(255,255,255,0,)"); 64 seekSlider->setToolTip(tr("播放进度条"));//鼠标停留显示 setAcceptDrops(true); 65 setAcceptDrops(true); 66 } 67 68 Widget::~Widget() 69 { 70 delete ui; 71 } 72 73 void Widget::exitSlot()//托盘菜单的关闭 74 { 75 this->hide(); 76 this->close(); 77 } 78 79 //上一首 80 void Widget::on_toolButton_previous_clicked() 81 { 82 int index = musicSourceList.indexOf(mediaObject->currentSource()) - 1; 83 if(index >= 0) 84 { 85 mediaObject->stop(); 86 mediaObject->setCurrentSource(musicSourceList.at(index)); 87 mediaObject->play(); 88 } 89 else 90 { 91 QMessageBox::information(this, tr("警告"), tr("没有上一首歌曲")); 92 return; 93 } 94 } 95 96 //播放/暂停 97 void Widget::on_toolButton_playpause_clicked() 98 { 99 if(musicSourceList.isEmpty()) 100 { 101 QMessageBox::information(this, tr("警告"), tr("没有歌曲")); 102 return ; 103 } 104 mediaObject->setQueue(musicSourceList);//列表循环 105 106 if(mediaObject->state() == Phonon::PlayingState) 107 mediaObject->pause(); 108 else 109 { 110 mediaObject->play(); 111 } 112 } 113 114 //停止播放 115 void Widget::on_toolButton_stop_clicked() 116 { 117 mediaObject->stop(); 118 } 119 120 //下一首 121 void Widget::on_toolButton_next_clicked() 122 { 123 int index = musicSourceList.indexOf(mediaObject->currentSource()) + 1; 124 if(index < musicSourceList.size()) 125 { 126 mediaObject->stop(); 127 mediaObject->setCurrentSource(musicSourceList.at(index)); 128 mediaObject->play(); 129 } 130 else 131 { 132 QMessageBox::information(this, tr("警告"), tr("没有下一首歌曲")); 133 return; 134 } 135 136 } 137 138 void Widget::on_toolButton_open_clicked() 139 { 140 QStringList list = QFileDialog::getOpenFileNames(this,tr("打开音乐文件"),QDesktopServices::storageLocation(QDesktopServices::MusicLocation),tr("Music (*.mp3 *.wma)")); 141 if(list.isEmpty()) 142 return; 143 int index = musicSourceList.size(); //获取当前列表的长度 144 foreach(QString string,list) 145 { 146 Phonon::MediaSource source(string); 147 musicSourceList.append(source);//在当前列表后加入一条记录 148 } 149 if(!musicSourceList.isEmpty()) 150 musicInformationMediaObject->setCurrentSource(musicSourceList.at(index)); 151 152 //将新加入的第一条记录添加到musicInformationMediaObject 153 ui->listWidget->clear(); 154 index = musicSourceList.size(); //获取当前列表的长度 155 for(int i = 0; i < index; i++) 156 { 157 musicInformationMediaObject->setCurrentSource(musicSourceList.at(i)); 158 QString fileName = musicInformationMediaObject->currentSource().fileName(); 159 QString mp3Name = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); 160 ui->listWidget->addItem(mp3Name); 161 //qDebug()<<mp3Name; 162 } 163 } 164 165 void Widget::creatActions() 166 { 167 QIcon iconstop(":/images/gtk-media-stop.png"); 168 QIcon iconopen(":/images/gtk-open.png"); 169 QIcon iconexit(":/images/exit.png"); 170 iconpause = new QIcon(":/images/gtk-media-pause.png"); 171 iconplay = new QIcon(":/images/gtk-media-play-ltr.png"); 172 173 play = new QAction(*iconplay,tr("播放"),this); 174 connect(play,SIGNAL(triggered()),this,SLOT(on_toolButton_playpause_clicked())); 175 176 stop = new QAction(iconstop,tr("停止"),this); 177 connect(stop,SIGNAL(triggered()),mediaObject,SLOT(stop())); 178 179 open = new QAction(iconopen,tr("打开文件"),this); 180 connect(open,SIGNAL(triggered()),this,SLOT(on_toolButton_open_clicked())); 181 182 exit = new QAction(iconexit,tr("退出"),this); 183 connect(exit,SIGNAL(triggered()),this,SLOT(exitSlot())); 184 185 /***系统托盘****/ 186 trayicon = new QSystemTrayIcon(this); 187 QIcon ico(":/images/icon.ico.png"); 188 trayiconMenu = new QMenu(this); 189 trayiconMenu->addAction(play); 190 trayiconMenu->addAction(stop); 191 trayiconMenu->addAction(open); 192 trayiconMenu->addSeparator(); 193 trayiconMenu->addAction(exit); 194 195 trayicon->setIcon(ico); 196 trayicon->setToolTip(tr("正在播放:")); 197 trayicon->setContextMenu(trayiconMenu); 198 199 trayicon->show(); 200 trayicon->showMessage(tr("MP3播放器"),tr("计算机091 黄华"),QSystemTrayIcon::Information,10000); 201 202 connect(trayicon,SIGNAL(activated(QSystemTrayIcon::ActivationReason)),this,SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));//图标被激活时 203 } 204 205 void Widget::iconActivated(QSystemTrayIcon::ActivationReason reason) 206 { 207 switch(reason) 208 { 209 case QSystemTrayIcon::Trigger://单击 210 case QSystemTrayIcon::DoubleClick://双击 211 this->setWindowState(Qt::WindowActive);//恢复窗口显示 212 this->show(); 213 break; 214 case QSystemTrayIcon::MiddleClick: 215 trayicon->showMessage(tr("音乐播放器"),tr("计算机091 黄华"),QSystemTrayIcon::Information,10000); 216 break; 217 default: 218 ; 219 } 220 } 221 222 void Widget::listWidget_cellDoubleClicked(QModelIndex index) 223 { 224 mediaObject->stop(); 225 mediaObject->clearQueue(); 226 int row = index.row(); 227 if (row >= musicSourceList.size()) 228 return; 229 mediaObject->setCurrentSource(musicSourceList[row]); 230 mediaObject->play(); 231 } 232 233 void Widget::showTime(qint64 time)//时间与歌词的更新显示 234 { 235 qint64 temp = mediaObject->totalTime(); 236 QTime totalTime(0,(temp / 60000) % 60,(temp / 1000) % 60,time %1000);//(h,min,s,ms) 237 QTime curTime(0,(time / 60000) % 60,(time / 1000) % 60,time %1000); 238 ui->label_time->setText(tr("%1 / %2").arg(curTime.toString("mm:ss")).arg(totalTime.toString("mm:ss"))); 239 ui->label_time->update(); 240 241 /**歌词的更新显示**/ 242 if(ui->textEdit->find(curTime.toString("mm:ss.zzz").left(7)))//向后找 243 { 244 QString str = ui->textEdit->textCursor().block().text().replace(QRegExp("\\[\\d{2}:\\d{2}\\.\\d{2}\\]"),""); 245 ui->label_lrc->setText(str); 246 247 QTime tt = curTime; 248 int b = 1; 249 int c= 0; 250 text->setText(ui->textEdit->document()->toPlainText()); 251 bool over = ui->textEdit->textCursor().block().next().text().isEmpty(); 252 while(!over &&!text->find(tt.addMSecs(b*100).toString("mm:ss.zzz").left(7))) 253 { 254 b++; 255 c++; 256 } 257 while(over && !text->find(tt.addMSecs(b*100).toString("mm:ss.zzz").left(7),QTextDocument::FindBackward)) 258 { 259 b++; 260 c++; 261 break; 262 } 263 264 }//找不到后向前找 265 else if(ui->textEdit->find(curTime.toString("mm:ss.zzz").left(7),QTextDocument::FindBackward)) 266 { 267 QString str = ui->textEdit->textCursor().block().text().replace(QRegExp("\\[\\d{2}:\\d{2}\\.\\d{2}\\]"),""); 268 ui->label_lrc->setText(str); 269 270 QTime tt = curTime; 271 int b = 1; 272 int c= 0; 273 text->setText(ui->textEdit->document()->toPlainText()); 274 275 bool over = ui->textEdit->textCursor().block().next().text().isEmpty(); 276 while(!over && !text->find(tt.addMSecs(b*100).toString("mm:ss.zzz").left(7))) 277 { 278 b++; 279 c++; 280 } 281 while(over && !text->find(tt.addMSecs(b*100).toString("mm:ss.zzz").left(7),QTextDocument::FindBackward)) 282 { 283 b++; 284 c++; 285 break; 286 } 287 } 288 } 289 290 void Widget::mediaObjectStateChanged(Phonon::State, Phonon::State) 291 { 292 switch(mediaObject->state()) 293 { 294 case Phonon::PlayingState: 295 { 296 ui->label_lrc->setText("Music ..."); 297 setCurrentLrc();//打开歌词文件 298 play->setIcon(*iconpause);//图标改为“暂停” 299 ui->toolButton_playpause->setIcon(*iconpause); 300 ui->toolButton_playpause->setToolTip(tr("暂停")); 301 play->setText(tr("暂停")); 302 QString fileName = mediaObject->currentSource().fileName(); 303 QString title = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); 304 this->setWindowTitle(title);//显示“*.mp3” 305 ui->label_palyname->setText(title); 306 trayicon->setToolTip(tr("正在播放:")+ title); 307 break; 308 } 309 case Phonon::PausedState: 310 { 311 play->setIcon(*iconplay); 312 ui->toolButton_playpause->setIcon(*iconplay); 313 ui->toolButton_playpause->setToolTip(tr("播放")); 314 ui->label_palyname->setText(tr("暂停")); 315 play->setText(tr("播放")); 316 trayicon->setToolTip(tr("暂停")); 317 break; 318 } 319 case Phonon::StoppedState: 320 { 321 ui->toolButton_playpause->setIcon(*iconplay); 322 play->setText(tr("播放")); 323 play->setIcon(*iconplay); 324 this->setWindowTitle(tr("MP3播放器")); 325 ui->label_palyname->setText(tr("停止")); 326 trayicon->setToolTip(tr("停止")); 327 ui->label_time->setText("00:00 / 00:00"); 328 ui->label_lrc->setText("Music ..."); 329 break; 330 } 331 332 case Phonon::LoadingState: 333 break; 334 case Phonon::ErrorState: 335 break; 336 case Phonon::BufferingState://缓冲状态 337 break; 338 } 339 } 340 341 void Widget::setCurrentLrc()//设置当前歌词显示 342 { 343 QString fileName = mediaObject->currentSource().fileName(); 344 345 QString lrcName = fileName.remove(fileName.right(3)) + "lrc"; //将"*.mp3"改为“*.lrc” 346 QFile file(lrcName); 347 if(!file.open(QFile::ReadOnly | QFile::Text)) 348 { 349 ui->label_lrc->setText(tr("未找到歌词文件")); 350 } 351 QTextStream in(&file); 352 ui->textEdit->setText(in.readAll());//将所有歌词写入textEdit,但textEdit是隐藏的,因此界面看不到 353 } 354 355 void Widget::musicAboutToFinish() //本首音乐快结束时 356 { 357 int index = musicSourceList.indexOf(mediaObject->currentSource()) + 1; //下一首 358 if(musicSourceList.size() > index) 359 mediaObject->enqueue(musicSourceList.at(index));//注意:不会产生状态的改变state 360 else 361 mediaObject->stop(); 362 } 363 364 void Widget::currentMusicSourceChanged(Phonon::MediaSource source)//当自动播放下一曲音乐时,在listWidget中让它为选中状态 365 { 366 ui->listWidget->setCurrentRow(musicSourceList.indexOf(source), QItemSelectionModel::ToggleCurrent); 367 setCurrentLrc(); 368 QString fileName = mediaObject->currentSource().fileName(); 369 QString title = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); 370 this->setWindowTitle(title);//显示“*.mp3” 371 ui->label_palyname->setText(title); 372 mediaObject->pause();//在此改变一下状态触发mediaObjectStateChanged槽函数 373 mediaObject->play(); 374 } 375 376 void Widget::keyPressEvent(QKeyEvent *key) 377 { 378 QString str=" "; 379 switch(key->modifiers()) 380 { 381 case Qt::ShiftModifier: 382 str += "Shift+"; 383 break; 384 case Qt::ControlModifier: 385 str += "Control+"; 386 break; 387 case Qt::AltModifier: 388 str += "Alt+"; 389 break; 390 default: 391 break; 392 } 393 switch(key->key()) 394 { 395 case Qt::Key_Up: 396 str += "Up"; 397 break; 398 case Qt::Key_Down: 399 str += "Down"; 400 break; 401 case Qt::Key_Right: 402 str += "Right"; 403 on_toolButton_next_clicked(); 404 break; 405 case Qt::Key_Left: 406 str += "Left"; 407 on_toolButton_previous_clicked();//上一首 408 break; 409 default: 410 break; 411 } 412 } 413 414 void Widget::musicInformationStateChanged(Phonon::State newState,Phonon::State) 415 { 416 if (newState != Phonon::StoppedState && newState != Phonon::PausedState) 417 return; //必须加入这句,不然歌曲列表中可能出现重复歌曲 418 if (musicInformationMediaObject->currentSource().type() == Phonon::MediaSource::Invalid) 419 return; 420 QMap<QString, QString> metaData = musicInformationMediaObject->metaData(); 421 QString fileName = musicInformationMediaObject->currentSource().fileName(); 422 QString mp3Name = fileName.right(fileName.length() - fileName.lastIndexOf('/') - 1); 423 ui->listWidget->addItem(mp3Name); 424 425 int index = musicSourceList.indexOf(musicInformationMediaObject->currentSource()) + 1; 426 if (musicSourceList.size() > index) //如果还未处理完 427 { 428 musicInformationMediaObject->setCurrentSource(musicSourceList.at(index)); 429 //处理下一首歌曲 430 if (musicInformationMediaObject->currentSource().type() == Phonon::MediaSource::Invalid) 431 musicInformationMediaObject->setCurrentSource(musicSourceList.at(index+1)); 432 } 433 if(mediaObject->state() != Phonon::PlayingState)//打开后播放 434 { 435 on_toolButton_playpause_clicked(); 436 } 437 } 438 439 void Widget::dragEnterEvent(QDragEnterEvent *event) 440 { 441 if (event->mimeData()->hasFormat("text/uri-list")) 442 event->acceptProposedAction(); 443 } 444 445 void Widget::dropEvent(QDropEvent *event) 446 { 447 QList<QUrl> urls = event->mimeData()->urls(); 448 if (urls.isEmpty()) 449 { 450 return; 451 } 452 QString fileName = urls.first().toLocalFile(); 453 if (fileName.isEmpty()) 454 { 455 return; 456 } 457 int index = musicSourceList.size(); //获取当前列表的长度 458 for(int i=0; i<urls.length(); i++) 459 { 460 QString string = urls.at(i).toString(); 461 Phonon::MediaSource source(string); 462 musicSourceList.append(source);//在当前列表后加入一条记录 463 } 464 465 if(!musicSourceList.isEmpty()) 466 musicInformationMediaObject->setCurrentSource(Phonon::MediaSource(musicSourceList.at(index))); 467 }
main.cpp
1 #include <QtGui/QApplication> 2 #include <QTextCodec> 3 #include "widget.h" 4 5 int main(int argc, char *argv[]) 6 { 7 QApplication a(argc, argv); 8 a.setApplicationName("MP3"); 9 QTextCodec::setCodecForTr(QTextCodec::codecForLocale()); 10 Widget w; 11 w.show(); 12 13 return a.exec(); 14 }