QT基础学习

2创建项目

2.1使用向导创建

打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项

弹出New Project对话框,选择Qt Widgets Application,

选择【Choose】按钮,弹出如下对话框

设置项目名称和路径,按照向导进行下一步,(不能有中文和空格

选择编译套件

向导会默认添加一个继承自CMainWindow的类,可以在此修改类的名字和基类。默认的基类有QMainWindow、QWidget以及QDialog三个,我们可以选择QWidget(类似于空窗口),这里我们可以先创建一个不带UI的界面,继续下一步

系统会默认给我们添加main.cpp、mywidget.cpp、 mywidget.h和一个.pro项目文件,点击完成,即可创建出一个Qt桌面程序。

对main原始代码的一些解释

#include "widget.h"
#include <QApplication>//包含一个应用程序类的头文件


//main程序入口 argc命令行变量的数量 argv命令行变量的数组
int main(int argc, char *argv[])
{
    //a应用程序对象,在gt中,应用程序对象 有且仅有一个
    QApplication a(argc, argv);
    //窗口对象 mywidget父类 ->Qwidget
    Widget w;
    //窗口对象 默认不会显示,必须要调用show方法显示窗口
    w.show();
    
    //让应用程序对象进入消息循环//当代码阻塞到这行
    return a.exec();

//    while (true)
//   {
//      if(点击叉子)
//         {
//           break;
//         }
//    }
}
QT       += core gui   //Qt包含的模块

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets  //大于4版本以上 包含 widget模块

TARGET = QTtest        //目标   生成的exe程序的名称
TEMPLATE = app


DEFINES += QT_DEPRECATED_WARNINGS

 before Qt 6.0.0


SOURCES += \                //源文件
        main.cpp \
        widget.cpp

HEADERS += \                //头文件
        widget.h
总结

快捷键   

帮助文档 第一种方式 F1 第二种 左侧按钮 第三种 D:\QT\5.11.1\mingw53_32\bin

// 命名规范
// 类名 首字母大写,单词和单词之间首字母大写
// 函数名 变量名称 首字母小写,单词和单词之间首字母大写
//快捷键//注释 ctrl+/
//运行 etrl + r//编译 ctrl + b
//字体缩放 ctrl + 鼠标滚轮
//查找 ctrl + f
//整行移动 ctrl + shift+,或者↓
//帮助文档 F1
//自动对齐 ctrl + i;
//同名之间的.h 和.cpp切换 F4

3第一个Qt小程序

3.1 按钮的创建

mywidget.h

#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>

class myWidget : public QWidget     //继承的语法
{
    Q_OBJECT

public:
    myWidget(QWidget *parent = 0);  //有参构造函数
    ~myWidget();
};

#endif // MYWIDGET_H

 mypushbutton.h

#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H

#include <QPushButton>

class MyPushButton : public QPushButton
{
    Q_OBJECT
public:
    explicit MyPushButton(QWidget *parent = 0);

    ~MyPushButton();

signals:

public slots:
};

#endif // MYPUSHBUTTON_H

 main.cpp

#include "mywidget.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    myWidget w; //窗口对象  myWidget的父类  -> QWidget
    w.show(); //窗口对象 默认不会显示,必须要调用show方法显示窗口

    return a.exec();//让应用程序对象进入消息循环//当代码阻塞到这行
    //    while(true)
    //    {
    //         if(点击叉子)
    //        {
    //            break;
    //        }
    //    }

}

 mypushbutton.cpp

#include "widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //创建一个按钮
    QPushButton * btn = new QPushButton;
    //btn->show(); //show以顶层方式弹出窗口控件
    //让btn对象依赖在mywidget窗口中
    btn->setParent (this);

    //显示文本
    btn->setText ("第一个按钮");


    //创建第二个按钮 按照控件的大小创建窗口
    QPushButton * btn2 = new QPushButton("第二个按钮",this):
    //移动btn2按钮
    btn2->move (100,100);
    
    //重置窗口大小
    resize (600, 400);

    //设置固定窗口大小
    setFixedSize (600, 400);

    //设置窗口标题
    setwindowTitle("第一个窗口");
 
Widget::~Widget()
{

}

 mywidget.h

#include "mywidget.h"
#include <QPushButton> //按钮控件的头文件
#include "mypushbutton.h"
#include <QDebug>

