Qt系统学习第二章 Qt窗口系统 (资源文件图片添加, QDialog, QMessageBox, 布局, 控件, Qt样式表)

资源文件:

QMainWindow : 

在菜单栏中,文件下面的下拉框中,不能直接输入中文,可以先随便写个英文名,然后在对应所属的状态栏中找到,将text右侧的“save”改为“保存”,即可

 

  这里的“保存”和“打开”可以通过拖动鼠标来改变顺序

 

 

  将菜单栏中的按钮放入工具栏:在ui界面中的Action Editor里面选择要放入工具栏的action;然后鼠标点住别放,往工具栏中拖,若出现红色竖杠,就表示此处可以拖入,此时松开鼠标即可完成拖入。

 

 

  运行起来的程序,工具栏是可以自由拖动停靠的,要想不可拖动停靠,可以在ui界面的右侧的对象中找mainToolBar,在下面的属性中找QToolBqr,将movable后面的框框里,把对号去掉,就无法移动了,将allowedAreas

 

 

 控件中的Dock Widget是浮动窗口;属性中的floating是浮动与否,windowTitle是浮动窗口的小标题

 

 

QMenu (菜单栏)----- 只有一个

toolbar  (工具栏)----- 可以有很多个

dockwidget (浮动窗口)--可以有很多个

statusBar(下状态栏)----- 只有一个

 程序中,初始化一个变量的方式有两种: 在.h的private下面定义一个int number; 可以在.cpp中这样初始化.

 

qt中,通过代码添加资源文件(.qrc)如图:

 

方式一:

 

这种比较麻烦;

 

方式二:

可以通过右键左侧文件夹  ->  添加新文件->  文件和类"Qt"  ->  Qt Resource File  ->  choose  ->  指定名称(英文)  ->  .qrc 添加到文件  ->  完成  ->  项目所属的.pro中出现 Resource  += ***.qrc

此时左侧文件树中出现,双击resource.qsc是无法打开的, 此时想要编辑,应该鼠标右键单击resource.qrc  ->  Open With  ->  资源编辑器;

 

打开后, 点击 "添加" 按钮  ->  添加前缀  ->  修改前缀(最简单的前缀就是一个/)  ->  点击 "添加" 按钮  ->  添加文件  ->  将所用到的图标资源文件放入一个Image文件夹中, 再复制粘贴到工程所在目录中  ->  鼠标左键拉选所用图片  ->  选好后,点击右下方  "打开"  即可完成添加资源文件;

此时的左侧文件树可以看到资源文件, 同时, 可以在添加前缀那块在添加个文件前缀, 放别的资源文件进来, 方便后期项目过大时区分资源文件;同时,将.cpp文件中的资源文件地址更换

ui->actionsave_as->setIcon(QIcon(":/caidanlan/Image/1.jpg"));

 

 此时的程序编译时, 运行速度会变慢, 是因为编译器在编译的时候, 将我们所添加的资源文件, 转换成了二进制文件, 存入了程序中, 以后打包软件的时候,也将图片一起打包了就.

 

方式三:

添加完资源文件前缀及文件后,在.ui界面的Action Editor中,选择所要添加资源文件的action; 然后查看右侧的属性窗口里找icon点开下拉框后,找到Normal Off/On,然后点击其中一个右侧的 "..." ,弹出资源文件窗口;此时选择一个图标, 选择, 点击OK即可;此时出现图标,若想改变图标大小, 可在.ui界面的右侧的对象窗口里 找到并选中mainToolBar, 然后在右下角的属性窗口中,找到QToolBar  ->  iconSize, 在这里可以改变图标的宽高;iconText是图标文本内容; 当图标插入后,Qt默认不显示文字,可将鼠标悬浮于图标之上,1s后,可显示出提示文字;提示文字可在iconText同级下面一行的toolTip后面设置;

 

 

 

 

QDialog : 

模态对话框: 无法对对话框后的文件进行编辑或处理;且有系统提示音;

非模态对话框: 可以对对话框后的文件进行编辑或处理;

 

PS: 使用QT类主要记 这个类, 都有哪些信号, 和槽函数.  Qt中,用宏的时候,记不住宏的名字,也可以用宏编码

dlg->setAttribute(Qt::WA_DeleteOnClose);        //关闭窗口后,自窗口自动被析构.此处的是QObject派生的子类,父类窗口不关闭(析构),子类也不会被析构

//dlg->setAttribute(55); //在文档助手里,上述宏对应的编号就是55

 

 

QMessageBox:

提示对话框: 

 

 

本节代码如下:

mainwindow.cpp

