ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

QT 学习笔记 对象树 信号槽 QMainWindow 资源使用 对话框 等

2022-04-08 00:33:55  阅读:223  来源: 互联网

标签:QMainWindow 窗口 函数 对话框 对象 QWidget 信号 QT Qt


目录

QT简介

Qt 是一套应用程序开发库,但与MFC不同,Qt是跨平台的开发库

  • 跨平台一位着只需要编写一次程序,在不同平台上无需改动或许少许改动后编译,就可以形成在不同平台上运行的版本
Qt是一个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供建立图形界面所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。

1 QT的获取与安装

下载地址: 点击下载

image-20220405235449914

image-20220405235825659

我们这里安装版本为 5.9.1

image-20220406000951558

2 新建一个项目

image-20220406003648457

QT Widgets Application : 桌面平台的图形用户界面(GUI) 应用程序

QT Console Application : 控制台应用程序,一般用于学习c/c++

QT Quick Application : 创建可部署的QT Quick2应用程序. Qt Quick是Qt支持的一套GUI开发架构,采用QML设计页面,程序框架采用C++

QT Quick Controls 2 Application 基于QT Quick Control2组件的可以部署Qt Quick2 应用程序

image-20220406004616896

image-20220406010648092

编译:

image-20220406011906905

//QMainWindow 带有工具栏,菜单栏,状态栏的视图窗口,类似主程序一般的窗口
//QDialog     对话框类,没有最大化
//QWeiget     是所有具有可视化页面类的基类,各种页面组件都支持
//QMainWindow QDialog 都继承自 QWeiget

2 一个最简单的Qt应用程序

main.cpp

Qt系统提供的类头文件没有.h后缀

Qt一个类对应一个头文件,类名和头文件名一致

#include "hellowidget.h"    // 导入hellowidget的文件头
#include <QApplication>     // 导入QApplication
#include <iostream>

int main(int argc, char *argv[])
{
    // 创建一个应用程序对象
    // 维护qt应用程序生命的一个对象,每个qt有且只有一个!
    QApplication a(argc, argv);

    // 窗口类的一个对象
    HelloWidget w;

    // 把窗口显示出来
    w.show();


    std::cout<<"before exec()" << std::endl;
    a.exec();
    /*
     * 死循环 让程序一直运行,生命循环,消息循环
     *
     * while(1)
     * {
     *     if(点击关闭按钮)break;
     *     if(点击最小化按钮)执行最小化动作;
     * }
     *
     */

    std::cout<<"after exec()" << std::endl;

    return 0;
}

QApplication应用程序类

管理图形用户界面应用程序的控制流和主要设置。

是Qt生命,一个程序要确保一直运行,就肯定至少得有一个循环,这就是Qt主消息循环,在其中完成来自窗口系统和其它资源的所有事件消息处理和调度。它也处理应用程序的初始化和结束,并且提供对话管理

对于任何一个使用Qt的图形用户界面应用程序,都正好存在一个QApplication 对象,不论这个应用程序在同一时刻有多少个窗口。

a.exec()

程序进入消息循环,等待对用户输入进行响应。这里main()把控制权转交给Qt,Qt完成事件处理工作,当应用程序退出的时候exec()的值就会返回。在exec()中,Qt接受并处理用户和系统的事件并且把它们传递给适当的窗口部件。

hellowidget.h

#ifndef HELLOWIDGET_H
#define HELLOWIDGET_H

#include <QWidget>    // 导入QWidget


class HelloWidget : public QWidget
{
    // 引入qt信号和槽的一个宏
    Q_OBJECT

public:
    // 构造函数,有默认参数
    // parent 窗口指针,父窗口对象的指针
    // 如果parent为0或者为None 表示当前窗口对象是个顶层窗口
    // 顶层窗口:在任务栏可以找到的窗口
    HelloWidget(QWidget *parent = 0);
    ~HelloWidget();
};

#endif // HELLOWIDGET_H

hellowidget.cpp

#include "hellowidget.h"

HelloWidget::HelloWidget(QWidget *parent): QWidget(parent) // 参数列表
{
    
}

