C++ with QT to develop a music player (QML+QT)

Written in front, this article is reproduced from CSDN blog: https://blog.csdn.net/xyygudu/article/details/130134269 , author: xyygudu

code address

xyygudu/Player: Qt and QML implement video player and music player (github.com)

Partial effect display

insert image description here

Implemented functions

Video related: playback pause, playback progress adjustment, volume adjustment, list display of video files in the specified directory

Audio-related: play pause, previous song, next song, random play and sequential play, playback progress adjustment, lyrics scrolling and highlighting, list display of audio files in the specified directory

Other functions: support skin switching, window maximization and minimization, window arbitrary shape adjustment, window movement, border shadow

main file description

insert image description here

video playback

Implementation ideas

The video list is implemented through TableView, and the data to be displayed by its delegate comes from m_videoTableModel of videoplayer.h. When a row in the list is double-clicked, a custom signal in VideoTable.qml is triggered, and the signal switches the page to VideoSecondPage.qml ( doubleClicked(int row)play Video page), and at the same time pass the double-clicked line number to VideoSecondPage.qml, so that VideoSecondPage.qml can call the C++ function according to the line number to obtain the video path corresponding to the double-clicked line, so that the video can be played

// 切换页面并传递行号 VideoPanel.qml
VideoFirstPage {
    
    
  onTableRowDoubleClicked: {
    
      // 其实就是VideoTable.qml的doubleClicked信号
    root.selectedRow = row  // 将选中的行号赋值给root.selectedRow便于传入到secondPage中
    stackView.push(secondPage)   // 跳转到第二个页面(播放视频的页面)
  }
}// 视频播放器 VideoSecondPage.qml
VideoPlayer {
    
    
  id: videoPlayer
  anchors.left: parent.left
  anchors.right: parent.right
  height: width * 9 / 16
  source: myVideoPlayer.getVideoPathByRow(root.selectedRow)
}

Audio Player

Implementation ideas

Audio playback implementation: the audio list is implemented through TableView, and the data to be displayed by its delegate (delegate) comes from m_musicTableModel of musicplayer.h. When a row in the list is double-clicked, a custom signal in MusicTable.qml is triggered, and the signal changes the double-clicked row doubleClicked(int row)number Pass it to MusicControlBar.qml (controlling audio playback and other pages), so that MusicControlBar.qml can call the C++ function according to the line number to obtain the video path corresponding to the current double-click line, so that the video can be played

Previous song/next song implementation: MusicControlBar.qml has a previous song and next song button. To realize song switching, you only need to change the selectedRow property of MusicControlBar.qml. The selectedRow records which row of the currently playing music is in the list. After clicking the next song, just increase the selectedRow by 1, no other operations are required, because the source property of MediaPlayer (located in MusicControlBar.qml) is bound to the selectedRow, as long as the selectedRow changes, the source of MediaPlayer will also be corresponding Change, and the change of source will trigger the onSourceChanged signal, onSourceChanged realizes the audio playback, the main code is as follows:

// 下一曲按钮
CusWidgets.ImageButton {
    
    
    ...省略代码一万行
    onClicked: {
    
    
        if (root.playMode === root.order) {
    
    // 如果是顺序播放
            if (root.seclectedRow !== -1) {
    
    
                if (root.seclectedRow === myMusicPlayer.musicTableModel.rowCount()-1) {
    
    
                    root.seclectedRow = 0
                } else {
    
    
                    root.seclectedRow += 1
                }
            } else {
    
    
                root.seclectedRow = 0
            }
        } else {
    
     // 如果是随机播放
            root.seclectedRow = getRandomNum(0, myMusicPlayer.musicTableModel.rowCount())
        }
    }
}
​
MediaPlayer {
    
    
    id: musicPlayer
    source: root.seclectedRow === -1 ? "" : myMusicPlayer.getMusicPathByRow(root.seclectedRow)
    onSourceChanged: {
    
    
        musicPlayer.play()
    }
}

Lyric display implementation:

(1) Update the lyrics model: As mentioned earlier, you only need to change the custom seclectedRow property of MusicControlBar.qml to cut songs. When the seclectedRow is changed, the signal triggered by it can update the lyrics model

MusicControlBar {
    
     // 位于MusicPanel.qml
    id: musicControlBar
    onSeclectedRowChanged: {
    
    
        myMusicPlayer.upDateLyricModelBy(seclectedRow) //调用C++函数来更新歌词信息
    }
}

(2) Implementation of lyrics scrolling: The LRC lyrics file is as follows:

