当前位置: 首页 > news >正文

嵌入式Qt 开发一个视频播放器

上篇文章:嵌入式 Qt开发一个音乐播放器,使用Qt制作了一个音乐播放器,并在OK3568开发板上进行了运行测试,实际测试效果还不错。

本篇继续来实现一个Qt视频播放器软件,可以实现视频列表的显示与选择播放等,先来看下最终的效果:

本篇的Qt代码从野火开发板的例程中移植修改而来,下面分析下程序的代码结构。

1 视频播放器开发总体结构

整个Qt视频播放器项目的代码结构如下:

  • 主代码中是视频播放器相关的代码,包括:
    • 视频播放器主界面
    • 视频名列表界面:在视频播放时可以查看视频列表并切换视频
    • Qt视频播放界面:实现单纯的视频播放
    • 操作按钮界面:实现播放、暂停、继续、上一个、下一个、进度调节,音量调节
    • 播放预览列表界面:在进入视频播放之前的视频预览列表界面
  • Ui代码中使用一些Qt的基本功能,包括:
    • 一个Qt界面基类
    • 滑条功能类
    • 图标按钮显示类
    • 列表功能类
    • 工具类
    • 视频帧解析
    • 页面列表类
  • Skin中是一些图片资源和字体/皮肤定义
  • 最后是编译的中间文件和编译结果存储的目录

下面分类介绍了程序的主要代码实现。

2 通用界面代码

上篇介绍音乐播放器时,介绍过一些自定义控件的代码,本篇的视频播放器,可以复用这些代码:

  • qtwidgetbase:窗口基类,该类的一个主要功能是可以向窗口内添加图片形式的按钮
  • qtsliderbar:用于实现自定义滑条控件,分为水平滑条与竖直滑条
  • qtpixmapbutton:图片按钮,支持未按下和按下后的两种样式的图片显示
  • qtlistwidget :基础的列表显示

相比于音乐播放器,视频播放器还需要其它额外的功能,如下:

2.1 qttoolbar

工具条的基类,通过创建一个QPropertyAnimation属性动画对象,主要实现工具条的显示与隐藏的动画效果。

例如,在用户无操作一段时间后,将上方的标题栏和下方的播放工具栏隐藏。

主要代码如下:

QtToolBar::QtToolBar(QWidget *parent) : QtWidgetBase(parent)
{m_animation = new QPropertyAnimation(this, "pos");m_animation->setDuration(200);m_animation->setEasingCurve(QEasingCurve::Linear);connect(m_animation, SIGNAL(finished()), this, SIGNAL(signalFinihed()));
}void QtToolBar::SetAnimation(const QPoint &startPos, const QPoint &endPos)
{m_animation->setStartValue(startPos);m_animation->setEndValue(endPos);m_animation->start();
}

2.2 qtvideowidgetsurface

视频帧解析类,继承自QAbstractVideoSurface类,这是一个抽象基类,通过实现它的派生类可以获取来自QMediaPlayer或QCamera视频的帧。

  • supportedPixelFormats 用于向Qt返回帧流的图像类型
  • present 用于获取到每一帧
class QtVideoWidgetSurface : public QAbstractVideoSurface
{Q_OBJECT
public:QtVideoWidgetSurface(QWidget *widget, QObject *parent = 0);QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const;bool isFormatSupported(const QVideoSurfaceFormat &format) const;bool start(const QVideoSurfaceFormat &format);void stop();bool present(const QVideoFrame &frame);QRect videoRect() const { return targetRect; }void updateVideoRect();void paint(QPainter *painter);private:QWidget *widget;QImage::Format imageFormat;QRect targetRect;QSize imageSize;QRect sourceRect;QVideoFrame currentFrame;
};

2.3 qtpagelistwidget

页面形式的预览排布以及左右页面的滑动切换

2.3.1 QtPageListWidgetItem

该类用于表示列表中的每一个项,可以是字符,并且可以带有图片(图标):

