【Qt设计开发】GUI界面设计开发

这篇具有很好参考价值的文章主要介绍了【Qt设计开发】GUI界面设计开发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


  本文是我在学习QT的GUI界面设计过程当中的心得和学习笔记,在学习时已经有C, C++,Python的基础。文章附上了学习的代码,仅供大家参考。如果有问题,有错误欢迎大家留言。此外,博主还有另外几篇文章,分别关于 Python基础知识Python的具体应用C语言指针结构体的难点C++入门和进阶知识点C++高阶知识点,大家点击即可翻阅。

一、Qt简介和下载安装

  Qt是一个1991年由Qt Company开发的跨平台C++图形用户界面(Graphic User Interface, GUI)应用程序开发框架。QT包括但不仅限于GUI的开发,也包含了诸如系统调用、网络编程、数据库编程,2D/3D图形处理等等。QT具有强大的跨平台运行的性能,几乎囊括了所有的操作系统,例如Linux、Windows、Mac OS、Android、IOS。我们所熟知的金山WPS、Google Earth谷歌地图、SKype网络电话就是用Qt开发的。

  博主使用的版本是Qt 5.14.2, 下载、安装 参照B站视频。

二、Qt入门

2.1 创建第一个项目

  第一步,选择new->Application->Qt Widgets Application->Choose:

qt界面开发,C++,qt

  第二步,修改项目名称和项目路径,点击下一步。

qt界面开发,C++,qt

  第三步,修改类名称,其中基类有三种,分别是QMainWindow(菜单类), QWidget, QDialog(对话框类),表示创建的类继承的基类,例如,图中所示mywidget类的父类就是QWidget。QDialog和QMainWindow是QWidget的子类。QMainWindow是菜单类,左上角有一些菜单选项,右上角有最小化最大化按钮。QDialog是对话框类,下图所示就是一个对话框类。

qt界面开发,C++,qt

  第四步,选择MinGW 64-bit 编译器,32位和64位的区别在于32位能在64位的机器上跑,64位不能在32位的机器上跑,初始项目选择任意一个就可以,点击下一步,然后在点击完成,就可以产生一个名为Qt_test的项目,项目底下有一个Qt_test.pro的项目文件。
qt界面开发,C++,qt

  之后的步骤默认就可以,一直点下一步,然后编译运行,出现一个空白窗口,创建完毕。

qt界面开发,C++,qt

  编译成功后,会在项目目录底下生成build文件,然后点击debug文件,里面有生成的.exe可执行文件,点击即可运行,结果就是一个空白图窗。博主在运行.exe的时候碰到了错误弹窗,显示程序“无法找到入口”,添加了环境变量之后还需要将环境变量上移,具体解决参考解决Qt生成exe错误:无法定位程序输入点。

# QT_hello.pro文件
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    # 版本大于4以上的添加widgets模块

CONFIG += c++11 # 用C++11标准来解释代码

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mywidget.cpp

HEADERS += \
    mywidget.h

TARGET = UAV    # 生成的.exe文件名称
TEMPLATE = app  # 应用程序模板 Application
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
// mywidget.h文件
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
class mywidget : public QWidget // 公共继承
{
    Q_OBJECT    // Q_OBJECT宏,允许类中使用信号和槽的机制

public:
    mywidget(QWidget *parent = nullptr);    // 构造函数
    ~mywidget();    // 析构函数
};
#endif // MYWIDGET_H
// main.cpp文件
# include <QApplication>
# include <QtWidgets>
# include <QDebug>
// main程序入口     argc命令行变量数量, argv命令行变量的数组
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);    // 应用程序对象, 在QT中,应用程序对象有且仅有一个    
    mywidget w;  // 窗口对象 mywidget是Qwidget的子类
    w.show();	// show方法, 窗口对象默认不会显示
	qDebug()<<"hello world";    // 在控制台输出, 用于调试    
    return a.exec();	// 让应用程序对象进入消息循环
}
// mywidget.cpp文件
#include "mywidget.h"
mywidget::mywidget(QWidget *parent)
    : QWidget(parent)
{
}
mywidget::~mywidget()
{
}

2.2 快捷键和命名规范

  QT如下,可以提高编码效率:

/* 快捷键
 * 运行代码: Ctrl + r
 * 编译:	Ctrl + b
 * 注释:	Ctrl + /
 * 缩放字体:Ctrl + 滚轮
 * 查找/替换字体: Ctrl + f
 * 整行移动代码: Ctrl + Shift + 上/下键
 * 自动对齐:Ctrl + i
 * 在同名文件和源文件之间切换: F4
 * 快速添加函数定义:鼠标移到声明的那一行,按Alt + Enter
 * 修改变量名,并应用到所有:Ctrl + Shift + r
 * 快捷打开输出窗口: Alt + number(1-8)
 * 书签功能: 快速跳到代码
 * 			Ctrl + M 添加/删除标签
 * 			Ctrl + . 查找并移动到下一个标签处
 * 查看帮助文档:
 * 			第一种:Qt Creator 查看 F1
 * 			第二种:独立的帮助文档程序查看
*/

/*
类名: 首字母大写,单词和单词之间首字母大写
函数名和变量名称: 首字母小写,单词和单词之间首字母大写
*/

qt界面开发,C++,qt

  Qt设计师创建的文件后缀为.ui, 无法直接运用到C++中,因此引入一个uic工具,可以将.ui文件转换为.c文件。rcc moc同样是这样类型的工具,将一些qt文件转换成C++语法格式的文件

2.3 Qt项目和VS2022项目相互转换

  博主最近需要使用QT和VS 2022联合编程,大家有需要也可以参考视频 VS项目和QT项目相互转换。

  使用VS2022创建的QT项目,输出为.pro文件,利用Qt createor打开,需要在.pro文件中加载模块(添加如下代码),因为VS2022是在项目配置的时候加载的。如下图所示。

# ----------------------------------------------------
# This file is generated by the Qt Visual Studio Tools.
# ------------------------------------------------------

QT += core gui widgets  
# 模块加载, 使用VS2022创建的项目,输出为.pro文件,利用Qt createor打开,需要在.pro文件中加载模块
# 因为VS2022是在项目配置的时候加载的。

TEMPLATE = app
TARGET = QtWidgetsTest

##########################################
# 以下代码可以不要
DESTDIR = ../x64/Debug
CONFIG += debug
LIBS += -L"."
DEPENDPATH += .
MOC_DIR += GeneratedFiles/$(ConfigurationName)
OBJECTS_DIR += debug
UI_DIR += GeneratedFiles
RCC_DIR += GeneratedFiles
###########################################
HEADERS += ./qtwidgetstest.h
SOURCES += ./qtwidgetstest.cpp \
    ./main.cpp
