Qt开发 | Qt界面布局 | 水平布局 | 竖直布局 | 栅格布局 | 分裂器布局 | setLayout使用 | 添加右键菜单 | 布局切换与布局删除重构

文章目录

  • 一、Qt界面布局
  • 二、Qt水平布局--QHBoxLayout
  • 三、Qt竖直布局
  • 四、Qt栅格布局
  • 五、分裂器布局代码实现
  • 六、setLayout使用说明
  • 七、布局切换与布局删除重构
    • 1.如何添加右键菜单
    • 2.布局切换与布局删除重构

一、Qt界面布局

  Qt的界面布局类型可分为如下几种

  • 水平布局(Horizontal Layout)

    水平布局将控件水平排列。控件按照从左到右的顺序排列,可以设置控件之间的间距。

  • 竖直布局(Vertical Layout)

    竖直布局将控件垂直排列。控件按照从上到下的顺序排列,也可以设置控件之间的间距。

  • 栅格布局(Grid Layout)

    栅格布局将控件排列在网格中。你可以指定控件的行和列,以及行和列的间距。栅格布局非常适合需要将控件整齐排列在表格中的场景。

  • 分裂器布局(Splitter Layout)

    分裂器布局允许用户通过拖动分隔条来调整相邻控件的大小。这种布局通常用于需要动态调整空间分配的界面,例如在文本编辑器中调整工具栏和文本区域的大小。

除了这些基本布局,Qt 还提供了其他一些布局管理器,例如:

  • 表单布局(Form Layout):用于创建表单界面,控件和标签按照两列排列。
  • 堆栈布局(Stack Layout):允许在同一个空间内堆叠多个控件,并且一次只能显示一个。
  • 工具箱布局(Tool Box Layout):类似于网页上的选项卡,允许用户在多个页面之间切换。

ui设计器设计界面很方便,为什么还要手写代码

  • 更好的控制布局
  • 更好的设置qss
  • 代码复用

二、Qt水平布局–QHBoxLayout

介绍手写水平布局,不使用ui设计器来设置布局,因此,可将ui文件等删掉

  • 创建水平布局

    #include <QHBoxLayout>
    QHBoxLayout *pHLay = new QHBoxLayout(父窗口指针); //一般填this
    
  • 相关方法

    • addWidget:在布局中添加一个控件
    • addLayout:在布局里添加布局
    • setMargin:设置水平布局最外边界与相邻空间左上右下的间隙,这时左上右下的间隙相同;如果想设置成不同,可以使用setContentMargins方法
    • setSpacing:设置相邻控件之间的间隙,默认值大概是7
    • addSpacing:在setSpacing的基础上进行相加,例如:addSpacing(-7),相当于两个控件之间没有距离;addSpacing(13)相当于setSpacing(20);
    • addStretch:在水平布局时添加一个水平的伸缩空间(QSpacerItem),在竖直布局时,添加一个竖直的伸缩空间

示例:

xx.h

#pragma once

#include <QtWidgets/QWidget>

class ch2_3_hLayout : public QWidget
{
    Q_OBJECT

public:
    ch2_3_hLayout(QWidget *parent = Q_NULLPTR);

};

xx.cpp

#include "ch2_3_hLayout.h"
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QDebug>

ch2_3_hLayout::ch2_3_hLayout(QWidget *parent)
    : QWidget(parent)
{
    this->resize(400, 80);
    //新建三个控件
    QLabel* pPath = new QLabel(this);
    pPath->setObjectName("pPath");
    //pPath->setFixedSize(40, 32);
    pPath->setText(u8"路径");

    QLineEdit* pEdit = new QLineEdit(this);
    pEdit->setObjectName("pEdit");
    //pEdit->setFixedSize(100, 32);
    pEdit->setMinimumWidth(50);

    QPushButton* pBtn = new QPushButton(this);
    pBtn->setObjectName("pBtn");
    //pBtn->setFixedSize(50, 32);
    pBtn->setText(u8"打开");

    //创建水平布局
    QHBoxLayout* pHLay = new QHBoxLayout(this);

    //pHLay->setMargin(0);  //设置水平布局最外边界与相邻空间左上右下的间隙
    //pHLay->setContentsMargins(0, 100, 10, 0); //设置左上右下的间隙
    //将三个控件添加到水平布局中
    pHLay->addStretch();    //添加水平弹簧
    pHLay->addWidget(pPath);
    pHLay->addSpacing(10);  //添加相邻两个控件间的间隙
    pHLay->addWidget(pEdit);
    pHLay->addWidget(pBtn);
    pHLay->addStretch();
}