HelloWidget::~HelloWidget()
{

}
总结:第一个qt的项目结构
    创建项目的时候 QWidget QMainWindow QDialog
    QWidget是所有能看到的窗口或者控件的父类,QMainWindow QDialog都继承他

    main.cpp文件:
        1 导入了一个 #include <QApplication> : 程序的生命对象,生命循环,消息循环,有且只有一个
        2 QApplication a; 实例化了生命对象
        3 导入了hellowidget对象 实例化hellowidget e;
        4 e.show(); 把窗口显示出来
        5 a.exec(); 生命循环,消息循环开始

    hellowidget.h文件:
        1 生成 HelloWidget对象继承QWidget
        2 Q_OBJECT宏对象,引入信号和槽
        3 构造函数和析构函数 构造函数(QWidget *parent = 0) 默认参数 parent父对象的指针,0或none表示顶级窗口

    HelloWidget.cpp文件:
        1 构造函数 列表参数:  HelloWidget::HelloWidget(QWidget * parent):QWidget(parent){};

3 .pro文件介绍

pro就是工程文件(project),它是qmake自动生成的用于生产makefile的配置文件。类似于VS中的.sln 和vsproj文件

#-------------------------------------------------
#
# Project created by QtCreator 2022-04-06T14:53:43
#
#-------------------------------------------------

# QT是工程模块变量,引入了qt的core 和 gui模块
QT       += core gui

# 如果qt版本号大于4就引入widgets模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

# 指定目标,生成一个可执行程序的名字
TARGET = helloword
# 生成什么文件 app表示应用程序exe ....
TEMPLATE = app


#下面的定义使你的编译器发出警告,如果你使用
# Qt中任何被标记为已弃用的特性(确切的警告
#取决于你的编译器)。 请参阅
# deprecated API,以便知道如何移植你的代码。
# 如果你使用了过时的api 他会waring
DEFINES += QT_DEPRECATED_WARNINGS

#如果你使用弃用的api,你的代码也会编译失败。
#为了做到这一点,取消下面一行的注释。
#你也可以选择禁用某些版本的Qt的deprecated api。
# define += QT_DISABLE_DEPRECATED_BEFORE=0x060000 #禁用所有在Qt 6.0.0之前弃用的api


# \是换行
# 控制SOURCES下有什么文件
# 要编译的源文件列表
SOURCES += \
        main.cpp \
        hellowidget.cpp
# 要编译的头文件列表
HEADERS += \
        hellowidget.h

.pro文件的规则

注释 从“#”开始,到这一行结束。

模块引入:

QT += 模块名,表示当前项目引入Qt哪些模块。

引入模块的意思就简单理解为引入C/C++头文件搜索路径,如果没引入对应模块就使用该头文件的话会报错说找不到该头文件。当然不必要的模块还是别引入,因为引入模块不仅仅是引入头文件搜索路径那么简单,还包括引入连接的库等一系列操作,会让程序变臃肿。

Qt详细模块有哪些可以参照附录。

image-20220406160104985

模板变量:告诉qmake为这个应用程序生成哪种makefile。下面是可供使用的选择:TEMPLATE = app

  • app -建立一个应用程序的makefile。这是默认值,所以如果模板没有被指定,这个将被使用。

  • lib - 建立一个库的makefile。

  • vcapp - 建立一个应用程序的VisualStudio项目文件。

  • vclib - 建立一个库的VisualStudio项目文件。

  • subdirs -这是一个特殊的模板,它可以创建一个能够进入特定目录并且为一个项目文件生成makefile并且为它调用make的makefile。

指定生成的应用程序名: TARGET = QtDemo

工程中包含的头文件: HEADERS += include/painter.h

工程中包含的.ui设计文件: FORMS += forms/painter.ui

工程中包含的源文件: SOURCES += sources/main.cpp sources

工程中包含的资源文件: RESOURCES += qrc/painter.qrc

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets : 这条语句的含义是,如果QT_MAJOR_VERSION大于4(也就是当前使用的Qt5及更高版本)需要增加widgets模块。如果项目仅需支持Qt5,也可以直接添加QT += widgets一句。不过为了保持代码兼容,最好还是按照QtCreator生成的语句编写

配置信息:CONFIG用来告诉qmake关于应用程序的配置信息。

CONFIG += c++11 //使用c++11的特性(qt5.6以上版本默认使用C++11)

在这里使用“+=”,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“=”那样替换已经指定的所有选项更安全。

