创建项目和编译

新建Qt Widgets应用

我们启动qt creator 创建项目,选择Qt Widgets应用

https://cdn.llfc.club/2Dhh7c4Ylcy0qPCBesia08MjpV4.png


接下来选择项目目录,项目名字就叫helloworld


https://cdn.llfc.club/2DhhIcFvC94IfaTM0lq84WpnBon.png

构建系统选择qmake

https://cdn.llfc.club/2DhhM6ZdjFG9oKYM4Nb5fmKW5Rb.png

我们创建一个名字为HelloDialog的类,继承于QDialog

https://cdn.llfc.club/2DhhP4Pl56WhLbLci1yeP6zXQez.png

构建套件选择你们安装的就行了,我这里选择了msvc2019,如果不知道选哪个就全选,系统自己会默认一个。

https://cdn.llfc.club/2DhhRs0jwbLDS7sdJzvuJ6lwMkV.png

接下来一步步完成就可以了,creator会为我们生成代码,在项目目录会多出如下的目录

https://cdn.llfc.club/2DhhUPhRZZKiNy2kHDFfRk6Orbu.png

我们运行程序后会弹出界面

https://cdn.llfc.club/2DhhXJGoe24vmmAi87ZqsBvLOEd.png


同时文件夹里会生成ui文件的类,保存在ui_hellodialog.h文件里


https://cdn.llfc.club/2DhhZfGTEyCxsmWSi5ZVsYCbPki.png

这个类是用来管理qt desinger 的ui 里的控件的,是自动生成的

我们看一下项目结构

https://cdn.llfc.club/2DhhcMrSmV1niDj38JtkQbmmwLh.png

helloworld.pro是qt 的qmake最终要执行编译时使用的文件,相当于我们用cmake编译时要使用makefile文件一样。

我们点击pro查看以下

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    hellodialog.cpp

HEADERS += \
    hellodialog.h

FORMS += \
    hellodialog.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target


  1. 第1行 表示使用qt的core和gui库,如果以后我们想用其他的库,可以往这里添加。
  2. 第3行 表示如果qt的版本大于4,则引入widgets库,因为qt4之前的版本widgets库是不需要引用的,qt4之后需要引用。
  3. 11行主要是告诉编译器要编译的源文件
  4. 15行告诉编译器要编译的源文件
  5. 18行FORMS 描述了要用到哪些ui文件。   

接下来我们为刚才的应用添加一个icon,先准备一个head.ico文件,如果没有可以去https://www.bitbug.net/制作一个,然后我们将head.ico放到项目目录里

https://cdn.llfc.club/2Dhi5ZPz2ZjvcfE53IaO94giW4b.png
然后修改pro文件,新增 RC_ICONS = head.ico 代码

SOURCES += \
    main.cpp \
    hellodialog.cpp

HEADERS += \
    hellodialog.h

FORMS += \
    hellodialog.ui

RC_ICONS = head.ico

然后我们编译生成界面,就可以看到图标了

https://cdn.llfc.club/2DhiC668pTFipvB5xwcHv9Je23X.png

接下来我们双击项目目录的hellodialog.ui 会进入Qt Designer界面,然后我们添加一个label,label里写上 “Hello World! Hello Qt!”

https://cdn.llfc.club/2DhiGHr6VX8kO6dWspFReiLgwzI.png

再次运行程序就会弹出新的界面,里面有我们添加的label。

由于新增了label,那么ui文件就会变化,ui文件变化,之前编译生成的ui_hellodialog.h文件也会自动更新
我们查看以下这个文件

#ifndef UI_HELLODIALOG_H
#define UI_HELLODIALOG_H

#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>

QT_BEGIN_NAMESPACE

class Ui_HelloDialog
{
public:

    void setupUi(QDialog *HelloDialog)
    {
        if (HelloDialog->objectName().isEmpty())
            HelloDialog->setObjectName(QString::fromUtf8("HelloDialog"));
        HelloDialog->resize(800, 600);

        retranslateUi(HelloDialog);

        QMetaObject::connectSlotsByName(HelloDialog);
    } // setupUi

