当前位置: 首页 > news >正文

【Qt】QMainWindow类

🌈 个人主页:Zfox_
🔥 系列专栏:Qt

目录

  • 一:🔥 QMainWindow 概述
    • 🦋 菜单栏
      • 🎀 具体使用
      • 🎀 综合案例
    • 🦋 工具栏
    • 🦋 状态栏
    • 🦋 窗口布局
      • 🎀 浮动窗口 -- QDockWidget
      • 🎀 Splitter
  • 二:🔥 共勉

一:🔥 QMainWindow 概述

🐳 Qt 窗口是通过 QMainWindow 类来实现的。

  • QMainWindow 是一个为用户提供主窗口程序的类。
  • 该类继承自 QWidget,并提供了一个预定义的布局
  • QMainWindow 包含一个菜单栏(Menu Bar)、多个工具栏(Tool Bars)、多个浮动窗口(铆接部件 子窗口)(Dock Widgets)、⼀个状态栏(Status Bar)和一个中心部件(Central Widget),它是许多应用程序的基础,如文本编辑器,图片编辑器等。

如下图为 QMainwindow 中各组件所处的位置

image-20250121092138114

🦋 菜单栏

🐠 Qt 中的菜单栏是通过 QMenuBar 这个类来实现的。一个主窗口最多只有一个菜单栏,位于主窗口顶部、主窗口标题栏下面。

菜单栏中包含菜单,菜单中包含菜单项

image-20250121092454550

  • 工具栏本质上就是把菜单中一些比较常用的选项直接放到工具栏里,直接点工具栏中的按钮就能快速生效。

🎀 具体使用

一、创建菜单栏

(1)方式一

菜单栏的创建可以借助于 QMainWindow 类提供的 menuBar() 函数来实现。menubar() 函数原型如下:

QMenuBar* menuBar() const

image-20250121095506419

(2)方式二 – 在堆上创建

如果是获取到已经存在的 QMenuBar,那么这里的设置就是 自己替换自己,仍然在对象树上

image-20250121095654300

如果我们自己创建的项目没有勾选自动生成 ui 文件,那么上述代码是没有问题的。

  • 但如果勾选了自动生成 ui 文件(Qt 已经给我们生成了一个 QMenuBar),那么上述代码就会引起内存泄漏

img

程序自己已经创建好了一个 QMenuBar,当设置新的 QMenuBar 进来时,就会导致旧的 QMenuBar 脱离了 Qt 的对象树,意味着后续就无法对这个对象进行释放了

  • 上述程序如果窗口关闭,对象树释放,此时进程就结束了,自然所有的内存都回收给系统,上述内存泄漏也就不会造成影响。
  • 但是如果上述代码是出现在一个多窗口的程序中,如果涉及到窗口的频繁跳转切换(窗口的频繁创建销毁),上述内存泄漏就会更严重。但是实际上由于现在的计算机内存比较充裕,上述内存泄漏都还好,但还是要求代码写得更规范一些,所以采用下面这种写法

image-20250121112837161

image-20250121101944270

  • 菜单栏(QMenuBar) -> 菜单(QMenu) -> 菜单项(QAction)

  • 上面通过图形化的方式还是不够方便,下面通过代码来创建

二、在菜单栏中添加菜单 并且 创建菜单项

  • 创建菜单,并通过 QMenu 提供的 addMenu() 函数 来添加菜单。
  • 在 Qt 中,并没有专门的菜单项类(QMenuBarItem),可以通过 QAction 类,抽象出公共的动作,如在菜单中添加菜单项。

image-20250121102848409

但是上面的菜单项点了之后没有反应,这个时候就需要我们通过 connecttrigged 绑定槽函数,总体代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 1. 先创建一个菜单栏QMenuBar* menuBar = new QMenuBar();this->setMenuBar(menuBar);// 2. 创建菜单QMenu* menu1 = new QMenu("文件");QMenu* menu2 = new QMenu("编辑");QMenu* menu3 = new QMenu("视图");menuBar->addMenu(menu1);menuBar->addMenu(menu2);menuBar->addMenu(menu3);// 3. 给菜单添加菜单项QAction* action1 = new QAction("新建");QAction* action2 = new QAction("打开");QAction* action3 = new QAction("保存");QAction* action4 = new QAction("另存为");QAction* action5 = new QAction("退出");menu1->addAction(action1);menu1->addAction(action2);menu1->addAction(action3);menu1->addSeparator(); // 在保存和另存为中添加分割线menu1->addAction(action4);menu1->addAction(action5);// 4. 给 action 添加信号槽connect(action1, &QAction::triggered, this, &MainWindow::handle);
}void MainWindow::handle()
{qDebug() << "触发新建操作!!!";
}

结果如下:

image-20250121104042938

三、在菜单项之间添加分割线

🔥 在菜单项之间可以添加分割线。分割线如下图所示,添加分割线是通过 QMenu 类提供的 addSeparator() 函数来实现:

image-20250121094922589

示例:

image-20250121103045780

  • QAction 可以给菜单栏使用,也可以给工具栏使用。

四、添加快捷键

🔥 一般来说菜单都会有对应的快捷键,方便我们更好操作,因此我们也可以 在设置菜单的 title 时,在字母前加 & 符号

示例:

QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);QMenu* menu1 = new QMenu("文件(&F)");
menuBar->addMenu(menu1);// 创建四个菜单项
QAction* action1 = new QAction("action1 (&Q)");
QAction* action2 = new QAction("action2 (&W)");
menu1->addAction(action1);
menu1->addAction(action2);// 我们这需要绑定槽函数, 不然通过快捷键选中也没啥反应
connect(action1, &QAction::triggered, this, &MainWindow::handle1);