4 QT命名规范

类名:单词首字母大写,单词和单词之间直接连接,无需连接字符 。

class MainWindow{}

Qt中内置的类型,头文件和类命名同名。

#include <QString>
QSring str;
		
#include <QWidget>
QWidget w;

函数名字,变量名:首字母小写,之后每个单词首字母大写,单词和单词之间直接连接,无需连接字符

void connectTheSignal();

类的成员变量设置函数用使用 set+成员变量名,获取成员变量的函数直接用成员变量名(如果是bool类型,有可能会用一些表示状态的术语,如isVisilble,hasFocus)

//普通成员变量设置和获取
void setText(QString text);
QString text()const;
//bool的成员变量设置和获取
void setEnabled(bool enabled);
bool isEnabled()const;

5 QtCreator常用快捷键

运行  ctrl +R
编译  ctrl +B
帮助文档  F1 ,点击F1两次跳到帮助界面
跳到符号定义 F2 或者ctrl + 鼠标点击
注释 ctrl+/
字体缩放  ctrl + 鼠标滚轮
整行移动代码 ctrl + shift + ↑或↓
自动对齐   ctrl + i
同名之间的.h和.cpp文件跳转 F4

6 添加一个按钮

// 添加一个按钮到窗口
QPushButton * button = new QPushButton;
// 设置父窗口 默认情况没有建立父子关系都是顶层窗口
button->setParent(this);
// 设置文本
button->setText("click");
// 设置大小  坐标系是以窗口的左上角为0,0 右方向为x 向下为y
button->resize(100,50);
// 设置窗口大小
this->resize(600,800);
// 设置按钮位置
button->move(100,100);

// 方法2 构造函数传参
QPushButton * button2 = new QPushButton("download",this);
button2->resize(200,300);
button2->move(300,300);
// 设置窗口标题
this->setWindowTitle("你好");
// 限制窗口大小
this->setFixedSize(600,400);

​ 上面代码中,一个按钮其实就是一个QPushButton类的对象,如果只是创建出对象,是无法显示到窗口中的,所以我们需要依赖一个父窗口,也就是指定一个父亲,利用setParent函数或者按钮创建的时候通过构造函数传参,此时我们称两个窗口建立了父子关系。在有父窗口的情况下,窗口调用show会显示在父窗口中,如果没有父窗口,那么窗口调用show显示的会是一个顶层的窗口(顶层窗口是能够在任务栏中找到的,不依赖于任何一个窗口而独立存在)(按钮也是继承于QWidget,也属于窗口)。

如果想设置按钮上显示的文字可以用setText,移动按钮位置用move

对于窗口而言,我们可以修改左上角窗口的标题setWindowTitle,重新指定窗口大小:resize,或者设置固定的窗口大小setFixedSize

button.setGeometry(400,400,500,500);  // 同时设置窗口对的位置和大小

QT常用API函数:

  • move 移动窗口到父窗口某个位置,或父窗口位置
  • resize 重新设置窗口大小
  • setFixedSize 设置窗口的固定大小
  • setWindowTitle 设置窗口标题
  • setGeometry 同时设置位置和大小,相当于move和resize的结合体

对于嵌套窗口,其坐标是相对于父窗口来说的。顶层窗口的父窗口就是屏幕。

7 对象树

image-20220406180608271

#include "widget.h"
#include <QPushButton>
#include "mypushbutton.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    // 局部变量 构造函数执行完毕后就会释放
    QPushButton btn;
    btn.setText("hello");
    // 解决方法 在堆区开辟内存 new

    // QPushButton * button = new QPushButton("hello",this);
    // 没有delete

    // 验证析构
    // 再继承一个按钮类,在子类的析构函数里面cout
    MyPushButton * button = new MyPushButton(this);
    button->setText("按钮1");
    // 软件关闭就释放了 可肆无忌惮的用了

}

Widget::~Widget()
{

}

概念:各个窗口对象通过建立父子关系构造对的一个关系树

内存管理: 父对象释放的时候会自动释放每一个子对象(使用children列表)

以后基本都是使用new的方式来创建窗口对象

注意点:

  • 父对象能够被释放
  • 父对象,子对象,直接或间接继承自QObject

对象树模型