class QtPageListWidgetItem
{
public:QtPageListWidgetItem(int id, const QStringList &args);QtPageListWidgetItem(int id, const QString &name);QtPageListWidgetItem(int id, const QString &name, const QPixmap &icon);QtPageListWidgetItem(int id, const QString &path, const QString &name, const QPixmap &icon);int m_nId;QString m_strText;QPixmap m_pixmapIcon;QString m_strBaseName;QString m_strPath;QRect m_rect;QStringList m_strMultiParameters;
};

2…3.2 QtPageListWidget

class QtPageListWidget : public QtWidgetBase
{Q_OBJECT
public:typedef enum{None,LeftDirection,RightDirection} MoveDirection;Q_PROPERTY(int xPos READ Xpos WRITE setXPos)explicit QtPageListWidget(QWidget *parent = 0);~QtPageListWidget();void AddItem(int id, QtPageListWidgetItem *item);void SetItems(const QMap<int, QtPageListWidgetItem *> &items);void SetBackground(const QPixmap &pixmap);void SetBackground(const QColor &color);void SetPageCount(int count);void SetItemLayut(int rows, int columns);void SetItemLayoutSpace(int row, int col);void SetLoopbackChange(bool bOk);signals:void currentItemClicked(QtPageListWidgetItem *item);void currentPageChanged(int index);protected:QMap<int, QtPageListWidgetItem *> m_listItems;// skinQColor m_backgroundColor;QPixmap m_pixmapWallpaper;int m_nPageCnt;int m_nCurrentPage;int m_nPrevPage;int m_nLayoutRows;int m_nLayoutColumns;qreal m_nItemWidth;qreal m_nItemHeight;int m_nDirection;QTimer *m_timerMove;bool m_bLoopbackChange;QPropertyAnimation *m_animationMove;private:bool m_bPressed;QPoint m_startPos;int m_nStartPos;int m_nMoveEndValue;bool m_bRecovery;private:void setXPos(int nValue);int Xpos() { return m_nStartPos; }void resizeRect();
private slots:protected:int m_nCurrentIndex;int m_nHorSpace;int m_nVSpace;protected:void mousePressEvent(QMouseEvent *e);void mouseReleaseEvent(QMouseEvent *);void mouseMoveEvent(QMouseEvent *e);void paintEvent(QPaintEvent *);void drawListItem(QPainter *painter, int page, int xOffset = 0);virtual void drawItemInfo(QPainter *painter, QtPageListWidgetItem *item);
};

注意,该类和qtlistwidget类的功能比较相似

3 视频播放器代码

首先是整体的主界面部分,进行各项功能的初始化显示,主要包括:

  • 播放列表初始化(视频预览列表界面)
  • 视频播放界面初始化(先隐藏播放界面)

界面效果如下:

主要代码逻辑:

{QtWidgetTitleBar *m_widgetTitle = new QtWidgetTitleBar(this);m_widgetTitle->SetScalSize(Skin::m_nScreenWidth, 80);m_widgetTitle->SetBackground(Qt::transparent);m_widgetTitle->setFont(QFont(Skin::m_strAppFontNormal));m_widgetTitle->SetTitle(tr("视频播放器"), "#ffffff", 32);QVBoxLayout *verLayoutCentor = new QVBoxLayout(this);verLayoutCentor->setContentsMargins(0, 0, 0, 0);verLayoutCentor->setSpacing(0);verLayoutCentor->addWidget(m_widgetTitle, 1);// 播放列表(视频预览列表界面)m_videosList = new VideoListViewer(this);m_videosList->SetBackground(Qt::transparent);connect(m_videosList, SIGNAL(currentItemClicked(QtPageListWidgetItem *)), this, SLOT(SltItemClicked(QtPageListWidgetItem *)));verLayoutCentor->addWidget(m_videosList, 5);// 视频播放界面(先隐藏播放界面)m_videoWidget = new QtVideoWidget(this);m_videoWidget->hide();
}

初始化各个界面后,还要连接对应的槽函数,如切换视频播放列表中的视频时的处理等。

3.1 视频播放

视频播放部分,主要有两部分功能:

  • 视频解码播放:使用Qt自带的媒体播放器组件进行音频播放
  • 播放时的按钮操作:实现播放、暂停、继续、上一个、下一个、进度调节,音量调节