    void retranslateUi(QDialog *HelloDialog)
    {
        HelloDialog->setWindowTitle(QCoreApplication::translate("HelloDialog", "HelloDialog", nullptr));
    } // retranslateUi

};

namespace Ui {
    class HelloDialog: public Ui_HelloDialog {};
} // namespace Ui

QT_END_NAMESPACE

#endif // UI_HELLODIALOG_H

定义了一个Ui_HelloDialog类,成员函数setupUi用来指定将ui加载到哪个类对象上。retranslateUi主要是重新翻译一下界面上的文字等信息。Ui_HelloDialog被定义在Ui作用域里。

那这个类Ui_HelloDialog是怎么加载到程序中的呢?
当我们创建对话框程序时,系统自动生成了hellodialog.cpp文件,在HelloDialog的构造函数里创建了Ui_HelloDialog类型对象,并调用setupUi加载了界面。

#include "hellodialog.h"
#include "ui_hellodialog.h"

HelloDialog::HelloDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::HelloDialog)
{
    ui->setupUi(this);
}

HelloDialog::~HelloDialog()
{
    delete ui;
}

以上就是整个界面初始化和创建的过程,接下来我们试着单独创建ui文件和cpp文件,加载界面。

创建空项目

先创建一个空项目,然后我们手动添加代码完成和之前程序自动帮我们生成的代码类似的功能。
先创建一个空项目

https://cdn.llfc.club/2Dhj25xFbrKYKrNHxWfLUmryciE.png

操作步骤和之前类似,项目名字就helloworld,编译套件选择自己安装的,点击finish就完成了。
此时项目目录只有一个pro文件。

https://cdn.llfc.club/2Dhj5Ryzc1DygDlioSLRhwofIpN.png

接下来我右键单击项目,选择添加C++ 源文件

https://cdn.llfc.club/2Dhj8zPrAZ9x243kkSD73hMGn6P.png

文件名就叫main.cpp

https://cdn.llfc.club/2DhjBdsLQdbjmzu0VWWsh5aRVkq.png

项目里添加main.cpp后,需要在pro里添加widgets说明

greaterThan(QT_MAJOR_VERSION,4): Qt+=widgets

主要原因是qt4以上版本,Qt不包含widgets库,需要引入。另外为了保证我们能使用qt的核心库如QApplication等,我们也要添加gui和core库,这样一个简单的pro文件是这样的。

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

SOURCES += \
    main.cpp

然后我们往main.cpp中添加逻辑

#include <QApplication>
#include <QDialog>
#include <QLabel>

int main(int argc, char* argv[]){
    QApplication a(argc, argv);
    QDialog w;
    QLabel label(&w);
    label.setText("Hello World! Hello Qt!");
    w.show();
    return a.exec();
}

上述逻辑就是创建了一个对话框w,然后将label设置在w上。然后再调用w显示出来。
然后点击绿色三角运行,可以看到生成界面了

https://cdn.llfc.club/2DhjyrlVrsMcVi6uflipzv4dRZs.png
界面有点小,我们可以重设dialog的大小,以及label的位置

int main(int argc, char* argv[]){
    QApplication a(argc, argv);
    QDialog w;
    QLabel label(&w);
    label.setText("Hello World! Hello Qt!");
    w.resize(400,300);
    label.move(120,120);
    w.show();
    return a.exec();
}

再次运行生成界面就正常了

https://cdn.llfc.club/2DhkABLPQNGnHf617ZqusCdjigI.png

以上就是通过纯手动的方式添加文件并修改pro完成界面的加载,实际生产中我们多采用creator自动帮我们创建文件和界面的方式。

使用ui文件

我们同样可以创建空项目,并在空项目中引入ui文件,加载界面。
我们在当前项目基础上,添加ui文件
选择Qt的form文件