QObject是Qt里边绝大部分类的根类

  • QObject对象之间是以对象树的形式组织起来的。
    • 当两个QObject(或子类)的对象建立了父子关系的时候。子对象就会加入到父对象的一个成员变量叫children****(孩子)list****(列表)中。
    • 父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里是说父对象和子对象,不要理解成父类和子类)
  • QWidget是能够在屏幕上显示的一切组件的父类
    • QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。我们向某个窗口中添加了一个按钮或者其他控件(建立父子关系),当用户关闭这个窗口的时候,该窗口就会被析构,之前添加到他上边的按钮和其他控件也会被一同析构。这个结果也是我们开发人员所期望的。
    • 当然,我们也可以手动删除子对象。当子对象析构的时候会发出一个信号destroyed,父对象收到这个信号之后就会从children列表中将它剔除。比如,当我们删除了一个按钮时,其所在的主窗口会自动将该按钮从其子对象列表(children)中删除,并且自动调整屏幕显示,按钮在屏幕上消失。当这个窗口析构的时候,children列表里边已经没有这个按钮子对象,所以我们手动删除也不会引起程序错误。Qt 引入对象树的概念,在一定程度上解决了内存问题。
  • 对象树中对象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
  • 任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。

8 信号和槽

信号: 各种事件

槽: 响应信号的动作

信号:当某个事件发生后,如某个按钮被点击了一下,它就会发出一个被点击的信号(signal)

槽: 某个对象接收到这个信号之后,就会做一些相关的处理动作(称为槽slot)

但是Qt对象不会无故收到某个信号,要想让一个对象收到另一个对象发出的信号,这时候需要建立连接(connect)

8.1 系统自带的信号和槽

比如我们点击按钮,就把当前的窗口给关闭掉,那么在Qt中,这样的功能如何实现

QPushButton * quitBtn = new QPushButton("关闭窗口",this);
connect(quitBtn,&QPushButton::clicked,this,&MyWidget::close);
// connect函数是建立信号发送者、信号、信号接收者、槽四者关系的函数:
// connect(sender, signal, receiver, slot);

参数解释:

  • sender:信号发送者

  • signal:信号

  • receiver:信号接收者

  • slot:接收对象在接收到信号之后所需要调用的函数(槽函数)

​ 在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个

这里要注意的是connect的四个参数都是指针,信号和槽是函数指针。

8.2 自定义信号和槽

Qt框架默认提供的标准信号和槽不足以完成我们日常应用开发的需求,比如说点击某个按钮让另一个按钮的文字改变,这时候标准信号和槽就没有提供这样的函数。但是Qt信号和槽机制提供了允许我们自己设计自己的信号和槽

8.2.1自定义信号使用条件

  • 声明在类的signals域下

  • 没有返回值,void类型的函数

  • 只有函数声明,没有定义

  • 可以有参数,可以重载

  • 通过emit关键字来触发信号,形式:emit object->sig(参数);

8.2.2 自定义槽函数使用条件

  • qt4 必须声明在 private/public/protected slots域下面,qt5之后可以声明public下,同时还可以是静态的成员函数,全局函数,lambda表达式

  • 没有返回值,void类型的函数

  • 不仅有声明,还得要有实现

  • 可以有参数,可以重载

8.2.3使用自定义信号和槽

定义场景:下课了,老师跟同学说肚子饿了(信号),学生请老师吃饭(槽)

首先定义一个学生类和老师类:

#ifndef TEACHER_H
#define TEACHER_H

#include <QWidget>
#include <QString>

class Teacher : public QWidget
{
    Q_OBJECT
public:
    explicit Teacher(QWidget *parent = nullptr);
    QString name;
    void test01(Teacher * t);

signals:
    // 1.声明在signals域下
    // 2.没有返回值 void
    // 3.只用声明,无需定义
    // 4.可以有参数,可以重载
    // 5.使用 emit 调用 emit teacherobje-> 信号函数(参数)
    void hungry(QString name);

public slots:
};

#endif // TEACHER_H

#include "teacher.h"

Teacher::Teacher(QWidget *parent) : QWidget(parent)
{

}
// 测试
void Teacher::test01(Teacher * t){
    // 发送信号
    emit t->hungry(t->name);
}

学生类:

#ifndef STUDENT_H
#define STUDENT_H

#include <QWidget>

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

signals:

public slots:
    // 槽
    // 没有返回值 void
    // 需要定义和声明
    // 可以有参数 可以重载
    // qt4需要声明在 protected/public/private slots下 qt5 public 全局函数 lambda 静态成员函数
    void toEat(QString name);
};

#endif // STUDENT_H

#include "student.h"
#include <iostream>
#include <QDebug>
Student::Student(QWidget *parent) : QWidget(parent)
{

}

void Student::toEat(QString name)
{
   qDebug() <<"请"<< name<< "老师吃饭";
}

测试:

// 生成老师
Teacher * teacher = new Teacher(this);
teacher->name = "老王";
// 生成学生
Student * student = new Student(this);
// 建立关系
connect(teacher,&Teacher::hungry,student,&Student::toEat);
teacher->test01(teacher);

当发生了重载 解决方法:

// 当信号槽函数发生了重载,所以编译器不知道是哪个
connect(pTeacher,&Teacher::hungry,student,&Student::toEat); // 报错
// 解决方法1 使用函数指针赋值,让编译器挑选符合类型的函数
// 有参函数指针
void (Teacher::*teacher_qstring)(QString) = &Teacher::hungry;
void (Student::*student_qstring)(QString) = &Student::toEat;
connect(pTeacher,teacher_qstring,student,student_qstring);

// 无参函数指针
void (Teacher::*teacher_qstring2)() = &Teacher::hungry;
void (Student::*student_qstring2)() = &Student::toEat;
connect(pTeacher,teacher_qstring2,student,student_qstring2);
// 解决方法2 使用static_cast 强制转换 让编译器自动挑选符合类型的函数
// 无参
connect(pTeacher,
        static_cast<void(Teacher::*)()>(&Teacher::hungry),
        student,
        static_cast<void(Student::*)()>(&Student::toEat)
       );

// 有参
connect(pTeacher,
        static_cast<void(Teacher::*)(QString)>(&Teacher::hungry),
        student,
        static_cast<void(Student::*)(QString)>(&Student::toEat)
       );

8.3 信号和槽的扩展

  • 一个信号可以和多个槽相连
// 一个信号建立多个connect
// 那么当信号发射的时候,槽函数的调用顺序:随机!
  • 多个信号可以连接到一个槽

  • 一个信号可以连接到另外的一个信号

QPushButton * btn = new QPushButton("下课!",this);
void (Teacher::*teacher_qstring2)() = &Teacher::hungry;
connect(btn,&QPushButton::clicked,pTeacher,teacher_qstring2);
// 使用前提 teacher_qstring2已经连到了槽
  • 信号和槽可以断开连接 disconnect

    可以使用disconnect函数,当初建立连接时connect参数怎么填的,disconnect里边4个参数也就怎么填。这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽

  • 信号和槽函数参数类型和个数必须同时满足两个条件

    • 信号函数的参数个数必须大于等于槽函数的参数个数
    • 信号函数的参数类型和槽函数的参数类型必须一一对应
signal(QString) ---> slots();     // ok
signal(Qstirng) ---> slots(int)   // 编译失败

8.4 Qt4版本的信号槽写法

connect(
    teacher,
    SIGNAL(hungry(QString)),
    student,
    SLOT(treat(QString))
);

这里使用了SIGNAL和SLOT这两个宏,宏的参数是信号函数和槽函数的函数原型。

因为直接填入了函数原型,所有这里边编译不会出现因为重载导致的函数指针二义性的问题。但问题是如果函数原型填错了,或者不符合信号槽传参个数类型约定,编译期间也不会报错,只有运行期间才会看到错误log输出。

原因就是这两个宏将后边参数(函数原型)转化成了字符串。目前编译器还没有那么智能去判断字符串里边的内容符不符合运行条件。

9 QDebug

qDebug默认将 QString 转义输出

Debug().noquote() <<"请老师吃饭";  // 没有转义了

10 lambda表达式

C++11 中的Lambda 表达式 用于定义 匿名的函数对象,以简化编程工作

lambda构造分为4个部分

  • [局部变量捕获]

  • (函数参数)

  • 函数额外属性设置 opt

  • 函数返回值->retype

  • {函数体}