3.1.1 QMediaPlayer播放视频

这里使用Qt自带的QMediaPlayer组件进行视频的播放,QMediaPlayer播放视频于播放音频的步骤类似。

本项目的视频播放初始化部分:

QtVideoWidget::QtVideoWidget(QWidget *parent) : QtWidgetBase(parent)
{m_urlMedia = QUrl();m_bToolBarShow = false;m_nDuration = 0;m_nPostion = 0;m_player = new QMediaPlayer(this);surface = new QtVideoWidgetSurface(this);m_player->setVideoOutput(surface);m_playList = new MediaPlayListWidget(this);m_playList->setVisible(false);m_player->setPlaylist(m_playList->palyList());connect(m_player, SIGNAL(durationChanged(qint64)), this, SLOT(SltDurationChanged(qint64)));connect(m_player, SIGNAL(positionChanged(qint64)), this, SLOT(SltPostionChanged(qint64)));m_titleBar = new PlayTitleBarWidget(this);connect(m_playList, SIGNAL(signalMediaChanged(QString)), m_titleBar, SLOT(SetText(QString)));connect(m_titleBar, SIGNAL(signalBack()), this, SLOT(SltBackClicked()));m_playBar = new PlayerBarWidget(this);connect(m_playBar, SIGNAL(signalPlay(bool)), this, SLOT(SltBtnPlayClicked(bool)));connect(m_playBar, SIGNAL(currentPostionChanged(int)), this, SLOT(SltChangePostion(int)));connect(m_playBar, SIGNAL(signalPrev()), m_playList->palyList(), SLOT(previous()));connect(m_playBar, SIGNAL(signalNext()), m_playList->palyList(), SLOT(next()));connect(m_playBar, SIGNAL(signalMuenList()), this, SLOT(SltShowMenuList()));connect(m_playBar, SIGNAL(signalVolume()), this, SLOT(SltChangeVolume()));m_timerShow = new QTimer(this);m_timerShow->setSingleShot(true);m_timerShow->setInterval(5000);connect(m_timerShow, SIGNAL(timeout()), this, SLOT(SltAutoCloseToolBar()));m_volumeSlider = new QtSliderBar(this);m_volumeSlider->SetHorizontal(false);m_volumeSlider->SetValue(100);m_volumeSlider->hide();connect(m_volumeSlider, SIGNAL(currentValueChanged(int)), m_player, SLOT(setVolume(int)));
}

3.1.2 播放操作按钮

视频播放时,需要用到播放、暂停、继续、上一个、下一个、进度调节、音量调节等操作按钮,这里的对应按钮使用图标显示为对应的按钮,通过加载QPixmap来实现:

void PlayerBarWidget::InitWidget()
{m_btns.insert(0, new QtPixmapButton(0, QRect(295, 40, 60, 60), QPixmap(":/images/video/ic_prev.png"), QPixmap(":/images/video/ic_prev_pre.png")));m_btns.insert(1, new QtPixmapButton(1, QRect(375, 40, 60, 60), QPixmap(":/images/video/ic_play.png"), QPixmap(":/images/video/ic_pause.png")));m_btns.insert(2, new QtPixmapButton(2, QRect(465, 40, 60, 60), QPixmap(":/images/video/ic_next.png"), QPixmap(":/images/video/ic_next_pre.png")));m_btns.insert(3, new QtPixmapButton(3, QRect(655, 40, 60, 60), QPixmap(":/images/video/ic_volume.png"), QPixmap(":/images/video/ic_volume_pre.png")));m_btns.insert(4, new QtPixmapButton(4, QRect(728, 40, 60, 60), QPixmap(":/images/video/ic_list.png"), QPixmap(":/images/video/ic_list_pre.png")));m_btns.value(1)->setCheckAble(true);// 进度条m_progressBar = new QtSliderBar(this);m_progressBar->SetHorizontal(true);m_progressBar->SetSliderSize(2, 40);connect(m_progressBar, SIGNAL(currentValueChanged(int)), this, SIGNAL(currentPostionChanged(int)));
}