myWidget::myWidget(QWidget *parent)
    : QWidget(parent)//初始化列表
{
    //创建一个按钮
    QPushButton * btn = new QPushButton;
    //btn->show(); //show以顶层方式弹出窗口控件
    //让btn对象 依赖在 myWidget窗口中
    btn->setParent(this);

    //显示文本
    btn->setText("第一个按钮");
    //创建第二个按钮 按照控件的大小创建窗口
     QPushButton * btn2 = new QPushButton("第二个按钮",this);

     //移动btn2按钮
     btn2->move(100,100);

     //按钮可不可以 重新制定大小 可以!
     btn2->resize(50,50);

     //重置窗口大小
     resize(600,400);

     //设置固定窗口大小
     setFixedSize(600,400);

     //设置窗口标题
     setWindowTitle("第一个窗口");


     //创建一个自己的按钮对象
     MyPushButton * myBtn = new MyPushButton;
     myBtn->setText("我自己的按钮");

     myBtn->move(200,0);
     myBtn->setParent(this); //设置到对象树中

    //需求 点击我的按钮 关闭窗口
    //参数1 信号的发送者 参数2发送的信号(函数的地址)参数3 信号的接受者 参数4 处理的槽函数
    connect( myBtn, &MyPushButton::clicked, this, &myWidget::close );
    connect( myBtn, &QPushButton::clicked, this, &QWidget::close );
}

myWidget::~myWidget()
{

}

来自ChatGPT的代码解析解答

总结

3.2对象模型(对象树)

在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底是干什么的。

 

  • QObject是以对象树的形式组织起来的。
  1. 当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
  2. 这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
  3. 当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!
  4. 这种机制在 GUI 程序设计中相当有用。例如,一个按钮有一个QShortcut(快捷键)对象作为其子对象。当我们删除按钮的时候,这个快捷键理应被删除。这是合理的。
  • QWidget是能够在屏幕上显示的一切组件的父类。
  1. QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
  2. 当然,我们也可以自己删除子对象,它们会自动从其父对象列表中删除。比如,当我们删除了一个工具栏时,其所在的主窗口会自动将该工具栏从其子对象列表中删除,并且自动调整屏幕显示。

Qt 引入对象树的概念,在一定程度上解决了内存问题。

  •  当一个QObject对象在堆上创建的时候,Qt 会同时为其创建一个对象树。不过,对象树中对 象的顺序是没有定义的。这意味着,销毁这些对象的顺序也是未定义的。
  • 任何对象树中的 QObject对象 delete 的时候,如果这个对象有 parent,则自动将其从 parent 的children()列表中删除;如果有孩子,则自动 delete 每一个孩子。Qt 保证没有QObject会被 delete 两次,这是由析构顺序决定的。
  • 如果QObject在栈上创建,Qt 保持同样的行为。正常情况下,这也不会发生什么问题。来看下下面的代码片段:

  • {
        QWidget window;
        QPushButton quit("Quit", &window);
    }
    

    作为父组件的 window 和作为子组件的 quit 都是QObject的子类(事实上,它们都是QWidget的子类,而QWidget是QObject的子类)。这段代码是正确的,quit 的析构函数不会被调用两次,因为标准 C++要求,局部对象的析构顺序应该按照其创建顺序的相反过程。因此,这段代码在超出作用域时,会先调用 quit 的析构函数,将其从父对象 window 的子对象列表中删除,然后才会再调用 window 的析构函数。

    但是,如果我们使用下面的代码:

  • {
        QPushButton quit("Quit");
        QWidget window;
        quit.setParent(&window);
    }
    

    情况又有所不同,析构顺序就有了问题。我们看到,在上面的代码中,作为父对象的 window 会首先被析构,因为它是最后一个创建的对象。在析构过程中,它会调用子对象列表中每一个对象的析构函数,也就是说, quit 此时就被析构了。然后,代码继续执行,在 window 析构之后,quit 也会被析构,因为 quit 也是一个局部变量,在超出作用域的时候当然也需要析构。但是,这时候已经是第二次调用 quit 的析构函数了,C++ 不允许调用两次析构函数,因此,程序崩溃了。

    由此我们看到,Qt 的对象树机制虽然帮助我们在一定程度上解决了内存问题,但是也引入了一些值得注意的事情。这些细节在今后的开发过程中很可能时不时跳出来烦扰一下,所以,我们最好从开始就养成良好习惯,在 Qt 中,尽量在构造的时候就指定 parent 对象,并且大胆在堆上创建。

