网站模板演示/深圳市文化广电旅游体育局
前言
作者:小蜗牛向前冲
名言:我可以接受失败,但我不能接受放弃
如果觉的博主的文章还不错的话,还请
点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正
目录
一、窗口的分类
二、菜单栏
1、菜单栏基本知识
2、实战案例
三、工具栏
1、基础知识
2、实战案例
四、 状态栏
五、浮动窗口
六、对话框
1、简单介绍
2、二种自定义对话框的方式
2.1、纯代码实现
2.2、图形化界面实现
3、 Qt内置对话框
3.1、 消息对话框 QMessageBox
3.2、颜⾊对话框 QColorDialog
3.3、⽂件对话框QFileDialog
3.4、 字体对话框QFontDialog
3.5、输⼊对话框QInputDialog
本期学习:几中窗口属性:菜单栏,工具栏,状态栏,浮动窗口,对话框,在对话框中又细分了五种对话框
一、窗口的分类
在前面学习QT的过程中,我们学习的都是用QWidget类来实现的,今天要要学习的窗口部件都是围绕的QMainWindow类来实现的。
下面将是我们要学习的重点组件
QMainWindow是⼀个为用户提供主窗⼝程序的类,继承⾃QWidget类,并且提供了⼀个预定义的布局。QMainWindow包含⼀个菜单栏(menubar)、多个⼯具栏(toolbars)、多个浮动窗⼝(铆
接部件)(dockwidgets)、⼀个状态栏(statusbar)和⼀个中⼼部件(centralwidget),它是许多应
⽤程序的基础,如⽂本编辑器,图⽚编辑器等。如下图为QMainwindow中各组件所处的位置:
二、菜单栏
1、菜单栏基本知识
Qt中的菜单栏是通过QMenuBar这个类来实现的。⼀个主窗⼝最多只有⼀个菜单栏。位于主窗⼝顶部、主窗⼝标题栏下⾯。菜单栏中包含菜单.菜单中包含菜单项.
对于一个常用的操作是,我们先要通过QMenuBar的类来创建菜单栏
在堆上创建
在通过 setMenuBar把菜单放入大窗口中。
有需要的话我们还用通过addMenu函数来给菜单栏添加菜单。
添加好菜单后,一个菜单中可能存在多个选项,这个时候,我们通过QAction类抽出公众的动作,在进行菜单选项的添加。
这里的QAction既可以给菜单栏用也可以给状态栏用。
为了更好的区分菜单选项我们可以给菜单选择添加分割线,addSeparator函数实现。
2、实战案例
这里我们简单的创建一个菜单栏,在mainwindow.cpp中
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//设置标题this->setWindowTitle("记事本");//创建菜单栏
// QMenuBar* menuBar = new QMenuBar(this);//这种写法如果,我们在最初勾选ui自动生成会出现内存泄露//更规范的写法QMenuBar* menuBar = this->menuBar();//这里表示如果QMenuBar存在就直接返回获取,不存在在创建新的在返回this->setMenuBar(menuBar);//创建菜单QMenu* menu = new QMenu("文件");menuBar->addMenu(menu);//创建菜单选项QAction* action1 = new QAction("保存(&a)");//这里文件(&a)是对这个菜单选项添加快捷键alt+aQAction* action2 = new QAction("加载(&b)");menu->addAction(action1);menu->addAction(action2);//创建中央控件
// edit = new QTextEdit(this);
// this->setCentralWidget(edit);
// edit->setPlaceholderText("这里编写文本");}
其中我们也可以给菜单选项添加快捷键都是通过&实现的
三、工具栏
1、基础知识
工具栏是应⽤程序中集成各种功能实现快捷键使⽤的⼀个区域。可以有多个,也可以没有,它并不是应⽤程序中必须存在的组件。它是⼀个可移动的组件,它的元素可以是各种窗⼝组件,它的元素通常以图标按钮的⽅式存在。如下图为⼯具栏的⽰意图
我们可以通过addToolBar函数来创建一个工具栏,每次创建工具栏都需要调用该函数
工具栏不像菜单栏一般出现在窗口的顶部,他往往可以自己选择出现的位置。
有二种实现方式:
方式1:创建⼯具栏的同时指定其停靠的位置
在创建⼯具栏的同时,也可以设置⼯具栏的位置,其默认位置是在窗⼝的最上⾯;如上述代码,默认在最上⾯显⽰。⼯具栏允许停靠的区域由QToolBar类提供的allowAreas()函数决定,其中可以设置的位置包括
• Qt::LeftToolBarArea停靠在左侧
• Qt::RightToolBarArea停靠在右侧
• Qt::TopToolBarArea停靠在顶部
• Qt::BottomToolBarArea停靠在底部
• Qt::AllToolBarAreas以上四个位置都可停靠
方式2: 使⽤QToolBar类提供的setAllowedAreas()函数设置停靠位置。
这里简单区分一下:
第一种方式是默认工具栏所在的位置,当然在程序运行后,我们可以拖动改变。
第二种方式则运行停靠的位置 ,程序运行后,不可以拖动到不允许的地方。
如果我们不想让工具栏在程序运行后可以进行移动,通过设置⼯具栏的移动属性QToolBar类提供的setMovable()函数来设置。setMovable()函数原型为
void setMovable(bool movable)
其中ture是移动,false是不移动.
当我们如果想把状态栏脱离父窗口,我们就要甚至浮动,可以通过QToolBar类提供的setFloatable()函数来设置。setFloatable()函数原型为:
void setFloatable(bool floatable)
其中ture是浮动,false是不浮动
2、实战案例
这里大家按照练习一下:
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//设置窗口大小resize(800,600);//设置工具栏和位置,默认为窗口上面,这里设置为左边QToolBar* toolBar = new QToolBar(this);addToolBar(Qt::LeftToolBarArea,toolBar);//设置工具栏允许停靠的位置.只允许左右停靠toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);//设置工具栏的浮动属性toolBar->setFloatable(true);//设置工具栏的移动开关toolBar->setMovable(true);//设置工作栏的内容QAction * openAction = new QAction("open",this);QAction* newAction = new QAction("new",this);//添加toolBar->addAction(openAction);toolBar->addSeparator();//添加分割线toolBar->addAction(newAction);//在工具栏添加控件QPushButton * btn = new QPushButton(" 保存",this);toolBar->addWidget(btn);}
四、 状态栏
状态栏是应⽤程序中输出简要信息的区域。⼀般位于主窗⼝的最底部,⼀个窗⼝中最多只能有⼀个状态栏。在Qt中,状态栏是通过QStatusBar类来实现的。在状态栏中可以显⽰的消息类型有:
• 实时消息:如当前程序状态
• 永久消息:如程序版本号,机构名称
• 进度消息:如进度条提⽰,百分百提⽰
状态栏的创建外面可以通过QMainWindow类提供的statusBar()函数来创建
我们还可以设置状态提示信息:如下代码
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);//创建状态栏QStatusBar* stbar = statusBar();//将状态栏置于窗口setStatusBar(stbar);//在状态栏中显示信息stbar->showMessage("hello pjb",2000);//在状态 栏中显示信息2s//显示永久信息要用标签来显示,显示在 状态栏的右侧QLabel* label = new QLabel("提示信息",this);stbar->addPermanentWidget(label);
}
五、浮动窗口
在Qt中,浮动窗⼝也称之为铆接部件。浮动窗⼝是通过QDockWidget类来实现浮动的功能。浮动窗⼝⼀般是位于核⼼部件的周围,可以有多个。
当我们点开某个网站的时候,常会出现很多个浮动窗口的广告,让我们感觉很难受,他的设置也是非常简单的。
浮动窗⼝的创建是通过QDockWidget类提供的构造⽅法QDockWidget()函数动态创建的;⽰例如下
浮动窗口同样可以设置其出现的位置,可以通过QDockWidget类中提供setAllowedAreas()函数设置其允许停靠的位置。其中可以设置允许停靠的位置有
• Qt::LeftDockWidgetArea停靠在左侧
• Qt::RightDockWidgetArea停靠在右侧
• Qt::TopDockWidgetArea停靠在顶部
• Qt::BottomDockWidgetArea停靠在底部
• Qt::AllDockWidgetAreas以上四个位置都可停靠
六、对话框
1、简单介绍
对话框是GUI程序中不可或缺的组成部分。⼀些不适合在主窗⼝实现的功能组件可以设置在对话框
中。对话框通常是⼀个顶层窗⼝,出现在程序最上层,⽤于实现短期任务或者简洁的⽤户交互。Qt常⽤的内置对话框有:QFiledialog(⽂件对话框)、QColorDialog(颜⾊对话框)、QFontDialog
(字体对话框)、QInputDialog(输⼊对话框)和QMessageBox(消息框)
当我在画板中退出时,会弹出一个QMessageBox(消息框)告诉我是否要进行文件的保存。
这里我们简单创建一个对话框
MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);QDialog* dialog = new QDialog(this);dialog->setWindowTitle("对话框标题");dialog->resize(400,300);//通过show方法调用显示对话框dialog->show();//diaglog每次按下按键都会创建一个对象,当一个程序在允许的时候,可能遇到了无数次点击,内存消耗会非常大,甚至出现内存泄露//所有要设置在对话框点击关闭的时候,调用用deletedialog->setAttribute((Qt::WA_DeleteOnClose));
}
2、二种自定义对话框的方式
2.1、纯代码实现
首先要定义一个dialog.h的头文件
#ifndef DIALOG_H
#define DIALOG_H#include<QDialog>
class Dialog : public QDialog
{Q_OBJECT
public:Dialog(QWidget* parent);void handle();
};#endif // DIALOG_H
在dialog.cpp中实现自定义对话框
#include "dialog.h"
#include<QPushButton>
#include<QLabel>
#include<QVBoxLayout>Dialog::Dialog(QWidget* parent): QDialog(parent)
{//在Dialig对话框中添加控件QVBoxLayout* layout = new QVBoxLayout();this->setLayout(layout);QLabel* lable = new QLabel("这是一个对话框",this);QPushButton* button = new QPushButton("关闭",this);layout->addWidget(lable);layout->addWidget(button);connect(button,&QPushButton::clicked,this,&Dialog::handle);
}void Dialog::handle()
{this->close();
}
在mainwindow.cpp中实现点击按键触发stol函数,在函数中实现对话框的创建
void MainWindow::on_pushButton_clicked()
{Dialog* dialog = new Dialog(this);dialog->resize(400,300);dialog->setAttribute(Qt::WA_DeleteOnClose);dialog->show();
}
2.2、图形化界面实现
对图形化界面的实现,关键是实现一个dialog.ui文件
点击项目创建选择文件和类中的Qt设计师界面类
下面的一直选择默认的就好了
这里会生成一个 dialog.ui文件
点击进去,在这里就可以设计我们的对话框
实现的效果如下:
这里对话框可以分为模态和非模态。
模态简单来说,弹出对话框时,用户无法在操作父态对话框,必须完成对话框的内部操作才可以进行操作(强迫用户继续选择操作)。
他的调用无非是调用对话框的时候使用exec:
而对于模态者是可以进行多次操作
3、 Qt内置对话框
Qt提供了多种可复⽤的对话框类型,即Qt标准对话框。Qt标准对话框全部继承于QDialog类。常⽤标准对话框如下:
3.1、 消息对话框 QMessageBox
消息对话框是应⽤程序中最常⽤的界⾯元素。消息对话框主要⽤于为⽤⼾提⽰重要信息,强制⽤⼾进⾏选择操作
对于MessageBox他有二常用函数StandardButton
和Icon。
StandardButton
是 Qt 中定义的一组标准对话框按钮,常用于 QMessageBox
、QInputDialog
等对话框类中。这些标准按钮提供了一组常用的按钮选项,如 "OK"、"Cancel"、"Yes"、"No" 等,以便在对话框中使用。StandardButton
通过枚举值来表示,可以用于设置对话框的按钮和处理用户的按钮点击事件。
在 PyQt 中,图标(Icon)可以用于许多控件,如按钮(QPushButton)、标签(QLabel)、窗口(QMainWindow)等。图标可以增强用户界面,使其更具吸引力和易用性。使用 QIcon
类,可以方便地设置和管理图标。
QMessageBox类中定义了静态成员函数,可以直接调⽤创建不同⻛格的消息对话框,其中包括
这里我们点击按键的编写其槽函数
void MainWindow::on_pushButton_clicked()
{int result = QMessageBox::warning(this,"对话框的标题","对话框的文本",QMessageBox::Ok|QMessageBox::Cancel);if(result==QMessageBox::Ok){qDebug()<<"ok";}else{qDebug()<<"Cancel";}
}
3.2、颜⾊对话框 QColorDialog
颜⾊对话框的功能是允许⽤⼾选择颜⾊。继承⾃QDialog类。颜⾊对话框如下图⽰:
对于getColor函数能够弹出一个模态对话框,用户选择颜色后,点击确认就可以关闭对话框。
void MainWindow::on_pushButton_clicked()
{//函数的返回值就是用户的选择颜色QColor color = QColorDialog::getColor(QColor(0,255,0),this,"选择颜色");qDebug()<<color;char style[1024] = {0};sprintf(style,"backgroud-color: rgb(%d,%d,%d)",color.red(),color.green(),color.blue());this->setStyleSheet(style);
}
这里使用的是RGB用0-1之间的小数表示。
3.3、⽂件对话框QFileDialog
⽂件对话框⽤于应⽤程序中需要打开⼀个外部⽂件或需要将当前内容存储到指定的外部⽂件。
其中有二个关键函数:
getOpenFileName打开文件
getSaveFileName保存文件
通过这个二函数我们就可以打开或者保存文件
编写槽函数
void MainWindow::on_pushButton_clicked()
{QString filePath =QFileDialog::getOpenFileName(this);qDebug()<<filePath;
}void MainWindow::on_pushButton_2_clicked()
{QString filePath =QFileDialog::getSaveFileName(this);qDebug()<<filePath;
}
3.4、 字体对话框QFontDialog
Qt中提供了预定义的字体对话框类QFontDialog,⽤于提供选择字体的对话框部件。
运⾏效果如下:
3.5、输⼊对话框QInputDialog
Qt中提供了预定义的输⼊对话框类:QInputDialog,⽤于进⾏临时数据输⼊的场合。
这里可以让用户输入整数,浮点数,还可以是字符串(类似于下拉框)
双精度浮点型输⼊数据对话框:double getDouble
整型输⼊数据对话框:int getInt选择条⽬型输⼊数据框:QStringgetItem
⽰例1:浮点型数据输⼊对话框
⽰例2:整型数据输⼊对话框
⽰例3:打开选择条⽬对话框
相关文章:

