Qt学习笔记(更新至Qt样式表)

Qt学习笔记

1、创建第一个工程与Qt的工程结构

类信息

类名自己写就行了

基类主要是QMainWindow(PC端用),最常用的是QWidget,还有一个对话框,一般是选中间那个

左下角是运行,调试,编译不运行

工程结构是main.cpp,派生类名.cpp,派生类名.h

Qt的头文件没有.h,头文件和类名一样,前两个字母大写

比如QApplication应用程序类,并且这个对象有且只有一个。

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    //应用程序类的对象有且只有一个
    QApplication a(argc, argv);
    //窗口类,继承来自QWidget类
    Widget w;//w就是一个窗口
    w.show();//窗口创建默认隐藏,必须用show方法显示
    //return 后面那个就是等待事件发生
    return a.exec();
}

以下是我们自己的程序的框架

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    //应用程序类的对象有且只有一个
    QApplication a(argc, argv);
    //自己程序的内容
    return a.exec();
}

派生类的头文件内容

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT //信号与槽的时候需要这个东西

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
};
#endif // WIDGET_H

工程配置文件

#模块,在下面有讲
QT       += core gui

#对Qt4版本以下的兼容
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS

#应用程序名字,这个不会自动生成
TARGET = Vp_SoLo
#生成类型,也可以生成lib类型
TEMPLATE = app
#
SOURCES += \
    main.cpp \
    widget.cpp

HEADERS += \
    widget.h

TRANSLATIONS += \
    test_zh_CN.ts

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

Qt5模块

工程文件自动指定了core gui,其实还有很多基本模块。

img

2、第一个Qt程序

空项目的建立方法

新建时选择其他项目然后选择Empty qmake Project

对于很空的项目,我们要去右键项目文件夹,选择Add New

添加一个c++的源文件并把它命名成main

#include <QApplication>
#include <QWidget>
//开始从头写,头文件,QApplication,QWidget
int main(int argc, char **argv){
    //写主函数,参数弄好,先创建应用程序对象,再创建一个窗口对象
    QApplication app(argc , argv);

    QWidget w;
    //调用个方法测试测试
    w.setWindowTitle(QString("测试"));
    w.show();


    app.exec();
    return 0;
}

第一个HelloWorld级别的程序就写完了

3、指定父对象

给上面的窗口添加一个控件吧,比如按钮

引入按钮所在的头文件

#include <QPushButton>

再给他创建一个按钮对象,注意,所有对象必须调用show方法才能显示

QPushButton b;
b.setText("test");
b.show();

但是呢,不指定父对象的话,对象和对象就成了一个又一个窗口

所以必须指定父对象

两种方法

1)setParent

2)构造函数传递参数

具体代码-方法一

QPushButton b;
b.setText("test");
b.setParent(&w);//通过看函数的提示发现参数是个指针

具体代码-方法2

QPushButton b1(&w);

效果

指定父对象显示,子对象自动显示

整个文件这个样子

#include <QApplication>
#include <QWidget>
#include <QPushButton>

int main(int argc, char **argv){
    QApplication app(argc , argv);

    QWidget w;
    w.setWindowTitle(QString("测试"));

    QPushButton b;
    b.setText("test");
    b.setParent(&w);

    w.show();


    app.exec();
    return 0;
}

按钮默认位置在左上角,移动需要调用move方法,坐标原点在左上角

b.move(100,100);

4、信号和槽

对于3的补充

我们甚至可以这样:

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QWidget>
#include <QPushButton>

class MainWidget : public QWidget
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = nullptr);
    ~MainWidget();
private:
    QPushButton b;
    QPushButton *b2;
};
#endif // MAINWIDGET_H

这是在类的头文件做的手脚,干脆写成私有成员变量

然后在类的实现文件里面这么写:

#include "mainwidget.h"
#include <QPushButton>

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    b.setParent(this);
    b.setText("close");
    b.move(100,100);

    b2 = new QPushButton(this);
    b2->setText("abc");

}

MainWidget::~MainWidget()
{
}

这就是对于前面的补充

理解信号和槽

用我自己的理解

信号:对象发出消息

槽:消息处理函数