复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug>
#include <QPushButton>
#include <QLabel>
#include <QDialog>       //对话框类
#include <QMessageBox>      //提示对话框
#include <QColorDialog>     //颜色对话框
#include <QFontDialog>      //字体对话框

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    number(10)      //初始化  方式1
{
    ui->setupUi(this);
    //number = 10;  //初始化  方式2
    //ui->menuEdit->addAction();
    connect(ui->actionopen, &QAction::triggered, this, [=]()
    {
//        //创建一个对话框
//        QDialog dlg(this);          //如果没有(this),意思是dlg是个独立的顶层窗口,加了(this)意思是,指定了父类是MainWindow(看本代码第九行)
//        //显示模态对话框   .exec()
//        dlg.exec();     //阻塞  关闭模态对话框后,程序才可以继续执行

//        QString name = QFileDialog::getOpenFileName(this, "打开文件", "D:\\", "Image (*.jpg *.png )");
//        qDebug() << name.toUtf8().data();       //qDebug不能直接打印Qstring类型的,需要先转成QByteArray{toUtf8()},,再转成char *QByteArray {data()}

        //QMessageBox::about(this,"about","*******");
        //QMessageBox::critical(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel);        //  |  是为了区分,在Open的时候可能会加参数,比如只读/只写,  QMessageBox::Ok 和QMessageBox::Cancel 对应的都是数值, 转换为二进制后, 只占其中一位.将这两个按位异或的方式放入整数里,占很多的位,通过对应位来判断所设属性
        //if(QMessageBox::Ok == QMessageBox::critical(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel))      //是个红色大错号
        //if(QMessageBox::Ok == QMessageBox::information(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel))  //是个蓝色感叹号
        //if(QMessageBox::Ok == QMessageBox::warning(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel))     //是个黄色感叹号, 并设置Cancel为默认按钮
//        if(QMessageBox::Ok == QMessageBox::question(this,"error","系统文件错误!!!",QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel))  //是个蓝色问号
//        {
//            QDialog dlg(this);
//            dlg.exec();
//        }
//        QColor color = QColorDialog::getColor();
//        qDebug() << color.red() << color.green() << color.blue();       //颜色对话框
        bool ok;
        QFont font = QFontDialog::getFont(&ok, QFont("华文彩云"), this, "我的字体设置");
        if(ok)
        {
            qDebug() << font.family() << font.italic() << font.pointSize() << font.bold();  //字体类型 << 倾斜与否  << 高度 << 加粗与否
        }


    });

    connect(ui->actionsave, &QAction::triggered, this, [=]()
    {
        //创建一个对话框
        QDialog *dlg = new QDialog(this);      //此时运行,非模态对话框一闪而过,此处new是为了不析构这个dlg,使对话框一直存在,也可以while(1){}
        //但是弊端是,这个程序运行起来后,有可能会反复点击一万次"save"按钮, 来创建这个窗口, 这就意味着被new了一万次, 但是一次都没被析构. 解决办法是 将QDialog *dlg定义为成员变量.这样就可以在外部释放,这样比较麻烦.
        //也可以设置对话框属性
        dlg->setAttribute(Qt::WA_DeleteOnClose);        //关闭窗口后,自窗口自动被析构.此处的是QObject派生的子类,父类窗口不关闭(析构),子类也不会被析构
        //dlg->setAttribute(55);        //在文档助手里,上述宏对应的编号就是55

        //显示非模态对话框   .show()
        dlg->show();     //非阻塞
    });

    ui->dockWidget->show();     //浮动窗口

    QPushButton* btn =  new QPushButton("hello",this);      //给下状态栏的左侧添加“hello”按钮
    ui->statusBar->addWidget(btn);  //下状态栏

    QLabel* label = new QLabel("world",this);               //给下状态栏“hello”按钮的左侧添加一个label显示内容为"world"
    ui->statusBar->addWidget(label);

    //ui->actionsave_as->setIcon(QIcon("D:\\1.jpg"));        //给菜单栏下拉框中的"save as"添加图标,图标路径为:D:/1.jpg

    //添加完资源文件后, 可用下面这种添加方式
    ui->actionsave_as->setIcon(QIcon(":/caidanlan/Image/1.jpg"));
}

MainWindow::~MainWindow()
{
    delete ui;
}
复制代码

 

 

 

布局:
一般ui界面中,常用的是前三种布局垂直布局, 水平布局, 网格布局.

 

 