[captrue](parameters)opt->retType
{
    
}
// 1.最简单的方式
// 调用lambda的方式,使用函数指针
void (*p)() =
[]()
{
    qDebug().noquote()<<"hello lambda1";
};
p();

局部变量引入方式

// 直接后面加()
[]()
{
    qDebug().noquote()<<"hello lambda2";
}();
// 局部变量捕获
// 捕获局部变量分为两种方式,一种是值传递,一种是引用
// 默认情况下值传递的局部变量就是const 只读,如果需要修改 opt 改为mutable
int a = 10;
int b = 20;
[&a,b]() mutable
{
    qDebug().noquote()<<"hello lambda";
    qDebug().noquote()<<a; // 提示a没有被捕获 在[]中 添加外部变量 内部可以访问到
    qDebug().noquote()<<b;

    b = 15; //
    a = 55;
}();

// = 捕获局部变量包括this(值传递方式)
[=]() mutable
{
    qDebug().noquote()<<b;
}();


// & 捕获局部变量包括this(引用方式)
[&]() mutable
{
    qDebug().noquote()<<b;
}();


// 遇到特殊的 除了b是值传递,其他都是引用传递
[&,b]() mutable
{
    qDebug().noquote()<<b;
}();

所以在无特殊情况下建议使用={}的形式

函数参数

​ (params)表示lambda函数对象接收的参数,类似于函数定义中的小括号表示函数接收的参数类型和个数。参数可以通过按值(如:(int a,int b))和按引用(如:(int &a,int &b))两种方式进行传递。函数参数部分可以省略,省略后相当于无参的函数。

选项Opt

​ Opt 部分是可选项,最常用的是mutable声明,这部分可以省略。外部函数局部变量通过值传递引进来时,其默认是const,所以不能修改这个局部变量的拷贝,加上mutable就可以

函数返回值 ->retType

​ ->retType,标识lambda函数返回值的类型。这部分可以省略,但是省略了并不代表函数没有返回值,编译器会自动根据函数体内的return语句判断返回值类型,但是如果有多条return语句,而且返回的类型都不一样,编译会报错

槽函数使用Lambda表达式

connect(btn,&QPushButton::clicked,[=](){
        qDebug()<<"Clicked";
});
// 槽使用lambda表达式
QPushButton * btn = new QPushButton("lambda",this);
int num = 200;
connect(btn,&QPushButton::clicked,[=](){
    qDebug()<<"执行了!";
    qDebug()<<num;
});

11 QMainWindow

QMainWindow是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(tool bars)、多个停靠部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等。

![img](file:///C:\Users\DSF-LSJ\AppData\Local\Temp\ksohtml\wpsAE4B.tmp.jpg)

1 菜单栏 menuBar

一个主窗口最多只有一个菜单栏。位于主窗口顶部、主窗口标题栏下面。

通过QMainWindow类的menubar()函数获取主窗口菜单栏指针,如果当前窗口没有菜单栏,该函数会自动创建一个。

  QMenuBar *	menuBar() const;

创建菜单,调用QMenu的成员函数addMenu来添加菜单

QAction* addMenu(QMenu * menu);
QMenu* addMenu(const QString & title);
QMenu* addMenu(const QIcon & icon, const QString & title);
this->resize(800,600);
// 菜单栏,获取当前窗口的菜单栏,没有的话会自己创建一个
QMenuBar * bar = this->menuBar();
// 添加菜单 没有提示添加头文件
QMenu * menuFile = bar->addMenu("文件"); // 返回值是QMenu
QMenu * menuEdit = bar->addMenu("编辑");
// 往菜单添加菜单项
QAction *actionCreate = menuFile->addAction("新建");  // 返回值是QAction
QAction *actionOpen = menuFile->addAction("打开");
// 添加分割符号
QAction *actionSeparator = menuFile->addSeparator();
// 添加二级菜单
QMenu * menuTwoFile = menuFile->addMenu("最近打开的文件");
menuTwoFile->addAction("d:xxxxx");
menuTwoFile->addAction("d:wwww");

2 工具栏 addToolBar

  • 调用QMainWindowd对象的成员函数addToolBar(),该函数每次调用都会创建一个新的工具栏,并且返回该工具栏的指针。

  • 插入属于工具条的项,这时工具条上添加项也是用QAction。通过QToolBar类的addAction函数添加。

  • 工具条是一个可移动的窗口,它的停靠区域由QToolBar的allowAreas决定

// 工具栏,可以有多个 
QToolBar * toolBar = this->addToolBar("tool");
// 添加工具
toolBar->addAction(actionCreate);
toolBar->addAction(actionOpen);
// 初始化停靠左边
this->addToolBar(Qt::ToolBarArea::LeftToolBarArea,toolBar);
// 只能停靠左边或者右边
toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);
// 设置工具不能浮动
toolBar->setFloatable(false);
// 设置工具栏不允许拖动
toolBar->setMovable(false);