应用-标准信号和槽

用connect()函数处理信号和槽,以标准信号为例,比如我要接收一个按钮的按下信号,传递给窗口,让其关闭,一般是调用槽函数

connect(发出信号对象的地址,信号,接收对象,槽函数)

代码实现如下:

connect(&b,&QPushButton::pressed,this,&MainWidget::close);
}
/*
&b:信号发出者:指针类型
&QPushButton::pressed:处理的信号
this:信号接收者,指针类型
&MainWidget::close:槽函数名字
*/

5、自定义槽函数

在Qt5中,自定义槽函数可以是成员函数,也可以是普通全局函数,一句话,槽函数。

槽函数需要和信号一致(指参数和返回值)

自己写个最简单最直观的成员函数,点击改变按钮字符

void MainWidget::mySlot(){
    b2->setText("123");
}

由于b2已经是指针类型,所以connect函数不必取地址

connect(b2,&QPushButton::released,this,&MainWidget::mySlot);

经过测试还是很成功的

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    b.setParent(this);
    b.setText("close");
    b.move(100,100);

    b2 = new QPushButton(this);
    b2->setText("abc");

    connect(&b,&QPushButton::pressed,this,&MainWidget::close);
    connect(b2,&QPushButton::released,this,&MainWidget::mySlot);
}

整个MainWidget的构造函数长这个样子

一个对象的同一信号被多个槽接收

这是合法的,比如

connect(b2,&QPushButton::released,this,&MainWidget::mySlot);
    connect(b2,&QPushButton::released,&b,&QPushButton::hide);

合法有效

6、典型问题-两个独立窗口

理论上

**不就是两个QWidget的派生类吗,**这样理解的话编程思路就很清晰了

操作上

就是新建一个类呗,指定基类为QWidget

创建好后,写一个按钮,并且写一些装饰性的工作:

this->setWindowTitle("child");
b.setParent(this);
b.setText("jump to parent");

按钮对象已经在新的窗口类中声明成了私有成员变量

如何创建联系?

如果有过MFC基础的同学可以很自然的想到在主要窗口的头文件中包含其他窗口的头文件

并且创建信号和槽的关系,自己写一个自定义槽函数

完整代码如下

#include "mainwidget.h"
#include <QPushButton>

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle("farther");

    b3.setParent(this);
    b3.move(50,50);
    b3.setText("jump to child");
    connect(&b3,&QPushButton::released,this,&MainWidget::jump);

}
void MainWidget::mySlot(){
    b2->setText("123");
}
void MainWidget::jump(){
    w.show();
    this->hide();
}
MainWidget::~MainWidget()
{
}


实现第一个窗口跳转到第二个窗口

那么如何实现第二个窗口跳转回第一个窗口?请看自定义信号

7、自定义信号

用处

自定义信号是用来进行窗口和窗口间的一个通信的

为何要这么实现

在子窗口中,如果我们include父窗口的头文件就会引发灾难性错误,显然,相互引用的方法是行不通的,必须找别的方法。

所以要借助自定义信号

如何实现

在子窗口的头文件里,我们可以看到这么一个东西

signals:
    
};

这就是用户自定义信号的地方。

自定义信号要求

没有参数也没有返回值,实际上他就是一个信号。

触发自定义信号

我们还是用学过的信号和槽的概念,当子窗口的按钮被按下,让他触发一个槽函数,这个槽函数用于把自定义信号传播到其他窗口

connect(&b,&QPushButton::clicked,this,&NewWidget::sendSignal);

这个是槽函数写法

void NewWidget::sendSignal(){
    emit mySignal();
}

emit是关键字,英文意思就是散发,很好理解,就是把这个信号传播出去

接收自定义信号

在父窗口,我们要捕获子窗口对象w的自定义信号,所以要监听子窗口,绑定信号和槽函数

connect(&w,&NewWidget::mySignal,this,&MainWidget::dealSub);

槽函数就很简单啦,隐藏子窗口,显示父窗口

void MainWidget::dealSub(){
    w.hide();
    this->show();
}

这样就实现了两个窗口对象通讯

8、有参数的信号

信号也可以重载

void mySignal(int ,QString);