main.cpp

#include "ch2_3_hLayout.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ch2_3_hLayout w;
    w.show();
    return a.exec();
}

运行结果

image-20240624170042686

三、Qt竖直布局

  • 创建水平布局

    #include <QVBoxLayout>
    QVBoxLayout *pMainVLay = new QVBoxLayout(父窗口指针); //一般填this
    
  • 相关方法:与水平布局类似

    • addWidget:在布局中添加一个控件
    • addLayout:在布局里添加布局
    • setMargin:设置水平布局最外边界与相邻空间左上右下的间隙,这时左上右下的间隙相同;如果想设置成不同,可以使用setContentMargins方法
    • setSpacing:设置相邻控件之间的间隙,默认值大概是7
    • addSpacing:在setSpacing的基础上进行相加,例如:addSpacing(-7),相当于两个控件之间没有距离;addSpacing(13)相当于setSpacing(20);
    • addStretch:在水平布局时添加一个水平的伸缩空间(QSpacerItem),在竖直布局时,添加一个竖直的伸缩空间

示例:

xx.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

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

xx.cpp

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //新建三个按钮
    QPushButton *pBtn1 = new QPushButton(this);
    pBtn1->setObjectName("pBtn1");
    pBtn1->setText("pBtn1");
    // pBtn1->setFixedSize(40, 32);

    QPushButton *pBtn2 = new QPushButton(this);
    pBtn2->setObjectName("pBtn2");
    pBtn2->setText("pBtn2");
    // pBtn1->setFixedSize(40, 32);

    QPushButton *pBtn3 = new QPushButton(this);
    pBtn3->setObjectName("pBtn3");
    pBtn3->setText("pBtn3");
    // pBtn1->setFixedSize(40, 32);

    //新建竖直布局
    QVBoxLayout *pVLay = new QVBoxLayout(this);
    // pVLay->setMargin(100);
    // pVLay->setContentsMargins(80, 70, 60, 50);
    pVLay->addWidget(pBtn1);
    pVLay->addSpacing(10);
    pVLay->addWidget(pBtn2);
    pVLay->addSpacing(50);
    pVLay->addWidget(pBtn3);
}

Widget::~Widget()
{

}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

运行结果

image-20240624171928197

四、Qt栅格布局

  • 创建栅格布局

    #include <QGridLayout>
    QGridLayout *pGridLayout = new QGridLayout(this);
    
  • 相关方法:与水平布局类似

    • 栅格布局添加控件

      class Q_WIDGETS_EXPORT QGridLayout : public QLayout
      {
          //...
          inline void addWidget(QWidget *w) { QLayout::addWidget(w); }
          //基于行、列、对齐方式来添加控件
          void addWidget(QWidget *, int row, int column, Qt::Alignment = Qt::Alignment());
          //基于行、列、跨多少行、跨多少列、对齐方式来添加控件
          void addWidget(QWidget *, int row, int column, int rowSpan, int columnSpan, Qt::Alignment = Qt::Alignment());
          //基于行、列、对齐方式来添加子布局
          void addLayout(QLayout *, int row, int column, Qt::Alignment = Qt::Alignment());
          void addLayout(QLayout *, int row, int column, int rowSpan, int columnSpan, Qt::Alignment = Qt::Alignment());
      	//...
      }
      
    • 栅格布局设置间隙

      • 设置水平间距

        pGridLayout->setHorizontalSpacing(10);
        
      • 设置垂直间距

        pGridLayout->setVerticalSpacing(10);
        