效果展示:

  • 先按下 Alt 键,再按 F,其显示的 W 下面会有下划线,表示是有快捷键的,快捷键为 W。

image-20250121104352948

这个 ("文件 (&F)") 就和 之前QLabel 那学的设置伙伴类似,大家可以去看看之前写的文章

五、添加子菜单

  • 菜单栏 -> 菜单 -> 菜单栏
  • 菜单栏 -> 菜单 -> 子菜单 -> 子菜单 -> 菜单栏

QMenu 也提供了 addMenu,通过这个操作可以给某个菜单项添加子菜单。

QMenuBar* menuBar = new QMenuBar();
this->setMenuBar(menuBar);QMenu* menuParent = new QMenu("父菜单");
QMenu* menuChild = new QMenu("子菜单");menuBar->addMenu(menuParent);
menuParent->addMenu(menuChild);QAction* action1 = new QAction("菜单项1");
QAction* action2 = new QAction("菜单项2");
menuChild->addAction(action1);
menuChild->addAction(action2);QMenu* menuChild2 = new QMenu("子菜单2");
menuChild->addMenu(menuChild2);

六、添加图标

按照之前设置图标的方法编写,代码如下:

image-20250121112131382

  • 如果给 QMenu 设置图标。因为当前 QMenu 是长在 QMenuBar 上的,此时文本就不显示,图标会覆盖文本。而 QMenu子菜单,图标和文本都是可以显示的

🎀 综合案例

在窗口上创建一个菜单栏,在菜单栏中添加一些菜单,在某一个菜单中添加一些菜单项。

(1)新建 Qt 项目

注意:此时新建项目时选择的基类 QMainwindow !!!

(2)在 “mainwindow.cpp” 文件中创建菜单和中央控件,并且给 action 添加一些动作

image-20250121112950694

  • 创建一个菜单栏,一个菜单
  • 两个菜单项:保存,加载
  • 创建一个 QTextEdit 作为窗口的中央控件
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 设置标题this->setWindowTitle("我的记事本");// 创建菜单栏QMenuBar* menuBar = new QMenuBar(this);this->setMenuBar(menuBar);// 创建菜单QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);// 创建菜单项QAction* action1 = new QAction("保存");QAction* action2 = new QAction("加载");menu->addAction(action1);menu->addAction(action2);// 创建中央控件edit = new QTextEdit(this);this->setCentralWidget(edit);edit->setPlaceholderText("此处编写⽂本内容...");// 连接信号槽,点击 action 时触发一定的效果//实现这两个槽函数:使用 QFileDialog 来实现选择文件的效果// 1. getSaveFileName 用于保存文件的场景,此时的对话框可以输入文件名// 2. getOpenFileName 用于打开文件的场景,此时的对话框可以获取到鼠标选择的文件名connect(action1, &QAction::triggered, this, &MainWindow::save);connect(action2, &QAction::triggered, this, &MainWindow::load);
}
  • 搭配 C++ 标准库的文件操作实现文件读写
void MainWindow::save()
{// 弹出对话框,选择写入文件的路径QFileDialog* dialog = new QFileDialog(this);QString fileName = dialog->getSaveFileName(this, "保存⽂件", "C:/Users/1/");qDebug() << "fileName: " << fileName;// 写⼊⽂件std::ofstream file(fileName.toStdString().c_str());if (!file.is_open()) {qDebug() << "文件保存失败!";return;}const QString& text = edit->toPlainText();file << text.toStdString();file.close();
}void MainWindow::load()
{// 弹出对话框,选择打开的文件QFileDialog* dialog = new QFileDialog(this);QString fileName = dialog->getOpenFileName(this, "加载文件", "C:/Users/1/");qDebug() << "fileName: " << fileName;// 读取文件std::ifstream file(fileName.toStdString().c_str());if (!file.is_open()) {qDebug() << "文件加载失败!";return;}std::string content;std::string line;while (std::getline(file, line)) {content += line;content += "\n";}file.close();// 显示到界面上QString text = QString::fromStdString(content);edit->setPlainText(text);
}

执行程序,可以看到此时就可以通过程序来保存 / 加载文件了,并且对文件进行编辑。

img

🦋 工具栏

🧀工具栏是应用程序中集成各种功能,实现快捷键使用的一个区域。可以有多个,也可以没有,它并不是应用程序中必须存在的组件。

  • 它是一个可移动的组件,它的元素可以是各种窗口组件,它的元素通常以图标按钮的方式存在。如下图为工具栏的示意图:

image-20250121113350511

一、创建菜单栏

调用 QMainWindow 类的 addToolBar() 函数来创建工具栏,每增加⼀个工具栏都需要调用一次该函数。

  • 如下添加一个工具栏:
// 工具类需要手动创建,自身不会自动创建
QToolBar* toolBar = new QToolBar(toolBar);
this->addToolBar(toolBar);

image-20250121114506195

  • 左边是无工具栏,右边是有工具栏

工具栏往往是和菜单栏搭配使用的,工具栏中的 QAction 也可以出现在菜单中。

注意:

img

// 创建菜单栏
QMenuBar* menuBar = this->menuBar();
this->setMenuBar(menuBar);// 创建菜单
QMenu* menu = new QMenu("文件");
menuBar->addMenu(menu);// 工具栏是需要手动创建出来的. 自身不会自动创建.
QToolBar* toolBar = new QToolBar();
this->addToolBar(toolBar);// 创建两个菜单项
QAction* action1 = new QAction("保存");
QAction* action2 = new QAction("打开");
// action1->setToolTip("点击这里保存文件");
action1->setIcon(QIcon(":/picture/Save.png"));
action2->setIcon(QIcon(":/picture/open.png"));// 菜单项还可以放到菜单中
menu->addAction(action1);
menu->addAction(action2);// 菜单项放到工具栏中
toolBar->addAction(action1);
toolBar->addAction(action2);//存在覆盖connect(action1, &QAction::triggered, this, &MainWindow::handle1);
connect(action2, &QAction::triggered, this, &MainWindow::handle2);