如何接收?这里可以借助函数指针

void (NewWidget::*funSignal)()=&NewWidget::mySignal;
    connect(&w,funSignal,this,&MainWidget::dealSub);

    void (NewWidget::*testSignal)(int,QString)=&NewWidget::mySignal;
    connect(&w,testSignal,this,&MainWidget::dealSlot);

这样,区分重载后的信号,就可以做到分别接收了

Qt4写法和为什么不建议用Qt4写法

connect(&w,SIGNAL(mySignal()),this,SLOT(dealSub()));
    connect(&w,SIGNAL(mySignal(int,QString)),this,SLOT(dealSub()));

SIGNAL和SLOT会将后面的转换为字符串而不检查错误,相当于宏定义,编译时不会检查错误,只有在运行时才会提示错误

9、Lambda表达式与信号

这是C++11引入的功能,需要在配置文件里面写入一下来启动Lambda表达式

CONFIG += C++11

lambda函数在python应该有接触过,不过在python用的不是很明白

用lambda函数可以简化对于本窗口对象的成员对象的操作,比如点击改变按钮本身的文字,之前我们要借助自定义槽函数来实现(详情见第五节

为了方便索性直接用指针对象

如果用lambda表达式就可以这么写:

	QPushButton *b4 = new QPushButton(this);
    b4->setText("Lambda");
    b4->move(150,150);
    int a=1,b=2;
    connect(b4,&QPushButton::released,
            //[]内的等号是把所有局部变量,类中全部成员以值传递进来
            //值传递就意味着只读
            [=](){
        b4->setText("success");
        qDebug()<<a<<b;
    });    
    resize(400,300);

如何变成可写的?

[=]() mutable{
        b4->setText("success");
        qDebug()<<a<<b;
    });

mutable关键字就可以把传进来的变量设置为可写(比如给a赋新的值)

中括号

[]内部可以填写这几个:

=:上面用了

this:把类中所有成员以值传递

&:引用独好,把外部的所有局部变量

不建议使用第三种,涉及到内存释放和不释放的问题

第一种虽然是把他复制过来慢了点但是还是比较好的

带参数的信号给lambda函数传入参数

[=](参数类型 信号的参数名……){
	lambda函数语句体
}

总结,lambda表达式结构:

[=]() {
	lambda函数语句体
}

信号是谁发出来的?

子窗口点击按钮信号是谁发出的?

很明显啊,信号属于谁,谁就发出来

信号属于子窗口,自然是子窗口发出的

10、坐标系统

对于一个应用程序的父窗口,他的坐标系统相对于屏幕

原点位于屏幕左上角

x:向右递增

y:向下递增

如果坐标是负数就会移除屏幕一部分,如果足够大窗口就跑没了

指定了父对象的子对象

当然是从父对象的左上角开始算起的坐标系统

MainWidget::MainWidget(QWidget *parent)
    : QWidget(parent)
{
    move(100,100);

    resize(400,400);
    QPushButton *b = new QPushButton(this);
    b->move(100,100);
    b->setText("test");
    b->resize(100,100);

    QPushButton *b2 = new QPushButton(b);
    b2->setText("child_child");
    b2->resize(50,50);
}

比如上面按钮内套了个按钮

11、内存回收机制

指定父对象并且是直接或间接继承于QObject

如果子对象是动态分配内存的(new)

不需要手动释放delete,系统会自动释放内存

12、菜单栏-工具栏

构建菜单栏和工具栏需要用到一系列头文件

#include <QMenuBar>
#include <QMenu>
#include <QAction>

菜单栏

在窗口的构造函数这样写:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    //菜单栏
    QMenuBar *mBar = menuBar();

    //添加菜单
    QMenu *pFile = mBar->addMenu("文件");

    //添加菜单项
    QAction *pNew = pFile->addAction("新建...");
}

怎么实现菜单项的动作?自然是捕捉他的信号

通过查询帮助文档发现有个叫triggered的信号,connect函数自然是这么写了:

connect(pNew,&QAction::triggered,
    [=]()
    {
        qDebug()<<"test";
    });

用到了lambda表达式,是不是很简单啊

一个菜单多个菜单项怎么办?