FORMS += ./qtwidgetstest.ui
RESOURCES += qtwidgetstest.qrc

qt界面开发,C++,qt

    w.setWindowTitle(u8"VS2022 QT 窗口"); // 不乱码
    /* 
    产生乱码, 英文不会有乱码,英文编码格式都是同意的ASCII,QT中文编码格式是UTF-8,
    windows中文编码格式是GB2312,u8为转换成UTF-8,QT就可以识别了  
    */

三、Qt基础

3.1 Qt对象树和窗口坐标系概念

  当创建的对象在堆区的时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放操作,QT会对象会放入到对象树中,会自动释放内存,一定程度上简化了内存回收机制。这也是QT的优点之一,因此,我们在构造时候就指定parent对象,就不需要操心内存释放问题。

  Qt窗口的坐标系:以左上角顶点为原点(0, 0),X向右增加,Y向下增加。对于嵌套窗口,其坐标系是相对于父窗口而言。

3.2 QPushButton

  在编写这部分代码时,博主的编辑器竟然没有代码补全功能,于是又在网上找了解决办法,这里给出链接。
  在学习QT的各种类的过程中,最重要的是 学会如何查找帮助文档以及看懂帮助文档。例如QPushButton类,帮助文档中给出详细解释:添加头文件,同时要在.pro文件中加入widgets模块,其父类是QAbstractButton,其子类是QCommandLinkButton等等信息。

qt界面开发,C++,qt

3.3 信号和槽(signals and slots)

3.3.1 pushbutton关闭窗口

  信号和槽是学习Qt的一个非常重要知识点,在信号和槽当中,我们引入一个连接函数connect( ),将信号发送者和信号接收者链接起来。connect( )一共有四个参数

  • 参数1:信号发送者;
  • 参数2:发送的信号(函数地址);
  • 参数3:信号接收者;
  • 参数4:处理的槽函数(函数地址)。

  在空白项目的基础上改写mywidget.cpp函数,实现点击按钮,关闭窗口案例:

# include "mywidget.h"
# include <QPushButton>
# include <QDebug>

mywidget::mywidget(QWidget *parent)
    : QWidget(parent)
{
    qDebug() << "hello world";  // 调试信息
    // 创建一个按钮
    QPushButton * btn = new QPushButton;
    //btn->show();    // show以顶层(新窗口)的方式弹出窗口控件
    btn->setParent(this);   // 让btn对象依赖在mywidget窗口中
    btn->setText("第一个按钮");
    QPushButton *btn2 = new QPushButton("第二个按钮",this);
    btn2->move(100,100);    // 移动btn2按钮
    resize(600,400);    // 重置窗口大小
    btn2->resize(50,50);    // 设置btn2按钮大小
    setWindowTitle("第一个窗口应用");  // 设置窗口名称
    connect(btn,&QPushButton::clicked, this, &mywidget::close);
}
mywidget::~mywidget()
{
}

3.3.2 自定义信号和槽

  创建一个下课,老师饿了,学生请客的案例。添加自定义的老师类和学生类,选择C++类,这个两个类不是窗口类,直接继承QObject类。分别产生了teacher和student的.cpp .h文件。

qt界面开发,C++,qt

  头文件中定义,变量名称和函数声明,在.cpp文件中写实现。

// mywidget.h
#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
# include "teacher.h"
# include "student.h"

class mywidget : public QWidget // 公共继承
{
    Q_OBJECT    // Q_OBJECT宏,允许类中使用信号和槽的机制

public:
    mywidget(QWidget *parent = nullptr);    // 构造函数
    ~mywidget();    // 析构函数

    Teacher *t;     // 在头文件中声明变量和函数
    Student *s;
    void ClassIsOver();
};
#endif // MYWIDGET_H
// student.h
#ifndef STUDENT_H
#define STUDENT_H

#include <QObject>

class Student : public QObject
{
    Q_OBJECT
public:
    explicit Student(QObject *parent = nullptr);

signals:

public slots:
    /* 早期的QT版本必须要写到,public slots,高级版本可以写到public或全局下
     * 返回值void,需要声明,也需要实现
     * 可以有参数,可以发生重载
     */
    void treat();
    void treat(QString foodName);
};

#endif // STUDENT_H
// teacher.h
#ifndef TEACHER_H
#define TEACHER_H

#include <QObject>

class Teacher : public QObject
{
    Q_OBJECT
public:
    explicit Teacher(QObject *parent = nullptr);

signals:
    /* 自定义信号类,没有返回值
     * 只需要声明,不需要实现
     * 可以有参数,可以重载
     */
    void hungry();
    void hungry(QString foodName);
public slots:
    /* 早期的QT版本必须要写到,public slots,高级版本可以写到public或全局下
     * 返回值void,需要声明,也需要实现
     * 可以有参数,可以发生重载
     */
};

#endif // TEACHER_H
// mywidget.cpp
# include "mywidget.h"
# include <QPushButton>
# include <QDebug>

mywidget::mywidget(QWidget *parent)
    : QWidget(parent)
{
    // 创建老师和学生对象
    this->t = new Teacher(this);
    this->s = new Student(this);
    // 无参
//    //ClassIsOver();  // 调用下课函数   没有链接,没有任何响应
//    connect(t,&Teacher::hungry, s, &Student::treat);    // 先链接后触发信号,才能响应
//    ClassIsOver();  // 调用下课函数
    // 链接代参数的函数,
    void (Teacher:: *f1)(QString) = &Teacher::hungry;
    void (Student:: *f2)(QString) = &Student::treat;
   // connect(t,f1, s, f2);    // 因为发生了函数重载,不能简单的用取地址符,编译器判断不了是哪个函数,用函数指针
    ClassIsOver();  // 调用下课函数

    // 点击一个按钮, 触发下课
    QPushButton *btn = new QPushButton("下课",this);
    this->resize(800,600);  // 重置窗口大小
    connect(btn,&QPushButton::clicked,this, &mywidget::ClassIsOver);
    // disconnect(btn,&QPushButton::clicked,this, &mywidget::ClassIsOver); // 断开链接
    /* 1、信号可以链接信号
     * 2、一个信号可以链接到多个槽函数
     * 3、多个信号可以链接到一个槽函数
     * 4、信号和槽函数的参数必须类型一一对应(槽函数要接收信号的参数)
     * 5、信号参数个数可以多于槽函数参数个数,但是类型也要一一对应
     */
    // QT5 6 向下兼容 QT4版本以前的信号和槽的链接方式
    connect(t,SIGNAL(hungry()), s, SLOT(treat(QString))); // 优点,直观,缺点,类型不做检测
}

mywidget::~mywidget()
{

}