[Qt的学习日常]--窗口
前言 作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、窗口的分…...

Vue发送http请求
1.创建项目 创建一个新的 Vue 2 项目非常简单。在终端中,进入您希望创建项目的目录(我的目录是D:\vue),并运行以下命令: vue create vue_test 2.切换到项目目录,运行项目 运行成功后,你将会看到以下的编译成功的提示…...

学习使用js和jquery修改css路径,实现html页面主题切换功能
学习使用js和jquery修改css路径,实现html页面主题切换功能 效果图html代码js切换css关键代码jquery切换css关键代码 效果图 html代码 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>修改css路径</title&g…...

(转)请介绍一下Redis的数据淘汰策略
1. **NoEviction(不淘汰)**:当内存不足时,直接返回错误,不淘汰任何数据。该策略适用于禁止数据淘汰的场景,但需要保证内存足够。 2. **AllKeysLFU(最少使用次数淘汰)**:…...

APP自动化测试-Appium常见操作之详讲
一、基本操作 1、点击操作 示例:element.click() 针对元素进行点击操作 2、初始化:输入中文的处理 说明:如果连接的是虚拟机(真机无需加这两个参数,加上可能会影响手工输入),在初始化配置中…...

写给大数据开发:谈谈数仓建模的反三范式
在数仓建设中,我们经常谈论反三范式。顾名思义,反范式化指的是通过增加冗余或重复的数据来提高数据库的读性能。简单来说,就是浪费存储空间,节省查询时间。用行话讲,这就是以空间换时间。听起来像是用大炮打蚊子&#…...