很简单啊,在刚才那个菜单指针那里再添加一个选项卡指针不就行了?

多菜单项如下:

 //添加菜单项
    QAction *pNew = pFile->addAction("新建...");
    connect(pNew,&QAction::triggered,
    [=]()
    {
        qDebug()<<"new test";
    });
    QAction *pOpen = pFile->addAction("打开...");
    connect(pOpen,&QAction::triggered,
    [=]()
    {
        qDebug()<<"open test";
    });

工具栏

菜单项的快捷方式,参考word下面那一串小图标(点击图标就能快速执行一些操作)

需要引入头文件

#include <QToolBar>

代码和注释如下:

//工具栏,就是菜单项的快捷方式
    QToolBar *toolBar = addToolBar("toolBar");

//工具栏添加东西
    QPushButton *b = new QPushButton(this);
    b->setText("test");
    connect(b,&QPushButton::released,
            [=](){
        qDebug()<<"toolbar pressed";
        b->setText("success");
    });
//添加
    toolBar->addWidget(b);

就把一个按钮添加进去并且处理它的信号

13、状态栏

就是左下角的一个小东西

添加方法如下:

	QStatusBar *stBar = statusBar();
  	QLabel *label = new QLabel(this);
    label->setText("label test");
    stBar->addWidget(label);

添加菜单项是addAction,而工具栏和状态栏则是addWidget

简单点写呢?

通过观察QLabel的构造函数的重载,我们发现还能在new新的label对象的时候同时指定文字和父对象,故有下列代码

stBar->addWidget(new QLabel("2",this));

多个状态栏默认是从左往右依次添加

状态栏对象的addPermanentWidget()方法就是从右往左添加

14、核心部件和浮动窗口

核心部件举例:文本编辑区

基本上用到啥部件就要包含他的头文件

比如文本编辑框的头文件就是

#include <QTextEdit>

继续在构造函数里面写

QTextEdit *textEdit = new QTextEdit(this);
//设置为核心部件
setCentralWidget(textEdit);

就目前来看,核心部件好像是直接占满除了工具栏状态栏的空间,如果有误,笔者会在后续的笔记中纠正错误

浮动窗口

浮动窗口需要引入头文件

#include <QDockWidget>

声明对象的时候,使用动态内存分配是个好的技巧

 //浮动窗口
QDockWidget *dockWidget = new QDockWidget(this);
addDockWidget(Qt::RightDockWidgetArea,dockWidget);

需要说明的是第二个函数

对于函数的帮助文档,我们可以先随便填两个参数,然后按F1即可打开帮助文档

比如此处第一个参数的意思就是浮动窗口初始贴在右边

给浮动窗口内部添加控件

    QTextEdit *textEdit1 = new QTextEdit(this);
    dockWidget->setWidget(textEdit1);

稍微要注意的是给浮动窗口添加控件,并不影响该控件的父对象还是指向整个应用程序窗口

至于是setWidget还是add什么什么。。提示函数应该会有

15、模态和非模态对话框

什么意思

模态的对话框,意思就是只能操作当前对话框,对话框背后的界面在对话框尚未关闭之前不能再次操作

非模态就是随便操作

代码实现

模态对话框
    QMenuBar *mBar = new QMenuBar(this);
    setMenuBar(mBar);
    QMenu *menu = mBar->addMenu("dialog");
//菜单栏固定套路
    QAction *p1 = menu->addAction("this is a model dialog");
    connect(p1,&QAction::triggered,
            [=](){
        QDialog dlg;
                //等待用户操作
        dlg.exec();
        qDebug()<<"test";
    });

点击菜单栏第一个选卡的第一个选项弹出他来

非模态
 QAction *p2 = menu->addAction("this is a normal dialog");
    connect(p2,&QAction::triggered,
            [=](){
        QDialog dlg2;
        dlg2.show();
        qDebug()<<"test2";
    });

但是要是只这么写,对话框就会一闪而过,为什么呢

这就是生命周期的问题了,函数被执行完,里面的变量就被销毁了

而这个对话框作为它的一个成员变量,自然被销毁了

非模态的注意事项