https://cdn.llfc.club/2DhkD0z3Q7gXRNHTqJ9kD9ZXN7a.png

然后选择dialog without buttons

https://cdn.llfc.club/2DhkFl4pnekNnT3HZxsBi3wYbIn.png


接下来给这个ui命名为hellodialog.ui, 点击完成后进入designer界面,我们在界面上添加一个label,写上”Hello World! Hello Qt!”

https://cdn.llfc.club/2DhkI3lrTJkpAh5LgKfdEXbDcnN.png

在qt designer里修改label的geometry大小和位置

https://cdn.llfc.club/2DhkKFYQE3nhed0CO0TG6Sq0ufQ.png

修改dialog名字为HelloDialog

https://cdn.llfc.club/2DhkMHpMWkZ9hJzM8IRjTdx5L8Y.png

然后我们ctrl s 保存该ui
先运行一下程序,因为之前main函数加载ui还是我们之前的方式写的,所以会弹出界面。我们改一下main函数

#include <QApplication>
#include <QDialog>
#include <QLabel>
#include "ui_hellodialog.h"
int main(int argc, char* argv[]){
    QApplication a(argc, argv);
    QDialog w;
//    QLabel label(&w);
//    label.setText("Hello World! Hello Qt!");
//    w.resize(400,300);
//    label.move(120,120);
    Ui::HelloDialog ui;
    ui.setupUi(&w);
    w.show();

    return a.exec();
}

通过调用ui的setupUi将界面设置给对话框w,然后调用w的show函数。再次运行程序可以显示界面了。

使用自定义的C++类

在上面的项目里我们新增C++类,右键项目目录选择Add New,然后选择C++类

https://cdn.llfc.club/2DhkS8uaYMAaLkawa5aEeCp8PPj.png

我们将这个类命名为HelloDialog,Base选择custom,然后写入QDialog

https://cdn.llfc.club/2DhkUXpafvbYyogLT99w9vd5Iu9.png

点击下一步直到完成
此时编译会出问题,因为我们要在生成的hellodialog.h文件里包含Qdialog头文件和ui头文件,并且声明ui成员变量

#ifndef HELLODIALOG_H
#define HELLODIALOG_H

#include <QWidget>
#include <QDialog>
#include "ui_hellodialog.h"
class HelloDialog : public QDialog
{
public:
    HelloDialog();
    ~HelloDialog();
private:
    Ui::HelloDialog *_ui;
};

#endif // HELLODIALOG_H

然后在hellodialog.cpp里加载我们的ui文件

#include "hellodialog.h"
#include "ui_hellodialog.h"
HelloDialog::HelloDialog():_ui(new  Ui::HelloDialog())
{
    _ui->setupUi(this);
}

HelloDialog::~HelloDialog(){
    delete _ui;
}

修改main.cpp,调用HelloDialog创建界面

#include <QApplication>
#include <QDialog>
#include <QLabel>
#include "hellodialog.h"
int main(int argc, char* argv[]){
    QApplication a(argc, argv);
    HelloDialog dialog;
    dialog.show();
    return a.exec();
}

再次运行就加载了我们的界面。

使用QtDesigner类

其实我们添加一个带界面的类不需要上面那么麻烦,分别创建类和界面,然后再写代码加载,这种方式是正确的但是并不高效,Qt给我们提供了设计师界面类,我们可以直接通过为项目创建一个设计师界面类,自动就会实现类文件和界面的关联。
我们在现有的项目目录右键点击添加New Item,添加设计师界面类

https://cdn.llfc.club/2DhkiXqZ5xZXz5h1EH0gPzWlmvl.png

接下来依旧选择 Dialog without buttons

https://cdn.llfc.club/2Dhkkekwuyyr92UrduC4bDk9H6O.png

只是我们将界面类的名字改为HelloDialog2

https://cdn.llfc.club/2Dhkmk7xLOUzDBdqWw96K3QqjR0.png