Stable diffusion 3 正式开源
6月12日晚,著名开源大模型平台Stability AI正式开源了,文生图片模型Stable Diffusion 3 Medium(以下简称“SD3-M”)权重。 SD3-M有20亿参数,平均生成图片时间在2—10秒左右推理效率非常高,同时对硬件的需求…...

如何配置node.js环境
文章目录 step1. 下载node.js安装包step2. 创建node_global, node_cache文件夹step3.配置node环境变量step3. cmd窗口检查安装的node和npm版本号step4. 设置缓存路径\全局安装路径\下载镜像step5. 测试配置的nodejs环境 step1. 下载node.js安装包 下载地址:node.js…...

python tensorflow 各种神经元
感知机神经元(Perceptron Neuron): 最基本的人工神经元模型,用于线性分类任务。 import numpy as npclass Perceptron:def __init__(self, input_size, learning_rate0.01, epochs1000):self.weights np.zeros(input_size 1) #…...

Gone框架介绍27 - 再讲 Goner 和 依赖注入
gone是可以高效开发Web服务的Golang依赖注入框架 github地址:https://github.com/gone-io/gone 文档地址:https://goner.fun/zh/ 文章目录 Goner 和 依赖注入Goner的定义依赖标记Goners 注册Priest函数 Goner 和 依赖注入 Gone 作为一个依赖注入框架&am…...

