// 初始化播放器 void MyWidget::initPlayer() { // 设置主界面标题、图标和大小 setWindowTitle(tr("MyPlayer音乐播放器")); setWindowIcon(QIcon(":/images/icon.png")); setMinimumSize(320, 160); setMaximumSize(320, 160); // 创建媒体图 mediaObject = new Phonon::MediaObject(this); Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); Phonon::createPath(mediaObject, audioOutput); // 关联媒体对象的tick()信号来更新播放时间的显示 connect(mediaObject, SIGNAL(tick(qint64)), this, SLOT(updateTime(qint64))); // 创建顶部标签,用于显示一些信息 topLabel = new QLabel(tr("<a href = \" http://www.yafeilinux.com \"> www.yafeilinux.com </a>")); topLabel->setTextFormat(Qt::RichText); topLabel->setOpenExternalLinks(true); topLabel->setAlignment(Qt::AlignCenter); // 创建控制播放进度的滑块 Phonon::SeekSlider *seekSlider = new Phonon::SeekSlider(mediaObject, this); // 创建包含播放列表图标、显示时间标签和桌面歌词图标的工具栏 QToolBar *widgetBar = new QToolBar(this); // 显示播放时间的标签 timeLabel = new QLabel(tr("00:00 / 00:00"), this); timeLabel->setToolTip(tr("当前时间 / 总时间")); timeLabel->setAlignment(Qt::AlignCenter); timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); // 创建图标,用于控制是否显示播放列表 QAction *PLAction = new QAction(tr("PL"), this); PLAction->setShortcut(QKeySequence("F4")); PLAction->setToolTip(tr("播放列表(F4)")); connect(PLAction, SIGNAL(triggered()), this, SLOT(setPlaylistShown())); // 创建图标,用于控制是否显示桌面歌词 QAction *LRCAction = new QAction(tr("LRC"), this); LRCAction->setShortcut(QKeySequence("F2")); LRCAction->setToolTip(tr("桌面歌词(F2)")); connect(LRCAction, SIGNAL(triggered()), this, SLOT(setLrcShown())); // 添加到工具栏 widgetBar->addAction(PLAction); widgetBar->addSeparator(); widgetBar->addWidget(timeLabel); widgetBar->addSeparator(); widgetBar->addAction(LRCAction); // 创建播放控制动作工具栏 QToolBar *toolBar = new QToolBar(this); // 播放动作 playAction = new QAction(this); playAction->setIcon(QIcon(":/images/play.png")); playAction->setText(tr("播放(F5)")); playAction->setShortcut(QKeySequence(tr("F5"))); connect(playAction, SIGNAL(triggered()), this, SLOT(setPaused())); // 停止动作 stopAction = new QAction(this); stopAction->setIcon(QIcon(":/images/stop.png")); stopAction->setText(tr("停止(F6)")); stopAction->setShortcut(QKeySequence(tr("F6"))); connect(stopAction, SIGNAL(triggered()), mediaObject, SLOT(stop())); // 跳转到上一首动作 skipBackwardAction = new QAction(this); skipBackwardAction->setIcon(QIcon(":/images/skipBackward.png")); skipBackwardAction->setText(tr("上一首(Ctrl+Left)")); skipBackwardAction->setShortcut(QKeySequence(tr("Ctrl+Left"))); connect(skipBackwardAction, SIGNAL(triggered()), this, SLOT(skipBackward())); // 跳转到下一首动作 skipForwardAction = new QAction(this); skipForwardAction->setIcon(QIcon(":/images/skipForward.png")); skipForwardAction->setText(tr("下一首(Ctrl+Right)")); skipForwardAction->setShortcut(QKeySequence(tr("Ctrl+Right"))); connect(skipForwardAction, SIGNAL(triggered()), this, SLOT(skipForward())); // 打开文件动作 QAction *openAction = new QAction(this); openAction->setIcon(QIcon(":/images/open.png")); openAction->setText(tr("播放文件(Ctrl+O)")); openAction->setShortcut(QKeySequence(tr("Ctrl+O"))); connect(openAction, SIGNAL(triggered()), this, SLOT(openFile())); // 音量控制部件 Phonon::VolumeSlider *volumeSlider = new Phonon::VolumeSlider(audioOutput, this); volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); // 添加到工具栏 toolBar->addAction(playAction); toolBar->addSeparator(); toolBar->addAction(stopAction); toolBar->addSeparator(); toolBar->addAction(skipBackwardAction); toolBar->addSeparator(); toolBar->addAction(skipForwardAction); toolBar->addSeparator(); toolBar->addWidget(volumeSlider); toolBar->addSeparator(); toolBar->addAction(openAction); // 创建主界面布局管理器 QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(topLabel); mainLayout->addWidget(seekSlider); mainLayout->addWidget(widgetBar); mainLayout->addWidget(toolBar); setLayout(mainLayout); // 在3-2中添加的代码 connect(mediaObject, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(stateChanged(Phonon::State, Phonon::State))); // 以下是在3-3中添加的代码 // 创建播放列表 playlist = new MyPlaylist(this); connect(playlist, SIGNAL(cellClicked(int, int)), this, SLOT(tableClicked(int))); connect(playlist, SIGNAL(playlistClean()), this, SLOT(clearSources())); // 创建用来解析媒体的信息的元信息解析器 metaInformationResolver = new Phonon::MediaObject(this); // 需要与AudioOutput连接后才能使用metaInformationResolver来获取歌曲的总时间 Phonon::AudioOutput *metaInformationAudioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); Phonon::createPath(metaInformationResolver, metaInformationAudioOutput); connect(metaInformationResolver, SIGNAL(stateChanged(Phonon::State, Phonon::State)), this, SLOT(metaStateChanged(Phonon::State, Phonon::State))); connect(mediaObject, SIGNAL(currentSourceChanged(Phonon::MediaSource)), this, SLOT(sourceChanged(Phonon::MediaSource))); connect(mediaObject, SIGNAL(aboutToFinish()), this, SLOT(aboutToFinish())); // 初始化动作图标的状态 playAction->setEnabled(false); stopAction->setEnabled(false); skipBackwardAction->setEnabled(false); skipForwardAction->setEnabled(false); topLabel->setFocus(); }
Player::Player(QWidget *parent) : KXmlGuiWindow(parent) { //SETUP DATABASE QDir(KGlobal::dirs()->saveLocation("data")).mkdir("projekt7"); //NOTE: creates the projekt7 directory if it doesn't already exist QString db_path = KGlobal::dirs()->saveLocation("data") + "projekt7/tracks_db"; int return_code = sqlite3_open(qtos(db_path), &tracks_db); if (return_code) { showError("Failed to open the Projekt7 Track Database: ", sqlite3_errmsg(tracks_db)); exit(return_code); } const char *create_table = "CREATE TABLE IF NOT EXISTS `tracks` (`tid` INTEGER PRIMARY KEY, `artist` VARCHAR KEY ASC, `year` INT KEY ASC, `album` VARCHAR, `track_number` INT KEY ASC, `title` VARCHAR, `path` VARCHAR, `length` INT, `playcount` INT)"; //TODO make use of the `length` and `playcount` columns char *errmsg; return_code = sqlite3_exec(tracks_db, create_table, 0, 0, &errmsg); if (return_code) { showError("Failed to create `tracks` table: ", errmsg); sqlite3_free(errmsg); exit(return_code); } updateNumTracks(); //SETUP PHONON now_playing = new Phonon::MediaObject(this); Phonon::AudioOutput *audioOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this); createPath(now_playing, audioOutput); now_playing->setTickInterval(1000); //SETUP WIDGETS QWidget *central_widget = new QWidget(this); KToolBar *toolbar_widget = new KToolBar(i18n("Main Toolbar"), central_widget); toolbar_widget->setIconDimensions(32); playlist_widget = new QWidget(central_widget); artist_list = new KListWidget(playlist_widget); artist_list->addItem(ALL); album_list = new KListWidget(playlist_widget); titles_list = new KListWidget(playlist_widget); QAction* tb_previousAction = toolbar_widget->addAction(KIcon("media-skip-backward"), ""); QString previousHelpText = i18n("Play the previous track"); tb_previousAction->setToolTip(previousHelpText); QAction* tb_pauseAction = toolbar_widget->addAction(KIcon("media-playback-pause"), ""); QString plauseHelpText = i18n("Plause playback"); tb_pauseAction->setToolTip(plauseHelpText); QAction* tb_playAction = toolbar_widget->addAction(KIcon("media-playback-start"), ""); QString playHelpText = i18n("Play the track"); tb_playAction->setToolTip(playHelpText); QAction* tb_nextAction = toolbar_widget->addAction(KIcon("media-skip-forward"), ""); QString nextHelpText = i18n("Play the next track"); tb_nextAction->setToolTip(nextHelpText); toolbar_widget->addSeparator(); Phonon::VolumeSlider *volumeSlider = new Phonon::VolumeSlider; volumeSlider->setAudioOutput(audioOutput); volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); toolbar_widget->addWidget(volumeSlider); toolbar_widget->addSeparator(); Phonon::SeekSlider *seekSlider = new Phonon::SeekSlider(now_playing); volumeSlider->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); toolbar_widget->addWidget(seekSlider); toolbar_widget->addSeparator(); cur_time = new QLabel(" 0:00", toolbar_widget); cur_time->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); toolbar_widget->addWidget(cur_time); toolbar_widget->addWidget(new QLabel(" / ", toolbar_widget)); track_duration = new QLabel("0:00", toolbar_widget); track_duration->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); toolbar_widget->addWidget(track_duration); queued = new KIcon("go-next-view"); QHBoxLayout *listLayout = new QHBoxLayout; listLayout->addWidget(artist_list); listLayout->addWidget(album_list); listLayout->addWidget(titles_list); playlist_widget->setLayout(listLayout); QVBoxLayout *mainLayout = new QVBoxLayout; mainLayout->addWidget(toolbar_widget); mainLayout->addWidget(playlist_widget); central_widget->setLayout(mainLayout); setCentralWidget(central_widget); //SETUP STATUS BAR KStatusBar* bar = statusBar(); bar->insertPermanentItem("", SONG_NAME, true); bar->setItemAlignment(SONG_NAME, Qt::AlignLeft | Qt::AlignVCenter); //SETUP SYSTEM TRAY ICON tray_icon = new KSystemTrayIcon("projekt7", this); tray_icon->show(); //SETUP METADATA WINDOW metadata_window = new QWidget(this, Qt::Dialog); metadata_window->setWindowModality(Qt::WindowModal); metadata_window->setWindowTitle("Track Details | Projekt 7"); mw_ok_button = new KPushButton(KIcon("dialog-ok-apply"), "OK", metadata_window); mw_ok_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); QGridLayout *mwLayout = new QGridLayout; mwLayout->addWidget(new QLabel("Artist:", metadata_window), 0, 0); mwLayout->addWidget(new QLabel("Year:", metadata_window), 1, 0); mwLayout->addWidget(new QLabel("Album:", metadata_window), 2, 0); mwLayout->addWidget(new QLabel("Track Number:", metadata_window), 3, 0); mwLayout->addWidget(new QLabel("Title:", metadata_window), 4, 0); mwLayout->addWidget(new QLabel("File Path:", metadata_window), 5, 0); mwLayout->addWidget(mw_artist = new QLabel(metadata_window), 0, 1); mwLayout->addWidget(mw_year = new QLabel(metadata_window), 1, 1); mwLayout->addWidget(mw_album = new QLabel(metadata_window), 2, 1); mwLayout->addWidget(mw_track_number = new QLabel(metadata_window), 3, 1); mwLayout->addWidget(mw_title = new QLabel(metadata_window), 4, 1); mwLayout->addWidget(mw_path = new QLabel(metadata_window), 5, 1); mwLayout->addWidget(mw_ok_button, 6, 0, 1, 2, Qt::AlignCenter); metadata_window->setLayout(mwLayout); //SETUP QUEUE EDITOR WINDOW queue_window = new QWidget(this, Qt::Dialog); queue_window->setWindowModality(Qt::WindowModal); queue_window->setWindowTitle("Track Queue Editor | Projekt 7"); qw_ok_button = new KPushButton(KIcon("dialog-ok-apply"), "OK", queue_window); qw_ok_button->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); QVBoxLayout *qw_buttons_layout = new QVBoxLayout; KPushButton *qw_top_button = new KPushButton(KIcon("go-top"), "", queue_window); KPushButton *qw_up_button = new KPushButton(KIcon("go-up"), "", queue_window); KPushButton *qw_down_button = new KPushButton(KIcon("go-down"), "", queue_window); KPushButton *qw_bottom_button = new KPushButton(KIcon("go-bottom"), "", queue_window); KPushButton *qw_remove_button = new KPushButton(KIcon("edit-delete"), "", queue_window); qw_buttons_layout->addWidget(qw_top_button); qw_buttons_layout->addWidget(qw_up_button); qw_buttons_layout->addWidget(qw_down_button); qw_buttons_layout->addWidget(qw_bottom_button); qw_buttons_layout->addWidget(qw_remove_button); QHBoxLayout *qw_list_buttons_layout = new QHBoxLayout; qw_queue_list = new KListWidget(queue_window); QWidget *qw_button_holder = new QWidget(queue_window); qw_button_holder->setLayout(qw_buttons_layout); qw_list_buttons_layout->addWidget(qw_queue_list); qw_list_buttons_layout->addWidget(qw_button_holder); QVBoxLayout *qwLayout = new QVBoxLayout; QWidget *qw_list_buttons = new QWidget(queue_window); qw_list_buttons->setLayout(qw_list_buttons_layout); qwLayout->addWidget(qw_list_buttons); qwLayout->addWidget(qw_ok_button, 0, Qt::AlignCenter); queue_window->setLayout(qwLayout); //SETUP ACTIONS KStandardAction::quit(kapp, SLOT(quit()), actionCollection()); connect(kapp, SIGNAL(aboutToQuit()), this, SLOT(quit())); connect(now_playing, SIGNAL(aboutToFinish()), this, SLOT(enqueueNext())); connect(now_playing, SIGNAL(totalTimeChanged(qint64)), this, SLOT(updateDuration(qint64))); connect(now_playing, SIGNAL(tick(qint64)), this, SLOT(tick(qint64))); KAction *openFilesAction = setupKAction("document-open", i18n("Open"), i18n("Load the selected files"), "files"); openFilesAction->setShortcut(QKeySequence::Open); connect(openFilesAction, SIGNAL(triggered(bool)), this, SLOT(loadFiles())); KAction *openDirectoryAction = setupKAction("document-open-folder", i18n("Open Directory..."), i18n("Load all files in the selected directory and its subdirectories"), "directory"); openDirectoryAction->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D)); connect(openDirectoryAction, SIGNAL(triggered(bool)), this, SLOT(loadDirectory())); KAction *previousAction = setupKAction("media-skip-backward", i18n("Previous"), previousHelpText, "previous"); previousAction->setShortcut(QKeySequence(Qt::Key_Z)); connect(previousAction, SIGNAL(triggered(bool)), this, SLOT(previous())); connect(tb_previousAction, SIGNAL(triggered(bool)), this, SLOT(previous())); KAction *pauseAction = setupKAction("media-playback-pause", i18n("Pause"), plauseHelpText, "pause"); pauseAction->setShortcut(QKeySequence(Qt::Key_C)); connect(pauseAction, SIGNAL(triggered(bool)), this, SLOT(pause())); connect(tb_pauseAction, SIGNAL(triggered(bool)), this, SLOT(pause())); KAction *playAction = setupKAction("media-playback-start", i18n("Play"), playHelpText, "play"); playAction->setShortcut(QKeySequence(Qt::Key_X)); connect(playAction, SIGNAL(triggered(bool)), this, SLOT(play())); connect(tb_playAction, SIGNAL(triggered(bool)), this, SLOT(play())); KAction *nextAction = setupKAction("media-skip-forward", i18n("Next"), nextHelpText, "next"); nextAction->setShortcut(QKeySequence(Qt::Key_V)); connect(nextAction, SIGNAL(triggered(bool)), this, SLOT(next())); connect(tb_nextAction, SIGNAL(triggered(bool)), this, SLOT(next())); KAction *queueAction = setupKAction("go-next-view", i18n("Queue Track"), "Enqueue the current track", "queue"); queueAction->setShortcut(QKeySequence(Qt::Key_Q)); connect(queueAction, SIGNAL(triggered(bool)), this, SLOT(queue())); shuffleAction = setupKAction("media-playlist-shuffle", i18n("Suffle"), "The next track will be random when checked", "shuffle"); shuffleAction->setCheckable(true); connect(shuffleAction, SIGNAL(triggered(bool)), this, SLOT(shuffle(bool))); KAction *viewCurrentTrackAction = setupKAction("go-last", i18n("Current Track"), i18n("Show the Current Track in the Playlist"), "current_track"); connect(viewCurrentTrackAction, SIGNAL(triggered(bool)), this, SLOT(viewCurrentTrack())); KAction *viewTrackDetailsAction = setupKAction("view-media-lyrics", i18n("Track Details"), i18n("View the playing track's metadata"), "track_details"); connect(viewTrackDetailsAction, SIGNAL(triggered(bool)), this, SLOT(viewTrackDetails())); KAction *viewTrackQueueAction = setupKAction("view-time-schedule-edit", i18n("Track Queue"), i18n("Edit the track queue"), "track_queue"); connect(viewTrackQueueAction, SIGNAL(triggered(bool)), this, SLOT(viewTrackQueue())); viewPlaylistAction = setupKAction("view-file-columns", i18n("Playlist"), i18n("Show/Hide the playlist"), "playlist"); viewPlaylistAction->setCheckable(true); connect(viewPlaylistAction, SIGNAL(triggered(bool)), this, SLOT(viewPlaylist(bool))); connect(artist_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(updateAlbumList(QListWidgetItem *, QListWidgetItem *))); connect(album_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(updateTitlesList(QListWidgetItem *, QListWidgetItem *))); connect(titles_list, SIGNAL(currentItemChanged(QListWidgetItem *, QListWidgetItem *)), this, SLOT(showTrackInfo(QListWidgetItem *, QListWidgetItem *))); connect(titles_list, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(play(QListWidgetItem *))); connect(mw_ok_button, SIGNAL(clicked()), this, SLOT(hideTrackDetails())); connect(qw_top_button, SIGNAL(clicked()), this, SLOT(moveQueuedTrackToTop())); connect(qw_up_button, SIGNAL(clicked()), this, SLOT(moveQueuedTrackUp())); connect(qw_down_button, SIGNAL(clicked()), this, SLOT(moveQueuedTrackDown())); connect(qw_bottom_button, SIGNAL(clicked()), this, SLOT(moveQueuedTrackToBottom())); connect(qw_remove_button, SIGNAL(clicked()), this, SLOT(dequeueTrack())); connect(qw_ok_button, SIGNAL(clicked()), this, SLOT(hideTrackQueue())); //SETUP GUI qsrand(QDateTime::currentDateTime().toTime_t()); setupGUI(Default, "projekt7ui.rc"); updateArtistList(0); //READ CONFIG config = KGlobal::config(); KConfigGroup curTrackDetails(config, "curTrackDetails"); cur_artist = artist_list->item(curTrackDetails.readEntry("artist", QString()).toInt()); cur_album = curTrackDetails.readEntry("album", QString()).toInt(); cur_title = curTrackDetails.readEntry("title", QString()).toInt(); KConfigGroup applicationSettings(config, "applicationSettings"); viewPlaylistAction->setChecked(applicationSettings.readEntry("playlistVisible", QString()).toInt()); shuffle_tracks = applicationSettings.readEntry("shuffleTracks", QString()).toInt(); shuffleAction->setChecked(shuffle_tracks); viewCurrentTrack(); if (titles_list->count() > 0) { if (titles_list->currentRow() == -1) titles_list->setCurrentRow(0); play(titles_list->currentItem()->data(Qt::UserRole).toInt(), false, false); pause(); quint64 song_position = curTrackDetails.readEntry("tick", QString()).toLongLong(); now_playing->seek(song_position); tick(song_position); //TODO update the seekSlider's position to match the "tick" location of the song } }