3.3 Qt窗口坐标体系 

坐标体系:

以左上角为原点(0,0),X向右增加,Y向下增加。

 对于嵌套窗口,其坐标是相对于父窗口来说的。

4 信号和槽机制

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。

信号:各种事件

槽: 响应信号的动作

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

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

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

4.1 系统自带的信号和槽

        下面我们完成一个小功能,上面我们已经学习了按钮的创建,但是还没有体现出按钮的功能,按钮最大的功能也就是点击后触发一些事情,比如我们点击按钮,就把当前的窗口给关闭掉,那么在Qt中,这样的功能如何实现呢?

如下图:

connect( 信号的发送者,发送的具体信号,信号的接受者,信号的处理(槽) )

信号槽的优点,松散耦合,信号发送端和接受端本身是没有关联的,通过connect连接,将两端耦合在一起

           其实两行代码就可以搞定了,我们看下面的代码

QPushButton * quitBtn = new QPushButton("关闭窗口",this);
  connect(quitBtn,&QPushButton::clicked,this,&MyWidget::close);

    第一行是创建一个关闭按钮,这个之前已经学过,第二行就是核心了,也就是信号槽的使用方式

    connect函数是建立信号发送者、信号、信号接收者、槽四者关系的函数:

connect(sender, signal, receiver, slot);

参数解释:

        1)sender:信号发送者

        2)signal:信号

        3)receiver:信号接收者

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

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

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

        这里的clicked就是我们要找到,槽函数的寻找方式和信号一样,只不过他的关键字是slot。 

4.2 自定义信号和槽

使用connect()可以让我们连接系统提供的信号和槽。但是,Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。

4.2.1自定义信号使用条件
  1. 声明在类的signals域下
  2. 没有返回值,void类型的函数
  3. 只有函数声明,没有定义
  4. 可以有参数,可以重载
  5. 通过emit关键字来触发信号,形式:emit object->sig(参数);
 4.2.3 使用自定义信号和槽

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

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

        老师类中声明信号 饿了 hungry

signals:
       void hungry();

      学生类中声明槽 请客treat

public slots:
       void treat();

    在窗口中声明一个公共方法下课,这个方法的调用会触发老师饿了这个信号,而响应槽函数学生请客

	void MyWidget::ClassIsOver()
{
    //发送信号
    emit teacher->hungry();
}

        学生响应了槽函数,并且打印信息

        //自定义槽函数 实现

void Student::treat()
{
       qDebug() << "Student treat teacher";
}

       在窗口中连接信号槽

 teacher = new Teacher(this);
    student = new Student(this);
    connect(teacher,&Teacher::hungury,student,&Student::treat);

        并且调用下课函数,测试打印出相应log 

4.3 信号和槽的扩展

        1.一个信号可以和多个槽相连

        如果是这种情况,这些槽会一个接一个的被调用,但是槽函数调用顺序是不确定的。像上面的例子,可以将一个按钮点击信号连接到关闭窗口的槽函数,同时也连接到学生请吃饭的槽函数,点击按钮的时候可以看到关闭窗口的同时也学生请吃饭的log也打印出来。

        2. 多个信号可以连接到一个槽

        只要任意一个信号发出,这个槽就会被调用。如:一个窗口多个按钮都可以关闭这个窗口。

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

        当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。注意这里还是使用connect函数,只是信号的接收者和槽函数换成另一个信号的发送者和信号函数。如上面老师饿了的例子,可以新建一个按钮btn。

connect(btn,&QPushButton::clicked,teacher,&Teacher::hungry);

        4.信号和槽可以断开连接

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

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

                1)信号函数的参数个数必须大于等于槽函数的参数个数

                2)信号函数的参数类型和槽函数的参数类型必须一一对应

 自定义信号槽需要注意的事项

  1. 发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
  2. 信号和槽函数返回值是 void
  3. 信号只需要声明,不需要实现
  4. 槽函数需要声明也需要实现
  5. 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
  6. 使用 emit 在恰当的位置发送信号;
  7. 使用connect()函数连接信号和槽。
  8. 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
  9. 信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。
  10. 如果信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为,你可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。