水平布局:使所选空间处于水平位置;

    eg:在ui界面拖入两个label和两个Text Browser, 选中用户名和右边的Text Browser, 点击ui界面上方的水平布局,此时变为;

     但是不推荐使用,因为很容易水平变为右图这种; 顺序搞反后,不容易点击改变; 

 

 

    建议先放入一个widget窗口,再将用户名和Text Browser放入widget窗口,,选中widget窗口后,点击水平布局即可,,密码和Text Browser2,同理, 两个按钮同理,最上面的label不用管,如图,状态树的所属为:

 

 

 

垂直布局: 选中后, 点垂直布局, 变为: ;

 

 

此时拉拽ui界面, 按钮和框表会随之改变,要想让上方的label中的内容居中,可在对应label所属的属性框中找到,将水平的格式调为AlignVCenter,或者同理, 把label放入widget中, 再做一个水平布局;

 

 

加弹簧,弹簧也可以设置属性,sizeType中,Expanding,是默认可伸展的弹簧, Fixed是固定弹簧长度,

按钮固定大小:在按钮的属性框中,找到,将最大和最小的宽度设置为同一数值, 按钮大小就不会发生改变,或者两个按钮中间加个弹簧; 

 

 

水平和垂直布局只能改变一行或一列, 效果图如下

 

 

 网格布局:  打破用户名和密码的布局后,将这四个模块放入同一个widget,然后选择网格布局, 此时, , 将整个主窗口Widget垂直布局,将最大和最小的宽高都设置为192*173,此时:,用户名左侧边框太宽,可以在主窗口Widget的属性中,找到

 

将layoutLeftMargin 设置为0. Top是顶部间距, Right是右侧边距, Bottom是底部边距, Spacing是控件直接的默认边距

 

控件介绍:

Layouts(布局): 垂直 水平 网格 表格

 

Spaces(弹簧): 水平 垂直

 

Buttons(按钮): 

    Push Button  普通按钮  三种信号:点击clicked ;按下pressed ; 释放 released;  可以给按钮设置图标

    Radio Button 单选按钮  成组使用, ui界面的多个按钮只可点击一个.要想分两组使用, 将一组单选按钮放入Group Box框中. 比如性别 只有男女, 单选题.

    Check Box  复选按钮  可以有多个选择, 没有选择限制. 比如爱好, 多选题. 信号是stateChanged, 使用lambda表达式时,()中要加参数 int  state

    connect(ui->checkBox, &QCheckBox::stateChanged, this, [=](int state)
    {
        QMessageBox::information(this, "checkbox", QString::number(state));
        //QString::number(state) 把int型的state转为字符串
        qDebug() << state;    //选中复选框就打印2 未选就打印0
    });

Item Views 比较高级, 老师不给教

 

Item Widget:

    List Widget 数据一行一行的显示

    ui->listWidget->addItem("hello,world!");
    //QListWidgetItem* Item = new QListWidgetItem(QIcon("C:\\Users\\muchai\\Desktop\\1.jpg"),"l",ui->listWidget);
    //ui->listWidget->addItem(Item);
    ui->listWidget->addItem(new QListWidgetItem(QIcon("C:\\Users\\muchai\\Desktop\\1.jpg"),"1"));

 

 

 Table Widget 数据如Excel表显示, 有行列表格线.  使用时需要指定行数 列数;

复制代码
    //1、指定行数
    ui->tableWidget->setRowCount(100);
    //2、指定列数
    ui->tableWidget->setColumnCount(3);

    //给每列起名字
    QStringList list;
    list << "姓名" << "性别" << "年龄" ;
    //给每行起名字
    QStringList list2;
    list2 << "人员1" << "人员2" << "人员3";
    ui->tableWidget->setHorizontalHeaderLabels(list);
    ui->tableWidget->setVerticalHeaderLabels(list2);
复制代码

,框中可以进行编辑。

 

 

 

Group Box(组框):一般会将Radio Button放入组框中。

 

Scroll Area(滚动区域):很小的窗口,显示很多的内容

 

 

 

Tool Box:抽屉一样的盒子,像QQ的分组列表,点开后,里面的好友被弹出,Page里面可以放控件,比如在Page1中放入本例的Group Box1,在Page2中放入本例的Scroll Area

 

 

 

Tab Widget:选择页面,可以设置Tab按钮的位置,按钮文字。

 

 

 

Stacked Widget(栈窗口):可以设置多个页面,通过连接按钮来切换页面;连接按钮时,可在Stacked Widget的属性栏中的QStackedWidget下的currentIndex的数值来查看窗口序号,同时这个序号也是连接外部按钮的槽函数的参数(此法的槽函数带int型的参数,与button的clicked的bool返回值不匹配,一般使用lambda表达式作为槽函数使用,在lambda的{}中写槽函数返回)。除了用序号连接外部按钮外,还可以根据Stacked Widget对应的窗口属性栏中QObject下的objectName来连接。

 