示例:

xx.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

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

xx.cpp

#include "widget.h"
#include <QGridLayout>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QCheckBox>
#include <QDebug>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    //无边框窗口且可以最大化与最小化
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);

    /**新建控件**/
    //头像
    QLabel* pImageLabel = new QLabel(this);
    QPixmap pixMap(":/resources/user_image.png");
    pImageLabel->setFixedSize(150, 150);
    pixMap.scaled(pImageLabel->size(), Qt::KeepAspectRatio);
    pImageLabel->setPixmap(pixMap);
    pImageLabel->setScaledContents(true);

    //用户名
    QLineEdit* pUserNameLineEdit = new QLineEdit(this);
    pUserNameLineEdit->setFixedSize(300, 50);
    pUserNameLineEdit->setPlaceholderText("QQ号码/手机/邮箱"); //设置提示信息

    //密码
    QLineEdit* pPwdLineEdit = new QLineEdit(this);
    pPwdLineEdit->setFixedSize(300, 50);
    pPwdLineEdit->setPlaceholderText("密码");
    pPwdLineEdit->setEchoMode(QLineEdit::Password); //密码模式

    //找回密码
    QPushButton* pForgetButton = new QPushButton(this);
    pForgetButton->setText("找回密码");
    pForgetButton->setFixedWidth(80);

    //记住密码
    QCheckBox* pRemCheckBox = new QCheckBox(this);
    pRemCheckBox->setText("记住密码");

    //自动登陆
    QCheckBox* pAutoLoginCheckBox = new QCheckBox(this);
    pAutoLoginCheckBox->setText("自动登陆");

    //登陆
    QPushButton* pLoginBtn = new QPushButton(this);
    pLoginBtn->setFixedHeight(48);
    pLoginBtn->setText("登陆");

    //注册账号
    QPushButton* pRegisterBtn = new QPushButton(this);
    pRegisterBtn->setFixedHeight(48);
    pRegisterBtn->setText("注册账号");

    //新建栅格布局
    QGridLayout* pGridLayout = new QGridLayout(this);
    pGridLayout->addWidget(pImageLabel, 0, 0, 3, 1);
    pGridLayout->addWidget(pUserNameLineEdit, 0, 1, 1, 2);
    pGridLayout->addWidget(pPwdLineEdit, 1, 1, 1, 2);
    pGridLayout->addWidget(pForgetButton, 2, 1, 1, 1);
    pGridLayout->addWidget(pRemCheckBox, 2, 2, 1, 1, Qt::AlignLeft | Qt::AlignVCenter);
    pGridLayout->addWidget(pAutoLoginCheckBox, 2, 2, 1, 1, Qt::AlignRight | Qt::AlignVCenter);
    pGridLayout->addWidget(pLoginBtn, 3, 1, 1, 2);
    pGridLayout->addWidget(pRegisterBtn, 4, 1, 1, 2);

    //设置水平布局与垂直布局
    pGridLayout->setHorizontalSpacing(20);
    //pGridLayout->setVerticalSpacing(20);
    pGridLayout->setContentsMargins(30, 30, 30, 30);
}

Widget::~Widget() {}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

运行结果

image-20240624190548535

五、分裂器布局代码实现

在Qt设计器中使用两个按钮实现分裂器

image-20240624205827817

  • 水平分裂器

    QSplitter* pHSplitter = new QSplitter(Qt::Horizontal, this);
    
  • 竖直分裂器

    QSplitter* pVSplitter = new QSplitter(Qt::Vertical, pHSplitter);
    
  • 分裂器也是QWidget的子类,因此,分裂器也有addWidget方法,而布局也可以使用addWidget往布局里添加分裂器。

示例:

xx.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

class Widget : public QWidget
{
    Q_OBJECT

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

xx.cpp:

#include "widget.h"
#include <QHBoxLayout>
#include <QSplitter>
#include <QTextBrowser>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowTitle("Qt分裂器布局_c++代码");

    QHBoxLayout* pHboxLayout = new QHBoxLayout(this);

    //整体的水平分裂器
    QSplitter* pHSplitter = new QSplitter(Qt::Horizontal, this);
    //左侧widget
    QWidget* pLeftWidget = new QWidget(this);
    pLeftWidget->setStyleSheet("background-color:rgb(54, 54, 54)");
    pLeftWidget->setMinimumWidth(200);

    //分裂器添加widget
    pHSplitter->addWidget(pLeftWidget);

    //右侧的竖直分裂器
    QSplitter* pVSplitter = new QSplitter(Qt::Vertical, pHSplitter);

    //在拖动到位并弹起鼠标后再显式分隔条
    pVSplitter->setOpaqueResize(false);

    //右侧顶部widget
    QWidget* pRightTopWidget = new QWidget(this);
    pRightTopWidget->setStyleSheet("background-color:rgb(154, 154, 154)");
    //右侧底部窗体
    QTextBrowser* pRightBottom = new QTextBrowser(this);

    pVSplitter->addWidget(pRightTopWidget);
    pVSplitter->addWidget(pRightBottom);

    pHSplitter->addWidget(pVSplitter);

    //布局添加分裂器
    pHboxLayout->addWidget(pHSplitter);

    //设置整体布局
    //this->setLayout(pHboxLayout);
}

Widget::~Widget() {}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

运行结果

image-20240624212248737

六、setLayout使用说明

  QWidget::setLayout(QLayout *layout) 是 Qt 框架中的一个成员函数,用于为窗口小部件(widget)设置布局管理器(layout manager)。

  • 设置此窗口小部件的布局管理器为 layout
  • 如果此窗口小部件上已经安装了布局管理器,QWidget 不会允许你安装另一个。你必须首先删除现有的布局管理器(由 layout() 返回),然后才能使用新的布局调用 setLayout()
  • 如果 layout 是另一个窗口小部件上的布局管理器,setLayout() 将重新为其设置父级,并使其成为此窗口小部件的布局管理器。

示例:

QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(formWidget);
setLayout(layout);

还可以通过将窗口小部件作为参数传递给布局的构造函数来设置布局,这样窗口小部件就会自动接管布局的所有权。

七、布局切换与布局删除重构

1.如何添加右键菜单

  • 菜单事件

    void contextMenuEvent(QContextMenuEvent* event) override;
    
  • 设置菜单策略

    this->setContextMenuPolicy(Qt::DefaultContextMenu);
    
  • 创建菜单

    void Widget::initMenu()
    {
        m_pMenu = new QMenu(this);
    
        QAction *pAction1 = new QAction("查看");
        QAction *pAction2 = new QAction("排序方式");
        QAction *pAction3 = new QAction("刷新");
        m_pMenu->addAction(pAction1);
        m_pMenu->addAction(pAction2);
        m_pMenu->addAction(pAction3);
    }
    
  • 弹出菜单

    void Widget::contextMenuEvent(QContextMenuEvent* event)
    {
        m_pMenu->exec(QCursor::pos());
    }
    

示例:

xx.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMenu>

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //菜单事件
    void contextMenuEvent(QContextMenuEvent* event) override;
    void initMenu();    //创建菜单


private:
    QMenu* m_pMenu = nullptr;
};
#endif // WIDGET_H

xx.cpp

#include "widget.h"
#include <QAction>
#include <QMessageBox>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinMaxButtonsHint);
    //设置菜单策略
    this->setContextMenuPolicy(Qt::DefaultContextMenu);
    initMenu(); //初始化菜单
}

Widget::~Widget() {}