3.2 播放列表

播放列表功能用来实现视频文件的显示,以及手动指定切换要播放的视频。

3.2.1 读取视频文件

通过读取指定目录下的文件,查找类型为mp4的视频文件,构造视频播放列表。

void MediaPlayListWidget::ScanDirMedias(const QString &path)
{QDir dir(path);if (!dir.exists())return;dir.setFilter(QDir::Dirs | QDir::Files);dir.setSorting(QDir::DirsFirst);QFileInfoList list = dir.entryInfoList();int index = m_mapItems.size();for (int i = 0; i < list.size(); i++){QFileInfo fileInfo = list.at(i);if (fileInfo.fileName() == "." || fileInfo.fileName() == ".."){continue;}if (fileInfo.isDir()){ScanDirMedias(fileInfo.filePath());}else if (fileInfo.suffix() == "mp4"){QString strName = fileInfo.baseName().toLocal8Bit().constData();QString strPath = fileInfo.absoluteFilePath().toLocal8Bit().constData();m_playList->addMedia(QUrl::fromLocalFile(strPath));m_mapItems.insert(index, new QtListWidgetItem(index, strPath, strName, QPixmap(":/images/video/ic_video_preview.png")));index++;}}
}

3.2.2 视频列表界面

视频列表的具体界面实现,主要是在对应的矩形位置,显示各个视频文件的名称:

void VideoListViewer::drawItemInfo(QPainter *painter, QtPageListWidgetItem *item)
{painter->save();QFont font(Skin::m_strAppFontBold);font.setPixelSize(18);painter->setFont(font);QPixmap pixmap = item->m_pixmapIcon;int nXoffset = (item->m_rect.width() - pixmap.width()) / 2;int nYoffset = (item->m_rect.height() - pixmap.height() - painter->fontMetrics().height() - 10) / 2;QRect rectPixmap(nXoffset + item->m_rect.left(), item->m_rect.top() + nYoffset, pixmap.width(), pixmap.height());if (pixmap.isNull()){painter->setPen(QColor("#7effffff"));painter->drawRect(item->m_rect);}else{painter->drawPixmap(rectPixmap.topLeft(), pixmap);}painter->setPen(Qt::white);painter->drawText(item->m_rect.left(), rectPixmap.bottom() + 10, item->m_rect.width(), 30, Qt::AlignCenter, item->m_strBaseName);painter->restore();
}

3.3 视频预览列表

在进入正式的视频播放前,会先有一个视频预览列表界面,在这个界面会列出指定搜索目录下的所有视频,点击任意视频图标即可进入播放界面。

此部分的列表绘制代码逻辑如下:

void QtPageListWidget::drawItemInfo(QPainter *painter, QtPageListWidgetItem *item)
{painter->save();QRect rect = item->m_rect;int nXoffset = (rect.width() > ICON_SIZE) ? (rect.width() - ICON_SIZE) / 2 : 0;QRect rectPixmap(rect.left() + nXoffset + ICON_SIZE / 2, rect.top() + ICON_SIZE / 2, ICON_SIZE, ICON_SIZE);if (item->m_pixmapIcon.isNull()){painter->setPen(Qt::NoPen);painter->setBrush(QColor("#02a7f0"));painter->drawEllipse(rectPixmap.topLeft(), ICON_SIZE / 2, ICON_SIZE / 2);}else{painter->drawPixmap(rect.left() + nXoffset, rect.top(), item->m_pixmapIcon);}if (m_nCurrentIndex == item->m_nId){painter->setPen(Qt::NoPen);painter->setBrush(QColor("#32000000"));painter->drawEllipse(rectPixmap.topLeft(), ICON_SIZE / 2, ICON_SIZE / 2);}QFont font = painter->font();font.setPixelSize(16);painter->setFont(font);painter->setPen("#ffffff");int nTextHeight = painter->fontMetrics().height();QRect rectText(rect.left(), rect.bottom() - nTextHeight, rect.width(), nTextHeight);painter->drawText(rectText, Qt::AlignCenter, item->m_strText);painter->restore();
}