4.4 Qt4版本的信号槽写法 

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

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

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

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

 4.5 Lambda 表达式

        C++11中的Lambda表达式用于定义匿名的函数对象,以简化编程工作。首先看一下Lambda表达式的基本构成:

        分为四个部分:[局部变量捕获列表]、(函数参数)、函数额外属性设置opt、函数返回值->retype、{函数主体}

[capture](parameters) opt ->retType
{
    ……;
}
4.5.1 局部变量引入方式 

        [ ],标识一个Lambda的开始。由于lambda表达式可以定义在某一个函数体A里边,所以lambda表达式有可能会去访问A函数中的局部变量。中括号里边内容是描述了在lambda表达式里边可以使用的外部局部变量的列表:

        []

            表示lambda表达式不能访问外部函数体的任何局部变量

        [a]

            在函数体内部使用值传递的方式访问a变量

        [&b]

            在函数体内部使用引用传递的方式访问b变量

        [=]

            函数外的所有局部变量都通过值传递的方式使用, 函数体内使用的是副本

        [&]

            引用的方式使用lambda表达式外部的所有变量

        [=, &foo]

            foo使用引用方式, 其余是值传递的方式

        [&,foo]

            foo使用值传递方式, 其余是引用传递的方式

         [this]

           在函数内部可以使用类的成员函数和成员变量,=和&形式也都会默认引入

        由于引用方式捕获对象会有局部变量释放了而lambda函数还没有被调用的情况。如果执行lambda函数那么引用传递方式捕获进来的局部变量的值不可预知。

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

 4.5.2 函数参数

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

4.5.3 选项 Opt

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

int a = 10 ;
[=]()
{
    a=20;//编译报错,a引进来是const
}
 
[=]()mutable
{
    a=20;//编译成功
};
4.5.5 是函数主体{}

        {},标识函数的实现,这部分不能省略,但函数体可以为空。

 4.5.6 槽函数使用 Lambda 表达式

以QPushButton点击事件为例:

connect(btn,&QPushButton::clicked,[=](){
        qDebug()<<"Clicked";
});

        这里可以看出使用Lambda表达式作为槽的时候不需要填入信号的接收者。当点击按钮的时候,clicked信号被触发,lambda表达式也会直接运行。当然lambda表达式还可以指定函数参数,这样也就能够接收到信号函数传递过来的参数了。

        由于lambda表达式比我们自己自定义槽函数要方便而且灵活得多,所以在实现槽函数的时候优先考虑使用Lambda表达式。一般我们的使用习惯也是lambda表达式外部函数的局部变量全部通过值传递捕获进来,也就是:

[=](){  }的形式

 老师学生吃饭例子:

student.h

teacher.h
widget.h

main.cpp
student.cpp

teacher.cpp

widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QDebug>
//Teacher 类  老师类
//Student 类  学生类
//下课后 ,老师会触发一个信号,饿了 ,学生响应信号,请客吃饭

void func()
{
    qDebug() <<"aaa";

}

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

    //创建一个老师对象
    this->zt = new Teacher(this);

    //创建一个学生对象
    this->st = new Student(this);


//    //老师饿了 学生请客的连接
//    connect(zt,&Teacher::hungry,st,&Student::treat);