怎么解决呢?思路有不少,比如干脆把他声明成类的一个成员变量,主窗口关闭时才被销毁

还有一个就是直接动态分配内存,就是new的方法。。

其实养成上面良好的习惯不就可以避免这个问题吗(Qt都是智能指针,内存泄漏问题可以不用担心)

 QDialog *dlg2 = new QDialog(this);
 dlg2->show();
 qDebug()<<"test2";

建议就是模态了

16、标准对话框和文件对话框

需要包含头文件

#include <QMessageBox>

“关于”对话框

查看帮助文档这个是个静态成员,不用分配新的对象,直接调用

还是借助刚才的窗口

QAction *p3 = menu->addAction("this is a about dialog");
    connect(p3,&QAction::triggered,
            [=](){
        QMessageBox::about(this,"about","about this project");
    });

问题对话框

不必引入新的头文件

还是借助窗口菜单

QAction *p4 = menu->addAction("this is a question dialog");
    connect(p4,&QAction::triggered,
            [=](){
        int ret = QMessageBox::question(this,"qusetion","Are you ok?",QMessageBox::Yes |QMessageBox::No);
        switch (ret) {
        case QMessageBox::Yes:
            qDebug()<<"i am ok";
            break;
        case QMessageBox::No:
            qDebug()<<"i am not ok";
            break;
        }
    });

需要说一下question

查阅帮助文档

[static] int QMessageBox::question(QWidget *parent, const QString &title, const QString &text, int button0, int button1 = 0, int button2 = 0)

需要传入父对象,标题,内容文字,第一个按钮,第二个按钮,第三个按钮

Opens a question message box with the given title and text. The dialog may have up to three buttons. Each of the buttons, button0, button1 and button2 may be set to one of the following values:

If you don’t want all three buttons, set the last button, or last two buttons to QMessageBox::NoButton.

它内部其实是个枚举类型,这个被点击之后会返回一个整数,可以用switch语句判断,这就是为什么赋值然后判断的原因

文件对话框

这个就有点意思了

QAction *p5 = menu->addAction("this is a file dialog");
    connect(p5,&QAction::triggered,
            [=](){
        QString path = QFileDialog::getOpenFileName(this,"open","../","souce(*.cpp);;Text(*.txt);;All(*.*)");
        qDebug()<<path;
    });

帮助文档是这么写的

[static] QString QFileDialog::getOpenFileName(QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString(), const QString &filter = QString(), QString *selectedFilter = nullptr, QFileDialog::Options options = Options())

这个怎么用呢,它会返回一个文件的路径,所以要用QString类型的对象接收,所以在实际应用的代码里面也是这么体现的

参数呢,还是绑定父对象,第二个参数以字符串传入,传入open就是打开文件界面,第三个就是默认路径,第四个参数是筛选类型,每种类型之间用双分号**(;;)**隔开,格式就是

你要显示的类型名字(*.拓展名)

挺复杂的吧,但是用起来看到打开文件的界面,内心感觉还是挺神奇的

17、UI界面设计

上Qtdesigner设计是不是就很方便啊

image-20210310185901192

左侧是UI控件列表,右侧是一系列被放置的控件的属性调整列表

有了ui文件之后,怎么访问我们的控件呢?

ui->b1->setText("2333");

也就是说,调用有ui的部件用指针访问成员对象的方法来访问就好

18、常用控件01和信号与槽的便捷设置

左侧有分类,具体可以去看

这个不是重点,重点是新的信号和槽的连接方法

右键按钮,有一个转到槽

image-20210310204224123

右键,选择自己想要的槽函数

image-20210310204439824

转到编辑界面,发现自动的多了个函数,不需要用connect函数链接

image-20210310204636810

比如有一个栈容器,我们要在按钮点击时切换指定的页面,我们就可以在刚才的槽函数里面这么写:

void MainWindow::on_b2_clicked()
{
    static int i=0;
    i =++i %2;
    ui->stackedWidget->setCurrentIndex(i);
}

这里,是不会提示ui的成员变量有这么个东西,但是写上就行,不会报错,效果正常

QtLineEdit

这个控件比较重要,拿出来单独讲讲