4 编译与测试

4.1 在Windows平台编译

Qt程序编写好后,可以先在Windows电脑上编译查看效果,在运行时,可能会遇到如下问题:

DirectShowPlayerService::doRender: Unresolved error code 0x80040266 (IDispatch error #102)

编译的时候没问题,但运行的时候报错:

这是因为Qt 中的多媒体播放,底层是使用DirectShowPlayerService,所以Windows电脑上需要先安装一个DirectShow解码器,例如LAV Filters。可以到这里(https://github.com/Nevcairiel/LAVFilters/releases)下载并安装 LAVFilters:

下载exe安装包安装即可,安装后,再运行就不会报错了,在Windows系统上运行视频播放器的效果如下:

4.2 交叉编译并在板子上运行

通过交叉编译,来测试视频播放器在OK3568-C板子上的播放效果。

使用编译音乐播放器时编写my3568build.sh的编译脚本编译即可,无需修改:

#! /bin/bashmkdir -p build
cd buildexport PATH=/home/xxpcb/myTest/OK3568/sourcecode/OK3568-linux-source/buildroot/output/OK3568/host/bin:$PATHqmake .. && make

执行该脚本即可编译:

./my3568build.sh 

将编译成功的可执行文件VIdeoPlayer复制到OK3568-C板子中,然后在其同目录下创建一个video文件夹,里面放入若干个mp4视频文件,然后就可以测试了,此外,代码中,还指定了/userdata/media这个搜索目录,这里有板子自带的一些视频:

文件复制到板子,我这里仍然使用的ADB无线传输的方式,比较方便,具体ADB操作演示,可参考之前这篇文章: RK3568源码编译与交叉编译环境搭建最后的Qt交叉编译与测试部分

需注意的是,板子里的这个Linux系统,不支持中文的显示,视频名不要有中文。

实测效果见文末视频,整体体验播放流畅,视频切换流程,进度条调整播放进度没有音乐播放器调整的顺畅,另外不知道怎么原因,视频播放的声音外放声音特别小,用耳机插孔听是正常的。

5 总结

本篇介绍了使用Qt开发一个视频播放器,一些功能代码是复用上篇的音乐播放器的代码,使用Qt Creator编写视频播放器的代码,首先在Windows电脑上编译运行测试,然后交叉编译,在OK3568-C开发板上进行实际测试。

该视频播放器实现的功能包括基础的播放功能、暂停与继续,音量调节,视频列表显示,下一个、下一个切换,进度条调节播放进度等。

相关文章:

嵌入式Qt 开发一个视频播放器

上篇文章&#xff1a;嵌入式 Qt开发一个音乐播放器&#xff0c;使用Qt制作了一个音乐播放器&#xff0c;并在OK3568开发板上进行了运行测试&#xff0c;实际测试效果还不错。 本篇继续来实现一个Qt视频播放器软件&#xff0c;可以实现视频列表的显示与选择播放等&#xff0c;先…...

阿里巴巴内网 Spring Cloud Alibaba 强势来袭,开创微服务的新时代

Spring Cloud 发展史 Spring Cloud 从 15 年的 3 月份推出之后&#xff0c;迅速在 Java 微服务生态中&#xff0c;成为开发人员的首选技术栈。 Spring Cloud 在 Spring Boot 的基础上&#xff0c;保留 Java 开发习惯&#xff0c;加入分布式特性&#xff0c;提供了一系列通用工…...

边界检测方法总结

1&#xff1a;经典的边界检测方法有sobel&#xff0c;拉普拉斯&#xff0c;canny等。 sobel&#xff1a; def get_sobel(in_chan, out_chan):filter_x np.array([[1, 0, -1],[2, 0, -2],[1, 0, -1],]).astype(np.float32)filter_y np.array([[1, 2, 1],[0, 0, 0],[-1, -2, -…...

Softing dataFEED OPC Suite Extended新版本支持从XML文件中读取生产数据

Softing dataFEED OPC Suite Extended V5.25的新功能——“文件读取&#xff08;File Read&#xff09;”&#xff0c;支持访问XML文件中可用的过程数据。 &#xff08;文件读取功能支持获取由XML文件提供的过程数据&#xff09;dataFEED OPC Suite Extended是用于OPC通信和云连…...

央行罚单!金融机构被罚原因揭秘

近日&#xff0c;人民银行公布了2023年首批行政处罚罚单&#xff0c;引发业内广泛关注。 顶象防御云业务安全情报中心统计了人民银行官网&#xff0c;2020年1月至2023年2月10日期间&#xff0c;公布的101份行政处罚。 统计显示&#xff0c;16家金融机构被罚27066.9万元&#…...

js中var、let、const详解

首先 var、let、const 在项目开发中都是用来声明变量的&#xff0c;在ES5中只有两种声明变量的方法&#xff1a;var和function&#xff0c;在ES6中新增了 let、const、class、import 四种声明变量的方法&#xff0c;本文主要讲解 var、let 与 const 的语法&#xff0c;其他的大…...

【数据库】MySQL概念知识语法-基础篇(DCL),真的很详细,一篇文章你就会了

目录通用语法及分类DCL&#xff08;数据控制语言&#xff09;管理用户查询用户权限控制函数字符串函数数值函数日期函数流程函数约束外键约束多表查询一对多多对多一对一通用语法及分类 ● DDL: 数据定义语言&#xff0c;用来定义数据库对象&#xff08;数据库、表、字段&…...

Blender骨骼动画快速教程

有关创建模型的更多详细信息&#xff0c;请参阅在 Blender 中创建模型。 我们将为这个例子做一个非常简单的模型——蠕虫&#xff01; 从我们的初始立方体开始&#xff0c;进入编辑模式&#xff0c;切换到面选择&#xff0c;然后选择任何面&#xff1a; 推荐&#xff1a;将 NSD…...

【C++算法】dfs深度优先搜索(下) ——【全面深度剖析+经典例题展示】

&#x1f483;&#x1f3fc; 本人简介&#xff1a;男 &#x1f476;&#x1f3fc; 年龄&#xff1a;18 &#x1f91e; 作者&#xff1a;那就叫我亮亮叭 &#x1f4d5; 专栏&#xff1a;关于C/C那点破事 文章目录0.0 写在前面1. 中国象棋1.1 题干信息① 背景说明概述② 问题描述…...

HIVE 基础(三)

目录 建表语句 表数据 Hive建表高阶语句 - CTAS and WITH CTAS – as select方式建表 CTE (CTAS with Common Table Expression) LIKE 创建临时表 清空表数据 修改表&#xff08;Alter针对元数据&#xff09; 改名 修正表文件格式 修改列名 添加列 替换列 动态分…...

redis-cluster集群搭建

安装redis所需环境 yum install -y gcc-c yum install -y wget 创建文件夹 cd / mkdir redis/redis-cluster/7001 cd redis/redis-cluster mkdir 7002 7003 7004 7005 7006 7007 7008下载redis压缩包并解压安装 wget https://download.redis.io/redis-stable.tar.gz tar -…...

【C语言】可变参数列表va_list

本篇博客让我们来认识一下C语言学习过程中往往被忽略的可变参数列表 所谓可变参数&#xff0c;就是一个不限定参数数量的函数&#xff0c;我们可以往里面传入任意个数的参数&#xff0c;以达成某些目的。 关联&#xff1a;C11可变模板参数 1.函数 #include <stdarg.h>…...

CentOS7.6 MySQL8安装

1 检查是否安装过 MySQL rpm -qa | grep -i mysqlmariadb rpm -qa | grep mariadb2 卸载之前的安装 MySQL rpm -e --nodeps 软件名 //强力删除&#xff0c;对相关依赖的文件也进行强力删除卸载 rpm -e --nodeps mariadb-libs-5.5.60-1.el7_5.x86_643 官网下载 MySQL :: D…...

安装Tomcat的步骤?

首先先完成JDK配置&#xff0c;javac -version 检测 1.把tomcat下载到本地硬盘 2.创建tomcat8.0文件夹&#xff0c;完成解压&#xff08;免安装&#xff09;4.打开解压之后的目录,进入bin目录,双击startup.bat,启动tomcat5.可以看到弹出一个黑色的窗口,不要关闭,如果关闭意味着…...

Redis之分布式锁

随着业务发展的需要&#xff0c;原单体单机部署的系统被演化成分布式集群系统后&#xff0c;由于分布式系统多线程、多进程并且分布在不同机器上&#xff0c;这将使原单机部署情况下的并发控制锁策略失效&#xff0c;单纯的 Java API并不能提供分布式锁的能力。为了解决这个问题…...

2022年中国前10电商GMV总结

我是卢松松&#xff0c;点点上面的头像&#xff0c;欢迎关注我哦&#xff01; 1&#xff0c;阿里8万亿;2&#xff0c;京东3万亿;3&#xff0c;拼多多3万亿;4&#xff0c;小程序私域电商3万亿;5&#xff0c;抖音电商1.4万亿。6&#xff0c;抖音本地生活服务电商600亿。7&#xf…...

ES6新增扩展:字符串-数值-数组-函数-对象

ES6新增扩展字符串的扩展判断字符串是否包含在另一个字符中字符串补全字符串重复消除字符串空格replaceAll()替换全部字符串at字符串匹配输出数值的扩展数值分隔符检测数值是否有限检测是否为NaNNumber.parseInt()、Number.parseFloat()isInteger()判断是否为整数Math.sign()判…...

python中import原理

0. 前言 在 python 中引入 Module 是再常见不过了&#xff0c;那么当我们 import 时它做了什么事情呢&#xff1f;它是如何加载 Module 使用的呢&#xff1f; 1. 什么是 module&#xff1f; 一般&#xff0c;Module 是一个后缀为 .py 的文件&#xff0c;其 module 名称一般…...

《Qt6开发及实例》6-4 显示SVG格式图片

目录 一、简介与设计 1.1 简介 1.2 设计 二、SvgWidget 2.1 鼠标滚轮事件 三、svgwindow 四、MainWindow 一、简介与设计 1.1 简介 1、SVG 的英文全称是 Scalable Vector Graphics&#xff0c;即可缩放的矢量图形。它是由万维网联盟&#xff08;W3C&#xff09;在 200…...

OpenGL ES 绘制一张图片

GLSL 语法与内建函数 GLSL 的修饰符与数据类型 GLSL 中变量的修饰符 const&#xff1a;修饰不可被外界改变的常量attribute&#xff1a;修饰经常更改的变量&#xff0c;只可以在顶点着色器中使用uniform&#xff1a;修饰不经常更改的变量&#xff0c;可用于顶点着色器和片段…...

Flask RESTful 示例

目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题&#xff1a; 下面创建一个简单的Flask RESTful API示例。首先&#xff0c;我们需要创建环境&#xff0c;安装必要的依赖&#xff0c;然后…...

Xshell远程连接Kali(默认 | 私钥)Note版

前言:xshell远程连接&#xff0c;私钥连接和常规默认连接 任务一 开启ssh服务 service ssh status //查看ssh服务状态 service ssh start //开启ssh服务 update-rc.d ssh enable //开启自启动ssh服务 任务二 修改配置文件 vi /etc/ssh/ssh_config //第一…...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍

文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结&#xff1a; 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析&#xff1a; 实际业务去理解体会统一注…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

【Java学习笔记】BigInteger 和 BigDecimal 类

BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点&#xff1a;传参类型必须是类对象 一、BigInteger 1. 作用&#xff1a;适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...

技术栈RabbitMq的介绍和使用

目录 1. 什么是消息队列&#xff1f;2. 消息队列的优点3. RabbitMQ 消息队列概述4. RabbitMQ 安装5. Exchange 四种类型5.1 direct 精准匹配5.2 fanout 广播5.3 topic 正则匹配 6. RabbitMQ 队列模式6.1 简单队列模式6.2 工作队列模式6.3 发布/订阅模式6.4 路由模式6.5 主题模式…...