void mywidget::ClassIsOver()
{
    // emit t->hungry();
    emit t->hungry("宫保鸡丁");
}
// student.cpp
#include "student.h"
# include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{

}
void Student::treat()
{
    qDebug() << "请老师吃饭";
}
void Student::treat(QString foodName)
{
    // qDebug() << "请老师吃 :" << foodName;    // 带引号,用toUtf8()先将它转成QbyteArray类型,然后用data()在转成char *类型
    qDebug() << "请老师吃 :" << foodName.toUtf8().data();
}

  main.cpp和teacher.cpp默认即可。信号和槽使用时必须先链接后触发信号,才能响应。

3.4 Lambda表达式

  Lambda表达式是C++11中用来定义并创建匿名的函数对象。实际上是一个匿名方法,用来声明一个只在此次使用的匿名函数
[函数对象参数](操作符重载函数参数)mutable->返回值(函数体)

  • 1、函数对象参数:[],标识一个lambda的开始,这部分不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构迨函数。函数对象参数只能使用那些到定义Lambda 为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下几种形式:
参数 作用
没有使用任何函数对象参数
= 函数体可以使用lambda所在作用范围内所有可见的局部变量
this 函数体可以使用lambda所在类中的成员变量
a 将a按值进行传递
&a 将a按引用进行传递
a, &b 将a按值传递,b按引用传递
=, &a, &b 除a b按引用传递外,其余值按值进行传递
&, a, b 除a b按值进行传递外,其余值按引用进行传递

  其中=传递了包括Lambda所在类的this,并且是引用传递方式,相当于编译器自动为我们引用传递了所有局部变量。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符。

  • 2、操作符重载函数参数:标识函数重载的()参数,没有参数时,可以省略。参数可以用过按值传递和按引用两种方式进行传递。
  • 3、可修改标识符:mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符,可以修改按值传递进来的拷贝(注意仅仅是能修改拷贝, 而不是修改值本身)
  • 4、函数返回值:->返回值类型, 标识函数返回值的类型,当返回值为void,或者函数体中只有溢出return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。
  • 5、函数体: {},标识函数的实现,这部分不能省略,但函数体可以为空。
[capture](parameters)mutable->return-type
    {
        statement;
    }

  在空项目的基础之上改变mywidget.cpp函数:

#include "mywidget.h"
#include <QPushButton>
mywidget::mywidget(QWidget *parent)
    : QWidget(parent)
{
    // 利用lambda表达式,点击按钮,关闭窗口
    QPushButton *btn = new QPushButton("关闭", this);
    btn->move(100,100);
    connect(btn,&QPushButton::clicked,this, [=](){this->close();});
}

mywidget::~mywidget()
{
}

3.5 菜单栏工具栏的创建

  在空项目的基础之上改变mywidget.cpp函数:

#include "mainwindow.h"
#include <QPushButton>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QDockWidget>
#include <QLabel>
#include <QTextEdit>

#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    resize(1400,900);   // 重置窗口大小

    /********** 菜单栏创建 **********/
    QMenuBar *bar = menuBar();
    setMenuBar(bar);    // 将菜单栏放置到窗口中
    QMenu *fileMenu = bar->addMenu("文件");     // 创建菜单
    QMenu *editMenu = bar->addMenu("编辑");     // 创建菜单
    QAction *newAction = fileMenu->addAction("新建");
    fileMenu->addSeparator();        // 添加分隔线
    QAction *openAction = fileMenu->addAction("打开");

    /********** 工具栏创建 **********/
    QToolBar *toolBar = new QToolBar(this); // 工具栏,可以有多个
    addToolBar(Qt::LeftToolBarArea, toolBar);
    toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);// 后期设置只允许左右停靠
    toolBar->setFloatable(false);// 设置浮动
    toolBar->setMovable(false);      // 允许移动(总开关)
    toolBar->addAction(newAction);
    toolBar->addSeparator();
    toolBar->addAction(openAction);
    QPushButton *btn = new QPushButton("aaa",this);
    toolBar->addWidget(btn);

    /********** 状态栏创建,最多一个 **********/
    QStatusBar *stBar = statusBar();
    setStatusBar(stBar);
    QLabel *label = new QLabel("提示信息",this);
    stBar->addWidget(label);
    QLabel *label2 = new QLabel("右侧提示信息",this);
    stBar->addPermanentWidget(label2);

    /********** 铆接部件(浮动窗口,可以有多个)**********/
    QDockWidget *dockWidget = new QDockWidget("浮动窗口",this);
    addDockWidget(Qt::BottomDockWidgetArea,dockWidget);
    dockWidget->setAllowedAreas(Qt::BottomDockWidgetArea | Qt::TopDockWidgetArea);   // 设置停靠区域,只允许上下

    /********** 设置中心部件,只能有一个 **********/
    QTextEdit *edit = new QTextEdit(this);
    setCentralWidget(edit);

    /*总结: 使用set加入窗口的部件智能有一个,而add加入的能有多个*/
}

MainWindow::~MainWindow()
{
}

3.6 资源文件添加和UI界面使用

  在新建空白项目的第三步点击generate form,生成项目后就会产生一个.ui文件。UI界面可以直接拖拽控件,输入文本,我们开发窗口应用就变得很方便。
qt界面开发,C++,qt

  在此界面的基础上,创建文件,编辑,工具,帮助等菜单,菜单的一级目录是无法键入中文的,只能输入英文,然后在创建好的对象中将文本改成中文,建立完成后的文件如下。点击项目添加文件,add new file -> Qt -> Qt resource file -> choose,然后更改文件名称,一般设置为res,然后会在Resources底下生成一个res.qrc的文件。

qt界面开发,C++,qt

  将图片复制到项目目录底下的Image文件(所有图片文件都放进去),以资源编辑器的方式打开res.qrc,添加前缀(可以直接使用默认或者“/”),添加文件,使用“ : + 前缀名 + 文件名称” 。mainwindow.cpp文件如下所示:

// mainwindow.cpp文件
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//    ui->actionnew->setIcon(QIcon("C:/Users/19080/Pictures/Camera Roll/文件图标.JPEG") );	// 绝对路径
    // 使用添加Qt资源文件
    ui->actionnew->setIcon(QIcon(":Image\\fileIcon.JPEG") );	
    ui->actionopen->setIcon(QIcon(":Image\\Luffy.jpg") );
}

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

3.7 对话框

3.7.1 模态和非模态

  mainwindow.cpp文件如下所示:


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // 点击新建按钮 弹出一个对话框
    connect(ui->actionnew,&QAction::triggered,[=](){
    /* 对话框 分类
     * 模态对话框(不可以对其他窗口进行操作) 非模态对话框则相反
     */
        /*  模态创建 阻塞   */
//     QDialog dig(this);
//     dig.resize(200,100);
//     dig.exec();
//     qDebug() <<"模态对话框弹出";
    /*  非模态创建   */
     QDialog *dig2 = new QDialog(this);
     dig2->resize(200,100);
     dig2->show();
     dig2->setAttribute(Qt::WA_DeleteOnClose);  // 55号属性
     qDebug() << "非模态对话框弹出";
    });

}

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

