0x00 前言
用 C++ 写窗口程序的话...Visual C++ 有内置的一套模板来着
但它是用 Windows API 来绘制窗口(构建窗口 -> 注册窗口类 -> 创建窗口 -> 显示窗口),加个控件就还得再用 CreateWindow () 来画控件,而且控件坐标需要自己填,没有生成器(网上应该有下载的吧),有点麻烦...
用 Qt C++ 就能让 C++ 窗口程序的编写变得简单很多
IDE:Visual Studio 2019 Community(别去网上找破解过的专业版了,Community 就完全够用)(当然也能用 Qt 自带的 IDE)
Qt C++ 下载:百度网盘,密码 2333
Visual Studio 的安装方法请自行百度,安装的时候没截图
0x01 安装和准备
0x01+1 Qt C++ 安装
下载来之后运行,会弹出一个界面让你登录,不用管,Skip 就行
接着选一下要安装的组件
因为是在 VS 里打 Add-in,所以只选这两个就行
如果你想要通过 Qt 自带的 IDE 开发的话建议百度一下安装教程,反正大同小异(本文并未介绍针对 Qt IDE 的编程方法)
安装好之后退出,就要开始装 VS 的 Add-in 了(如果你选择使用 Qt 自带的 IDE,请直接空降 0x02)
0x01+2 安装 VS 的 Add-in
在 VS 界面的上方有个扩展菜单,里头有个管理扩展的选项
点进去转到联机,搜索 Qt
下载完之后关掉 VS,再打开,会出来一个界面
点击 Modify,然后等待安装完成
进入 VS 主界面之后需要配置一下 Qt 的设置
进去之后设置一下编译器版本
点击 Add 添加版本,Name 自己取,Path 是你的 Qt 安装的 VC 编译器的路径,最好 32 位和 64 位都装上,Default 那里选 32 位,然后点 OK,接着退出 VS
再打开 VS 时新建一个项目,就能看到 Qt 的模板了
0x02 开始编写
Qt IDE 的操作应该... 大同小异吧?
因为要做窗口程序,就新建一个 Qt GUI Application。
创建项目时 Qt 会弹出一个窗口让你设置项目:
下一步
这里你可以选择你需要的一些东西,比如蓝牙、NFC、OpenGL 引擎以及 WebSocket 之类的东西,按你需求添加。
这里做一个登录程序来当作例程,并不需要这些花里胡哨的东西
剩下的默认,然后它会自动帮你生成一段代码,需要注意的是它生成的模板会自动报错:
找不到头文件,运行代码分析也无法通过,这个先不管,先设计窗口。
在右边的解决方案资源管理器里有个 UI 文件,这个就是程序的窗口文件了,双击它会打开 Qt Designer,这时候就能绘制窗口了
在左边把你需要的控件拖到窗口上然后调整大小,右边属性编辑器里可以更改对象名称(连接按钮事件时要用)以及按钮文本。
这里画一个登录用的窗口:
画完之后在左上角文件那里点一下保存,然后开始解决头文件缺失的问题。
右键刚保存的 UI 文件,点击编译
在项目目录 / Debug/uic 目录下就能看到生成的头文件,复制到项目根目录即可
如果错误没消失,把引入头文件的代码剪切再粘贴一下就行,现在头文件和 UI 的问题解决了,可以写代码了。
Doge.h(文件名取决于你创建项目时指定的项目名,下同)
class Doge : public QMainWindow
{
Q_OBJECT
public:
Doge(QWidget *parent = Q_NULLPTR);
public slots:
void btnEvent();
private:
Ui::DogeClass ui;
};
/*
* 12,13行定义一个槽(slot,Qt内专有名词)并声明一个函数,
* 用于后面的按钮事件
*/
这里定义完槽之后去 Doge.cpp:
Doge::Doge(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(btnEvent()));
}
void Doge::btnEvent() {
QString usr = ui.user->text();
QString pwd = ui.lineEdit_2->text();
if (usr == QString::fromLocal8Bit("littledoge")) {
if (pwd == QString::fromLocal8Bit("littledoge233")) {
MessageBoxA(NULL, "SUCCESS", "LOGIN", 0);
}else{
MessageBoxA(NULL, "PASS INCORRECT", "LOGIN", 0);
}
}else{
MessageBoxA(NULL, "USER INCORRECT", "LOGIN", 0);
}
}
2,3,4 行的头文件引入是按钮事件中用到的,自动生成的模板只包含 Doge.h
10 行使用 Qt 的 connect () 函数将窗口类(Doge.h 中在 15 行给其指定了一个对象 ui)中的按钮 pushButton(取决于你在绘制窗口中指定的按钮的对象名称)产生的 clicked 信号(被点击)绑定到槽中的 btnEvent 函数来实现按钮事件的附加,按钮事件代码在第 11 行
需要注意的是 btnEvent 函数需要在 Doge 类里面(在 Doge.h 中以 public slots 将其声明在 Doge 类中(6 行 class Doge)),而且要读取控件的信息需要使用 Qt 内置的数据类型(QString 等)而不能使用 C++ 的数据类型(int char float 等),所以要在这方面做好适配。
13,14 行使用 Qt 控件中的 text () 函数将指定控件的内容转化为 QString 并返回,那这里有个小问题,“->” 是啥子东西哦?
还记得在绘制窗体后编译了一个 ui_Doge.h 吗?
Doge.h 里面正好引用了它,来康康这个 ui_Doge.h 有啥东西:
QLineEdit *lineEdit_2;
在 18 行引入了一个叫 QLineEdit 的头文件,32 行定义了一个对象,它以指针的形式访问 QLineEdit 类,那这个头文件(QLineEdit)肯定就是定义控件的一堆操作的辣(因为下面也没东西 就是控件的坐标 内容等设置)
QLineEdit:
class Q_WIDGETS_EXPORT QLineEdit : public QWidget
public:
enum ActionPosition {
LeadingPosition,
TrailingPosition
};
Q_ENUM(ActionPosition)
explicit QLineEdit(QWidget *parent = Q_NULLPTR);
explicit QLineEdit(const QString &, QWidget *parent = Q_NULLPTR);
~QLineEdit();
QString text() const;
QString displayText() const;
QString placeholderText() const;
在 11 行(原文件 98 行,已删减空行)声明了一个 text () 函数,数据类型是 QString,具体代码我们就不用分析了,因为我们要探究的是 “->” 的用法
那 “->” 的用法就知道辣:
用于以指针的形式访问一个类
给个例子
using namespace std;
class doge{
public:
int dogenum=0;
};
int main(){
//使用指针访问doge类:
doge *obj;
//这两种方法都可以哒
*obj.dogenum=1;
obj->dogenum=1;
/*
*这俩方法主要还是用法不同
*实现的功能都一样的
*/
return 0;
}
“->” 的操作说完了,来继续看按钮事件,把代码再放一下:
Doge::Doge(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
connect(ui.pushButton, SIGNAL(clicked()), this, SLOT(btnEvent()));
}
void Doge::btnEvent() {
QString usr = ui.user->text();
QString pwd = ui.lineEdit_2->text();
if (usr == QString::fromLocal8Bit("littledoge")) {
if (pwd == QString::fromLocal8Bit("littledoge233")) {
MessageBoxA(NULL, "SUCCESS", "LOGIN", 0);
}else{
MessageBoxA(NULL, "PASS INCORRECT", "LOGIN", 0);
}
}else{
MessageBoxA(NULL, "USER INCORRECT", "LOGIN", 0);
}
}
对于 Qt 这种数据类型我们也只能以相同的方式和它适配,使用 QString::fromLocal8Bit () 来把一个字符串转换为 QString 类型来进行比较
问题来了“::” 啥意思?
一种调用类的静态方法 就是非正式的把一个类看作一个对象来使用,给个例程:
using namespace std;
class doge{
public:
void printdoge(){
cout << "DogeJoin";
}
};
int main(){
//doge obj;
//obj.printdoge();
//上面这段代码塞了一个对象给doge类,来让这个对象能调用类中的函数,但我特 例 独 行
doge::printdoge();
//CodeMirror好像不认这种用法耶...全红的...反正扔编译器里能过
//这样也能调用doge类中的printdoge函数
return 0;
}
但是 Qt 不能使用 && 来在一个判断里指定多个条件,只能用一个条件来做判断...
就用这种套娃的方式呗
下面 MessageBoxA 没啥好说的 了解过 Windows API 的都知道这玩意儿 windows.h 和 cstdio 里的
0x03 进行编译
以为编译就只是编译 cpp 文件就完了?
但是Q t 有 B U G !
当你运行代码分析 / 编译时,会有这个错误:
出错的文件在外部依赖项里,很明显,这就是bug
要修补这个 bug 的话,点这里获取官方补丁
然后把 Qt 编程器目录 /includes/qalgorithms.h 里面的文件替换成官方补丁,然后编译 Doge.cpp(Release 模式,调试一遍才能出程序,直接编译不行)
生成的程序在项目目录 / Release 下,点开它~
这程序毕竟是用的 Qt 框架,要用一些组件呢
安装 Qt 的时候它会给你的开始菜单塞个东西,除非你没勾
用 32-bit 还是 64-bit 看你编译的程序的位数
然后把你程序单独放一个文件夹里,最好别带中文和空格以及特殊符号
进入你程序所在文件夹,使用自带工具 windeployqt 来为它设置依赖支持库(但是程序内引用的图片等资源不会自动添加 需要手动复制
完活之后你程序就能正常打开辣~
进入你程序所在文件夹,使用自带工具 windeployqt 来为它设置依赖支持库(但是程序内引用的图片等资源不会自动添加 需要手动复制
进入你程序所在文件夹,使用自带工具 windeployqt 来为它设置依赖支持库(但是程序内引用的图片等资源不会自动添加 需要手动复制
0x04 技术总结
项目下载地址:点我,密码 2333
原文始发于微信公众号(天禧信安):用Qt C++写窗口程序
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论