//    //调用下课函数
//    classIsOver();

    //连接带参数的 信号和槽
    //指针 -> 地址
    // 函数指针 -> 函数地址

    void(Teacher:: *teacherSignal)(QString  ) = &Teacher::hungry;
    void(Student:: *studentSlot)(QString  )  = &Student::treat;
    connect(zt,teacherSignal,st,studentSlot);
   // classIsOver();


    //点击一个 下课的按钮 ,再触发下课
    QPushButton * btn = new QPushButton("下课",this);
    //重置窗口大小
    this->resize(600,400);

    //点击按钮 触发下课
    //connect(btn,&QPushButton::clicked,this,&Widget::classIsOver);

    //无参信号和槽连接
    void(Teacher:: *teacherSignal2)(void) = &Teacher::hungry;
    void(Student:: *studentSlot2)(void)  = &Student::treat;
    //connect(zt,teacherSignal2,st,studentSlot2);

    //信号连接信号
    connect(btn,&QPushButton::clicked, zt, teacherSignal2);

    //断开信号
    //disconnect(zt,teacherSignal2,st,studentSlot2);

    //拓展
    //1、信号是可以连接信号
    //2、一个信号可以连接多个槽函数
    //3、多个信号 可以连接 同一个槽函数
    //4、信号和槽函数的参数 必须类型一一对应
    //5、信号和槽的参数个数  是不是要一致?信号的参数个数 可以多余槽函数的参数个数

    //Qt4版本以前的信号和槽连接方式
    //利用Qt4信号槽 连接无参版本
    //Qt4版本 底层SIGNAL("hungry")  SLOT( "treat")
    connect(zt,SIGNAL(hungry()) , st , SLOT(treat()));
    //Qt4版本优点:参数直观,缺点 :类型不做检测
    //Qt5以上  支持 Qt4的版本写法,反之不支持

//    QPushButton * btn2 = new QPushButton;

//    [btn](){
//        btn->setText("aaaa");
//        btn2->setText("bbb"); //btn2看不到
//    }();

    // mutable关键字 用于修饰值传递的变量,修改的是拷贝,而不是本体

//    QPushButton * myBtn = new QPushButton (this);
//    QPushButton * myBtn2 = new QPushButton (this);
//    myBtn2->move(100,100);
//    int m = 10;

//    connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });

//    connect(myBtn2,&QPushButton::clicked,this,[=] ()  { qDebug() << m; });

//    qDebug() << m;

//    int ret = []()->int{return 1000;}();
//    qDebug() << "ret = " << ret ;

    //利用lambda表达式 实现点击按钮 关闭窗口
    QPushButton * btn2 = new QPushButton ;
    btn2->setText("关闭");
    btn2->move(100,0);
    btn2->setParent(this);
    connect(btn2,&QPushButton::clicked, [=](){
//        this->close();
//        emit zt->hungry("宫保鸡丁");

        btn2->setText("aaaa");
    });

    //lambda表达式 最常用  [=](){}
}

void Widget::classIsOver()
{
    //下课函数,调用后 触发老师饿了的信号
    //emit zt->hungry();
    emit zt->hungry("宫保鸡丁");
}

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

 

5QMainWindow

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

5.1 菜单栏

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

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

   QMenuBar *  menuBar() const;

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

    QAction* addMenu(QMenu * menu);
    QMenu* addMenu(const QString & title);
    QMenu* addMenu(const QIcon & icon, const QString & title);

        3.创建菜单项,调用QMenu的成员函数addAction来添加菜单项

    QAction* activeAction() const;
    QAction* addAction(const QString & text);
    QAction* addAction(const QIcon & icon, const QString & text);
    QAction* addAction(const QString & text, const QObject * receiver,
    const char * member, const QKeySequence & shortcut = 0);
    QAction* addAction(const QIcon & icon, const QString & text, 
    const QObject * receiver, const char * member, 
    const QKeySequence & shortcut = 0);

         Qt 并没有专门的菜单项类,只是使用一个QAction类,抽象出公共的动作。当我们把QAction对象添加到菜单,就显示成一个菜单项,添加到工具栏,就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击快捷键来激活这个动作。

 5.2 工具栏

        主窗口的工具栏上可以有多个工具条,通常采用一个菜单对应一个工具条的的方式,也可根据需要进行工具条的划分。

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

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

        1)Qt::LeftToolBarArea           停靠在左侧

        2)Qt::RightToolBarArea         停靠在右侧

        3)Qt::TopToolBarArea           停靠在顶部

        4)Qt::BottomToolBarArea   停靠在底部       

        5)Qt::AllToolBarAreas           以上四个位置都可停靠

使用setAllowedAreas()函数指定停靠区域:

setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea)

使用setFloatable(trueOrFalse)函数来设定工具栏可否浮动

使用setMoveable(trueOrFalse)函数设定工具栏的可移动性:

setMoveable(false)//工具条不可移动, 只能停靠在初始化的位置上

 5.3 状态栏

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

 QMenuBar *	menuBar() const;

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