img

如果一个 QAction 既是 QMenu 的子元素,又是 QToolBar 的子元素,那么在释放的时候是否会重复 delete 呢?

  • 只会释放一次,不会重复 delete。Qt 内置的机制已经帮我们解决了这个问题。

二、设置停靠位置

工具栏停靠位置的设置有两种方式。

  1. 第一种是在创建工具栏的同时指定停靠的位置

  2. 第二种是通过 QToolBar 类提供的 setAllowedAreas() 函数来设置。

(1)方式一

创建工具栏的同时指定其停靠的位置。
在创建工具栏的同时,也可以设置工具栏的位置,其默认位置是在窗口的最上面;如上述代码,默认在最上面显示。
工具栏允许停靠的区域由 QToolBar 类提供的 allowAreas() 函数决定,其中可以设置的位置包括:

  • Qt::LeftToolBarArea 停靠在左侧
  • Qt::RightToolBarArea 停靠在右侧
  • Qt::TopToolBarArea 停靠在顶部
  • Qt::BottomToolBarArea 停靠在底部
  • Qt::AllToolBarAreas 以上四个位置都可停靠
// 2. 设置停靠位置 -> 指定在右侧显示
QToolBar* toolBar1 = new QToolBar(this);
this->addToolBar(Qt::RightToolBarArea, toolBar1);

(2)方式二

使用 QToolBar 类提供的 setAllowedAreas()函数 设置停靠位置。

// 只允许停靠在左侧和右侧
QToolBar* toolBar2 = new QToolBar(this);
toolBar2->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);

说明:

  • 在创建工具栏的同时指定其停靠的位置,指的是程序运行时工具栏默认所在的位置
  • 而使用 setAllowedAreas() 函数 设置停靠位置,指的是工具栏允许其所能停靠的位置

三、设置 浮动 和 移动 属性

设置工具栏的浮动属性可以通过 QToolBar 类提供的 setFloatable()函数来设置。

(1)setFloatable() 函数原型:void setFloatable (bool floatable)

(2)参数

  • true:浮动

  • false:不浮动

(3)示例

image-20250121115245757

设置工具栏的移动属性可以通过 QToolBar 类提供的 setMovable() 函数来设置。

(1)setMovable()函数的原型:void setMovable (bool movable)

(2)参数

  • true:移动

  • false:不移动

说明:若设置工具栏为不移动状态,则设置其停靠位置的操作就不会生效,所以设置工具栏的移动属性类似于总开关的效果。

(3)示例:

image-20250121115257697

四、综合案例

QToolBar *toolBar = new QToolBar(this);
// 设置工具栏位置,默认在窗口上,此处设置在左处
addToolBar(Qt::LeftToolBarArea, toolBar);toolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);   // 设置工具栏停靠位置
toolBar->setFloatable(false); //浮动
toolBar->setMovable(true);// 设置工具类内容
QAction* openAction = new QAction("open", this);
QAction* newAction = new QAction("new", this);toolBar->addAction(openAction);
toolBar->addSeparator(); // 在 open 和 new 之间添加分割线
toolBar->addAction(newAction);// 工具栏中也可以添加控件
QPushButton* button = new QPushButton("保存", this);
toolBar->addWidget(button);

运行如下:

🦋 状态栏

状态栏是应用程序中输出简要信息的区域。

一般位于主窗口的最底部,一个窗口中最多只能有一个状态栏。在 Qt 中,状态栏是通过 QStatusBar 类来实现的。 在状态栏中可以显示的消息类型有:

  • 实时消息:如当前程序状态
  • 永久消息:如程序版本号,机构名称
  • 进度消息:如进度条提示,百分百提示

一、状态栏的创建

状态栏的创建是通过 QMainWindow 类提供的 statusBar() 函数来创建。

// 存在就获取,不存在就创建
QStatusBar* statusBar = this->statusBar();
this->setStatusBar(statusBar);

二、在状态栏中显示实时消息

在状态栏中显示实时消息是通过 showMessage() 函数来实现。

// 显示临时信息
statusBar->showMessage("这是一个状态信息", 3000);

通过 showMessage 可以在状态栏中显示一个文本。

此时这个 文本存在的时间 可以自定义,timeout 参数是一个单位为 ms 的时间。如果 timeout 为 0(不填),消息就会持久存在。

三、在状态栏中显示永久消息

在状态栏中可以显示永久消息,此处的永久消息是通过标签来显示的。

新增一条显示消息,新增一个进度条和按钮:

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);// 存在就获取,不存在就创建QStatusBar* statusBar = this->statusBar();this->setStatusBar(statusBar);// 给状态栏添加子控件 -- 永久信息QLabel* lab = new QLabel("这是一个 QLabel");statusBar->addWidget(lab);// 进度条QProgressBar* progreeBar = new QProgressBar();progreeBar->setRange(0, 100);progreeBar->setValue(50);statusBar->addWidget(progreeBar);QPushButton* button = new QPushButton("按钮");statusBar->addPermanentWidget(button);
}

image-20250122212324800

🦋 窗口布局

之前我们在 [QT 控件](【QT】控件 – 多元素类 | 容器类 | 布局类-CSDN博客)里已经讲过了大部分的布局类,现在我们来了解来自 QMainWindow 的窗口类布局,如下:

🎀 浮动窗口 – QDockWidget

在 Qt 中,浮动窗口也称之为铆接部件。浮动窗口是通过 *QDockWidget* 类来实现浮动的功能。浮动窗口一般是位于核心部件的周围,可以有多个。

一、浮动窗口的创建

浮动窗口的创建是通过 QDockWidget 类提供的构造方法 QDockWidget() 函数动态创建的。

// 给主窗口添加一个子窗口
QDockWidget* dockWidget =new QDockWidget();
// 使用addDockwidget方法,把浮动窗口加入到子窗口中
this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget)// 给浮动窗口设置标题
dockwidget->setwindowTitle("这是浮动窗口");

结果如下:

二、设置停靠的位置

浮动窗口是位于中心部件的周围。可以通过 QDockWidget类 中提供 setAllowedAreas() 函数设置其允许停靠的位置。其中可以设置允许停靠的位置有:

  • Qt::LeftDockWidgetArea 停靠在左侧
  • Qt::RightDockWidgetArea 停靠在右侧
  • Qt::TopDockWidgetArea 停靠在顶部
  • Qt::BottomDockWidgetArea 停靠在底部
  • Qt::AllDockWidgetAreas 以上四个位置都可停靠

不能直接给浮动窗口添加子控件,而是需要创建出一个单独的 QWidget,把需要添加的控件加入到 QWidget 中,然后再把这个 QWidget 设置到 dockWidget 中。

示例如下:设置浮动窗口只允许在左边或者上边停靠:

// 给主窗口添加一个子窗口.
QDockWidget* dockWidget = new QDockWidget();
// 使用 addDockWidget 方法, 把浮动窗口加入到子窗口中.
this->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);// 浮动窗口也是可以设置标题的.
dockWidget->setWindowTitle("这是浮动窗口");// 给浮动窗口内部, 添加一些其他的控件.
QWidget* container = new QWidget();
dockWidget->setWidget(container);// 创建布局管理器, 把布局管理器设置到 QWidget 中
QVBoxLayout* layout = new QVBoxLayout;
container->setLayout(layout);// 创建其他控件添加到 layout 中.
QLabel* label = new QLabel("这是一个 QLabel");
QPushButton* button = new QPushButton("这是按钮");
layout->addWidget(label);
layout->addWidget(button);// 设置浮动窗口允许停靠的位置
dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::TopDockWidgetArea);

image-20250122212918083

涉及函数 / 方法:**setFeatures()**设置窗体特性:Movable可移动、Closable 可关闭、Floatable 可浮动


MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QTextEdit *text = new QTextEdit(this);//新建文本编辑框QTextEdit类对象text->setText(tr("主窗口"));      //设置文本内容text->setAlignment(Qt::AlignCenter);  //文本编辑框TextEdit中文字的对齐方式为【文字居中】setCentralWidget(text);               //将此编辑框设为主窗口的中央窗体//停靠窗口1:可移动QDockWidget *dock = new QDockWidget(tr("窗口一"),this);//新建QDockWidget类对象dock->setFeatures(QDockWidget::DockWidgetMovable);          //窗体特性:Movable可移动、Closable可关闭、Floatable可浮动dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);//窗体可停靠区域:左侧停靠、右侧停靠QTextEdit *te1 = new QTextEdit(this);//新建文本编辑框QTextEdit类对象te1->setText(tr("Window1, The dock widget can be moved between docks by the user" ""));      //设置文本内容dock->setWidget(te1);addDockWidget(Qt::RightDockWidgetArea,dock);//窗体可停靠区域:右侧停靠//停靠窗口2:可关闭、可浮动dock = new QDockWidget(tr("窗口二"),this);        //新建QDockWidget类对象dock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable);//窗体特性:Movable可移动、Closable可关闭、Floatable可浮动dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);              //窗体可停靠区域:左侧停靠、右侧停靠QTextEdit *te2 = new QTextEdit(this);//新建文本编辑框QTextEdit类对象te2->setText(tr("Window2, The dock widget can be detached from the main window,"" and floated as an independent window, and can be closed"));      //设置文本内容dock->setWidget(te2);addDockWidget(Qt::RightDockWidgetArea,dock);//窗体可停靠区域:右侧停靠}

运行如下

image-20250213115341937

🎀 Splitter

涉及函数/方法:setOpaqueResize():设定分割窗口的分隔条是否为实时更新显示。true为实时更新显示,false为拖拽时显示灰色粗线条。