【Python/Pytorch 】-- 滑动窗口算法
文章目录 文章目录 00 写在前面01 基于Python版本的滑动窗口代码02 算法效果 00 写在前面 写这个算法原因是:训练了一个时序网络,该网络模型的时序维度为32,而测试数据的时序维度为90。因此需要采用滑动窗口的方法,生成一系列32…...

Clickhouse集群create drop database可删除集群数据库或只删除本地数据库
集群环境下,在任意一个节点创建数据库,如果加上了ON CLUSTER clustername,则在集群环境的所有节点上都创建了该数据库,并在集群环境的所有节点上都创建了该数据库对应的目录,且数据库的metadata_path对应的目录路径在所…...

【docker】adoptopenjdk/openjdk8-openj9:alpine-slim了解
adoptopenjdk/openjdk8-openj9:alpine-slim 是一个 Docker 镜像的标签,它指的是一个特定的软件包,用于在容器化环境中运行 Java 应用程序。 镜像相关的网站和资源: AdoptOpenJDK 官方网站 - AdoptOpenJDK 这是 AdoptOpenJDK 项目的官方网站&…...

Vscode interaction window
python 代码关联到 jupyter 模式 在代码前添加: # %%print("hellow wolrd!") 参考文档链接: https://code.visualstudio.com/docs/python/jupyter-support-py...