3.7.2 消息对话框

  目前Qt内置对话框有:

名称 作用
QColorDialog 选择颜色
QFileDialog 选择文件或者目录
QFontDialog 选择字体
QInputDialog 允许用户输入一个值,并将值返回
QMessageBox 模态对话框,用于显示信息、询问信息等等
QPageSetupDialog 为打印机提供纸张相关的选项
QPrintDialog 打印机配置
QPrintPreviewDialog 打印预览
QProgressDialog 显示操作过程

  mainwindow.cpp文件如下所示,其中QMessageBox::question的返回值是QMessageBox::StandardButton类型,我们就可以利用if语句去判断返回值是否为QMessageBox::Save,从而进一步做其他操作。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QMessageBox>
#include <QDebug>
#include <QColorDialog>
#include <QFileDialog>
#include <QFontDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->actionnew,&QAction::triggered,[=](){
    // 错误对话框
//    QMessageBox::critical(this, "critical", "错误");
    // 信息对话框
//    QMessageBox::information(this, "info", "信息");
    // 提问对话框 参数1:父类,参数2:title, 参数3:提示信息, 参数4:按键选项, 参数5: 默认选项(关联回车选项)
//    if(QMessageBox::Save == QMessageBox::question(this, "ques", "提问",QMessageBox::Save|QMessageBox::Cancel,QMessageBox::Save))
//    {
//        qDebug() << "选择的是保存";
//    }
//    else
//    {
//        qDebug() << "选择的是取消";
//    }
    // 警告对话框
    //QMessageBox::warning(this,"warning","警告");

    // 其他标准对话框
    // 颜色对话框
//    QColor color = QColorDialog::getColor(QColor(255, 0, 0));
//    qDebug() << "  r = " << color.red() << "  g = "<< color.green() << "  b = " << color.blue();
    // 文件对话框 参数1: 父类, 参数2: 对话框标题  参数3:默认打开路径,参数4:过滤器(仅能选取该类型文件) 返回值是选取文件路径
//    QString str= QFileDialog::getOpenFileName(this, "打开文件", "C:\\Users\\19080\\Desktop", "(*.txt)");
//    qDebug() << str;
    // 字体对话框
        bool flag;
    QFont font = QFontDialog::getFont(&flag, QFont("华文云彩",  36) );
    qDebug() <<" 字体: "<< font.family() <<" 大小:"<< font.pointSize()<< "是否加粗:"<< font.bold() << "是否倾斜:"<< font.italic();
    });

}

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

3.8 设计登录界面

  首先我们现在UI界面创建如下控件,用户名和密码用Label控件,输入框用Line Edit控件,登录和退出用PushButton控件。

qt界面开发,C++,qt

  然后在左侧工具栏Containers中选择Widget控件,将用户名、密码和输入框拖入Widget中选择,在上方工具栏中选择栅格布局(适用于多行多列的,如果是单行或单列可以选择水平布局或垂直布局),布局之后就变得更整齐。登录和退出就选择水平布局。为了在窗口缩放是保持各个空间的相对位置不变,可以加入Spacers控件(也可以不加),其效果于弹簧。

qt界面开发,C++,qt

  登录界面一般开发时就确定大小,我们找到MainWindow->sizePolicy->水平和垂直策略都选择Fixed,然后将minnumSize和maxiumSize都选择固定的尺寸(具体数值任意,大小合适即可)。操作完毕后窗口大小就固定下来。
  最后修改窗口名称,选中密码对应的编辑框,QLineEdit->echoMode->Password(输入密码的编程一个个黑圈圈),到目前为止我们将登录窗口的UI界面设计完毕,但是具体的功能还需要底层代码才能实现。
qt界面开发,C++,qt

3.9 各类控件

3.9.1 按钮组

  Qt的UI设计界面的按钮组有:PushButton,ToolButton, Radio Button, Check Box等等。
  ToolButton建立后,可以添加图片和修改文本,选择Icon->选择资源文件(前面部分有介绍),然后选择QToolButton->autoRaise,其效果是当光标移动到该按钮时,按钮自动高光亮起。
  依次创建4个Radio Button,分别命名为男 女, 已婚, 未婚。然后添加Group Box, 将男女添加今一个Group Box, 修改文本为性别。同理,已婚和未婚这两个Radio Button为另外一组。
  创建4个Check Box依次修改文本,放入Group Box中,设置垂直布局。然后在添加一个ListWidget,在预览图中显示为白色框。
qt界面开发,C++,qt

  在mainwindow.cpp中输入如下代码,形成代码和界面的联动:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // 设置单选按钮 默认男选中
    ui->radioButton->setChecked(true);

    // 选中女后打印信息
    connect(ui->radioButton_2, &QRadioButton::clicked,[=](){
        qDebug() << "选中了女性按钮";
    });

    // 多选按钮  2:选中  1:半选中  0:未选中
    // 信号为stateChanged, 槽函数为lambda表达式, 信号的参数会自动传给槽函数
    connect(ui->checkBox_4, &QCheckBox::stateChanged,[=](int state){
        qDebug() << state;
    });

    // 利用listWidget写诗
    QListWidgetItem *item = new QListWidgetItem("窗前明月光");
    // 将一行诗放到listWidget控件中
    ui->listWidget->addItem(item);
    item->setTextAlignment(Qt::AlignHCenter);   // 设置为水平居中
    // QStringList     QList<QString>
    QStringList list;
    list << "疑是地上霜"<< "举头望明月"<<"低头思故乡"; // 将这几句诗加入链表类中
    ui->listWidget->addItems(list);     //  这种方法无法设置对齐格式
}

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

3.9.2 QTreeWidget和QTableWidget控件

  QTreeWidget控件代码如下:

#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // treeWidget树控件使用

    // 设置水平头
    // 从下面两行代码可以看出,str相当于一个string类型的列表(例如,vector<string>) <<操作符相当于 append()函数的作用