#include "mainwindow.h"#include <QApplication>#include <QSplitter>  //添加头文件
#include <QTextEdit>
#include <QFont>int main(int argc, char *argv[])//这里是应用程序的入口。几乎所有使用Qt的情况下,main()函数只需在将控制转交给Qt库之前执行初始化,然后Qt库通过事件向程序告知用户的行为。//所有Qt程序必须有且只有一个main()函数。argc是命令行变量的数量,argv是命令行变量的数组。
{QApplication a(argc, argv); //a是创建的QApplication类的对象,用来处理命令行变量。所有被Qt识别的命令行参数都将从argv中移去,argc也因此减少QFont font("ZYSong18030",12);a.setFont(font);            //设置字体及大小//1.主分割窗口//(1.1)新建主分割窗口QSplitter类对象:水平布局的分割窗口QSplitter *splitterMain = new QSplitter(Qt::Horizontal,0);   //水平布局,0表示主窗口//(1.2)新建文本编辑框QTextEdit类对象,将其插入主分割窗口中QTextEdit *textLeft = new QTextEdit(QObject::tr("Left Widget"),splitterMain);   //插入主分割窗口中textLeft->setAlignment(Qt::AlignCenter); //文本编辑框TextEdit中文字的对齐方式为【文字居中】//2.右分割窗口//(2.1)新建右分割窗口QSplitter类对象:垂直布局的分割窗口QSplitter *splitterRight = new QSplitter(Qt::Vertical,splitterMain);   //垂直布局,并以splitterMain主分割窗口为父窗口splitterRight->setOpaqueResize(false);   //setOpaqueResize():设定分割窗口的分隔条是否为实时更新显示。true为实时更新显示,false为拖拽时显示灰色粗线条//(2.2)新建文本编辑框QTextEdit类对象,将其插入右分割窗口中QTextEdit *textUp = new QTextEdit(QObject::tr("Top Widget"),splitterRight); //插入右分割窗口中textUp->setAlignment(Qt::AlignCenter);   //文本编辑框TextEdit中文字的对齐方式为【文字居中】//(2.3)新建文本编辑框QTextEdit类对象,将其插入右分割窗口中QTextEdit *textBottom = new QTextEdit(QObject::tr("Bottom Widget"),splitterRight);  //插入右分割窗口中textBottom->setAlignment(Qt::AlignCenter);//文本编辑框TextEdit中文字的对齐方式为【文字居中】splitterMain->setStretchFactor(1,1);//第一个参数表示插入时控件序号为1的控件(即第2个控件),第二个参数大于0表示该控件可伸缩splitterMain->setWindowTitle(QObject::tr("Splitter"));//设置窗口标题splitterMain->show();//显示窗口//    MainWindow w;//    w.show();return a.exec();//main()函数将控制权交给Qt,Qt完成事件处理工作,当应用程序退出的时候,exec()函数的值就会返回。//exec()函数中,Qt接收并处理用户和系统的事件,并且将他们传递给适当的窗口部件。
}

运行如下

image-20250213115739427

二:🔥 共勉

😋 以上就是我对 【Qt】QMainWindow类 的理解, 觉得这篇博客对你有帮助的,可以点赞收藏关注支持一波~ 😉
在这里插入图片描述

相关文章:

【Qt】QMainWindow类

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Qt 目录 一&#xff1a;&#x1f525; QMainWindow 概述 &#x1f98b; 菜单栏&#x1f380; 具体使用&#x1f380; 综合案例 &#x1f98b; 工具栏&#x1f98b; 状态栏&#x1f98b; 窗口布局&a…...

缓存 --- 缓存击穿, 缓存雪崩, 缓存穿透

缓存 --- 缓存击穿, 缓存雪崩, 缓存穿透 缓存击穿&#xff08;Cache Breakdown&#xff09;概念原理实际场景代码实现&#xff08;互斥锁方案&#xff09; 缓存雪崩&#xff08;Cache Avalanche&#xff09;概念原理实际场景代码实现&#xff08;随机过期时间&#xff09; 缓存…...

第五章 SQLite数据库:5、SQLite 进阶用法:ALTER 命令、TRUNCATE 操作、视图创建、事务控制和子查询的操作

1. SQLite ALTER 命令 SQLite 的 ALTER TABLE 命令允许在不完全重建表的情况下修改现有的表结构。通过 ALTER TABLE&#xff0c;您可以执行如重命名表名、添加新列等操作&#xff0c;但无法执行复杂的修改&#xff0c;如删除列或修改列的数据类型。 语法 重命名表 用于重命名…...

【2】Kubernetes 架构总览

Kubernetes 架构总览 主节点与工作节点 主节点 Kubernetes 的主节点&#xff08;Master&#xff09;是组成集群控制平面的关键部分&#xff0c;负责整个集群的调度、状态管理和决策。控制平面由多个核心组件构成&#xff0c;包括&#xff1a; kube-apiserver&#xff1a;集…...

【数据结构】红黑树

红黑树&#xff08; R e d B l a c k T r e e Red\ Black\ Tree Red Black Tree&#xff09;是一种自平衡二叉搜索树&#xff0c;也可以看作一种特化的 A V L AVL AVL 树&#xff08;通过颜色规则来实现自平衡功能&#xff09;&#xff0c;都是在进行插入和删除操作时通过特定…...

ThreadLocal - 原理与应用场景详解

ThreadLocal 的基础概念 在 Java 的多线程世界里&#xff0c;线程之间的数据共享与隔离一直是一个关键话题。如果处理不当&#xff0c;很容易引发线程安全问题&#xff0c;比如数据混乱、脏读等。而 ThreadLocal 这个工具类&#xff0c;就像是为线程量身定制的 “私人储物柜”…...

VS Code 远程连接服务器:Anaconda 环境与 Python/Jupyter 运行全指南。研0大模型学习(第六、第七天)

VS Code 远程连接服务器&#xff1a;Anaconda 环境与 Python/Jupyter 运行全指南 在使用 VS Code 通过 SSH 远程连接到服务器进行开发时&#xff0c;尤其是在进行深度学习等需要特定环境的工作时&#xff0c;正确配置和使用 Anaconda 环境以及理解不同的代码运行方式非常关键。…...

chili3d调试6 添加左侧面板

注释前 一个一个注释看对应哪个窗口 无事发生 子方法不是显示的窗口 注释掉看看 没了 注释这个看看 零件页面没了 这个浏览器居然完全不用关的&#xff0c;刷新就重载了 注释看看 无工具栏版本 sidebar&#xff1a; 往框框里面加入 div({ className: style.input }, user_…...

Python变量全解析:从基础到高级的命名规则与数据类型指南

一、变量基础与内存机制 1.1 变量的三元构成 每个Python变量由三个核心要素构成&#xff1a; ​标识&#xff08;Identity&#xff09;​&#xff1a;对象的内存地址&#xff0c;通过id(obj)获取&#xff08;如id(name)输出0x5a1b2c3d&#xff09;​类型&#xff08;Type&am…...