3 状态栏 statusBar

一个QMainWindow的程序最多只有一个状态栏。QMainWindow中可以有多个的部件都使用add…名字的函数,而只有一个的部件,就直接使用获取部件的函数,如menuBar。同理状态栏也提供了一个获取状态栏的函数statusBar(),没有就自动创建一个并返回状态栏的指针。

添加小部件(从状态栏左侧添加)

void addWidget(QWidget * widget, int stretch = 0);
//插入小部件
int	insertWidget(int index, QWidget * widget, int stretch = 0);
//删除小部件
void removeWidget(QWidget * widget);
// 状态栏 只有一个
// 获取窗口状态栏
QStatusBar * statusbar = this->statusBar();
// 往状态栏里面添加信息
// 左侧信息
QLabel * statusLeftLable = new QLabel("左侧信息",statusbar);
statusbar->addWidget(statusLeftLable);
// 右侧信息
QLabel * statusRightLable = new QLabel("右侧信息",statusbar);
statusbar->addPermanentWidget(statusRightLable);

4 停靠部分

停靠部件 QDockWidget,也称浮动窗口,可以有多个。

// 停靠部件,可以有多个
QDockWidget * dockWidget = new QDockWidget("停靠部件",this);
// 默认情况下没有核心部件作为参照物,停靠部件会占完窗口
this->addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea,dockWidget);

// 添加核心部件
QTextEdit * textEdit = new QTextEdit(this);
this->setCentralWidget(textEdit);

5 核心部分

// 添加核心部件
QTextEdit * textEdit = new QTextEdit(this);
//设置mainWindow的核心部件
this->setCentralWidget(textEdit);

12 ui

13 资源文件使用

// 使用图片资源
// 1 使用绝对路径
ui->actionnew->setIcon(QIcon("D:\\QTcode\\07_ui\\Luffy.png"));

// 2 使用资源文件
// 默认工程目录添加 创建一个资源文件 添加前缀,添加文件
// 使用资源文件形式:
// 冒号: 前缀/+目录文件名
ui->actionOpen->setIcon(QIcon(":/image/Luffy.png"));

14 对话框

没有最大化最小化的窗口

模态对话框 : 就是对话框没有关闭前,不能操作同一个进程的其他窗口

非模态对话框: 就是对话框没有关闭前,也能操作同一个进程的其他窗口

connect(ui->actionModal,&QAction::triggered,[=](){
    // 创建一个模态对话框
    QDialog dlg(this);
    dlg.exec(); // 消息循环
});

connect(ui->actionNoModal,&QAction::triggered,[=](){
    // 创建 非模态对话框
    QDialog * dialog = new QDialog(this);
    // 释放问题,只有父对象释放的时候子对象才释放
    // 通过设置窗口属性,让他关闭的时候自动释放
    dialog->setAttribute(Qt::WidgetAttribute::WA_DeleteOnClose);
    dialog->show();
});

15 标准对话框

所谓标准对话框,是 Qt 内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。

Qt 的内置对话框大致分为以下几类:

  • QMessageBox: 模态对话框,用于显示信息、询问问题等;

  • QColorDialog: 选择颜色;

  • QFontDialog: 选择字体;

  • QFileDialog: 选择文件或者目录;

  • QInputDialog: 允许用户输入一个值,并将其值返回;

  • QPageSetupDialog: 为打印机提供纸张相关的选项;

  • QPrintDialog: 打印机配置;

  • QPrintPreviewDialog:打印预览;

  • QProgressDialog: 显示操作过程。

QMessageBox

// 消息dialog info
connect(ui->pushButton,&QPushButton::clicked,[=](){
    QMessageBox::information(this,"info","info提示");
});