void Widget::contextMenuEvent(QContextMenuEvent* event)
{
    m_pMenu->exec(QCursor::pos());
}

void Widget::initMenu()
{
    m_pMenu = new QMenu(this);

    QAction *pAction1 = new QAction("查看");
    QAction *pAction2 = new QAction("排序方式");
    QAction *pAction3 = new QAction("刷新");
    m_pMenu->addAction(pAction1);
    m_pMenu->addAction(pAction2);
    m_pMenu->addAction(pAction3);

    connect(pAction1, &QAction::triggered, [=]{
        QMessageBox::information(this, "title", "查看");
    });
}

main.cpp

#include "widget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}

运行结果

image-20240624215757223

2.布局切换与布局删除重构

  通过右键菜单项,实现布局的切换与布局删除重构。

示例:

SwitchWidget.h

#pragma once

#include <QtWidgets/QWidget>
#include <QLabel>
#include <QList>
#include <QMenu>

// 视频分屏类型
enum VideoLayoutType
{
	OneVideo = 0,
	TwoVideo,
	ThreeVideo,
	FourVideo,
	FiveVideo,
	SixVideo,
	SeventVideo,
	EightVideo,
	NineVideo,
};

class SwitchWidget : public QWidget
{
    Q_OBJECT

public:
    SwitchWidget(QWidget* parent = nullptr);
    ~SwitchWidget();

private:
    void initWidget();
    void initMenu();
    void contextMenuEvent(QContextMenuEvent* event) override;  //菜单事件
    void switchLayout(VideoLayoutType type);    //切换不同布局

private:
    QList<QLabel*> m_videoLabelList;    //用于保存视频区域
    QMenu* m_switchMenu;
};

SwitchWidget.cpp

#pragma execution_character_set("utf-8")
#include "SwitchWidget.h"
#include <QGridLayout>
#include <QContextMenuEvent>
#include <QDebug>

SwitchWidget::SwitchWidget(QWidget* parent)
    : QWidget(parent)
{
    this->setWindowTitle(u8"Qt布局切换与布局删除重构");
    initWidget();
    this->resize(QSize(800, 500));
    this->setContextMenuPolicy(Qt::DefaultContextMenu); //设置菜单策略
}

SwitchWidget::~SwitchWidget() {}

void SwitchWidget::initWidget() //初始化界面
{
    initMenu(); //初始化菜单

    for (int i = 0; i < 9; i++)
    {
        QLabel* label = new QLabel();
        label->setStyleSheet(QString("QLabel{background-image:url(:/SwitchWidget/resources/%1.png); \
			border:1px solid gray; \
			background-position:center; \
			background-repeat:no-repeat; \
			}").arg(QString::number(i + 1)));

        m_videoLabelList.append(label);
    }

    switchLayout(VideoLayoutType::OneVideo);
}

void SwitchWidget::initMenu() //初始化菜单
{
    m_switchMenu = new QMenu(this);
    m_switchMenu->addAction(u8"一分屏");
    m_switchMenu->addAction(u8"四分屏");
    m_switchMenu->addAction(u8"五分屏");
    m_switchMenu->addAction(u8"六分屏");
    m_switchMenu->addAction(u8"九分屏");

    QMap<QString, int> strTypeMap;
    strTypeMap["一分屏"] = VideoLayoutType::OneVideo;
    strTypeMap["四分屏"] = VideoLayoutType::FourVideo;
    strTypeMap["五分屏"] = VideoLayoutType::FiveVideo;
    strTypeMap["六分屏"] = VideoLayoutType::SixVideo;
    strTypeMap["九分屏"] = VideoLayoutType::NineVideo;

    //信号槽
    connect(m_switchMenu, &QMenu::triggered, this, [=](QAction* action) {
        QString strText = action->text();
        qDebug() << "strText = " << strText;
        qDebug() << strTypeMap[strText];
        VideoLayoutType type = static_cast<VideoLayoutType>(strTypeMap[strText]);
        
        qDebug() << "type = " << type;
        switchLayout(type);
    });
}