void MainWindow::on_b4_clicked()
{
    ui->lineEdit->setText("success");
//    ui->lineEdit->setEchoMode(QLineEdit::Password);

}

这里,是不会提示ui的成员变量有这么个东西,但是写上就行,不会报错,效果正常

更换文字试一下,成功

如果想要实现它的补全提示,那么就要引入这俩头文件

#include <QCompleter>
#include <QStringList>

然后在构造函数里面写这些玩意

	QStringList ls;
    ls<<"hello"<<"how are you"<<"haha";

    QCompleter *com = new QCompleter(ls,this);
    com->setCaseSensitivity(Qt::CaseInsensitive);

    ui->lineEdit->setCompleter(com);

19、常用控件02

QLabel是我们最常用的控件之一,其功能很强大,我们可以用来显示文本,图片和动画等。

显示文字 (普通文本、html)

通过QLabel类的setText函数设置显示的内容:

void  setText(const QString &)

l 可以显示普通文本字符串

QLable *label = new QLable;

label->setText(“Hello, World!);

l 可以显示HTML格式的字符串

比如显示一个链接:

QLabel * label = new QLabel(this);

label ->setText("Hello, World");

label ->setText("<h1><a href=\"https://www.baidu.com\">

百度一下</a></h1>");

label ->setOpenExternalLinks(true);

其中setOpenExternalLinks()函数是用来设置用户点击链接之后是否自动打开链接,如果参数指定为true则会自动打开,如果设置为false,想要打开链接只能通过捕捉linkActivated()信号,在自定义的槽函数中使用QDesktopServices::openUrl()打开链接,该函数参数默认值为false

QLabel * label = new QLabel(this);

label ->setText("Hello, World");

label ->setText("<h1><a href=\"https://www.baidu.com\">

百度一下</a></h1>");

// label->setOpenExternalLinks(true);

connect(label, &QLabel::linkActivated, 

this, &MyWidget::slotOpenUrl);

 

//槽函数  

void MyWidget::slotOpenUrl(const QString &link)

{

  QDesktopServices::openUrl(QUrl(link));

}

显示图片

可以使用QLabel的成员函数setPixmap设置图片

void  setPixmap(const QPixmap &)

首先定义QPixmap对象

QPixmap pixmap;

然后加载图片

pixmap.load(":/Image/boat.jpg");

最后将图片设置到QLabel中

QLabel *label = new QLabel;
label.setPixmap(pixmap);

显示动画

可以使用QLabel 的成员函数setMovie加载动画,可以播放gif格式的文件

void  setMovie(QMovie * movie)

首先定义QMovied对象,并初始化:

QMovie *movie = new QMovie(":/Mario.gif");

播放加载的动画:

movie->start();

将动画设置到QLabel中:

QLabel *label = new QLabel;
label->setMovie(movie);

20、布局

选择东西才能布局啊

布局有俩概念,一个是局部,一个是整体

局部布局就是圈起来一部分控件,然后点击布局按钮

image-20210314095214605

前四个别管,第五个开始时水平布局,垂直布局,分裂水平,分裂垂直,(后面俩没用过),跳出布局,调整大小

局部布局

image-20210314095715203

圈起来点击,就能进行局部的水平布局,局部布局的效果就是只能作用于局部而非全部区域,比如拉动窗口不会适应变形

整体布局

image-20210314095847314

比如这样,点击应用窗口的空白地方点击布局就能进行整体布局,效果就是会随着窗口变而随时调整空间大小

image-20210314095957581

image-20210314100012450

比如这样。。

可以在右侧观察是整体还是局部

image-20210314100202765

比如现在就是整体(指布局图标在centralwidget)

网格布局

就比较神奇。。

会根据你的控件大小来分配排放方式,也会强行改变你的控件大小

image-20210314100935275

弹簧和布局

很神奇的玩意

image-20210314101504521

这是弹簧被全局水平布局的效果

选中中间的弹簧,我们就能看到这些属性,sizeType的话,如果是不想让中间的弹簧那么大,我们可以选择Fixed,然后在下面调整大小,就能缩短弹簧了

image-20210314101701629

分裂布局

其实还是蛮好理解的,使用起来也基本没啥区别。。

嵌套

image-20210314102309331

可以看到,局部弄了个分裂布局,整体网格布局

内部两个文本框是可以随意拉动的

布局属性

image-20210314102804419

看右下角就是布局属性,可以调整左右,每个控件的间隔

你已经学会了吧,做个登陆器页面布局吧

image-20210314105037079

image-20210314105056435

海星。。

21、自定义控件

自己写个类,然后弄进去新建一个类,然后继承自QWidget,之后编写自己的Widget里面有的东西

之后呢,返回你要插入自定义组件的窗口,右键对应的QWidget对象,选提升为

image-20210314124458670

在下面的新建提升的类里写上自己写好的自定义组件

image-20210314124553884

之后点添加

image-20210314124618545

上面就变了

image-20210314124640494

然后点提升,提升不会马上在编辑里面实现,运行时就会显现

自定义控件的信号和槽函数

这个,和之前的处理方法一样,只不过在自定义控件自己的cpp文件里面写就行了

22、Qt样式表

写过CSS基本都明白

还是在构造函数里面写

ui->label->setStyleSheet("QLabel{color:red;}");

什么意思就8用我说了吧,大概就是调用对象的setStyleSheet方法,然后写QSS(我管他叫QSS(neta CSS))

image-20210316202325120

image-20210316202348715

就是这,梦回前端开发和微信小程序开发

那啥意思呢,怎么控制css选择器呢?

如果把上面的代码改成这样

image-20210316202632059

就是对这个窗口所有的QLabel类对象都进行样式设置

css适用的继承规则在这里也是用,其实就是表达最具体的样式,子样式覆盖父样式

image-20210316203026579

xed,然后在下面调整大小,就能缩短弹簧了

[外链图片转存中…(img-4k1oubPP-1616894545489)]

分裂布局

其实还是蛮好理解的,使用起来也基本没啥区别。。

嵌套

[外链图片转存中…(img-7O0jnpfK-1616894545489)]

可以看到,局部弄了个分裂布局,整体网格布局

内部两个文本框是可以随意拉动的

布局属性

[外链图片转存中…(img-HeeNjTrC-1616894545490)]

看右下角就是布局属性,可以调整左右,每个控件的间隔

你已经学会了吧,做个登陆器页面布局吧

[外链图片转存中…(img-UbKtu2Us-1616894545491)]

[外链图片转存中…(img-cj5iGquN-1616894545492)]

海星。。

21、自定义控件

自己写个类,然后弄进去新建一个类,然后继承自QWidget,之后编写自己的Widget里面有的东西

之后呢,返回你要插入自定义组件的窗口,右键对应的QWidget对象,选提升为

[外链图片转存中…(img-K8B5jqmi-1616894545492)]

在下面的新建提升的类里写上自己写好的自定义组件

[外链图片转存中…(img-NMpr43QT-1616894545493)]

之后点添加

[外链图片转存中…(img-D3a2eHxJ-1616894545494)]

上面就变了

[外链图片转存中…(img-2OPBsSDr-1616894545495)]

然后点提升,提升不会马上在编辑里面实现,运行时就会显现

自定义控件的信号和槽函数

这个,和之前的处理方法一样,只不过在自定义控件自己的cpp文件里面写就行了

22、Qt样式表

写过CSS基本都明白

还是在构造函数里面写

ui->label->setStyleSheet("QLabel{color:red;}");

什么意思就8用我说了吧,大概就是调用对象的setStyleSheet方法,然后写QSS(我管他叫QSS(neta CSS))

[外链图片转存中…(img-wpBfC5vO-1616894545496)]

[外链图片转存中…(img-Zg9G6Ddr-1616894545496)]

就是这,梦回前端开发和微信小程序开发

那啥意思呢,怎么控制css选择器呢?

如果把上面的代码改成这样

[外链图片转存中…(img-YuMvOU3z-1616894545497)]

就是对这个窗口所有的QLabel类对象都进行样式设置

css适用的继承规则在这里也是用,其实就是表达最具体的样式,子样式覆盖父样式

[外链图片转存中…(img-9zUzIQ45-1616894545498)]

image-20210316203037682

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值