// 第一个数字表示分钟,第二个数字表示秒,第三个数字可能是毫秒
// 不过我们只用到前两个数字和歌词内容
[0:0.250.00]沉默是金 - 张国荣
[0:1.500.00]词:许冠杰
[0:2.190.00]曲:张国荣
[0:27.450.00]夜风凛凛 独回望旧事前尘
[0:33.120.00]是以往的我充满怒愤
​
// 另一种lrc歌词文件格式是下面这样的
// 第一个数字是分钟,第二个数字是秒,第三个数字是多少个10毫秒,也就是说,
// 第三个数最大为100
[ver:v1.0]     // 我的程序为了方便没有解析这些信息
[ti:]          
[00:00.36]- 许巍 
[00:01.04]词:许巍
[00:01.69]曲:许巍
[00:37.95]拥抱着亲人的时候

After understanding the lyrics format, you can parse the lyrics through regular expressions (see the parseLyrics function in lyrics.h), which combines the timestamp of the lyrics (such as [0:27.450.00]) and the index corresponding to the lyrics (the index marks this is The first few lyrics, such as [0:27.450.00] corresponding index is 3, the index starts from 0) is stored in QMap, that is, in the m_lyric2IdxMap of the following code, the timestamp is the key, the index is the value, and then the lyrics content (such as : [0:27.450.00] Corresponding to the lyrics: Night Breeze Alone Looking Back at the Past) Stored in the lyrics model LyricModel, LyricModel actually manages QStringList. After the lyrics analysis is completed, the next step is to realize the lyrics scrolling. As shown in the following code, we can obtain the index number of the lyrics that should be displayed currently in the onPositionChanged signal processing of MediaPlayer. The idea of ​​obtaining the index is based on the current music playback progress (ie, the shape Refer to the value of qint64 pos), traverse the above m_lyric2IdxMap, find that pos is in the time period of the lyrics, and then return the index of the lyrics in LyricModel.

MediaPlayer {
    
          
    onPositionChanged: {
    
    
        // 实时显示歌词 调用c++函数,返回此时应该显示的歌词的索引
        var idx = myMusicPlayer.getLyricIdxByPosition(position)
        if (idx === -1) {
    
    
            root.lyricIdx = -1   // -1表示当前position没有合适的歌词
        } else {
    
    
            root.lyricIdx = idx
        }
    }
}
// c++函数,见musicplayer.cpp
int MusicPlayer::getLyricIdxByPosition(qint64 pos)
{
    
    
     QMap<qint64, int>::iterator iter = m_lyric2IdxMap.begin();
     while (iter != m_lyric2IdxMap.end())
     {
    
    
         if ((iter.key()-500<=pos)  && (iter+1).key()-500 > pos)
         {
    
    
             return iter.value();
         }
         iter++;
     }
     return -1;
}

After obtaining the current lyrics index according to the playback progress, you only need to assign the lyrics index value to the currentIndex property of the ListView that displays the lyrics

ListView {
    
    
  id: lyricsList
  currentIndex: lyricIndex===-1?currentIndex:lyricIndex
  // 省略代码一万行
}

BUG

Click the audio player in the left navigation bar, then maximize the window, click the left video player, and found that the video table does not change with the width of the window. I don’t know why, but I have already called forceLayout() in TableView’s onWidthChangede. . Please let me know if it is resolved

TableView {
    
    
    id: tableView
    // 省略代码
    columnWidthProvider: function(colum) {
    
     return root.columnWidths[colum] }
    onWidthChanged: {
    
    
        // If you change the values that a rowHeightProvider or a columnWidthProvider
        // return for rows and columns inside the viewport, you must call forceLayout.
        // This informs TableView that it needs to use the provider functions again to
        // recalculate and update the layout.
        forceLayout()
    }
}

References

Realization of skin switching: playing with Qml(3)-changing skin | Taoge's blog

Parsing Lyrics: Qt-Based Network Music Player (5) Implementing Lyrics Scrolling and Displaying Qt Lyrics Scrolling Flower Dog Fdog's Blog-CSDN Blog; ListView Scrolling Up Effect in QML_hp_cpp's Blog-CSDN Blog

Lyric display: ListView scrolling effect in QML - hp_cpp's blog - CSDN blog

Window width and height adjustment: qml removes the title bar and drags the window and changes the window size_qml cannot move the title bar_Lin Xingnan's Blog-CSDN Blog

Guess you like

Origin blog.csdn.net/hallobike/article/details/130263803