复制代码
    //connect(ui->btn_music, &QPushButton::clicked, ui->stackedWidget, &QStackedWidget::setCurrentIndex());      //信号与槽返回值类型不匹配,前者为bool 后者为int
    connect(ui->btn_music, &QPushButton::clicked, this, [=]()
    {
        ui->stackedWidget->setCurrentIndex(0);          //参数可在ui界面的Stacked Widget的属性栏中的QStackedWidget下的currentIndex的数值来查看窗口序号
    });
    connect(ui->btn_tiktok, &QPushButton::clicked, this, [=]()
    {
        ui->stackedWidget->setCurrentWidget(ui->video);     //video是Stacked Widget对应的窗口属性栏中QObject下的objectName
    });
    connect(ui->btn_cale, &QPushButton::clicked, this, [=]()
    {
        ui->stackedWidget->setCurrentIndex(2);
    });
复制代码

 

 

 

Dock Widget(浮动窗口):可以停靠在主窗口边框,还可以独立出来的窗口

 

Combo Box(下拉框):可以通过additem添加字符串,直接加字符串就行,或者图标加字符串

 

Font Combo Box(下拉框):字体下拉框

 

Label(文本图形框):可以放入图片(静态、动态)或文字;在Qt中 Picture不是图片,Pixmap才是图片!!

复制代码
    //ui->label->setPixmap(QPixmap(":/Image/1.jpg"));
   
//      QMovie movie(":/Image/yaw.gif");    //这样不行,因为movie对象创建在构造函数里面,movie对象创建出来后,构造函数里面的对象就被析构了,movie在播放的时候就已经被析构掉了,播放不出来画面.
//      ui->label->setMovie(&movie);
//      movie.start();     
        
        QMovie* movie = new QMovie(":/Image/yaw.gif");
        ui->label->setMovie(movie);
        movie->start();    
复制代码

自定义控件: (封装SpinBox和水平进度条)

  Spin Box的默认大小是0-99; 可通过 setRang(0,10000) 来设置Spin Box的大小; 

 

  本节就是将这两个控件(Spin Box & 滑动条)封装成一个控件(widget窗口), 方便后期重复使用;

步骤:

  1. 先给项目中新建一个类

  选中项目的名字, 鼠标右键 -> 添加新文件; 此时可以添加一个C++-> C++ Class, 但是C++ Class不带ui界面, 需要用代码来创建控件和编辑其属性;故此处用Qt -> Qt设计师界面类 -> Widget(空白界面,所有类的父类) -> 在<类名:>后面的LineEdit中, 给封装的类起个响亮的名字(SmallWidget), 头文件、源文件、界面文件自动修改 -> 完成;

  2. 在smallwiddget.ui 中, 将Spin Box 和 水平滑动条放入, 将整个ui界面水平布局, 再将ui界面的窗口拖动到最小; 

  3. 此时在widget.ui中, 想用封装的自定义控件, 先在widget.ui中放入一个Widget控件(窗口), 鼠标右键单击刚放入的Widget窗口, 鼠标左键选择 "提升为..."; 在弹出的提升的窗口部件中,基类名称不用管, 在提升的类的名称中写入刚才创建的类的类名(SmallWidget), 写的时候注意大小写 !  头文件不用管, 选中全局包含(在项目中的任何一个窗口都可以使用此控件) , 点击 "添加"按钮. 添加完成后, 提升的类会上升到上面的窗口, 此时点击对话框底部的"提升"按钮, 回到widget.ui界面, 此时可以看到ui界面的右侧属性栏中, widget的类名称已改变成SmallWidget, 而不再是QWidget. 此时再拉入一个widget_2,右键单击 -> 左键 "提升为" -> SmallWidget (全局包含的意义:可不限制窗口的将一个QWidget类提升为SmallWidget类)

  此时的smallwidget.ui:

  此时的widget.ui:

 

   运行界面:

   4. 因为把SmallWidget封装成了一个类, 在SmallWidget类中维护这两个控件要在smallwidget.cpp中的构造函数中编写代码, 进行Spin Box于滑动模块的对应的信号槽连接,使Spin Box增大,滑块随之移动, 滑块移动, Spin Box随之改变; 

void (QSpinBox::*sigValeChange)(int) = &QSpinBox::valueChanged;       //Qt5中不能直接将信号直接写入connect(因为valuechanged是个重载信号),需要定义一个指针;
connect(ui->spinBox, sigValeChange, ui->horizontalSlider, &QSlider::setValue);      //&QSlider里面没有对应的槽函数, 它的父类QAbstractSlider里面有setValue
connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);  

   5. 提供接口函数, 在smallwidget.h的public中,定义接口函数

    int getValue();  //获取值
    void SetValue(int value);  //设置值 

   6. 在smallwidget.cpp中实现