void SwitchWidget::contextMenuEvent(QContextMenuEvent* event) //菜单事件
{
    m_switchMenu->exec(QCursor::pos()); //弹出菜单--使用当前鼠标位置来执行菜单
}

void SwitchWidget::switchLayout(VideoLayoutType type) //切换不同布局
{
    QLayout* layout = this->layout();   //获取当前窗口的布局
    //当切换布局时,若布局不为空,则清空布局内的所有元素
    if (layout)
    {
        QLayoutItem* child; //布局中的子项
        //删除布局中的所有子项
        while ((child = layout->takeAt(0)) != 0)
        {
            //调用 setParent(NULL) 方法将控件的父对象设置为 NULL。这样做可以防止控件在从布局中删除后界面上仍然显示。
            if (child->widget())
            {
                child->widget()->setParent(NULL);
            }
            delete child;
        }
        delete layout;
    }

    //设置新的布局
    switch (type)
    {
    case OneVideo:
    {
        qDebug() << "OneVideo\n";
        QGridLayout* gLayout = new QGridLayout(this);
        gLayout->addWidget(m_videoLabelList[0]);
        gLayout->setMargin(0);
    }
    break;

    case FourVideo:
    {
        qDebug() << "FourVideo\n";
        QGridLayout* gLayout = new QGridLayout(this);
        gLayout->setSpacing(0);
        gLayout->setMargin(0);

        for (int i = 0; i < 4; i++)
        {
            gLayout->addWidget(m_videoLabelList[i], i / 2, i % 2);
        }
    }
    break;

    case FiveVideo:
    {
        qDebug() << "FiveVideo\n";
        QVBoxLayout* pVLay = new QVBoxLayout(this);
        pVLay->setSpacing(0);

        QHBoxLayout* pHTopLay = new QHBoxLayout(this);
        pHTopLay->setSpacing(0);
        for (int i = 0; i < 3; i++)
        {
            pHTopLay->addWidget(m_videoLabelList[i]);
        }

        QHBoxLayout* pHBottomLay = new QHBoxLayout(this);
        pHBottomLay->setSpacing(0);
        for (int i = 3; i < 5; i++)
        {
            pHBottomLay->addWidget(m_videoLabelList[i]);
        }

        pVLay->addLayout(pHTopLay);
        pVLay->addLayout(pHBottomLay);
    }
    break;

    case SixVideo:
    {
        QGridLayout* gLayout = new QGridLayout(this);
        gLayout->addWidget(m_videoLabelList[0], 0, 0, 2, 2);
        gLayout->addWidget(m_videoLabelList[1], 0, 2);
        gLayout->addWidget(m_videoLabelList[2], 1, 2);
        gLayout->addWidget(m_videoLabelList[3], 2, 0);
        gLayout->addWidget(m_videoLabelList[4], 2, 1);
        gLayout->addWidget(m_videoLabelList[5], 2, 2);
        gLayout->setSpacing(0);
        gLayout->setMargin(0);
    }
    break;

    case NineVideo:
    {
        QGridLayout* gLayout = new QGridLayout(this);
        gLayout->setSpacing(0);
        gLayout->setMargin(0);

        for (int i = 0; i < 9; i++)
        {
            gLayout->addWidget(m_videoLabelList[i], i / 3, i % 3);
        }
    }
    break;

    default:
        break;
    }

}

main.cpp

#include "SwitchWidget.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    SwitchWidget w;
    w.show();
    return a.exec();
}

运行结果

image-20240625125930032

image-20240625125956501

image-20240625130018525

image-20240625130033826

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

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

相关文章

Python+Pytest+Allure+Yaml接口自动化测试框架详解

PythonPytestAllureYaml接口自动化测试框架详解 编撰人&#xff1a;CesareCheung 更新时间&#xff1a;2024.06.20 一、技术栈 PythonPytestAllureYaml 版本要求&#xff1a;Python3.7.0,Pytest7.4.4,Allure2.18.1,PyYaml6.0 二、环境配置 1、安装python3.7&#xff0c;并配置…