//  warning
connect(ui->pushButton_2,&QPushButton::clicked,[=](){
    QMessageBox::warning(this,"警告","warning提示");
});

//  Question
connect(ui->pushButton_3,&QPushButton::clicked,[=](){
    if(QMessageBox::Ok ==  QMessageBox::question(this,"问你个事","你有对象嘛",QMessageBox::Ok|QMessageBox::Cancel)){
        qDebug().noquote()<<tr("点击了ok");
    }else if(QMessageBox::Cancel){
        qDebug().noquote()<<tr("点击了cancle");
    }
});

//  critical
connect(ui->pushButton_4,&QPushButton::clicked,[=](){
    QMessageBox::critical(this,"报错","错误信息");
});

image-20220407225215293

QFileDialog 标准文件对话框

// 打开一个文件对话框
QString fileName = QFileDialog::getOpenFileName(this,"打开一个文件","C:",tr("Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"));
qDebug().noquote()<<fileName;
#include "mainwindow.h"
#include <QMenuBar>
#include <QAction>
#include <QTextEdit>
#include <QString>
#include <QFileDialog>
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    this->setFixedSize(800,600);
    // 获取菜单
    QMenuBar * bar = this->menuBar();
    // 创建两个QAction对象 设置icon 和文本
    QMenu * fileBar = bar->addMenu(tr("文件"));
    QAction * openfile = fileBar->addAction(QIcon(":/image1"),tr("打开文件"));
    QAction * savefile = fileBar->addAction(QIcon(":/image2"),tr("保存文件"));
    this->textEdit = new QTextEdit(this);
    // 创建槽
    connect(openfile,&QAction::triggered,this,&MainWindow::MenuOpenFile);
    connect(savefile,&QAction::triggered,this,&MainWindow::MenuSaveFile);

    // 设置核心部分为textEdit
    this->setCentralWidget(textEdit);
}

MainWindow::~MainWindow()
{
    if(this->textEdit!=NULL){
        delete this->textEdit;
    }
}

void MainWindow::MenuOpenFile()
{
    // 打开文件 获取文件路径
    QString path = QFileDialog::getOpenFileName(this,"打开文件",".",tr("Text files (*.txt)"));
    qDebug()<<path;
    // 判断文件是否存在
    if(path.isEmpty()){
        // 为空
        QMessageBox::critical(this,"文件打卡提示","文件不存在");
        return;
    }
    // 打开文件
    QFile file(path);
    // 判断文件是否能打开
    if(!file.open(QIODevice::ReadOnly|QIODevice::Text)){
        // 文件不能打开
        QMessageBox::warning(this,"文件打开提示",tr("文件路径:%1").arg(path));
        return;
    }
    QTextStream in(&file);
    this->textEdit->setText(in.readAll());
    file.close();
}

void MainWindow::MenuSaveFile()
{
    // 保存文件
    QString path = QFileDialog::getSaveFileName(this,
                                                tr("打开文件"), ".", tr("Text Files(*.txt)"));
    if(!path.isEmpty())
    {
        QFile file(path);
        if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
        {
            QMessageBox::warning(this, tr("Write File"),
                                 tr("Cannot open file:\n%1").arg(path));
            return;
        }
        QTextStream out(&file);
        out << textEdit->toPlainText();
        file.close();
    }
}

在openFile()函数中,我们使用QFileDialog::getOpenFileName()来获取需要打开的文件的路径。这个函数原型如下:

QString getOpenFileName(QWidget * parent = 0,
                        const QString & caption = QString(),
                        const QString & dir = QString(),
                        const QString & filter = QString(),
                        QString * selectedFilter = 0,
                        Options options = 0);
  • parent:父窗口。

  • caption:对话框标题;

  • dir:对话框打开时的默认目录

    • “.” 代表程序运行目录
    • “/” 代表当前盘符的根目录(特指 Windows 平台;Linux 平台当然就是根目录),这个参数也可以是平台相关的,比如“C:\”等;
  • filter:过滤器。如果需要多个过滤器,使用“;;”分割

    • "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)"
      
  • selectedFilter:默认选择的过滤器;

  • options:对话框的一些参数设定

标签:QMainWindow,窗口,函数,对话框,对象,QWidget,信号,QT,Qt
来源: https://www.cnblogs.com/lddragon/p/16115015.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有