//    QStringList str = QStringList()<<"英雄"<<"英雄介绍";
//    qDebug() << str;
    ui->treeWidget->setHeaderLabels (QStringList()<<"卡牌类型"<<"卡牌介绍");
    QTreeWidgetItem *monster = new QTreeWidgetItem(QStringList()<< " 怪兽");
    QTreeWidgetItem *magic = new QTreeWidgetItem(QStringList()<< " 魔法");
    QTreeWidgetItem *trap = new QTreeWidgetItem(QStringList()<< " 陷阱");

    // 加载顶层节点
    ui->treeWidget->addTopLevelItem(monster);
    ui->treeWidget->addTopLevelItem(magic);
    ui->treeWidget->addTopLevelItem(trap);

    // 加载子节点
    QStringList m1 = QStringList()<< "增殖的G"<< "效果怪兽,每次对方对怪兽的特殊召唤成功,自己从卡组抽1张";
    QTreeWidgetItem *monster1 = new QTreeWidgetItem(m1);
    monster->addChild(monster1);

    QStringList m2 = QStringList()<< "效果遮蒙者"<< "效果怪兽,以对方场上1只效果怪兽为对象,其效果直到回合结束时无效。";
    QTreeWidgetItem *monster2 = new QTreeWidgetItem(m2);
    monster->addChild(monster2);

    QStringList ma1 = QStringList()<< "强欲之壶"<< "通常魔法,从卡组抽两张牌";
    QTreeWidgetItem *magic1 = new QTreeWidgetItem(ma1);
    magic->addChild(magic1);

    QStringList ma2 = QStringList()<< "天使的施舍"<< "通常魔法,从卡组抽三张,然后丢弃两张手牌";
    QTreeWidgetItem *magic2 = new QTreeWidgetItem(ma2);
    magic->addChild(magic2);

    QStringList t1 = QStringList()<< "技能抽取"<< "永续陷阱,能够使场上表侧表示的怪兽卡效果无效";
    QTreeWidgetItem *trap1 = new QTreeWidgetItem(t1);
    trap->addChild(trap1);

    QStringList t2 = QStringList()<< "王宫的敕命"<< "永续陷阱,能够使场上的魔法卡效果无效";
    QTreeWidgetItem *trap2 = new QTreeWidgetItem(t2);
    trap->addChild(trap2);
}

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

  效果图:

qt界面开发,C++,qt

  QTableWidget控件

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // TableWidget控件
    // 设置列数,一定要设置,不然会出现未知错误
    ui->tableWidget->setColumnCount(3);

    // 设置水平表头
    ui->tableWidget->setHorizontalHeaderLabels(QStringList()<<"姓名"<<"性别"<<"年龄");

    // 设置行数
    ui->tableWidget->setRowCount(5);

    // 设置正文
    //ui->tableWidget->setItem(0,0,new QTableWidgetItem("张三"));
    QStringList nameList = QStringList()<<"李大"<<"柳二"<<"张三"<<"刘四"<<"王五";
    QStringList sexList = QStringList()<<"男"<<"男"<<"女"<<"女"<<"女";
    for(int i=0;i<5;i++)
    {
        int col = 0;
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(nameList[i]));
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(sexList.at(i)));
        ui->tableWidget->setItem(i,col++,new QTableWidgetItem(QString::number(i+18)));
    }
}

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

  效果图:

qt界面开发,C++,qt

3.9.3 其他控件

  主要包括了scroll area、 tool box、tab widget、stacked widget等控件。其中scroll area 是滚动条控件,toolbox是列表页面(例如QQ的联系人列表),tab widget是类似网页页面的控件。stacked widget是栈控件,可以将以上三个页面全部放到栈控件中,然后实现多个页面的切换。代码中还包括了combo box下拉框,QLabel的简单使用。其中,QLabel可以用作显示图片,播放动态图,视频等等。

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QMovie>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // stacked Widget栈控件的使用
    // 默认定位
    ui->stackedWidget->setCurrentIndex(0);

    // scroll area 按钮
    connect(ui->btn_scroll,&QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(0);
    });
    // toolBox 按钮
    connect(ui->btn_toolBox,&QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(1);
    });
    // tabWidge 按钮
    connect(ui->btn_tabWidget,&QPushButton::clicked, [=](){
        ui->stackedWidget->setCurrentIndex(2);
    });

    // combo box 下拉框
    ui->comboBox->addItem("奔驰");
    ui->comboBox->addItem("宝马");
    ui->comboBox->addItem("拖拉机");

    // 点击按钮选中拖拉机
    connect(ui->pushButton_16,&QPushButton::clicked, [=](){
        // ui->comboBox->setCurrentIndex(2);
        ui->comboBox->setCurrentText("拖拉机");    // 两句代码效果一样
    });
    // 利用QLabel显示图片
    ui->imaLabel->setPixmap(QPixmap(":/Image/fileIcon.JPEG").scaled(ui->imaLabel->size()));

    //利用QLabel显示gif动态图片
    QMovie *movie = new QMovie(":/Image/picaqu.gif");
    movie->setScaledSize(ui->movieLabel->size());
    ui->movieLabel->setMovie(movie);
    // 播放动图
    movie->start();
}

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

  效果图:
qt界面开发,C++,qt

3.9.4 自定义控件封装

  建立一个自定义的控件,将QSpinBox和QSlider联动起来:QSpinBox移动,QSlider跟着移动,QSlider跟着移动,QSpinBox也跟着移动。

  项目文件点击->新建->Qt->设计师界面->widget,然后修改文件名(SmallWidget)。在smallwidget.up界面中添加,QSpinBox和QSlider两个控件:
qt界面开发,C++,qt
  右键SmallWidget窗口->提升为->添加->提升,成功以后,widget类底下就会包含SmallWidget类。
  修改smallwidget.cpp文件:

// smallwidget.cpp文件
#include "smallwidget.h"
#include "ui_smallwidget.h"

SmallWidget::SmallWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SmallWidget)
{
    ui->setupUi(this);
    // QSpinBox移动,QSlider跟着移动
    void (QSpinBox:: *spSignal)(int) = &QSpinBox::valueChanged; // valueChanged有重载版本,因此需要确定输入参数是哪种版本的,这里需要的是int输入
    connect(ui->spinBox, spSignal, ui->horizontalSlider, &QSlider::setValue);
    // QSlider跟着移动 QSpinBox移动
    connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);
}

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

3.10 鼠标和定时器事件以及事件分发器、过滤器

  添加myLabel类->C+±>C++Class,父类选择为QWidget,因为新建项目窗口能够选择父类有限,这里我们就选择QWidget类,项目文件建好后,修改mylabel.h文件中include头文件和父类,mylabel.cpp中构造函数的父类,全部修改为QLabel。

  进入UI界面,拖拽一个Label控件,修改为合适大小,文字删除,此时控件消失,为了方便观察,我们设置控件的边框为Box类型,属性页面QFrame->frameShape->Box,如下图所示。

qt界面开发,C++,qt

  UI界面的设置创建两个label控件,用来显示定时器数字。定时器主要使用到timerEvent(QTimerEvent *ev)函数,多个定时器之间用timeId来区分。

qt界面开发,C++,qt

  多个事件之间通过bool event(QEvent *ev)来进行事件分发,返回值是bool类型,如果返回值是true代表用户要处理这个事件,不向下分发事件。

