前言
我们一般使用QtCreator来编写QtWidgets的程序,或者QML程序。
在如今AI工具逐渐流行的时代,QtCreator这种几乎是没有办法快速集成AI先进成果用户改善编码效率的工具可能会逐渐被淘汰掉。
但这并不是说Qt会被淘汰掉,而是QtCreator这个编辑器会逐渐落伍。编写Qt程序和QtCreator之间实际上并没有必然联系。
Qt只是一个库,我们可以使用CMake来引入它进行编写。
我选择VSCode搭建“Qt + AI + 智能提示”这样编程环境,因为VSCode有着丰富的插件可以支持我们使用AI进行编程。
但对于大部分来说,引入AI并非难点,下载个插件,到大模型提供商那里拿到API Key,然后再引入这个API Key,最后就可以开始AI编程。这与具体的编程环境无关。
难点在于如何方便地运行Qt程序和搭建Qt的智能提示。本篇文章就是为了解决这个问题。
如何引入Qt
在VSCode中编写Qt代码其实并不需要我们添加一些额外的插件,只需要想办法在CMake中引入Qt的库并且链接引入的Qt库即可。
但是仅仅是这样的话,我们将会遇到这样的问题:
- 使用Qt的库的一些组件,比如:QWidget的时候,没有智能提示,会爆红。
- 如果Qt项目中有UI文件,那么编写UI文件很不方便,每次都需要你特地去打开QtDesigner,然后再使用QtDesigner打开UI文件。
在这里,我将扮演一个“不知道该如何在VSCode中配置Qt开发环境的人”来一步步配置这个环境,这样的话配置环境的过程中读者也能够了解到可能会遇到什么问题?产生这个问题的原因是什么?该怎样解决这个问题?
安装VSCode
Visual Studio Code - Code Editing. Redefined
在上述VSCode官网中下载并安装好VSCode,下载完成后运行程序即可并按照提示进行安装即可。
下载必要插件
C++插件
按照上述步骤安装好C++插件。
使用C++插件的示例(熟悉者可跳过)
按照我们平常使用那些大型IDE的经验,此时你可能会认为:这个时候我编写C++代码应该就可以有智能提示,并且编写完代码之后我们就可以直接运行这份C++代码了吧。因此,我就随便打开了一个文件夹,并在其中完成了以下内容:
然后,我点击进入main.cpp
文件,发现右上角有一个类似Run或者Debug的按钮:
该按钮需要安装好上面所说的C++插件才会出现。
那么我理所当然地就点击这个按钮,看看能否运行main.cpp。然后它在顶部显示这样一个对话框:
但选择这两个东西都会报错,无法运行main.cpp
。
请记住一点,VSCode仅仅只是一个编辑器,它不具备编译功能,它能够编译C++代码是因为你给了它编译器,所以它能够调用编译器并按照预定义好的命令行命令去运行这个编译器去编译你的代码。
在浏览器中搜索,vscode select a debug configuration
。我发现这里应该是需要我们选择一个关于C++的编译器和调试器,为了让C++插件能够正常运行,我们必须指定好这两个东西。
有两种方法可以进行指定:
- 在VSCode中明确设置好编译器和调试器的路径。
- 将编译器和调试器的访问路径添加到系统环境变量中,VSCode使用时自己去环境变量中扫描。
Windows下我不想自己设置太多环境变量,因此这里我直接在VSCode中设置:
然后就会出现下面的页面:
你可以看到,Compiler Path可以进行设置。这里我假设读者安装了Qt,并且Qt的编译器是MinGW。比如我这里Qt的安装目录是:D:\MySoftWare\Qt
,那么我就可以在D:\MySoftWare\Qt\Tools
中找到我安装的MinGW:
我这里安装的MinGW版本有点多,这里我选择mingw1310_64
。打开这个文件夹:
这个bin
目录下的g++.exe
就是编译器的路径。调试器也在bin
里面, 你可以打开去看看,g++.exe
,gdb.exe
,gcc.exe
里面全都有。
回到VSCode,我们设置编译器路径:
此时我们再点击运行,就会出现这样的提示:
可以看到我们设置的编译器出现在了选项中,选择它。然后就会自动运行,你可以在终端中查看到运行结果:
并且你会发现根目录下生成了一个main.exe
。
如果项目只有一个源文件那还好,C++插件还能应付地过来。但当项目变得复杂,就会出现很复杂的源文件结构项目大了,多个文件需要一起编译,这时候手动输入命令会很麻烦。CMake可以自动处理这些复杂的步骤,生成Makefile或者项目文件(CMake会根据平台的不同生成不同的文件),让编译更简单。
配置C++标准库的智能提示
由于C++插件不会自动根据编译器的位置给你找出C++标准库的位置,因此我们最好是配置以下C++插件的includePath
。
首先,我们需要知道C++标准库的包含目录在哪里。找到你g++.exe
(最好是相对路径或者绝对路径来寻找,否则可能找到不是你想要的标准库)。
运行:
g++ -E -v -
出现:
(一堆信息,我省略了)
#include "..." search starts here:
#include <...> search starts here:
D:/MySoftWare/Qt/Tools/mingw1310_64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include
D:/MySoftWare/Qt/Tools/mingw1310_64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/include-fixed
D:/MySoftWare/Qt/Tools/mingw1310_64/bin/../lib/gcc/x86_64-w64-mingw32/13.1.0/../../../../x86_64-w64-mingw32/include
End of search list.
这里面的路径就是includePath
,将其加入到settings.json
的如下位置:
CMake插件
使用CMake插件示例
在插件市场搜索CMake,并安装“CMake Tools”,就是有Microsoft认证的那个。然后在项目中创建CMakeLists.txt
并编写如下内容:
cmake_minimum_required(VERSION 3.16)
project(helloworld)
add_executable(${PROJECT_NAME} main.cpp)
使用Ctrl + Shift + P
,并输入
点击最顶端那个选项就会出现:
然后就会出现很多的编译器,这里显示什么编译器我猜测大概率和环境变量有关。这里GCC之所以显示,我猜测它可能去查找了C++插件的编译器路径,所以能够查找到GCC。这里选择GCC。
这里可能会配置错误,因为如果我们配置CMake到环境变量中,那么CMake插件就可能找不到cmake.exe来运行配置命令了。此时,我们需要在settings
中配置cmake路径,Ctrl + Shift + P
你可以选择图形化界面去配置cmake路径,我这里选择使用JSON来进行配置:
在安装Qt时我应该是选择了cmake,${QT安装路径}/Tools/CMake_64
才会出现。没有的话,可以自行到CMake官网中下载一个并安装(具体是不是Qt安装的影响不大,选择自己的cmake就好)。
再次执行cmake configuration
操作,你会发现出现了一个build目录(默认是这样的,你可以在settings中修改)。
按照CMakeList.txt制定好的编译规则,它会生成一堆符合这些规则的makefile,也可能是.ninjia。之后使用左下角的运行按钮来运行(CMake插件和C++插件的运行按键不一样)。
可以看到成功运行了,若要调试,则打断点,然后按虫子按钮进行Debug。或者在菜单栏的Run中选择Start Debugging
。
引入Qt库
CMakeLists.txt中使用find_package()
来找到Qt库:
cmake_minimum_required(VERSION 3.16)
project(helloworld)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets)
接着它进行了报错:
[cmake] By not providing "FindQt6.cmake" in CMAKE_MODULE_PATH this project has
[cmake] asked CMake to find a package configuration file provided by "Qt6", but
[cmake] CMake did not find one.
[cmake]
[cmake] Could not find a package configuration file provided by "Qt6" with any of
[cmake] the following names:
[cmake]
[cmake] Qt6Config.cmake
[cmake] qt6-config.cmake
[cmake]
[cmake] Add the installation prefix of "Qt6" to CMAKE_PREFIX_PATH or set "Qt6_DIR"
[cmake] to a directory containing one of the above files. If "Qt6" provides a
[cmake] separate development package or SDK, be sure it has been installed.
这里它报错,并给出提示:
- 设置
CMAKE_PREFIX_PATH
成Qt6的安装前缀,或者设置Qt6_DIR
成包含Qt6Config.cmake
和qt6-config.cmake
的目录。
这里我们设置CMAKE_PREFIX_PATH
为D:/MySoftWare/Qt/6.6.3/mingw_64
,你可以按照自己所使用的Qt版本来进行设置。
D:/MySoftWare/Qt
是我的Qt安装路径。6.6.3
是我的Qt6版本。mingw_64
是Qt6套件的目录
修改之后的CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(helloworld)
# 变量设置要在project()之后
set(CMAKE_PREFIX_PATH "D:/MySoftWare/Qt/6.6.3/mingw_64")
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets)
按照我们在QtCreator的写法,在main.cpp
中写入如下内容:
#include <QApplication>
#include <QWidget>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QWidget w;
w.show()
return app.exec();
}
运行,发现它似乎无法找到QApplication
和QWidget
。这样就会导致:
- 编译的时候无法通过头文件定位到lib中QApplication和QWidget的内容,从而导致链接失败,无法运行。
因此,当务之急是需要找到这些个头文件,临时的解决方案是在CMakeLists.txt中添加Qt库的includePath。但是的话换一个项目就需要我们再次在CMakeLists.txt中引入includePath,因此这里我直接在C++插件中添加Qt的includePath。
那么,Qt的includePath在哪里呢?如果你刚才设置了CMAKE_PREFIX_PATH
,那么它就在${CMAKE_PREFIX_PATH}/include
中,其内容大概是这样的:
有两种添加includePath的方法:
${CMAKE_PREFIX_PATH}/include
,添加到includePath中,这样就引用QApplication
就需要改成QtWidgets/QApplication
。- 在方法1的基础上,将
${CMAKE_PREFIX_PATH}/include
目录下的所有子目录都添加到includePath中,这样就可以像在QtCreator那样添加头文件。
这里演示第2种方法。
首先在${CMAKE_PREFIX_PATH}/include
打开PowerShell,运行以下命令获取所有子目录的绝对路径:
D:\MySoftWare\Qt\6.6.3\mingw_64\include\ActiveQt
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DAnimation
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DCore
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DExtras
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DInput
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DLogic
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuickAnimation
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuickExtras
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuickInput
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuickRender
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DQuickScene2D
D:\MySoftWare\Qt\6.6.3\mingw_64\include\Qt3DRender
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtAxBase
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtAxContainer
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtAxServer
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtBluetooth
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtBodymovin
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtCharts
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtChartsQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtConcurrent
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtCore
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtCore5Compat
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDataVisualization
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDataVisualizationQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDBus
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDesigner
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDesignerComponents
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtDeviceDiscoverySupport
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtExampleIcons
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtFbSupport
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtFreetype
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtGraphs
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtGrpc
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtGui
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtHarfbuzz
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtHelp
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtHttpServer
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtInsightTracker
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtInsightTrackerQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtJpeg
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtJsonRpc
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsAnimation
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsFolderListModel
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsQmlModels
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsSettings
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsSharedImage
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLabsWavefrontMesh
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLanguageServer
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtLocation
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtMultimedia
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtMultimediaQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtMultimediaWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtNetwork
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtNetworkAuth
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtNfc
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtOpenGL
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtOpenGLWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPacketProtocol
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPdf
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPdfQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPdfWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPng
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPositioning
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPositioningQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtPrintSupport
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtProtobuf
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtProtobufQtCoreTypes
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtProtobufQtGuiTypes
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtProtobufWellKnownTypes
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQDocCatch
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQDocCatchConversionsPrivate
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQDocCatchGeneratorsPrivate
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlCompiler
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlCore
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlDebug
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlDom
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlIntegration
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlLocalStorage
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlLS
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlModels
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlToolingSettings
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlTypeRegistrar
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlWorkerScript
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQmlXmlListModel
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3D
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DAssetImport
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DAssetUtils
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DGlslParser
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DHelpers
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DHelpersImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DIblBaker
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DParticles
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DPhysics
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DPhysicsHelpers
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DRuntimeRender
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DSpatialAudio
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuick3DUtils
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Basic
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2BasicStyleImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Fusion
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2FusionStyleImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Imagine
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2ImagineStyleImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Impl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Material
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2MaterialStyleImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2Universal
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControls2UniversalStyleImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickControlsTestUtils
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickDialogs2
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickDialogs2QuickImpl
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickDialogs2Utils
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickEffects
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickLayouts
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickParticles
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickShapes
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickTemplates2
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickTest
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickTestUtils
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickTimeline
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtQuickWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtRemoteObjects
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtRemoteObjectsQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtRepParser
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtScxml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtScxmlQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSensors
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSensorsQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSerialBus
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSerialPort
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtShaderTools
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSpatialAudio
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSql
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtStateMachine
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtStateMachineQml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSvg
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtSvgWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtTest
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtTextToSpeech
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtTools
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtUiPlugin
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtUiTools
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtVirtualKeyboard
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtVirtualKeyboardSettings
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWebChannel
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWebChannelQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWebSockets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWebView
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWebViewQuick
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtWidgets
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtXml
D:\MySoftWare\Qt\6.6.3\mingw_64\include\QtZlib
请注意,这里的绝对路径是我主机上的绝对路径,而不是你主机上的绝对路径,千万不要照搬。
将其一条一条加入到,settings.json
的C_Cpp.default.includePath
列表中,如下所示:
完成之后的情况类似于上面这张图片所显示的那样,至于如何将这么大量的路径包含进来(大概100多条),我这里使用了vim的宏来完成。再次运行程序,你会发现还是失败了,这时你需要配置CMake的运行环境,让它能够找到调试器:
在settings
中添加如下内容:
然后再次运行:
运行成功。这下就算是运行成功了。接下来就是使用CMake管理更多的文件(只不过我们不再可以使用QtCreator自动生成文件)。
自定义Widget
我们创建一个MyWidget
,其内容如下:
// MyWidget.h
#pragma once
#include <QWidget>
class QPushButton;
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget* parent = nullptr);
~MyWidget();
private:
QPushButton* button;
};
// MyWidget.cpp
#include "MyWidget.h"
#include <QPushButton>
#include <QVBoxLayout>
#include <QMessageBox>
MyWidget::MyWidget(QWidget* parent)
: QWidget{parent}
, button(new QPushButton("Hello", this))
{
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(button);
connect(button, &QPushButton::clicked, [=](){
QMessageBox::information(this, tr("消息"), tr("你好"));
});
}
MyWidget::~MyWidget()
{
}
// main.cpp
#include "MyWidget.h"
#include <QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}
此时还不能直接运行,因为MyWidget.h
和MyWidget.cpp
并未经过moc的处理。
接着,我们需要修改CMakeLists.txt文件:
cmake_minimum_required(VERSION 3.16)
project(helloworld)
# 变量设置要在project()之后
set(CMAKE_PREFIX_PATH "D:/MySoftWare/Qt/6.6.3/mingw_64")
# 由于Qt的一些宏,如Q_OBJECT, SIGNALS这些实际上是需要使用名为moc.exe的程序去扫描源文件然后进行宏替换来完成
# 开启CMAKE_AUTOMOC,则CMake会自动帮我们去找出源文件,然后使用moc.exe对这些源文件进行处理
set(CMAKE_AUTOMOC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME}
main.cpp
MyWidget.cpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets)
此时,才能够成功运行:
使用UI文件
创建UI文件
在QtCreator中,我们可以直接右键项目来创建.ui
文件。但是在VSCode中,我们没有这个功能。
通常,我们需要自己打开QtDesigner,然后创建.ui
文件,最后将.ui
文件保存在项目中。每当我们想要修改.ui
文件的时候,我们需要去系统中找到QtDesigner打开然后对.ui
文件进行修改。
每次都需要脱离VSCode去修改.ui
文件太过于麻烦,有没有什么方法能够让我们在VSCode中直接点击.ui
文件然后弹出qtdesigner对该文件进行修改呢?
我的想法是:
- 将
designer.exe
的路径注册到环境变量中,每次想要创建或者修改.ui
文件,就直接在VSCode终端中运行designer.exe
然后再创建或者选择.ui
文件。 - 当然,VSCode中有名为“Qt UI”的插件,可以让你右键对
.ui
文件打开QtDesigner。但是,如果我的项目中没有.ui
文件,我就需要创建一个空的.ui
文件来专门打开designer。
这里我选择使用第1种方法,因为这比较符合我的操作习惯。
使用:
designer.exe --no-scaling
--no-scaling
是因为我这里designer的软件图片太大的,因为给出的选项。
你可以将默认终端设置成bash,然后对上述命令起一个简短的别名,这样就可以快速打开designer。
编辑好直接保存成MyWidget.ui
:
如何使用这个.ui
文件呢?所有的<file>.ui
经过uic的处理过后会变成ui_<file>.h
,UI的类名也会变成Ui_<根widget的名字>
。
比如MyWidget.ui
中,我将其根widget的名字命名为MyWidget
,因此ui_MyWidget.h
中会产生Ui_MyWidget
的类。
于是,我们可以这样子引用它们:
// MyWidget.h
#pragma once
#include <QWidget>
class QPushButton;
class Ui_MyWidget;
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget* parent = nullptr);
~MyWidget();
private:
Ui_MyWidget* ui;
};
// MyWidget.cpp
#include "MyWidget.h"
#include "ui_MyWidget.h"
#include <QMessageBox>
MyWidget::MyWidget(QWidget* parent)
: QWidget{parent}
, ui(new Ui_MyWidget)
{
ui->setupUi(this);
connect(ui->helloButton, &QPushButton::clicked, this, [=](){
QMessageBox::information(this, tr("消息"), tr("你好"));
});
connect(ui->byeButton, &QPushButton::clicked, this, [=](){
QMessageBox::information(this, tr("消息"), tr("再见"));
});
}
MyWidget::~MyWidget()
{
delete ui;
}
// main.cpp
#include "MyWidget.h"
#include <QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}
# CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(helloworld)
# 变量设置要在project()之后
set(CMAKE_PREFIX_PATH "D:/MySoftWare/Qt/6.6.3/mingw_64")
# 由于Qt的一些宏,如Q_OBJECT, SIGNALS这些实际上是需要使用名为moc.exe的程序去扫描源文件然后进行宏替换来完成
# 开启CMAKE_AUTOMOC,则CMake会自动帮我们去找出源文件,然后使用moc.exe对这些源文件进行处理
set(CMAKE_AUTOMOC ON)
# 开启CMAKE_INCLUDE_CURRENT_DIR是为了让uic自动生成的.h文件能够被包含
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# CMAKE_AUTOUIC会自动对.ui文件进行处理,处理是有过程的(我的猜测)
# 1. 查找源文件中有没有引用"ui_<file>.h"的内容。
# 2. 若存在,则搜索名为"<file>.ui"的文件,并将其转化成ui_<file>.h文件
# 若你仅写了.ui文件,但没有引用它后面生成的.h文件(虽然它现在不存在),那么uic就不会对该.ui文件进行处理
set(CMAKE_AUTOUIC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(${PROJECT_NAME}
main.cpp
MyWidget.cpp
)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Widgets)
运行效果:
编写QML应用程序
我这边是仿照QtCreator的QML项目来写的CMakeLists.txt。
CMakeLists.txt:
cmake_minimum_required(VERSION 3.16)
project(helloworld)
# 变量设置要在project()之后
set(CMAKE_PREFIX_PATH "D:/MySoftWare/Qt/6.6.3/mingw_64")
# 由于Qt的一些宏,如Q_OBJECT, SIGNALS这些实际上是需要使用名为moc.exe的程序去扫描源文件然后进行宏替换来完成
# 开启CMAKE_AUTOMOC,则CMake会自动帮我们去找出源文件,然后使用moc.exe对这些源文件进行处理
set(CMAKE_AUTOMOC ON)
find_package(Qt6 REQUIRED COMPONENTS Quick)
# QML应用程序需要使用qt_add_executable代替add_executable
qt_add_executable(${PROJECT_NAME}
main.cpp
)
# QML的文件需要通过qt_add_qml_module来添加
# 之后可以使用"qrc:/xxx/main.qml"来引用
qt_add_qml_module(${PROJECT_NAME}
URI xxx # 自定义的前缀
VERSION 1.0
QML_FILES
main.qml # 若文件有前缀,比如 hellopage/page.qml,则需要使用qrc:/xxx/hellopage/page.qml来访问
)
target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Quick)
// main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QObject>
int main(int argc, char** argv)
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QObject::connect(
&engine,
&QQmlApplicationEngine::objectCreationFailed,
&app,
[]() { QCoreApplication::exit(-1); },
Qt::QueuedConnection
);
const QUrl url(u"qrc:/xxx/main.qml"_qs); // 按照CMakeLists.txt注释所说的那样来引用
engine.load(url);
return app.exec();
}
具体qml文件的在build文件夹下会生成什么,你可以自己观察一下,我说不上来,这有一定的规律,猜测和qt的资源文件系统有关。这方面的内容我不太了解。
最终的运行效果如下:
这里的main.qml
是我让AI给我写的。