解析分子筛自动填充高原制氧机的工作原理及优势

在高原地区&#xff0c;由于空气稀薄&#xff0c;氧气含量相对较低&#xff0c;这给人们的生活、工作和学习带来了诸多不便。为了解决这个问题&#xff0c;高原制氧机应运而生&#xff0c;其中分子筛自动填充高原制氧机以其高效、稳定、安全的特点受到了广泛的关注和应用。 一、…

CRMEB 多门店后台登录入口地址修改(默认admin)

一、>2.4版本 1、修改后端 config/admin.php 配置文件,为自定义的后缀 2、修改 平台后台前端源码中 view/admin/src/settings.js 文件,修改为和上面一样的配置 3、修改后重新打包前端代码,并且覆盖到后端的 public 目录下&#xff1a;打包方法 4、重启swoole 二、<2.4版…

蒙特卡洛树搜索

蒙特卡洛树搜索入门---强化学习 - 知乎蒙特卡洛树搜索&#xff08;Monte Carlo tree search&#xff09;简称MCTS&#xff0c;和一般的蒙特卡洛方法不是一个概念。通俗的理解&#xff0c;蒙特卡洛方法是随机现象中用频率来近似概率&#xff0c;模拟次数越多&#xff0c;结果越准…

从 Hadoop 迁移,无需淘汰和替换

我们仍然惊讶于有如此多的客户来找我们&#xff0c;希望从HDFS迁移到现代对象存储&#xff0c;如MinIO。我们现在以为每个人都已经完成了过渡&#xff0c;但每周&#xff0c;我们都会与一个决定进行过渡的主要、高技术性组织交谈。 很多时候&#xff0c;在这些讨论中&#xff…

项目实训-vue(十一)

项目实训-vue&#xff08;十一&#xff09; 文章目录 项目实训-vue&#xff08;十一&#xff09;1.概述2.页顶导航栏3.导航信息4.总结 1.概述 本篇博客将记录我在图片上传页面中的工作。 2.页顶导航栏 <divstyle"display: flex;justify-content: space-between;alig…

打造智能家居:用ESP32轻松实现无线控制与环境监测

ESP32是一款集成了Wi-Fi和蓝牙功能的微控制器&#xff0c;广泛应用于物联网项目。它由Espressif Systems公司开发&#xff0c;具有强大的处理能力和丰富的外设接口。下面我们将详细介绍ESP32的基础功能和引脚功能&#xff0c;并通过具体的实例项目展示其应用。 主要功能 双核处…

网络安全协议

1. 概述 1.1 网络安全需求 五种需求&#xff1a; 机密性&#xff1a;防止数据未授权公开&#xff0c;让消息对无关听众保密 完整性&#xff1a;防止数据被篡改 可控性&#xff1a;限制对网络资源&#xff08;硬件和软件&#xff09;和数据&#xff08;存储和通信&#xff0…

「2024中国数据要素产业图谱1.0版」重磅发布,景联文科技凭借高质量数据采集服务入选!

近日&#xff0c;景联文科技入选数据猿和上海大数据联盟发布的《2024中国数据要素产业图谱1.0版》数据采集服务板块。 景联文科技是专业数据服务公司&#xff0c;提供从数据采集、清洗、标注的全流程数据解决方案&#xff0c;协助人工智能企业解决整个AI链条中数据采集和数据标…

Kendryte K210 固件烧录

本章将为读者介绍 Kendryte K210 的固件烧录&#xff0c;以及 Kendryte K210 外部 NOR Flash 的空间 分布。 本章分为如下几个小节&#xff1a; 6.1 外部 NOR Flash 的空间分布 6.2 Ubuntu 下的固件烧录 6.3 Windows 下的固件烧录 外部 NOR Flash 的空间分布 Kendryte K210 的…

