C++调用Qt项目简易开发环境搭建(以视频播放器为例,附整个工程源码,支持win32

C++调用Qt项目简易开发环境搭建(以视频播放器为例,附整个工程源码,支持win32,第1张

一、本文主要内容介绍:
0、先附上工程源码下载链接(资源包括qt的vs2019所有库文件,免积分):https://download.csdn.net/download/qq_39660930/85135035
1、从零开始搭建一份Qt项目开发工程,只需安装了vs即可打开工程进行编译。

原理:使用C++调用Qt lib库的形式进行开发,不使用任何插件,不使用QtCreator。


2、vs配置项目教程。


3、注意点:对于C++开发者来讲,就是写cpp代码,然后进行编译,链接来生成可执行程序。

而Qt只是提供了一些自动生成cpp代码的功能而已。

比如使用Qt的uic.exe即可将它的.ui文件生成我们的.h文件。


4、Qt开发一个简易视频播放器,支持拖拽文件进行打开、双击全屏等功能。

软件界面如下:

二、项目开始
1、下载vs,本文使用的是 vs2019。


2、下载vs对应的Qt lib库,包括Qt的一些应用程序(本文附带的工程源码里有,包括win32和x64的debug及release),如图:

3、项目框架搭建

BaseFunc模块提供一些编码转换函数及获取可执行程序绝对路径函数。


GuiMediaPlayer模块进行界面设计及功能实现。


MediaPlayer主函数模块负责链接库生成可执行程序。


vs2019工程配置文件夹则是vs配置工程时自动生成的,接下来详细介绍如何配置项目工程。


4、打开vs,创建新项目,选择空白解决方案:



5、创建BaseFunc工程






将BaseFunc的头文件及源文件添加到工程里:

设置工程属性(输出目录、中间目录、配置类型、字符集、附加包含目录、预处理器):








生成项目即可看到对应的lib库:

至此BaseFunc项目配置完成。


6、创建GuiMediaPlayer工程



拖拽头文件、源文件、资源文件到工程里:

这里需要注意的是:qrc和ui文件创建时只需要按照qt语法写一个最简单的就行,后面使用qt对应的程序来进行设计即可。


接下来设置工程属性(输出目录、中间目录、配置类型、字符集、附加包含目录、预处理器):



预处理器:和BaseFunc项目一样。


Qt项目和普通的项目配置不同的地方就是要配置生成前事件,来使用Qt的exe来处理资源文件生成c++源码文件,配置如下:

命令行代码:

$(SolutionDir)..\openbsd\qt\lib\$(Platform)\Release\uic.exe $(SolutionDir)..\modules\$(ProjectName)\src\GuiMediaPlayer.ui -o $(SolutionDir)..\modules\$(ProjectName)\inc\ui_GuiMediaPlayer.h
$(SolutionDir)..\openbsd\qt\lib\$(Platform)\Release\moc.exe $(SolutionDir)..\modules\$(ProjectName)\inc\GuiMediaPlayer.h -o $(SolutionDir)..\modules\$(ProjectName)\src\moc_GuiMediaPlayer.cpp
$(SolutionDir)..\openbsd\qt\lib\$(platform)\Release\rcc.exe -binary $(SolutionDir)..\modules\$(ProjectName)\src\GuiMediaPlayer.qrc -o $(SolutionDir)..\modules\$(ProjectName)\src\GuiMediaPlayer.rcc

然后生成项目:

第一次生成项目后,需要把自动生成的源码文件添加到工程里,然后重新生成:

接下来配置如何编辑qrc和ui文件,右击qrc文件,选择打开方式,点击添加,选择QrcEditor.exe(Qt库文件里有),并且设置为默认值:


这样以后双击qrc文件就会自动使用QrcEditor来打开了:

同样右击ui文件,设置designer.exe来默认打开该文件:


这样就可以使用Qt Designer来设计我们的ui了,每次修改ui文件后,重新生成该项目即可。


至此GuiMediaPlayer项目配置完成。


7、创建主项目工程
右击解决方案,添加项目



将源文件替换为我们的main.cpp

右击该项目设为启动项目,并且设置依赖项目:


接下来设置工程属性(输出目录、中间目录、字符集、附加包含目录、预处理器、附加库目录)



预处理器:和BaseFunc项目相同。



接下来需要设置生成后事件,程序运行时需要拷贝一些资源文件及dll到对应目录:

命令行代码如下:

Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Core.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Gui.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Widgets.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Multimedia.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5MultimediaWidgets.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Network.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5OpenGL.dll"  "$(TargetDir)"
mkdir "$(TargetDir)platforms\"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\plugins\platforms\qwindows.dll"  "$(TargetDir)platforms\"
XCopy /D /i /e "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\plugins\mediaservice"  "$(TargetDir)mediaservice"

Copy /D "$(Solutiondir)..\modules\GuiMediaPlayer\src\GuiMediaPlayer.rcc"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\modules\GuiMediaPlayer\src\GuiMediaPlayer.rcc"  "$(ProjectDir)"
XCopy /D /i /e "$(Solutiondir)..\modules\GuiMediaPlayer\src\ico"  "$(TargetDir)ico"
XCopy /D /i /e "$(Solutiondir)..\modules\GuiMediaPlayer\src\ico"  "$(ProjectDir)ico"


命令行代码如下:

Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Cored.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Guid.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Widgetsd.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Multimediad.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5MultimediaWidgetsd.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5Networkd.dll"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\Qt5OpenGLd.dll"  "$(TargetDir)"
mkdir "$(TargetDir)platforms\"
Copy /D "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\plugins\platforms\qwindowsd.dll"  "$(TargetDir)platforms\"
XCopy /D /i /e "$(Solutiondir)..\openbsd\qt\lib$(Platform)$(Configuration)\plugins\mediaservice"  "$(TargetDir)mediaservice"

Copy /D "$(Solutiondir)..\modules\GuiMediaPlayer\src\GuiMediaPlayer.rcc"  "$(TargetDir)"
Copy /D "$(Solutiondir)..\modules\GuiMediaPlayer\src\GuiMediaPlayer.rcc"  "$(ProjectDir)"
XCopy /D /i /e "$(Solutiondir)..\modules\GuiMediaPlayer\src\ico"  "$(TargetDir)ico"
XCopy /D /i /e "$(Solutiondir)..\modules\GuiMediaPlayer\src\ico"  "$(ProjectDir)ico"

然后生成该项目后运行即可看到界面:

可以看到程序没有图标,接下来进行设置:
在MediaPlayer主工程目录下放一个ico,并且创建rc文件及修改MediaPlayer.vcxproj如下:

生成并启动项目后可以看到图标:

至此项目开发环境搭建完成。


8、ui界面设计,及功能实现
开发环境搭建好以后,我们就可以双击ui文件来进行设计界面了,我们的这个界面比较简单,菜单里增加一个文件打开按钮,并且设置该按钮的ico图标为qrc里的。

中央布局背景通过styleSheet来直接使用ico路径,这样我们可以在程序发布后灵活替换背景图片。


9、播放功能实现,代码比较简单,请直接看代码:
GuiMediaPlayer.h:

#pragma once

#include 
#include 
#include 
#include 

#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 

#include "ui_GuiMediaPlayer.h"

typedef enum enThreadState
{
	THREAD_STATE_E_Start = 0,
	THREAD_STATE_E_PrepareStop,
	THREAD_STATE_E_Stop
}THREAD_STATE_E;

class GuiMediaPlayer;
class GuiMediaPlayerThread :public QThread
{
	Q_OBJECT
public:
	GuiMediaPlayerThread(QObject* parent, GuiMediaPlayer* gui);
	~GuiMediaPlayerThread();

	void run();//线程入口函数(工作线程的主函数)

private:
	GuiMediaPlayer* m_gui;
};

class GuiMediaPlayer : public QMainWindow
{
	Q_OBJECT

public:
    static GuiMediaPlayer* instance();
    
	GuiMediaPlayer(QWidget* parent = Q_NULLPTR);
	~GuiMediaPlayer();

	THREAD_STATE_E	getThreadState() { return m_thread_state; };
	int				setThreadState(THREAD_STATE_E state) { return m_thread_state = state; };
	void			startThread();
	void			stopThread();

protected:
	//拖动进入事件
	void dragEnterEvent(QDragEnterEvent* event);

	//放下事件
	void dropEvent(QDropEvent* event);

	//关闭按钮触发
	void closeEvent(QCloseEvent* event);

	//鼠标按下
	void mousePressEvent(QMouseEvent* e);

	//鼠标移动
	void mouseMoveEvent(QMouseEvent* e);

	//鼠标释放
	void mouseReleaseEvent(QMouseEvent* e);

	//鼠标进入
	void enterEvent(QEvent* e);

	//鼠标离开
	void leaveEvent(QEvent* e);

	//窗口缩放
	void resizeEvent(QResizeEvent* event);

	//键盘按下
	void keyPressEvent(QKeyEvent* event);

	//事件捕获
	bool eventFilter(QObject* obj, QEvent* event);

private:
	void playFile(QString filename);

signals:
	void sigUpdateState();

private slots:
	void on_m_openFile_button_triggered();
	void updateState();

private:
	Ui::GuiMediaPlayerClass ui;
	THREAD_STATE_E			m_thread_state;
	GuiMediaPlayerThread*	m_thread;
	QMediaPlayer*			m_player;
	QVideoWidget*			m_playerWidget;
	int						m_twopress;
};

GuiMediaPlayer.cpp:

#include 
#include 

#include "GuiMediaPlayer.h"

#include "BaseFunc.h"

GuiMediaPlayerThread::GuiMediaPlayerThread(QObject* parent, GuiMediaPlayer* gui)
	:QThread(parent)
{
	m_gui = NULL;

	if (gui == NULL)
		return;

	m_gui = gui;

	start();
}

GuiMediaPlayerThread::~GuiMediaPlayerThread()
{
}

void GuiMediaPlayerThread::run()
{
	while (1)
	{
		//程序退出时终止线程
		if (m_gui->getThreadState() == THREAD_STATE_E_PrepareStop)
		{
			m_gui->setThreadState(THREAD_STATE_E_Stop);
			return;
		}

		emit m_gui->sigUpdateState();

		QThread::msleep(1000);
	}
}

GuiMediaPlayer* GuiMediaPlayer::instance()
{
	static GuiMediaPlayer* _ins = NULL;
	if ( _ins == NULL )
	{
		_ins = new GuiMediaPlayer();
	}

	return _ins;
}

GuiMediaPlayer::GuiMediaPlayer(QWidget* parent)
	: QMainWindow(parent)
{
    char path[1024] = {0};
    char processname[1024] = {0};
    GetExecutablePath(path, processname, sizeof(path));

    QString rcc = path;
	rcc += "GuiMediaPlayer.rcc";

	QResource::registerResource(rcc);

	ui.setupUi(this);
    
    //启用控件的放下 *** 作
	setAcceptDrops(true);

	m_player = NULL;
	m_playerWidget = NULL;

	m_twopress = 0;

	m_thread = NULL;

	connect(this, SIGNAL(sigUpdateState()), this, SLOT(updateState()));

	startThread();
}

GuiMediaPlayer::~GuiMediaPlayer()
{
	stopThread();
	if (m_player != NULL)
	{
		delete m_player;
		m_player = NULL;
	}
	if (m_playerWidget != NULL)
	{
		delete m_playerWidget;
		m_playerWidget = NULL;
	}
}

void GuiMediaPlayer::startThread()
{
	m_thread_state = THREAD_STATE_E_Start;
	m_thread = new GuiMediaPlayerThread(NULL, this);
}

void GuiMediaPlayer::stopThread()
{
	if (m_thread)
	{
		//设置准备停止状态
		m_thread_state = THREAD_STATE_E_PrepareStop;
		//一直等到停止
		while (1)
		{
			//printf("wait show img thread stop\n");
			if (m_thread_state == THREAD_STATE_E_Stop)
				break;
			QThread::msleep(100);
		}
		QThread::msleep(50);
		delete m_thread;
		m_thread = NULL;
	}
}

void GuiMediaPlayer::updateState()
{
	if (m_player)
	{
		if (m_player->mediaStatus() == QMediaPlayer::EndOfMedia)
		{
			if (m_playerWidget != NULL)
			{
				delete m_playerWidget;
				m_playerWidget = NULL;
			}

			delete m_player;
			m_player = NULL;
		}
	}
}

void GuiMediaPlayer::playFile(QString filename)
{
	if (m_playerWidget != NULL)
	{
		delete m_playerWidget;
		m_playerWidget = NULL;
	}

	if (m_player != NULL)
	{
		delete m_player;
		m_player = NULL;
	}

	m_playerWidget = new QVideoWidget;
	if (m_playerWidget == NULL)
	{
		return;
	}
	m_playerWidget->setObjectName(QString::fromUtf8("play_widget"));
	ui.verticalLayout->addWidget(m_playerWidget);
	m_playerWidget->installEventFilter(this);

	m_player = new QMediaPlayer;
	if (m_player == NULL)
	{
		return;
	}

	m_player->setVideoOutput(m_playerWidget);
	m_player->setMedia(QUrl::fromLocalFile(filename));
	m_player->play();
}

void GuiMediaPlayer::on_m_openFile_button_triggered()
{   
	QString filename = QFileDialog::getOpenFileName();
	if (filename.toStdString() == "")
		return;

	playFile(filename);

    return ;    
}

/*拖放分为拖动(Drag)和放下(Drop)两种 *** 作。

数据拖动时会被存储为MIME(Multipurpose- * Internet Mail Extensions)类型,在Qt使用QMimeData类来表示MIME类型数据,并还用 * QDrag类来完成数据的转换,而整个拖放 *** 作都是在几个鼠标事件和拖放事件中完成. */ void GuiMediaPlayer::dragEnterEvent(QDragEnterEvent* event)//拖动事件 { //可打开.txt,.h,.cpp文件 if (event->mimeData()->hasUrls()) //数据中是否包含URL event->acceptProposedAction(); //如果是则接受动作 else event->ignore(); } void GuiMediaPlayer::dropEvent(QDropEvent* event)//放下事件 { const QMimeData* mineData = event->mimeData();//获取MIME数据 if (mineData->hasUrls()) //如数据中包含URL { QList<QUrl>urlList = mineData->urls(); //获取URL列表 if (urlList.isEmpty()) return; //将其中第一个URL表示为本地文件路径 QString filename = urlList.at(0).toLocalFile(); if (filename.isEmpty()) return; playFile(filename); } } void GuiMediaPlayer::closeEvent(QCloseEvent* event) { if (1) { stopThread(); event->accept(); } else { event->ignore(); } } void GuiMediaPlayer::mousePressEvent(QMouseEvent* e) { QPoint lastPoint = e->globalPos(); //printf("%d %d\n", lastPoint.x(), lastPoint.y()); } void GuiMediaPlayer::mouseMoveEvent(QMouseEvent* e) { //printf("%d %d\n", e->globalX(), e->globalY()); } void GuiMediaPlayer::mouseReleaseEvent(QMouseEvent* e) { //printf("%d %d\n", e->globalX(), e->globalY()); } void GuiMediaPlayer::enterEvent(QEvent* e) { } void GuiMediaPlayer::leaveEvent(QEvent* e) { } void GuiMediaPlayer::resizeEvent(QResizeEvent* event) { } void GuiMediaPlayer::keyPressEvent(QKeyEvent* event) { if (event->key() == Qt::Key_Q) { } else if (event->key() == Qt::Key_Left) { } else if (event->key() == Qt::Key_Right) { } else if (event->key() == Qt::Key_Up) { } else if (event->key() == Qt::Key_Down) { } else if (event->key() == Qt::Key_Backspace) { } else if (event->key() == Qt::Key_Enter || event->key() == Qt::Key_Return) { } else { } } bool GuiMediaPlayer::eventFilter(QObject* obj, QEvent* event) { if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); if (keyEvent->key() == Qt::Key_Backspace) { } } if (obj == m_playerWidget) { if (event->type() == QEvent::MouseButtonDblClick) { m_twopress++; if (m_twopress % 2) m_playerWidget->setFullScreen(true); else m_playerWidget->setFullScreen(false); } } return QWidget::eventFilter(obj, event); }

10、其他注意项
依赖库输入直接在main.cpp里指定的:

关闭打开控制台代码也在main.cpp里:

程序运行后如果播放视频没图像,则需要安装解码器,安装包在openbsd\qt\lib\LAVFilters-0.76.1-Installer.exe。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/673355.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-19
下一篇 2022-04-19

发表评论

登录后才能评论

评论列表(0条)

保存