组装一台intel n95纯Linux Server服务器

前言 笔者自己的电脑是macmini m4&#xff0c;平时都是使用虚拟机来充当Linux服务器&#xff08;系统Ubuntu Server&#xff09;&#xff0c;但是毕竟是ARM CPU&#xff0c;而且黄金内存&#xff0c;开不了几个虚拟机&#xff08;加内存不划算&#xff09;&#xff0c;所以组装…...

计算机网络中的网络层:架构、功能与重要性

一、网络层概述 在计算机网络的分层模型中&#xff0c;网络层&#xff08;Network Layer&#xff09;位于 数据链路层 之上&#xff0c;传输层 之下。网络层的主要任务是处理数据包的路由选择、转发以及分段&#xff0c;使得信息能够从源设备传送到目标设备。它还通过 IP协议&…...

Transformer系列(一):NLP中放弃使用循环神经网络架构

NLP中放弃使用循环神经网络架构 一、符号表示与概念基础二、循环神经网络1. 依赖序列索引存在的并行计算问题2. 线性交互距离 三、总结 该系列笔记阐述了自然语言处理&#xff08;NLP&#xff09;中不再采用循环架构&#xff08;recurrent architectures&#xff09;的原因&…...

(学习总结34)Linux 库制作与原理

Linux 库制作与原理 库的概念静态库操作归档文件命令 ar静态库制作静态库使用 动态库动态库制作动态库使用与运行搜索路径问题解决方案方案2&#xff1a;建立同名软链接方案3&#xff1a;使用环境变量 LD_LIBRARY_PATH方案4&#xff1a;ldconfig 方案 使用外部库目标文件ELF 文…...

【QT】 QT中的列表框-横向列表框-树状列表框-表格列表框

QT中的列表框-横向列表框-树状列表框-表格列表框 1.横向列表框(1)主要方法(2)信号(3) 示例代码1:(4) 现象&#xff1a;(5) 示例代码2&#xff1a;加载目录项在横向列表框显示(6) 现象&#xff1a; 2.树状列表框 QTreeWidget(1)使用思路(2)信号(3)常用的接口函数(4) 示例代码&am…...

使用DeepSeek的AIGC的内容创作者,如何看待陈望道先生所著的《修辞学发凡》?

目录 1.从修辞手法的运用角度 2.从语言风格的塑造角度 3.从提高创作效率角度 4.从文化传承与创新角度 大家好这里是AIWritePaper官方账号&#xff0c;官网&#x1f449;AIWritePaper~ 《修辞学发凡》是陈望道 1932 年出版的中国第一部系统的修辞学著作&#xff0c;科学地总…...

使用 GitHub Actions 和 Nuitka 实现 Python 应用(customtkinter ui库)的自动化跨平台打包

目录 引言前置准备配置文件详解实现细节CustomTkinter 打包注意事项完整配置示例常见问题 引言 在 Python 应用开发中&#xff0c;将源代码打包成可执行文件是一个常见需求。本文将详细介绍如何使用 GitHub Actions 和 Nuitka 实现自动化的跨平台打包流程&#xff0c;支持 W…...

【Part 2安卓原生360°VR播放器开发实战】第一节|通过传感器实现VR的3DOF效果

《VR 360全景视频开发》专栏 将带你深入探索从全景视频制作到Unity眼镜端应用开发的全流程技术。专栏内容涵盖安卓原生VR播放器开发、Unity VR视频渲染与手势交互、360全景视频制作与优化&#xff0c;以及高分辨率视频性能优化等实战技巧。 &#x1f4dd; 希望通过这个专栏&am…...

【1】云原生,kubernetes 与 Docker 的关系

Kubernetes&#xff1f;K8s&#xff1f; Kubernetes经常被写作K8s。其中的数字8替代了K和s中的8个字母——这一点倒是方便了发推&#xff0c;也方便了像我这样懒惰的人。 什么是云原生&#xff1f; 云原生&#xff1a; 它是一种构建和运行应用程序的方法&#xff0c;它包含&am…...

基于Redis实现RAG架构的技术解析与实践指南

一、Redis在RAG架构中的核心作用 1.1 Redis作为向量数据库的独特优势 Redis在RAG架构中扮演着向量数据库的核心角色&#xff0c;其技术特性完美契合RAG需求&#xff1a; 特性技术实现RAG应用价值高性能内存存储基于内存的键值存储架构支持每秒百万级的向量检索请求分布式架构…...

trivy开源安全漏洞扫描器——筑梦之路

开源地址&#xff1a;https://github.com/aquasecurity/trivy.git 可扫描的对象 容器镜像文件系统Git存储库&#xff08;远程&#xff09;虚拟机镜像Kubernetes 在容器镜像安全方面使用广泛&#xff0c;其他使用相对较少。 能够发现的问题 正在使用的操作系统包和软件依赖项…...

pnpm确认全局下载安装了还是显示cnpm不是内部或外部命令,也不是可运行的程序

刚开始是正常使用的。突然开始用不了了一直报错 1.在确保自己node和npm都一直正常使用并且全局安装pnpm的情况下 打开cmd查看npm的环境所在位置 npm config get prefix 2.接着打开高级系统设置 查看自己的path配置有没有问题 确认下载了之后pnpm -v还报错说明没有查询到位置 …...

基于 pnpm + Monorepo + Turbo + 无界微前端 + Vite 的企业级前端工程实践

