做网站超链接,牡丹区住房和城乡建设局网站,专业团队张伟原图,wordpress 4.7.2 漏洞文章目录 效果图概述代码解析歌词歌词同步歌词特效 总结 效果图 概述
先整体说明一下这个效果的实现#xff0c;你所看到的歌词都是QGraphicsObject#xff0c;在QGraphicsView上绘制(paint)出来的。也就是说每一句歌词都是一个图元(item)。 为什么用QGraphicsView框架… 文章目录 效果图概述代码解析歌词歌词同步歌词特效 总结 效果图 概述
先整体说明一下这个效果的实现你所看到的歌词都是QGraphicsObject在QGraphicsView上绘制(paint)出来的。也就是说每一句歌词都是一个图元(item)。 为什么用QGraphicsView框架 在做歌词滚动效果时我看网上实现这一效果基本上都是用QLabel这样或许简单很多但是效果单一且不够灵活。使用图形视图这套图形项可以自由地被移动、缩放、旋转和编辑。当然主要还是为了提升自己可以更熟悉这套框架。 如何解析歌词 这里解析的是lrc文件为一般的歌词文件格式如下格式是固定的那么就可以通过正则表达式来解析。然后存放在一个QMap中key是时间value是歌词。 [02:08.496]乌蒙山连着山外山
[02:11.138]月光洒下了响水滩
[02:13.993]有没有人能告诉我
[02:16.487]可是苍天对你在呼唤如何同步歌词 QMediaPlayer中有一个信号positionChanged,播放音乐时会时刻刻触发可以获取当前播放时间。然后和前面我们存放在QMap中的时间进行对比所以QMap存放的时间格式要按positionChanged发出的时间格式来解析。但我试验过很多次俩者的时间都是无法精确相等的。这里采取的方案是遍历QMap找到第一个时间大于等于positionChanged发出的时间然后获取这个时间对应的歌词这便是当前的歌词。然后通过当前的key在获取前后几句的歌词。 歌词滚动以及那些特效如何实现的 同步歌词的时候会获取当前歌词以及前后几句歌词提前存好对应歌词的特效如下这里面存了一个QMap里面存放了每一句歌词的属性包括字体大小位置透明度等等。 m_textMapInfolst QMapQString, QString{
{index, 1},
{font, 12},
{y, -100},
{x, 300},
{opacity, 0.2}};我这里有七句歌词那么就存七个QMap在一个QList中当歌词刷新的时候就去遍历根据QMap中的属性来设置item歌词,这里的图元要自己实现重写paint函数。 代码
解析歌词
解析的时候把格式设置GB 2312不然会是乱码。按行已经QMediaPlayer的时间格式读取数据并全部存放到listLyricsMap中。
bool Lyrics::readLyricsFile(QString lyricsPath)
{listLyricsMap.clear();QFile file(lyricsPath);if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){listLyricsMap.clear();return false;}QTextStream in(file);in.setCodec(GB 2312);QString line;while (!in.atEnd()){line in.readLine();analysisLyricsFile(line);}return true;
}bool Lyrics::analysisLyricsFile(QString line)
{if (line NULL || line.isEmpty()){return false;}QRegExp timeRegExp(\\[(\\d):(\\d\\.\\d)\\]);if (timeRegExp.indexIn(line) ! -1){qint64 totalTime timeRegExp.cap(1).toInt() * 60000 // 分钟timeRegExp.cap(2).toFloat() * 1000; // 秒QString lyricText line.mid(timeRegExp.matchedLength());listLyricsMap.insert(totalTime, lyricText);}return true;
}歌词同步
绑定信号 connect(player, SIGNAL(positionChanged(qint64)),this, SLOT(updateTextTime(qint64)));读取对应listLyricsMap中的歌词 void MainWindow::updateTextTime(qint64 position)
{auto lrcMap lyric-getListLyricsMap();qint64 previousTime 0;qint64 currentLyricTime 0;QMapIteratorqint64, QString i(lrcMap);while (i.hasNext()){i.next();if (position i.key()){QString currentLyric lrcMap.value(previousTime);currentLyricTime previousTime;break;}previousTime i.key();}QStringList displayLyrics; // 存储将要显示的歌词列表。// 获取将要显示的歌词QMapqint64, QString::iterator it lrcMap.find(currentLyricTime);// 显示前三句如果it不是开头就向前移动迭代器for (int i 0; i 3 it ! lrcMap.begin(); i){--it;displayLyrics.prepend(it.value());}// 重置迭代器it lrcMap.find(currentLyricTime);QString currntStr QString();// 显示当前句if (it ! lrcMap.end()){currntStr QString(font colorred it.value() /font);displayLyrics.append(it.value());}// 显示后三句for (int i 0; i 3 it ! lrcMap.end(); i){it;if (it ! lrcMap.end()){displayLyrics.append(it.value());}}//更新显示imageViewWindow-textChanged(displayLyrics);
}歌词特效
同步于上述歌词的改动清空场景遍历特效m_textMapInfolst,重新进行图元绘制
void ImageViewWindow::textChanged(QStringList lsit)
{m_scene-clear();for (int index 0; index m_textMapInfolst.size(); index){const auto textInfoMap m_textMapInfolst[index];GraphicsText *item new GraphicsText();item-setStr(lsit[index]);item-setStrFont(textInfoMap[font].toInt());item-setItemOffset(QPointF(textInfoMap[x].toInt() image_xoffset, textInfoMap[y].toInt() image_yoffset));item-setZValue(textInfoMap[index].toInt());item-setOpacity(textInfoMap[opacity].toFloat());m_items item;m_scene-addItem(item);}
}自绘图元
void GraphicsText::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *)
{painter-setFont(m_font);if (m_font.pointSize() 20){painter-setPen(QPen(Qt::red));}else{painter-setPen(QPen(Qt::blue));}painter-drawText(offset, str);
}总结
实现这个功能遇到的问题挺多的比如绘制文本的时候只有一根线显示是要view设置setViewportUpdateMode(QGraphicsView::FullViewportUpdate)类似的问题挺多还不好找。歌词特效这块还可以再扩展字体入场效果等都可以设置。当然这个功能还有很多可以优化的地方BUG或许也不少实现标题的功能的逻辑就是如上可以作为参考。