void addWidget(QWidget * widget, int stretch = 0);
//插入小部件
int	insertWidget(int index, QWidget * widget, int stretch = 0);
//删除小部件
void removeWidget(QWidget * widget);

2.添加小部件(从状态栏右侧添加)

void addPermenentWidget (QWidget *widget, int stretch = 0);

5.4 停靠部件(也成为铆接部件、浮动窗口)

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

QDockWidget * dock = new QDockWidget("标题",this);
//添加停靠部件到mainWindow中,并且设定默认停靠在左边
addDockWidget(Qt::LeftDockWidgetArea,dock);
//设定停靠部件允许停靠的范围
dock->setAllowedAreas(Qt::LeftDockWidgetArea |
Qt::RightDockWidgetArea | Qt::TopDockWidgetArea); 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/169980.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

5分钟教你轻松搭建Web自动化测试框架

在程序员的世界中&#xff0c;一切重复性的工作&#xff0c;都应该通过程序自动执行。「自动化测试」就是一个最好的例子。 随着互联网应用开发周期越来越短&#xff0c;迭代速度越来越快&#xff0c;只会点点点&#xff0c;不懂开发的手工测试&#xff0c;已经无法满足如今的…

在网络攻击之前、期间和之后应采取的步骤

在当今复杂的威胁形势下&#xff0c;网络攻击是不可避免的。 恶意行为者变得越来越复杂&#xff0c;出于经济动机的攻击变得越来越普遍&#xff0c;并且每天都会发现新的恶意软件系列。 这使得对于各种规模和跨行业的组织来说&#xff0c;制定适当的攻击计划变得更加重要。 …

【Linux】指令详解(二)

目录 1. 前言2. 重新认识指令2.1 指令的本质2.1.1 which2.1.2 alias 3. 常见指令3.1 whoami3.2 cd3.2.1 cd -3.2.2 cd ~ 3.3 touch3.3.1 文件创建时间 3.4 stat3.5 mkdir3.5.1 创建一个目录3.5.2 创建路径 3.6 tree3.7 rm3.7.1 rm -f3.7.2 rm -r 3.8 man3.9 cp3.10 mv 1. 前言 …

【洛谷 P3743】kotori的设备 题解(二分答案+递归)

kotori的设备 题目背景 kotori 有 n n n 个可同时使用的设备。 题目描述 第 i i i 个设备每秒消耗 a i a_i ai​ 个单位能量。能量的使用是连续的&#xff0c;也就是说能量不是某时刻突然消耗的&#xff0c;而是匀速消耗。也就是说&#xff0c;对于任意实数&#xff0c;…

【Unity】万人同屏高级篇, 自定义BRGdots合批渲染,海量物体目标搜索

Unity万人同屏海量物体合批渲染 Unity万人同屏海量物体目标搜索 Unity万人同屏手机端测试&#xff0c;AOT和HybridCLR热更性能对比 博文开发测试环境&#xff1a; Unity&#xff1a;Unity 2022.3.10f1&#xff0c;URP 14.0.8&#xff0c;Burst 1.8.8&#xff0c;Jobs 0.70.0-p…

Spring Boot - 自定义注解来记录访问路径以及访问信息,并将记录存储到MySQL

1、准备阶段 application.properties&#xff1b;yml 可通过yaml<互转>properties spring.datasource.urljdbc:mysql://localhost:3306/study_annotate spring.datasource.usernameroot spring.datasource.password123321 spring.datasource.driver-class-namecom.mysq…

Mybatis系列之 parameterMap 弃用了

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 &#x1f3f7;️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公…

Java八股文(急速版)

Redis八股文 我看你在做项目的时候都使用到redis&#xff0c;你在最近的项目中哪些场景下使用redis呢? 缓存和分布式锁都有使用到。 问&#xff1a;说说在缓存方面使用 1.在我最写的物流项目中就使用redis作为缓存&#xff0c;当然在业务中还是比较复杂的。 2.在物流信息…

创新工具 | 教你6步用故事板设计用户体验事半功倍

问题 构思方案时团队在细节上难以共识 故事板是什么&#xff1f;故事板就像连环画一样&#xff0c;将用户使用解决方案的关键步骤顺序串联了起来&#xff0c;呈现了方案和用户之间的交互。 故事板以先后顺序展现团队票选出来的最佳解决方案&#xff0c;在过程中对于方案中未…