后端数据null前端统一显示成空
handleNullValues方法在封装请求接口返回数据时统一处理 // null 转 function handleNullValues(data) {// 使用递归处理多层嵌套的对象或数组function processItem(item) {if (Array.isArray(item)) {return item.map(processItem);} else if (typeof item object &&…...

【设计模式深度剖析】【9】【行为型】【访问者模式】| 以博物馆的导览员为例加深理解
👈️上一篇:备忘录模式 | 下一篇:状态模式👉️ 设计模式-专栏👈️ 文章目录 访问者模式定义英文原话直译如何理解呢? 访问者模式的角色类图代码示例 访问者模式的应用优点缺点使用场景 示例解析:博物馆的导览员代码示例 访问…...
Salesforce‘s 爱因斯坦机器人助手引领工业聊天机器人时代
CRM的对话式人工智能助手,根据公司数据提供可靠的人工智能响应及日本工业聊天机器人现状 【前言】 爱因斯坦助手(Einstein Copilot)提供可靠的响应,因为它基于公司独特的数据和元数据,使其能够深入了解公司的业务和客…...

Day7—zookeeper基本操作
ZooKeeper介绍 ZooKeeper(动物园管理员)是一个分布式的、开源的分布式应用程序的协调服务框架,简称zk。ZooKeeper是Apache Hadoop 项目下的一个子项目,是一个树形目录服务。 ZooKeeper的主要功能 配置管理 分布式锁 集群管理…...