复制代码
void SmallWidget::SetValue(int value)
{
    if(value > 0 && value < 100)
    {
        ui->spinBox->setValue(value);
    }
}
int SmallWidget::getValue()
{
    return ui->spinBox->value();
}
复制代码

 

Qt样式表

  在思想上很大程度来自于HTML的层叠式样式表(CSS), 通过调用 QWidget::setStyleSheet()或QApplication::setStyleSheet(),可为一个独立的子部件, 窗口, 甚至整个应用程序指定一个样式表; Qt样式表与CSS的语法几乎完全相同.

1. 语法基础: selector { attribute: value }      

  eg:(.cpp构造函数中)  ui -> label -> setStyleSheet ("QLabel { color: red} ");    //为一个独立的子部件指定一个样式表

  (.cpp构造函数中)       this -> setStyleSheet ("QLabel { color: red} ");         //为一整个窗口指定一个样式表(本例中,所有的label都是红色)

  (main.cpp中)      a.setStyleSheet ("QLabel { color: red} ");           //为整个应用程序指定一个样式表

  当为整个应用程序指定一个样式表后,可对其中的一个或多个窗口或子部件进行属性修改; 为窗口指定样式表后, 也可修改其中的子部件属性;

  

  选择器通常为一个类名 (eg: QComboBox), 属性(attribute)是一个样式表属性的名字, 值(value)是赋给该属性的值;

  为方便使用, 可使用以下简化形式的样式表:

  selector1, selector2, ... ... , selectorM 

  {

    attribute1: value1;

    attribute2: value2;

    ...

    attributeN: valueN;

  }

  这种简化形式可以同时为与M个选择器相匹配的部件设置N种属性

  QCheckBox, QComboBox, QSpinBox

  {

    color: red;

    background-color: white;

    font: bold;

  }

  这个规则设置了所有的QCheckBox, QComboBox和QSpinBox的前景色、背景色和字体

2. 方箱模型: 样式表中, 每个部件都可看成是一个由四个同心的矩形组成的箱体(方框套方框);

  空白(margin): 空白区域位于边框外, 且总是透明

  边框(border): 为部件提供了四周的框架, 其border-style属性可以设置为一些内置的框架风格,如inset, outset, solid, ridge;

  填充(padding):填充在边框和内容区域之间, 提供了空白间隔.

  内容(content): 对于一个平面部件, 例如一个空白、边框和填充都是0像素的部件而言,这四个矩形完全重合;

3. 前景和背景

  前景用于绘制上面的文本, 可以通过color: 属性指定, 背景色用于绘制部件的填充矩形, 可以通过 background-color: 属性指定; 

  背景图片使用background-image 属性定义,用于绘制由background-origin指定的矩形区域(空白, 边框, 填充, 内容), 对齐和平铺方式可以通过background-position和background-repeat属性指定;

4. 可伸缩样式:  

  默认情况下, 通过background-image指定的背景图片会自动重复平铺,以覆盖部件的整个填充矩形,若我们想创建能够随着部件大小自动缩放,而不是平铺的背景,我们需要设置"边框图片".  通过border-image:  指定属性;

  QPushButton{

    border-width: 4px; 

    border-image: url(button.png);  /*4 4 4 4 stretch stretch*/     }  //注释里的是往里裁剪图片的属性, 设的越大,裁的越多;

5. 控制大小:min-width, min-height (不常用,因为可以直接在ui界面属性栏中控制) 

6. 伪状态;

    ui -> pushButton -> setStyleSheet("QPushButton

    {"

      "border: 2px outset green;"    //按钮边框为绿

    "}");

伪状态列表:

:checked    button部件被选中

:disabled    部件被禁用

:enable       部件被启用

:fouces     部件获得焦点

:hover         鼠标位于部件上

:indeterminate  checkbox或radiobutton被部分选中

:off       部件可以切换, 且处于off状态

:on       部件可以切换, 且处于on状态

:pressed       部件被鼠标按下

:unchecked   button部件未被选中

    ui -> pushButton -> setStyleSheet("QPushButton

    {"

      "border-image:url(:/1.jpg);"    //按钮设置图标

    "}");

   

    ui -> pushButton -> setStyleSheet("QPushButton:hover

    {"

      "border-image:url(:/1.jpg);"    //鼠标位于按钮上,按钮图标亮出

    "}");

 

 

posted @   大白不会敲代码  阅读(1476)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示