如何以管理员身份运行CMD?

好久没更新博客了&#xff0c;今天在日常使用中遇到了一个问题&#xff0c;顺便记录下来。 据说国内的谷歌浏览器 Chrome 可以自动升级了&#xff0c;终于不用每次都自己跑去官网下载最新版本&#xff0c;然后安装迁移&#xff0c;重复劳动。下一篇讲如何讲迁移 Chrome&#x…

【Python】已解决:Python读取字典查询键报错“KeyError: ‘d‘”

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决&#xff1a;Python读取字典查询键报错“KeyError: ‘d’” 一、分析问题背景 在Python编程中&#xff0c;字典&#xff08;dictionary&#xff09;是一种非常重要的数据结构…

源码分析过滤器与拦截器的区别

博主最近刚拿到一个微服务的新项目&#xff0c;边研究边分析从框架基础开始慢慢带领大家研究微服务的一些东西&#xff0c;这次给大家分析下Springboot中的过滤器和拦截器的区别。虽然上次分析过过滤器&#xff0c;但是主要是分析的cas流程&#xff0c;所以就没太深入&#xff…

[创业之路-129] :制造业企业的必备管理神器-ERP-生产制造

目录 一、ERP生产制造的总体架构 1.1 主要功能模块 1.2 主要流程 二、关键功能详解 2.1 生产管理计划 2.2 物料需求计划MRP 2.3 能力需求计划 2.4 物料与库房管理 一、ERP生产制造的总体架构 1.1 主要功能模块 ERP&#xff08;企业资源计划&#xff09;生产制造系统主…

微信小程序修改应用名称

1、修改名称&#xff08;10分钟即可生效&#xff09; 账号管理员 2、修改icon&#xff08;如果logo带有名称则需要修改&#xff09;

零基础STM32单片机编程入门(二)GPIO详解及驱动LED灯实战含源码视频

文章目录 一.概要二.STM32F103C8T6单片机GPIO口特点二.STM32单片机GPIO内部结构图三.单片机GPIO推挽输出信号流向四.单片机GPIO浮空输入信号流向四.单片机GPIO引脚的复用以及重映射五.CubeMX配置一个GPIO输出驱动LED灯例程六.CubeMX工程源代码下载七.讲解视频链接地址八.小结 一…

MATLAB基础应用精讲-【数模应用】协方差分析 (ANCOVA)

目录 几个高频面试题目 协方差分析和多因素方差分析区别 因子方差分析和协方差分析对比 情景1 因子方差分析的主要内容 SPSS实现因子方差分析 情景2 协方差分析的主要内容 SPSS中进行协方差分析 几个相关概念 算法原理 什么是协方差分析 算法特点 ANCOVA 的步骤 …

如何处理消息积压问题

什么是MQ消息积压&#xff1f; MQ消息积压是指消息队列中的消息无法及时处理和消费&#xff0c;导致队列中消息累积过多的情况。 消息积压后果&#xff1a; ①&#xff1a;消息不能及时消费&#xff0c;导致任务不能及时处理 ②&#xff1a;下游消费者处理大量的消息任务&#…

制造业ERP五大生产模式详解!

制造业面临着从成本控制、生产效率到供应链管理的挑战&#xff0c;每一个环节都需要精细化的管理和高效的协同。而ERP系统&#xff0c;作为一种集信息技术与管理思想于一体的管理工具&#xff0c;正逐渐成为制造业转型升级的关键。那么&#xff0c;通过本文你将会了解到&#x…

压电风扇的显著特点及其在电子系统中的应用

压电已经存在了一个多世纪&#xff0c;人们发现某些晶体结构在受到机械应力时产生表面电荷。 这种形式的压电传感器是压电传感器的工作方式。与压电传感器&#xff08;或发电机&#xff09;类似&#xff0c;压电致动器&#xff08;或电机&#xff09;使用补丁[1,3]形式的压电陶…