基于 pnpm Monorepo Turbo 无界微前端 Vite 的企业级前端工程实践 一、技术演进&#xff1a;为什么引入 Vite&#xff1f; 在微前端与 Monorepo 架构落地后&#xff0c;构建性能成为新的优化重点&#xff1a; Webpack 构建瓶颈&#xff1a;复杂配置导致开发启动慢&#…...

软考高级系统架构设计师-第15章 知识产权与标准化

【本章学习建议】 根据考试大纲&#xff0c;本章主要考查系统架构设计师单选题&#xff0c;预计考3分左右&#xff0c;较为简单。 15.1 标准化基础知识 1. 标准的分类 分类 内容 国际标准&#xff08;IS&#xff09; 国际标准化组织&#xff08;ISO&#xff09;、国际电工…...

MySQL 视图

核心目标&#xff1a; 学习如何创建和使用视图&#xff0c;以简化复杂的查询、提供数据访问控制、实现逻辑数据独立性&#xff0c;并通过 WITH CHECK OPTION 保证数据一致性。 什么是视图&#xff1f; 视图&#xff08;View&#xff09;是一种虚拟表&#xff0c;其内容由一个 …...

[操作系统] 信号

信号 vs IPC 板书最后提到了 “信号 vs IPC”&#xff0c;暗示了信号也是一种进程间通信 (Inter-Process Communication, IPC) 的机制。虽然信号的主要目的是事件通知&#xff0c;但它也可以携带少量的信息&#xff08;即信号的类型&#xff09;。 初探“信号”——操作系统的“…...

网络基础(协议,地址,OSI模型、Socket编程......)

目录 一、计算机网络发展 二、协议 1.认识协议 2.OSI七层模型 3.TCP/IP 五层(或四层)模型 4.协议本质 三、网络传输流程 1.MAC地址 2.协议栈 3.IP地址 IP地址 vs MAC地址 1. 核心区别 2. 具体通信过程类比 3. 关键总结 为什么需要两者&#xff1f; 4.协议栈图解…...

产品经理学习过程

一&#xff1a;扫盲篇&#xff08;初始产品经理&#xff09; 阶段1&#xff1a;了解产品经理 了解产品经理是做什么的、产品经理的分类、产品经理在实际工作中都会接触什么样的岗位、以及产品经理在实际工作中具体要做什么事情。 二&#xff1a;准备篇 阶段2&#xff1a;工…...

深入理解Java包装类:自动装箱拆箱与缓存池机制

深入理解Java包装类&#xff1a;自动装箱拆箱与缓存池机制 对象包装器 Java中的数据类型可以分为两类&#xff1a;基本类型和引用类型。作为一门面向对象编程语言&#xff0c; 一切皆对象是Java语言的设计理念之一。但基本类型不是对象&#xff0c;无法直接参与面向对象操作&…...

Linux中的信号量

目录 信号量概念 定义 操作 类型 应用 信号量封装 一、创建信号量 头文件 函数原型 参数说明 返回值 示例 二、设置信号量初始值 头文件 函数原型 参数解释 返回值 示例 三、信号量的P操作 头文件 函数原型 参数解释 返回值 示例 四、信号量的V操作 示…...

深入理解linux操作系统---第15讲 Web 服务器 Nginx

15.1 Nginx 概述 核心特性与历史背景 Nginx由俄罗斯工程师Igor Sysoev于2002年开发&#xff0c;2004年正式发布&#xff0c;旨在解决传统服务器&#xff08;如Apache&#xff09;的C10K问题&#xff08;即单机万级并发连接处理&#xff09;。其采用事件驱动&#xff08;Event…...

深度解析算法之前缀和

25.【模版】一维前缀和 题目链接 描述 输入描述 输出描述 输出q行,每行代表一次查询的结果. 示例 输入&#xff1a; 3 2 1 2 4 1 2 2 3 复制 输出&#xff1a; 3 6 这个题的话就是下面的样子&#xff0c;我们第一行输入 3 2的意思即是这个数组是3个元素大小的数组&…...

混合精度训练中的算力浪费分析:FP16/FP8/BF16的隐藏成本

在大模型训练场景中&#xff0c;混合精度训练已成为降低显存占用的标准方案。然而&#xff0c;通过NVIDIA Nsight Compute深度剖析发现&#xff0c;‌精度转换的隐藏成本可能使理论算力利用率下降40%以上‌。本文基于真实硬件测试数据&#xff0c;揭示不同精度格式的计算陷阱。…...

6.8 Python定时任务实战:APScheduler+Cron实现每日/每周自动化调度

Python定时任务实战:APScheduler+Cron实现每日/每周自动化调度 实现每日和每周定时任务 关键词:定时任务调度、Python 原生调度器、Cron 脚本、异常重试机制、任务队列管理 1. 定时任务架构设计 采用 分层调度架构 实现灵活的任务管理: #mermaid-svg-PnZcDOgOklVieQ8X {f…...

[Android] 豆包爱学v4.5.0小学到研究生 题目Ai解析

[Android] 豆包爱学 链接&#xff1a;https://pan.xunlei.com/s/VOODT6IclGPsC7leCzDFz521A1?pwdjxd8# 拍照解析答案 【应用名称】豆包爱学 【应用版本】4.5.0 【软件大小】95mb 【适用平台】安卓 【应用简介】豆包爱学&#xff0c;一般又称河马爱学教育平台app,河马爱学。 关…...

swift-12-Error处理、关联类型、assert、泛型_

一、错误类型 开发过程常见的错误 语法错误&#xff08;编译报错&#xff09; 逻辑错误 运行时错误&#xff08;可能会导致闪退&#xff0c;一般也叫做异常&#xff09; 2.1 通过结构体 第一步 struct MyError : Errort { var msg: String &#xff5d; 第二步 func divide(_ …...