qt界面开发,C++,qt

// mylabel.h文件
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
class myLabel : public QLabel
{
public:
    explicit myLabel(QWidget *parent = nullptr);
    // 声明
    // 鼠标进入事件
    void enterEvent(QEvent *event);
    // 鼠标离开事件
    void leaveEvent(QEvent *);
    // 鼠标按下事件
    void mousePressEvent(QMouseEvent *event);
    // 鼠标释放事件
    void mouseReleaseEvent(QMouseEvent *event);
    // 鼠标移动事件
    void mouseMoveEvent(QMouseEvent *event);
    // 通过event事件分发器拦截 鼠标按下事件
    bool event(QEvent *e);
signals:

};
#endif // MYLABEL_H
// widget.h文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    // 定时器事件
    void timerEvent(QTimerEvent *);
    int id1;    // 定时器1的唯一标识
    int id2;    // 定时器2的唯一标识
    // 重写事件过滤器的时间
    bool eventFilter(QObject *obj, QEvent *e);
private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
// mylabe.cpp文件
#include "mylabel.h"
#include <QDebug>
#include <QMouseEvent>
myLabel::myLabel(QWidget *parent) : QLabel(parent)
{
    // 设置鼠标追踪
    setMouseTracking (true);      // 原来是点击后鼠标移动才能触发,现在只要鼠标移动就能触发鼠标移动事件。
}
// 鼠标进入事件
void myLabel::enterEvent(QEvent *event)
{
    qDebug() << "鼠标进入";
}
// 鼠标离开事件
void myLabel::leaveEvent(QEvent *)
{
    qDebug()<< "鼠标离开";
}
// 鼠标按下事件
void myLabel::mousePressEvent(QMouseEvent *event)
{
    // 要求:当鼠标左键按下时,打印信息,右键按下不打印
    if(event->button() == Qt::LeftButton)
    {
        QString str = QString("鼠标按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(event->x()).arg (event->y()).arg (event->globalX()).arg (event->globalY());
        qDebug()<< str;
    }
}
// 鼠标释放事件
void myLabel::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        qDebug()<< "鼠标释放";
    }
}
// 鼠标移动事件
void myLabel::mouseMoveEvent(QMouseEvent *event)
{
    qDebug()<< "鼠标移动";
//    if(event->buttons() & Qt::LeftButton) // &位与操作,buttons用于同时按下多个按钮,只要按下的按钮中包含左键,执行下面的操作。
//    {
//        qDebug()<< "鼠标移动";
//    }
}
// 通过event事件分发器拦截 鼠标按下事件
bool myLabel::event(QEvent *e)
{
    // 如果是鼠标按下,在event中做拦截操作,也就是说在这一层做处理,后面的 鼠标按下 相关代码就不会触发
    if(e->type() == QEvent::MouseButtonPress)
    {
        QMouseEvent *ev = static_cast<QMouseEvent *>(e);        // static_cast是C++的强制类型转换,大精度类型转小精度类型,有损
        QString str = QString("Event函数中,鼠标按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(ev->x()).arg (ev->y()).arg (ev->globalX()).arg (ev->globalY());
        qDebug() << str;
        return true;    // true代表用户自己处理这个事件,不向下分发
    }
    // 其他事件交给父类处理, 其余事件都正常传给后面的代码处理
    return QLabel::event(e);
}
// widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QTimer>
#include <QMouseEvent>
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    id1 = startTimer(1000);   // 启动计时器,参数1:间隔,单位毫秒
    id2 = startTimer(2000);

    // 定时器的第二种方式
    QTimer *timer = new QTimer(this);
    // 启动定时器
    timer->start(500);
    connect(timer, &QTimer::timeout, [=](){
        static int num3 = 1;
            // label4 每隔0.5秒+1
            ui->label_4->setText(QString::number(num3++));
    });

    // 点击按钮暂停定时器,第三个暂停
    connect(ui->btn1, &QPushButton::clicked, [=](){
        timer->stop();
    });

    // 给label 安装事件过滤器, 实际上是一个比event拦截器更高级的拦截器
    // 第一步
    ui->label->installEventFilter(this);
}
// 第二步 重写 eventfiler事件
bool Widget::eventFilter(QObject *obj, QEvent *e)
{
    if(obj == ui->label)
    {
        if(e->type() == QEvent::MouseButtonPress)
        {
            QMouseEvent *ev = static_cast<QMouseEvent * >(e);
            QString str = QString("事件过滤器中,鼠标按下了 x = %1, y = %2, globalx = %3, globaly = %4").arg(ev->x()).arg (ev->y()).arg (ev->globalX()).arg (ev->globalY());
            qDebug() << str;
            return true;    // true代表用户自己处理这个事件,不向下分发
         }
    }
    // 其他事件交给父类处理, 其余事件都正常传给后面的代码处理
    return QWidget::eventFilter(obj, e);
}

// 定时器事件
void Widget::timerEvent(QTimerEvent *ev)
{
    if(ev->timerId() == id1)
    {
        static int num1 = 1;
        ui->label_2->setText(QString::number(num1++));
    }
    if(ev->timerId() == id2)
    {
        static int num2 = 1;
        ui->label_3->setText(QString::number(num2++));
    }
}
Widget::~Widget()
{
    delete ui;
}

3.11 绘画

3.11.1 绘画设置

  这里主要介绍的是画类操作,画直线,画圆,画矩形等等,画笔,毛刷等等设置,widget.cpp文件如下,此外,还需要在widget.h文件声明函数void paintEvent(QPaintEvent *event)。

// widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    // 点击移动按钮,移动图片 ,paintEvent函数默认会调用一次,然后就是调用repaint函数,即重新绘画函数
    connect (ui->pushButton, &QPushButton::clicked, [=](){
        // 手动调用绘图事件函数,实际上是调用repaint函数
        PosX += 20;		// 需要在widget.h中声明, int PosX = 150;
        update();
    });

}
// 绘图事件
void Widget::paintEvent(QPaintEvent *event)
{
//    // 实例化画家对象, this制定绘图设备
//    QPainter painter(this);
//    //  设置画笔
//    QPen pen(QColor(255,0,0));      // 设置颜色
//    pen.setWidth (5);               // 设置宽度
//    pen.setStyle (Qt::DotLine);     // 设置风格
//    painter.setPen (pen);
//    // 设置画刷
//    QBrush brush(QColor(0,255,0));
//    brush.setStyle (Qt::Dense1Pattern);
//    painter.setBrush (brush);
//    // 画了一条线(两个点确定)
//    painter.drawLine(QPoint(0,0),QPoint(100,100));
//    // 画椭圆圆,圆心和长短轴焦点a,b确定 a=b就是圆
//    painter.drawEllipse (QPoint(100,100),50,50);
//    // 画矩形
//    painter.drawRect (QRect(20,20,50,50));
//    // 画文字
//    painter.drawText (QRect(10,200,150,50),"好好学习,天天向上");
    ****高级设置*******/
//    QPainter painter(this);
//    painter.drawEllipse (QPoint(200,200),100,100);
//    //  设置 抗锯齿能力,即画的仔细一点,毛边少一点,但是效率低一点
//    painter.setRenderHint (QPainter::Antialiasing);
//    painter.drawEllipse (QPoint(400,200),100,100);
//    // 画矩形
//    painter.drawRect (QRect(20,20,50,50));
//    painter.translate (100,0);  // 画家从0,0开始作画,变成从100,0开始作画
//    // 保存画家状态
//    painter.save();
//    painter.drawRect (QRect(20,20,50,50));
//    // 还原画家保存状态
//    painter.restore ();
//    painter.drawRect (QRect(20,20,50,50));

    / ******* 利用画家调用图片资源  **** //
    QPainter painter(this);

    // 如果超过屏幕宽度 ,从0开始
    if(PosX > this->width())
    {
        PosX = 0;
    }
    painter.drawPixmap(PosX,20,QPixmap(":/Image/Luffy.jpg"));
}

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

qt界面开发,C++,qt

3.11.2 绘图设备

  主要有QPixmap,QPicture,QImage三种,需要在widget.h文件声明函数void paintEvent(QPaintEvent *event)

#include "widget.h"
#include "ui_widget.h"
#include <QPixmap>
#include <QPainter>
#include <QPicture>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
//   //
//    // Pixmap绘图设备,专门为平台做了显示的优化
//    QPixmap pix(300,300); // 说明画纸大小

//    // 填充背景色
//    pix.fill(Qt::white);
//    // 声明画家
//    QPainter painter(&pix);
//    painter.setPen(QPen(Qt::green));
//    painter.drawEllipse(QPoint(150,150),100,100);

//    // 保存
//    pix.save("D:\\software\\QT\\QT_Project\\qtDemo10\\pix.png");

 // ///
//    // QImage 绘图设备 可以对每个像素进行访问
//    QImage img(300,300, QImage::Format_RGB32);
//    img.fill(Qt::white);

//    QPainter painter(&img);
//    painter.setPen(QPen(Qt::blue));
//    painter.drawEllipse(QPoint(150,150),100,100);

//    // 保存
//    img.save("D:\\software\\QT\\QT_Project\\qtDemo10\\img.png");

 
    // QPicture 绘图设备,可以记录和重现绘图指令
    QPainter painter;
    QPicture pic;
    painter.begin(&pic);    // 开始往pic上画画
    painter.setPen(QPen(Qt::blue));
    painter.drawEllipse (QPoint(150,150),100,100);
    painter.end();  // 结束画画

    // 保存到磁盘
    pic.save("D:\\software\\QT\\QT_Project\\qtDemo10\\pic.hyf");
    // hyf是博主的姓名缩写,在文件资源管理器中是无法打开这个图片的
    // 我们在绘图事件中使用load函数可以打开,准确来说是重新绘制,因此pic保存的不是图片本身而是绘制图片的指令
}
// 绘图事件
void Widget::paintEvent(QPaintEvent *event)
{
//    // 利用QImage 对像素进行修改
//    QPainter painter(this);
//    QImage img;
//    img.load(":/Image/fileIcon.JPEG");

//    // 修改像素点
//    for(int i=50; i<100; i++)
//    {
//        for (int j=50;j<100;j++)
//        {
//            QRgb value = qRgb(255,0,0);
//            img.setPixel(i,j,value);
//        }
//    }
//    painter.drawImage(0,0,img);

    // 重现QPicture绘图指令
    QPainter painter(this);
    QPicture pic;
    pic.load("D:\\software\\QT\\QT_Project\\qtDemo10\\pic.hyf");
    painter.drawPicture(0,0,pic);
}
Widget::~Widget()
{
    delete ui;
}

3.12 文件读取

  文件读取是主要注意打开文件,也要关闭文件,此外,QFile默认是UTF-8格式类型。widget.cpp文件如下所示:

#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QFile>
#include <QTextCodec>
#include <QFileInfo>
#include <QDebug>
#include  <QDateTime>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    connect (ui->pushButton, &QPushButton::clicked, [=](){
        QString path = QFileDialog::getOpenFileName (this,"打开文件","C:/Users/19080/Desktop");
        // 将路径放到lineEdit中
        ui->lineEdit->setText(path);

        // 编码格式类
        QTextCodec *codec = QTextCodec::codecForName("gbk");

        // 读取内容,放入到textEdit中
        // QFile默认支持的格式是UTF-8
        QFile file(path);   // 参数就是file path
        file.open(QIODevice::ReadOnly); // 设置打开方式
        //QByteArray array = file.readAll();

        QByteArray array;
        while( !file.atEnd() )
        {
            array += file.readLine();
        }

        // 将读取的数据放入到text Edit中
        ui->textEdit->setText(array);
        //ui->textEdit->setText(codec->toUnicode(array));
        file.close();   // 对文件对象进行关闭

         文件写入操作
        file.open(QIODevice::Append);   // 追加的方式写入
        file.write("123456789");
        file.close();

           QFileInfo        ///
        // QFileInfo 文件信息类
        QFileInfo info(path);
        qDebug() << "大小(字节):" << info.size()<< "后缀名:"<< info.suffix()<< "文件名称:"<< info.fileName() <<"文件路径:"<< info.filePath();
        qDebug() << "文件创建日期: "<< info.created().toString ("yyyy/MM/dd hh:mm:ss");  // 按格式输出 yyyy/MM/dd hh:mm:ss
        qDebug() << "文件创建日期: "<< info.lastModified().toString ("yyyy/MM/dd hh:mm:ss");
    });
}
Widget::~Widget()
{
    delete ui;
}

四、翻金币小游戏

4.1 出现的问题

  如果没有素材可以从网上找,图片资源都可以根据实际变化,不是唯一的。资源网站这里推荐阿里的图标库。
  博主在写这个代码的过程中出现了一些错误,第一个错误博主没有解决,将第二个错误解决后,第一个就没有出现了。第二个和第三个错误在头文件前面加上Q_OBJECT成员变量,加在public前面,问题解决参考自博客No Q_OBJECT in the class with the signal错误解决办法,然后在.pro文件末尾加上空格重新编译。