几个强力的nodejs库

几个强力的nodejs库 nodejs被视为许多Web开发人员的理想运行时环境。 nodejs的设计是为了在运行时中使用JavaScript编写的代码&#xff0c;它是世界上最流行的编程语言之一&#xff0c;并允许广泛的开发者社区构建服务器端应用程序。 nodejs提供了通过JavaScript库重用代码的…

Linux--网络编程

一、网络编程概述1.进程间通信&#xff1a; 1&#xff09;进程间通信的方式有**&#xff1a;管道&#xff0c;消息队列&#xff0c;共享内存&#xff0c;信号&#xff0c;信号量这么集中 2&#xff09;特点&#xff1a;依赖于linux内核&#xff0c;基本是通过内核来实现应用层…

计算机毕业设计选题推荐-家庭理财微信小程序/安卓APP-项目实战

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

SVG圆形 <circle>的示例代码

本专栏是汇集了一些HTML常常被遗忘的知识&#xff0c;这里算是温故而知新&#xff0c;往往这些零碎的知识点&#xff0c;在你开发中能起到炸惊效果。我们每个人都没有过目不忘&#xff0c;过久不忘的本事&#xff0c;就让这一点点知识慢慢渗透你的脑海。 本专栏的风格是力求简洁…

腾讯云助力港华能源上线“碳汭星云2.0”,推动能源行业绿色低碳转型

11月17日&#xff0c;港华能源与腾讯云联合打造的港华智慧能源生态平台“碳汭星云2.0”升级上线。依托双方的连接、大数据能力和行业深耕经验&#xff0c;该平台打破了园区“数据孤岛”&#xff0c;进一步提升了数据治理、应用集成和复制推广能力&#xff0c;未来有望以综合能源…

Docker发布简单springboot项目

Docker发布简单springboot项目 在IDEA工具中直接编写Dockerfile文件 FROM java:8COPY *.jar /app.jarCMD ["--server.prot 8080"]EXPOSE 8080ENTRYPOINT ["java", "-jar", "/app.jar"]将项目打包成对应的jar包&#xff0c;将Dockerf…

html主页框架,前端首页通用架构,layui主页架构框架,首页框架模板

html主页框架 前言功能说明效果使用初始化配置菜单加载主题修改回调 其他非iframe页面内容使用方式iframe页面内容使用方式 前言 这是一个基于layui、jquery实现的html主页架构 平时写的系统后台可以直接套用此框架 由本人整合编写实现&#xff0c;简单上手&#xff0c;完全免…

Android WMS——输入系统管理(十七)

一、简介 1、工作原理 输入子系统从驱动文件中读取事件后,再封装提交给 IMS,IMS 再发送给 WMS 进行处理。 Android 输入系统的工作原理概括来说,内核将原始事件写入到设备节点中,InputReader 不断地通过 EventHub 将原始事件取出来并翻译加工成 Android 输入事件,…

计算机网络(持续更新…)

文章目录 一、概述1. 计网概述⭐ 发展史⭐ 基本概念⭐ 分类⭐ 数据交换方式&#x1f970; 小练 2. 分层体系结构⭐ OSI 参考模型⭐TCP/IP 参考模型&#x1f970; 小练 二、物理层1. 物理层概述⭐ 四个特性 2. 通信基础⭐ 重点概念⭐ 极限数据传输率⭐ 信道复用技术&#x1f389…

C++:拷贝构造函数,深拷贝,浅拷贝

一.什么是拷贝构造函数&#xff1f; 同一个类的对象在内存中有完全相同的结构&#xff0c;如果作为一个整体进行复制&#xff08;拷贝&#xff09;是完全可行的。这个拷贝过程只需要拷贝数据成员&#xff0c;而函数成员是共用的&#xff08;只有一份拷贝&#xff09;。在建立对…

Java面试题07

1.线程池都有哪些状态&#xff1f; 线程池的状态有RUNNING&#xff08;运行中&#xff09;、SHUTDOWN&#xff08;关闭中&#xff0c;不接受新任务&#xff09;、 STOP&#xff08;立即关闭&#xff0c;中断正在执行任务的线程&#xff09;和TERMINATED&#xff08;终止&#x…
最新文章