计算机组成原理---Cache的基本工作原理习题
对应知识点: Cache的基本原理 1.某存储系统中,主存容量是Cache容量的4096倍,Cache 被分为 64 个块,当主存地址和Cache地址采用直接映射方式时,地址映射表的大小应为()(假设不考虑一致维护和替…...

springboot项目中切数据库(mysql-> pg)带来的适配问题:typeHandler
一、数据表中有一张表,名为role_permission,DDL如下: CREATE TABLE "public"."role_permission" ( "role_id" varchar(64) COLLATE "pg_catalog"."default" NOT NULL, "permiss…...

从零开始的<vue2项目脚手架>搭建:vite+vue2+eslint
前言 为了写 demo 或者研究某些问题,我经常需要新建空项目。每次搭建项目都要从头配置,很麻烦。所以我决定自己搭建一个项目初始化的脚手架(取名为 lily-cli)。 脚手架(scaffolding):创建项目时…...

Hadoop升级失败,File system image contains an old layout version -64
原始版本 Hadoop 3.1.3 升级版本 Hadoop 3.3.3 报错内容如下 datasophon 部署Hadoop版本 查看Hadoop格式化版本 which hadoop-daemon.sh/bigdata/app/hadoop-3.1.3/sbin/hadoop-daemon.sh删除原来的旧版本 rm -rf /bigdata/app/hadoop-3.1.3查看环境变量 env|grep HADOOPHAD…...

[机器学习算法]决策树
1. 理解决策树的基本概念 决策树是一种监督学习算法,可以用于分类和回归任务。决策树通过一系列规则将数据划分为不同的类别或值。树的每个节点表示一个特征,节点之间的分支表示特征的可能取值,叶节点表示分类或回归结果。 2. 决策树的构建…...

springboot应用cpu飙升的原因排除
1、通过top或者jps命令查到是那个java进程, top可以看全局那个进程耗cpu,而jps则默认是java最耗cpu的,比如找到进程是196 1.1 top (推荐)或者jps命令均可 2、根据第一步获取的进程号,查询进程里那个线程最占用cpu,发…...

反激开关电源EMI电路选型及计算
EMI :开关电源对电网或者其他电子产品的干扰 EMI :传导与辐射 共模电感的滤波电路,La和Lb就是共模电感线圈。这两个线圈绕在同一铁芯上,匝数和相位都相 同(绕制反向)。 这样,当电路中的正常电流(差模&…...

vue3前端对接后端的图片验证码
vue3前端对接后端的图片验证码 <template> <image :src"captchaUrl" alt"图片验证码" click"refreshCaptcha"></image> </template><script setup>import {ref} from "vue";import {useCounterStore} …...

【Unity】RPG2D龙城纷争(四)要诀、要诀数据集
更新日期:2024年6月20日。 项目源码:第五章发布(正式开始游戏逻辑的章节) 索引 简介要诀数据集(AbilityDataSet)一、定义要诀数据集类二、要诀属性1.要诀类型2.攻击距离3.基础命中、暴击率4.基础属性加成5.…...

一种基于非线性滤波过程的旋转机械故障诊断方法(MATLAB)
在众多的旋转机械故障诊断方法中,包络分析,又称为共振解调技术,是目前应用最为成功的方法之一。首先,对激励引起的共振频带进行带通滤波,然后对滤波信号进行包络谱分析,通过识别包络谱中的故障相关的特征频…...

HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)
系列文章目录 HarmonyOS Next 系列之省市区弹窗选择器实现(一) HarmonyOS Next 系列之验证码输入组件实现(二) HarmonyOS Next 系列之底部标签栏TabBar实现(三) HarmonyOS Next 系列之HTTP请求封装和Token…...

如果xml在mapper目录下,如何扫描到xml
如果xml在mapper目录下,如何扫描到xml 项目结构 src├── main│ ├── java│ │ └── com│ │ └── bg│ │ ├── Application.java│ │ ├── domain│ │ │ └── User.java│ │ …...