QT基础学习

news2025/1/11 2:55:37

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.coloradmin.cn/o/1232378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

11.15 监控目录文件变化

监视对指定目录的更改&#xff0c;并将有关更改的信息打印到控制台&#xff0c;该功能的实现不仅可以在内核层&#xff0c;在应用层同样可以。程序中使用ReadDirectoryChangesW函数来监视目录中的更改&#xff0c;并使用FILE_NOTIFY_INFORMATION结构来获取有关更改的信息。 Re…

requests库出现AttributeError问题的修复与替代方法

在使用App Engine时&#xff0c;开发者们通常会面临需要发送爬虫ip请求的情况&#xff0c;而Python中的requests库是一个常用的工具&#xff0c;用于处理爬虫ip请求。然而&#xff0c;在某些情况下&#xff0c;开发者可能会遇到一个名为AttributeError的问题&#xff0c;特别是…

适合您的智能手机的 7 款优秀手机数据恢复软件分享

如今&#xff0c;我们做什么都用手机&#xff1b;从拍照到录音&#xff0c;甚至作为 MP3 播放器&#xff0c;我们已经对手机变得非常依恋。这导致我们在手机上留下了很多珍贵的回忆。 不幸的是&#xff0c;我们有可能会丢失手机上的部分甚至全部数据。幸运的是&#xff0c;这不…

【练习】检测U盘并自动复制内容到电脑的软件

软件作用&#xff1a; 有U盘插在电脑上后&#xff0c;程序会检测到U盘的路径。 自己可以提前设置一个保存复制文件的路径或者使用为默认保存的复制路径&#xff08;默认为桌面&#xff0c;可自行修改&#xff09;。 检测到U盘后程序就会把U盘的文件复制到电脑对应的…

C#,数值计算——插值和外推,分段线性插值(Linear_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 分段线性插值 /// Piecewise linear interpolation object. /// Construct with x and y vectors, then call interp for interpolated values. /// </summary> …

C#,怎么修改(VS)Visual Studio 2022支持的C#版本

一些文字来自于 Microsoft . &#xff08;只需要读下面的红色文字即可&#xff01;&#xff09; 1 C# 语言版本控制 最新的 C# 编译器根据项目的一个或多个目标框架确定默认语言版本。 Visual Studio 不提供用于更改值的 UI&#xff0c;但可以通过编辑 .csproj 文件来更改值。…

(二)汇编语句组成

一个完整的 RISC-V 汇编程序有多条 语句&#xff08;statement&#xff09; 组成。 一条典型的 RISC-V 汇编 语句 由 3 部分组成&#xff1a; 1.标签 List item label&#xff08;标签&#xff09;: 标签是标识程序位置的记号。通常定义一个名称然后加上":"后缀。…

【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解

【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解 文章目录 【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解前言MobleNet_V2讲解反向残差结构(Inverted Residuals)兴趣流形(Manifold of interest)线性瓶颈层…

Python - Wave2lip 环境配置与 Wave2lip x GFP-GAN 实战 [超详细!]

一.引言 前面介绍了 GFP-GAN 的原理与应用&#xff0c;其用于优化图像画质。本文关注另外一个相关的项目 Wave2lip&#xff0c;其可以通过人物视频与自定义音频进行适配&#xff0c;改变视频中人物的嘴型与音频对应。 二.Wave2Lip 简介 Wave2lip 研究 lip-syncing 以达到视频…

PyTorch微调终极指南2:提升模型的准确性

作为一名机器学习从业者&#xff0c;你可能经常会发现自己处于这样一种情况&#xff1a;你正在针对特定任务微调预先训练的模型&#xff0c;但已经达到了无法进一步提高模型准确性的地步。 在本文中&#xff0c;我们将探讨可用于提高模型准确性的各种技术和策略。 这些方法旨在…

代码随想录算法训练营Day36 —— 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 思路&#xff1a; 按照左边排序&#xff0c;按照452引爆气球的思路即可&#xff0c;统计重叠区间个数就是最小删除个数&#xff0c; 直接改点就好。 代码&#xff1a; //手搓 class Solution { private:static bool cmp(const vector<int>& a, c…

从0开始学习JavaScript--深入探究JavaScript类型化数组

JavaScript类型化数组是一种特殊的数组类型&#xff0c;引入了对二进制数据的更底层的操作。这种数组提供了对内存中的二进制数据直接进行读写的能力&#xff0c;为处理图形、音频、视频等大规模数据提供了高效的手段。本文将深入探讨JavaScript类型化数组的基本概念、常见类型…

代码随想录算法训练营第六十天丨 单调栈03

84.柱状图中最大的矩形 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼应的。 为什么这么说呢&#xff0c;42. 接雨水 (opens new window)是找每个柱子左右两边第一个大于该柱子高度的柱子&#xff0c;而本题是找每个柱子左右两边第一个小于该柱子的柱子。 这里就涉…

机器人制作开源方案 | 智能照科植物花架

作者&#xff1a;付菲菲、于海鑫、王子敏单位&#xff1a;黑河学院指导老师&#xff1a;索向峰、李岩 1. 概述 1.1设计背景​ 随着时代的发展&#xff0c;城市化脚步加快、城市人口密度越来越大、城市生活节奏快压力大作息难成规律。城市建筑建筑面积迅速增加、而绿…

SpringCloud 微服务全栈体系(十五)

第十一章 分布式搜索引擎 elasticsearch 五、RestClient 操作文档 为了与索引库操作分离&#xff0c;再次参加一个测试类&#xff0c;做两件事情&#xff1a; 初始化 RestHighLevelClient酒店数据在数据库&#xff0c;需要利用 IHotelService 去查询&#xff0c;所以注入这个接…

Pandas数据集的合并与连接merge()方法_Python数据分析与可视化

数据集的合并与连接 merge()解析merge()的主要参数 merge()解析 merge()可根据一个或者多个键将不同的DataFrame连接在一起&#xff0c;类似于SQL数据库中的合并操作。 数据连接的类型 一对一的连接&#xff1a; df1 pd.DataFrame({employee: [Bob, Jake, Lisa, Sue], grou…

HDCTF2023 - Reverse方向全WP

文章目录 [HDCTF 2023]easy_re[HDCTF 2023]easy_asm[HDCTF 2023]fake_game[HDCTF 2023]enc[HDCTF 2023]double_code[HDCTF 2023]买了些什么呢[HDCTF2023]basketball [HDCTF 2023]easy_re UPX壳&#xff0c;脱壳 一个base64编码。 [HDCTF 2023]easy_asm ida打开后可以看到xor 10…

深入了解千兆光模块和万兆光模块

光模块是一种光电转换设备&#xff0c;在发射端&#xff0c;光模块能够将设备产生的电信号转换成光信号从而实现在光纤介质中传输&#xff0c;在接收端光模块将接收到的光信号再次转换为设备能够识别的电信号&#xff0c;从而实现高速、精准的数据传输。例如&#xff0c;在线视…

V100 GPU服务器安装CUDA教程

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

常见树种(贵州省):009楠木、樟木、桂木种类

摘要&#xff1a;本专栏树种介绍图片来源于PPBC中国植物图像库&#xff08;下附网址&#xff09;&#xff0c;本文整理仅做交流学习使用&#xff0c;同时便于查找&#xff0c;如有侵权请联系删除。 图片网址&#xff1a;PPBC中国植物图像库——最大的植物分类图片库 一、楠木 …