完成后会弹出ui界面,我们在界面添加label,同样写上”Hello World ! Hello Qt!”
我们可以看到qt自动为我们的类生成了代码并加载了ui文件

#include "hellodialog2.h"
#include "ui_hellodialog2.h"

HelloDialog2::HelloDialog2(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::HelloDialog2)
{
    ui->setupUi(this);
}

HelloDialog2::~HelloDialog2()
{
    delete ui;
}

接下来我们只要在main.cpp里添加代码完成新界面的加载即可。

#include <QApplication>
#include <QDialog>
#include <QLabel>
#include "hellodialog2.h"
int main(int argc, char* argv[]){
    QApplication a(argc, argv);
    HelloDialog2 dialog;
    dialog.show();
    return a.exec();
}

点击运行同样可以显示我们设计好的界面。
我们实际开发中基本就是以这种方式添加界面类的,方便快捷。

热门评论

热门文章

  1. vscode搭建windows C++开发环境

    喜欢(596) 浏览(84280)
  2. 聊天项目(28) 分布式服务通知好友申请

    喜欢(507) 浏览(6133)
  3. 使用hexo搭建个人博客

    喜欢(533) 浏览(12006)
  4. Linux环境搭建和编码

    喜欢(594) 浏览(13671)
  5. Qt环境搭建

    喜欢(517) 浏览(24969)