每日定投40刀BTC(14)20250409 - 20250419

定投 坚持 《磨剑篇》浮生多坎壈&#xff0c;志业久盘桓。松柏凌霜易&#xff0c;骅骝涉险难。砺锋临刃缺&#xff0c;淬火取金残。但使精魂在&#xff0c;重开万象端。...

【刷题Day20】TCP和UDP(浅)

TCP 和 UDP 有什么区别&#xff1f; TCP提供了可靠、面向连接的传输&#xff0c;适用于需要数据完整性和顺序的场景。 UDP提供了更轻量、面向报文的传输&#xff0c;适用于实时性要求高的场景。 特性TCPUDP连接方式面向连接无连接可靠性提供可靠性&#xff0c;保证数据按顺序…...

大数据建模与评估

文章目录 实战案例:电商用户分群与价值预测核心工具与库总结一、常见数据挖掘模型原理及应用(一)决策树模型(二)随机森林模型(三)支持向量机(SVM)模型(四)K - Means聚类模型(五)K - Nearest Neighbors(KNN)模型二、运用Python机器学习知识实现数据建模与评估(一…...

Python语法系列博客 · 第6期[特殊字符] 文件读写与文本处理基础

上一期小练习解答&#xff08;第5期回顾&#xff09; ✅ 练习1&#xff1a;字符串反转模块 string_tools.py # string_tools.py def reverse_string(s):return s[::-1]调用&#xff1a; import string_tools print(string_tools.reverse_string("Hello")) # 输出…...

Pandas取代Excel?

有人在知乎上提问&#xff1a;为什么大公司不用pandas取代excel&#xff1f; 而且列出了几个理由&#xff1a;Pandas功能比Excel强大&#xff0c;运行速度更快&#xff0c;Excel除了简单和可视化界面外&#xff0c;没有其他更多的优势。 有个可怕的现实是&#xff0c;对比Exce…...

《解锁图像“高清密码”:超分辨率重建之路》

在图像的世界里&#xff0c;高分辨率意味着更多细节、更清晰的画面&#xff0c;就像用高清望远镜眺望远方&#xff0c;一切都纤毫毕现。可现实中&#xff0c;我们常被低分辨率图像困扰&#xff0c;模糊的监控画面、老旧照片里难以辨认的面容……不过别担心&#xff0c;图像超分…...

杨校老师课堂之C++入门练习题梳理

采用C完成下列题目&#xff0c;要求每题目的时间限制&#xff1a;1秒 内存限制&#xff1a;128M 1. 交换个位与十位的数字 时间限制&#xff1a;1秒 内存限制&#xff1a;128M 题目描述 试编写一个程序&#xff0c;输入一个两位数&#xff0c;交换十位与个位上的数字并输出。 …...

基于springboot的老年医疗保健系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了六年的毕业设计程序开发&#xff0c;开发过上千套毕业设计程序&#xff0c;没有什么华丽的语言&#xff0…...

数据分析与挖掘

一 Python 基本语法 变量与数据类型 &#xff1a; Python 中变量无需声明&#xff0c;直接赋值即可。 常见的数据类型有数值型&#xff08;整型 int、浮点型 float、复数型 complex&#xff09;、字符串型&#xff08;str&#xff0c;用单引号、双引号或三引号括起来&#xff…...

RoBoflow数据集的介绍

https://public.roboflow.com/object-detection&#xff08;该数据集的网址&#xff09; 可以看到一些基本情况 如果我们想要下载&#xff0c;直接点击 点击图像可以看到一些基本情况 可以点击红色箭头所指&#xff0c;右边是可供选择的一些yolo模型的格式 如果你想下载…...

大模型Rag - 两大检索技术

一、稀疏检索&#xff1a;关键词匹配的经典代表 稀疏检索是一种基于关键词统计的传统检索方法。其基本思想是&#xff1a;通过词频和文档频率来衡量一个文档与查询的相关性。 核心原理 文档和查询都被表示为稀疏向量&#xff08;如词袋模型&#xff09;&#xff0c;只有在词…...

【T型三电平仿真】SVPWM调制

目录 仿真模型分析 克拉克变换 大扇区判断​编辑 小区域判断 计算基本电压矢量作用时间 确定基本电压矢量的作用顺序 作用时间和矢量作用顺序对应 七段式化生成阶梯图 矢量状态分布 本人学习过程中提出的问题和解释 SVPWM调制实现了什么功能 SVPWM的算法步骤是什么…...

树莓派5-开发应用笔记

0.树莓派系统目录 /home&#xff1a;用户目录。 除了root用户外&#xff0c;其他所有的使用者的数据都存放在这个目录下&#xff0c;在树莓派的系统中&#xff0c;/home目录中有一个pi的子目录,这个就是pi用户的默认目录。 /bin&#xff1a; 主要放置系统的必备执行文件目录。 …...

[Java实战经验]异常处理最佳实践

一些好的异常处理实践。 目录 异常设计自定义异常为异常设计错误代码&#xff08;状态码&#xff09;设计粒度全局异常处理异常日志信息保留 异常处理时机资源管理try-with-resources异常中的事务 异常设计 自定义异常 自定义异常设计&#xff0c;如业务异常定义BusinessExce…...

AOSP的Doze模式-LightIdle初识

前言 从Android 6.0开始&#xff0c;谷歌引入了Doze模式(打盹模式)的省电技术延长电池使用时间。根据第三方测试显示&#xff0c;两台同样的Nexus 5&#xff0c;开启的Doze的一台待机能达到533小时&#xff0c;而未开启Doze的一台待机只能达到200小时。Doze省电效果十分明显。…...