error: 'QtPrivate::QFunctorSlotObject<Func, N, Args, R>::QFunctorSlotObject(Func) [with Func = MainScene::MainScene(QWidget*)::<lambda()>; int N = 0; Args = QtPrivate::List<>; R = void]', declared using local type 'MainScene::MainScene(QWidget*)::<lambda()>', is used but never defined [-fpermissive]
         explicit QFunctorSlotObject(Func f) : QSlotObjectBase(&impl), function(std::move(f)) {}
                  ^~~~~~~~~~~~~~~~~~
 error: static assertion failed: No Q_OBJECT in the class with the signal
 #  define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
                                                ^
error: undefined reference to `vtable for

4.2 源码下载

  这里直接给大家分享一下成品,用百度网盘给出,步骤博主就不在一一介绍。
链接:https://pan.baidu.com/s/1QGdOGuyTYMGfSgi81O71vw?pwd=zajg
提取码:zajg

4.3 NSIS打包程序

  当我们写好程序后将编译运行按钮中的debug输出改为release输出,然后得到一个发布版本的.exe程序,如图所示:

qt界面开发,C++,qt

  我们将他单独拎出来放到桌面的release文件夹(自己命名的空文件夹都可以)中,然后找到对应编译器的命令行窗口,如下图所示,博主这里有两个编译器,博主的是MinGW 64-bit的。然后输入windeployqt.exe CoinFlip.exe,按回车键,程序打包成功,之前的release文件就多了一些生成的打包文件。

windeployqt.exe CoinFlip.exe

qt界面开发,C++,qt
qt界面开发,C++,qt

  windeployqt.exe文件实际上是Qt编译器提供的打包成window程序的可执行文件,可以在对应编译器的bin文件中找到。

qt界面开发,C++,qt

  这里需要注意不能使用普通的命令行窗口执行这个命令,会出现无法找到入口的问题。

qt界面开发,C++,qt

  然后我们使用HM NIS Edit软件进行Setup.exe文件的打包,需要配合NSIS软件一起使用。
  NSIS是"Nullsoft 脚本安装系统"(Nullsoft scriptable Installation System)的缩写,它是是一个免费的win32安装、卸载系统,可以很方便的打包windows应用程序。它的特点:脚本简洁高效;系统开销少;支持安装、卸载、系统设置、解压文件等功能。这里博主直接给出NSIS下载地址和HM NIS Edit下载地址,嫌麻烦的也可以用博主的百度网盘地址下载,链接:https://pan.baidu.com/s/1FrLENkVtB-B2lGslqw33bw?pwd=wybc
提取码:wybc。
  参考博客 手把手教NIS Edit安装向导的使用。当顺着教程做到这一步的时候,点击树形图,选择release文件,将release文件中的所有文件添加进来。其他部分按照教程或者默认即可。最终会在项目目录中生成Setup.exe文件。将Setup.exe安装之后,就会在桌面生成快捷方式,点击即可进行游戏。
qt界面开发,C++,qt文章来源地址https://www.toymoban.com/news/detail-783782.html

到了这里,关于【Qt设计开发】GUI界面设计开发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 软件设计开发笔记4:QT操作SQLite数据库

      有时候我们需要在软件中记录一些历史数据以便于对数据的查询。而我们希望软件不能太复杂,体量也不要太大,这个时候就需要如SQLite这样轻量级的数据库。这篇中我们就来讨论如何在使用QT开发应用是操作SQLite数据库。   SQLite是一款开源、轻量级、跨平台的数据库

    2024年02月09日
    浏览(49)
  • Qt音视频开发38-ffmpeg视频暂停录制的设计

    基本上各种播放器提供的录制视频接口,都是只有开始录制和结束录制两个,当然一般用的最多的也是这两个接口,但是实际使用过程中,还有一种可能需要中途暂停录制,暂停以后再次继续录制,将中间部分视频不需要录制,跳过这部分不需要的视频,而且录制的视频文件

    2023年04月20日
    浏览(47)
  • Qt开发_调用OpenCV(3.4.7)设计完成人脸检测系统

    近年来,人脸识别技术得到了广泛的应用,它可以在各种场景中实现自动化的人脸检测和识别,例如安防监控、人脸解锁、人脸支付等。 该项目的目标是设计一个简单易用但功能强大的人脸检测系统,可以实时从摄像头采集视频,并对视频中的人脸进行准确的检测和框选。通

    2024年02月09日
    浏览(28)
  • Qt音视频开发36-超时检测和自动重连的设计

    如果网络环境正常设备正常,视频监控系统一般都是按照正常运行下去,不会出现什么问题,但是实际情况会很不同,奇奇怪怪七七八八的问题都会出现,就比如网络出了问题都有很多情况(交换机故障、网线故障、带宽故障等),所以监控系统在运行过程中,还得做超时检

    2023年04月13日
    浏览(29)
  • Qt音视频开发45-音视频类结构体参数的设计

    视频监控内核组件重构和完善花了一年多时间,整个组件个人认为设计的最好的部分就是各种结构体参数的设计,而且分门别类,有枚举值,也有窗体相关的结构体参数,解码相关的结构体参数,同时将部分常用的结构体参数的获取和设置单独提供了函数,参阅海康大华等大

    2024年02月05日
    浏览(56)
  • QT软件开发-基于FFMPEG设计视频播放器-软解图像(一)

    QT软件开发-基于FFMPEG设计视频播放器-CPU软解视频(一) https://xiaolong.blog.csdn.net/article/details/126832537 QT软件开发-基于FFMPEG设计视频播放器-GPU硬解视频(二) https://xiaolong.blog.csdn.net/article/details/126833434 QT软件开发-基于FFMPEG设计视频播放器-解码音频(三) https://xiaolong.blog.csdn.

    2023年04月08日
    浏览(32)
  • 毕业设计项目——基于QT4+Opencv开发的道路偏移检测与预警系统

    完整项目地址:https://download.csdn.net/download/lijunhcn/88453342 基于QT4+Opencv的道路道路偏移检测与预警系统 开发环境:Ubuntu14.04+QT4.8.5+Opencv2.4.8 已经实现的功能: 道路偏移检测 道路偏移预警 串口读取外部传感器数据 部分源码展示:

    2024年02月03日
    浏览(33)
  • QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(四)

    QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(一) https://xiaolong.blog.csdn.net/article/details/126954626 QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(二) https://xiaolong.blog.csdn.net/article/details/126958188 QT软件开发-基于FFMPEG设计录屏与rt

    2023年04月19日
    浏览(45)
  • 06-1_Qt 5.9 C++开发指南_对话框与多窗体设计_标准对话框

    在一个完整的应用程序设计中,不可避免地会涉及多个窗体、对话框的设计和调用,如何设计和调用这些对话框和窗体是搞清楚一个庞大的应用程序设计的基础。本章将介绍对话框和多窗体设计、调用方式、数据传递等问题,主要包括以下几点。 Qt 提供的标准对话框的使用,

    2024年02月13日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包