最新评论

  1. 利用栅栏实现同步 Dzher:作者你好!我觉得 std::thread a(write_x); std::thread b(write_y); std::thread c(read_x_then_y); std::thread d(read_y_then_x); 这个例子中的assert fail并不会发生,原子变量设定了非relaxed内存序后一个线程的原子变量被写入,那么之后的读取一定会被同步的,c和d线程中只可能同时发生一个z++未执行的情况,最终z不是1就是2了,我测试了很多次都没有assert,请问我这个观点有什么错误,谢谢!
  2. 聊天项目(15) 客户端实现TCP管理者 lkx:已经在&QTcpSocket::readyRead 回调函数中做了处理了的。
  3. C++ 并发三剑客future, promise和async Yunfei:大佬您好,如果这个线程池中加入的异步任务的形参如果有右值引用,这个commit中的返回类型推导和bind绑定就会出现问题,请问实际工程中,是不是不会用到这种任务,如果用到了,应该怎么解决?
  4. 类和对象 陈宇航:支持!!!!
  5. 聊天项目(7) visualstudio配置grpc diablorrr:cmake文件得改一下 find_package(Boost REQUIRED COMPONENTS system filesystem),要加上filesystem。在target_link_libraries中也同样加上
  6. boost::asio之socket的创建和连接 项空月:发现一些错别字 :每隔vector存储  是不是是每个. asio::mutable_buffers_1 o或者    是不是多打了个o
  7. 网络编程学习方法和图书推荐 Corleone:啥程度可以找工作
  8. 聊天项目(13) 重置密码功能 Doraemon:万一一个用户多个邮箱呢 有可能的
  9. 利用C11模拟伪闭包实现连接的安全回收 搁浅:看chatgpt说 直接传递 shared_from_this() 更安全 提问: socket_.async_read_some(boost::asio::buffer(data_, BUFFSIZE), // 接收客户端发生来的数据 std::bind(&Session::handle_read, this, std::placeholders::_1, std::placeholders::_2, shared_from_this())); socket_.async_read_some(boost::asio::buffer(data_, BUFFSIZE), std::bind(&Session::handle_read, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); 这两种方式有区别吗? 回答 : 第一种方式:this 是裸指针,可能会导致生命周期问题,虽然 shared_from_this() 提供了一定的保护,但 this 依然存在风险。 第二种方式:完全使用 shared_ptr 来管理生命周期,更加安全。 通常,第二种方式更推荐使用,因为它可以确保在异步操作完成之前,Session 对象的生命周期得到完全管理,避免使用裸指针的潜在风险。
  10. 基于锁实现线程安全队列和栈容器 secondtonone1:我是博主,你认真学习的样子的很可爱,哈哈,我画的是链表由空变成1个的情况。其余情况和你思考的类似,只不过我用了一个无效节点表示tail的指向,最初head和tail指向的都是这个节点。
  11. 解决博客回复区被脚本注入的问题 secondtonone1:走到现在我忽然明白一个道理,无论工作也好生活也罢,最重要的是开心,即使一份安稳的工作不能给我带来事业上的积累也要合理的舍弃,所以我还是想去做喜欢的方向。
  12. 无锁并发队列 TenThousandOne:_head  和 _tail  替换为原子变量。那里pop的逻辑,val = _data[h] 可以移到循环外面吗
  13. 处理网络粘包问题 zyouth: //消息的长度小于头部规定的长度,说明数据未收全,则先将部分消息放到接收节点里 if (bytes_transferred < data_len) { memcpy(_recv_msg_node->_data + _recv_msg_node->_cur_len, _data + copy_len, bytes_transferred); _recv_msg_node->_cur_len += bytes_transferred; ::memset(_data, 0, MAX_LENGTH); _socket.async_read_some(boost::asio::buffer(_data, MAX_LENGTH), std::bind(&CSession::HandleRead, this, std::placeholders::_1, std::placeholders::_2, shared_self)); //头部处理完成 _b_head_parse = true; return; } 把_b_head_parse = true;放在_socket.async_read_some前面是不是更好
  14. 面试题汇总(一) secondtonone1:看到网络上经常提问的go的问题,做了一下汇总,结合自己的经验给出的答案,如有纰漏,望指正批评。
  15. C++ 线程安全的单例模式演变 183******95:单例模式的析构函数何时运行呢? 实际测试里:无论单例模式的析构函数为私有或公有,使用智能指针和辅助回收类,两种方法都无法在main()结束前调用单例的析构函数。
  16. 聊天项目(9) redis服务搭建 pro_lin:redis线程池的析构函数,除了pop出队列,还要free掉redis连接把
  17. Qt MVC结构之QItemDelegate介绍 胡歌-此生不换:gpt, google
  18. string类 WangQi888888:确实错了,应该是!isspace(sind[index]). 否则不进入循环,还是原来的字符串“some string”
  19. 堆排序 secondtonone1:堆排序非常实用,定时器就是这个原理制作的。
  20. Qt 对话框 Spade2077:QDialog w(); //这里是不是不需要带括号
  21. interface应用 secondtonone1:interface是万能类型,但是使用时要转换为实际类型来使用。interface丰富了go的多态特性,也降低了传统面向对象语言的耦合性。
  22. 创建项目和编译 secondtonone1:谢谢支持
  23. 再谈单例模式 secondtonone1:是的,C++11以后返回局部static变量对象能保证线程安全了。
  24. 构造函数 secondtonone1:构造函数是类的基础知识,要着重掌握
  25. slice介绍和使用 恋恋风辰:切片作为引用类型极大的提高了数据传递的效率和性能,但也要注意切片的浅拷贝隐患,算是一把双刃剑,这世间的常态就是在两极之间寻求一种稳定。
  26. 答疑汇总(thread,async源码分析) Yagus:如果引用计数为0,则会执行 future 的析构进而等待任务执行完成,那么看到的输出将是 这边应该不对吧,std::future析构只在这三种情况都满足的时候才回block: 1.共享状态是std::async 创造的(类型是_Task_async_state) 2.共享状态没有ready 3.这个future是共享状态的最后一个引用 这边共享状态类型是“_Package_state”,引用计数即使为0也不应该block啊
  27. visual studio配置boost库 一giao里我离giaogiao:请问是修改成这样吗:.\b2.exe toolset=MinGW
  28. protobuf配置和使用 熊二:你可以把dll放到系统目录,也可以配置环境变量,还能把dll丢到lib里

个人公众号

个人微信