Qt Model/View之Model
在检查如何处理选择之前,您可能会发现检查模型/视图框架中使用的概念很有用。
基本概念
在模型/视图架构中,模型提供了一个标准接口,用于视图和委托访问数据。在Qt中,标准接口由QAbstractItemModel类定义。无论数据项如何存储在任何底层数据结构中,QAbstractItemModel的所有子类都将数据表示为包含项目表的层次结构。视图使用这种约定来访问模型中的数据项,但它们向用户呈现这些信息的方式没有限制。
模型还通过信号和槽机制通知任何附加视图有关数据更改的信息。
本节描述了一些基本概念,这些概念对于其他组件通过模型类访问数据项的方式至关重要。后面的部分将讨论更高级的概念。
模型索引
为了确保数据的表示和访问方式是分开的,引入了模型索引的概念。可以通过模型获得的每条信息都由模型索引表示。视图和委托使用这些索引来请求要显示的数据项。
因此,只有模型需要知道如何获取数据,模型管理的数据类型可以定义得相当通用。模型索引包含一个指向创建它们的模型的指针,这可以防止在使用多个模型时产生混淆
QAbstractItemModel *model = index.model();
模型索引提供对信息片段的临时引用,可用于通过模型检索或修改数据。由于模型可能会不时地重新组织其内部结构,因此模型索引可能会变得无效,不应该被存储。如果需要对一个信息片段的长期引用,则必须创建一个持久的模型索引。这提供了对模型保持更新的信息的引用。临时模型索引由QModelIndex类提供,持久模型索引由QPersistentModelIndex类提供。
要获得对应于数据项的模型索引,必须为模型指定三个属性:行号、列号和父项的模型索引。下面将详细描述和解释这些属性。
行和列
在最基本的形式中,模型可以被访问为一个简单的表,其中项目按行号和列号定位。这并不意味着底层数据存储在数组结构中。使用行号和列号只是允许组件相互通信的约定。我们可以通过在模型中指定任意物品的行号和列号来获取它的信息,并得到表示该物品的索引:
QModelIndex index = model->index(row, column, ...);
为列表和表等简单的单层数据结构提供接口的模型不需要提供任何其他信息,但是,如上代码所示,在获取模型索引时,我们需要提供更多的信息。
行和列
该图显示了一个基本表模型的表示,其中每个项目通过一对行号和列号定位。通过将相关的行号和列号传递给模型,我们获得一个引用数据项的模型索引。
QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexB = model->index(1, 1, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());
模型中的顶级项总是通过指定QModelIndex()作为它们的父项来引用。这将在下一节中讨论。
项目(items)的父元素
当在表或列表视图中使用数据时,模型提供的类表接口是理想的。行和列的编号系统精确地映射到视图显示项目的方式。然而,像树视图这样的结构要求模型向其中的项公开更灵活的接口。因此,每个元素项也可以是另一个元素表的父元素,就像树视图中的顶层元素项可以包含另一个元素表一样。
在为模型元素请求索引时,必须提供元素父元素的一些信息。在模型外部,只有通过模型索引才能引用元素,因此还必须提供一个父模型索引:
QModelIndex index = model->index(row, column, parent);
父元素、行和列
该图显示了一个树模型的表示,其中每个项都由一个父项、一个行号和一个列号引用。
元素"A"和"C"在模型中被表示为顶层的兄弟元素:
QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());
A项有几个子项。项目“B”的模型索引由以下代码获得:
QModelIndex indexB = model->index(1, 0, indexA);
项目角色
模型中的项可以为其他组件执行不同的角色,从而允许为不同的情况提供不同类型的数据。例如,Qt::DisplayRole用于访问可以在视图中显示为文本的字符串。通常,项包含许多不同角色的数据,标准角色由Qt::ItemDataRole定义。
我们可以向模型请求项目的数据,方法是将项目对应的模型索引传递给模型,并指定一个角色来获得我们想要的数据类型:
QVariant value = model->data(index, role);
项目角色
角色指示模型引用的数据类型。视图可以以不同的方式显示角色,因此为每个角色提供适当的信息很重要。
创建新模型部分更详细地介绍了角色的一些特定用途。
项目数据的最常见用途是由Qt::ItemDataRole中定义的标准角色覆盖的。通过为每个角色提供适当的项目数据,模型可以向视图和委托提供提示,说明项目应该如何呈现给用户。不同类型的视图可以根据需要自由地解释或忽略此信息。还可以为特定于应用程序的目的定义其他角色
总结
- 模型索引以一种独立于任何底层数据结构的方式向视图和委托提供关于模型所提供的项目位置的信息。
- 元素项通过行号和列号以及父元素项的model索引进行引用。
- 模型索引是由模型根据其他组件(如视图和委托)的请求构建的。
- 如果在使用index()方法请求索引时为父元素指定了有效的模型索引,则返回的索引指向模型中父元素下面的元素。获得的索引指向该项的一个子项。
- 如果在使用index()方法请求索引时,为父元素指定了无效的模型索引,则返回的索引指向模型中的顶层元素。
- 角色区分与项相关联的不同类型的数据。
使用模型索引
为了演示如何使用模型索引从模型中检索数据,我们设置了一个没有视图的QFileSystemModel,并在一个小部件中显示文件和目录的名称。虽然这不是使用模型的正常方式,但它展示了模型在处理模型索引时使用的约定。
QFileSystemModel的加载是异步的,以最小化系统资源使用。在处理这个模型时,我们必须考虑到这一点。
我们用以下方式构建文件系统模型:
QFileSystemModel *model = new QFileSystemModel;connect(model, &QFileSystemModel::directoryLoaded, [model](const QString &directory) {QModelIndex parentIndex = model->index(directory);int numRows = model->rowCount(parentIndex);});model->setRootPath(QDir::currentPath);
在这种情况下,我们首先设置一个默认的QFileSystemModel。我们将它连接到一个lambda,使用该模型提供的index()的特定实现来获取父索引。在lambda表达式中,我们使用rowCount()函数计算模型的行数。最后,我们设置QFileSystemModel的根路径,让它开始加载数据并触发lambda表达式。
为简单起见,我们只对模型第一列中的项感兴趣。我们依次检查每一行,获取每行中第一个项目的模型索引,并读取存储在模型中该项目的数据。
for (int row = 0; row < numRows; ++row) {QModelIndex index = model->index(row, 0, parentIndex);
为了获得模型索引,我们指定行号、列号(第一列为零),以及我们想要的所有项的父项的适当模型索引。使用模型的data()函数检索存储在每个条目中的文本。我们指定模型索引和DisplayRole以字符串的形式获取项目的数据。
QString text = model->data(index, Qt::DisplayRole).toString();// Display the text in a widget.}
上面的例子演示了从模型中检索数据的基本原则:
- 使用rowCount()和columnCount()可以得到模型的维度。这些函数通常需要指定一个父模型索引。
- 模型索引用于访问模型中的项。指定项目需要行、列和父模型索引。
- 要访问模型中的顶层元素,可以用QModelIndex()指定一个空的模型索引作为父索引。
- 项目包含不同角色的数据。要获取特定角色的数据,必须向模型提供模型索引和角色。
创建新模型
模型/视图组件之间的功能分离,允许创建可以利用现有视图的模型。这种方法允许我们使用标准的图形用户界面组件(如QListView、QTableView和QTreeView)来表示来自各种来源的数据。
QAbstractItemModel类提供了一个足够灵活的接口来支持在层次结构中安排信息的数据源,允许数据被插入、删除、修改或以某种方式排序。它还支持拖放操作。
QAbstractListModel和qabstractttablemodel类提供了对更简单的非层次数据结构的接口支持,并且更容易作为简单列表和表模型的起点使用。
在本节中,我们创建一个简单的只读模型来探索模型/视图架构的基本原理。在本节的后面,我们将修改这个简单的模型,让用户可以修改物品。
有关更复杂模型的示例,请参见简单树模型示例。
QAbstractItemModel子类的需求在模型子类化参考文档中有更详细的描述。
设计模型
在为现有数据结构创建新模型时,重要的是要考虑使用哪种类型的模型来为数据提供接口。如果数据结构可以表示为一个列表或项目表,那么您可以子类化QAbstractListModel或qabstractttablemodel,因为这些类为许多函数提供了合适的默认实现。
然而,如果底层数据结构只能用层次树结构表示,则有必要将QAbstractItemModel子类化。在简单的树模型示例中采用了这种方法。
在本节中,我们基于字符串列表实现了一个简单的模型,因此QAbstractListModel提供了一个理想的基类来进行构建。
无论底层数据结构采用何种形式,在特殊模型中使用允许更自然地访问底层数据结构的API来补充标准QAbstractItemModel API通常是一个好主意。这使得用数据填充模型变得更容易,但仍然允许其他通用模型/视图组件使用标准API与之交互。下面描述的模型为此提供了一个自定义构造函数。
只读的示例模型
这里实现的模型是一个简单的、非层次的、只读的数据模型,基于标准的QStringListModel类。它有一个QStringList作为它的内部数据源,并且只实现了建立一个有效模型所需的功能。为了让实现更容易,我们创建了一个子类QAbstractListModel,因为它为列表模型定义了合理的默认行为,而且它公开了一个比qabstracttemmodel类更简单的接口。
当实现一个模型时,重要的是要记住,QAbstractItemModel本身不存储任何数据,它只是提供了一个接口,视图使用它来访问数据。对于最小只读模型,只需要实现一些函数,因为大多数接口都有默认实现。类声明如下:
class StringListModel : public QAbstractListModel
{Q_OBJECTpublic:StringListModel(const QStringList &strings, QObject *parent = nullptr): QAbstractListModel(parent), stringList(strings) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override;QVariant data(const QModelIndex &index, int role) const override;QVariant headerData(int section, Qt::Orientation orientation,int role = Qt::DisplayRole) const override;private:QStringList stringList;
};
除了模型的构造函数,我们只需要实现两个函数:rowCount()返回模型的行数,data()返回与指定模型索引对应的数据项。
表现良好的模型还实现了headerData()方法,为树视图和表视图提供在它们的标题中显示的内容。
请注意,这是一个非层次模型,因此我们不必担心父子关系。如果我们的模型是分层的,我们还必须实现index()和parent()函数。
字符串列表存储在内部私有成员变量stringList中。
模型的尺寸
我们希望模型中的行数与字符串列表中的字符串数相同。我们实现rowCount()函数时就考虑到了这一点:
int StringListModel::rowCount(const QModelIndex &parent) const
{return stringList.count();
}
由于模型是非层次化的,我们可以放心地忽略与父项对应的模型索引。默认情况下,从QAbstractListModel派生的模型只包含一列,因此我们不需要重新实现columnCount()函数。
模型头文件和数据
对于视图中的项目,我们希望返回字符串列表中的字符串。data()函数负责返回与index参数对应的数据项:
QVariant StringListModel::data(const QModelIndex &index, int role) const
{if (!index.isValid())return QVariant();if (index.row() >= stringList.size())return QVariant();if (role == Qt::DisplayRole)return stringList.at(index.row());elsereturn QVariant();
}
只有当提供的模型索引有效,行号在字符串列表的范围内,并且请求的角色是我们支持的角色时,我们才返回一个有效的QVariant。
有些视图,如QTreeView和QTableView,能够同时显示标题和项目数据。如果我们的模型显示在带有表头的视图中,我们希望表头显示行号和列号。我们可以通过继承headerData()函数来提供关于标题的信息:
QVariant StringListModel::headerData(int section, Qt::Orientation orientation,int role) const
{if (role != Qt::DisplayRole)return QVariant();if (orientation == Qt::Horizontal)return QStringLiteral("Column %1").arg(section);elsereturn QStringLiteral("Row %1").arg(section);
}
同样,仅当角色是我们支持的角色时,才返回有效的QVariant。在决定返回的确切数据时,首部的方向也要考虑在内。
并不是所有的视图都显示带有项目数据的标题,那些这样做的视图可能被配置为隐藏它们。尽管如此,还是推荐你实现headerData()函数,以提供模型提供的数据的相关信息。
一个项目可以有多个角色,根据指定的角色提供不同的数据。在我们的模型中,项目只有一个角色,即DisplayRole,因此无论指定的角色是什么,我们都返回项目的数据。不过,我们可以在其他角色中重用为DisplayRole提供的数据,比如在工具提示中显示项目信息的ToolTipRole。
一个可编辑的模型
只读模型展示了如何向用户提供简单的选择,但对于许多应用程序来说,可编辑列表模型更有用。要修改只读模型,可以修改为只读模型实现的data()函数,以及两个额外的函数:flags()和setData()。在类定义中添加了下列函数声明:
Qt::ItemFlags flags(const QModelIndex &index) const override;bool setData(const QModelIndex &index, const QVariant &value,int role = Qt::EditRole) override;
使模型可编辑
委托在创建编辑器之前检查项是否可编辑。模型必须让委托知道它的项目是可编辑的。为此,我们为模型中的每个元素返回正确的标志;在这种情况下,我们启用了所有元素,并使它们既可选择又可编辑:
Qt::ItemFlags StringListModel::flags(const QModelIndex &index) const
{if (!index.isValid())return Qt::ItemIsEnabled;return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}
注意,我们不需要知道委托是如何执行实际的编辑过程的。我们只需要为委托提供一种方法来设置模型中的数据。这是通过setData()函数实现的:
bool StringListModel::setData(const QModelIndex &index,const QVariant &value, int role)
{if (index.isValid() && role == Qt::EditRole) {stringList.replace(index.row(), value.toString());emit dataChanged(index, index, {role});return true;}return false;
}
插入和删除行
可以更改模型中的行数和列数。在字符串列表模型中,只改变行数是有意义的,所以我们只重新实现插入和删除行的函数。这些在类定义中声明:
bool insertRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;bool removeRows(int position, int rows, const QModelIndex &index = QModelIndex()) override;
因为这个模型中的行对应于列表中的字符串,所以insertRows()函数会在指定位置之前插入一些空字符串。插入的字符串数等同于指定的行数。
父索引通常用于确定应该将行添加到模型中的何处。在这个例子中,我们只有一个字符串的顶级列表,所以我们只是在该列表中插入空字符串。
bool StringListModel::insertRows(int position, int rows, const QModelIndex &parent)
{beginInsertRows(QModelIndex(), position, position+rows-1);for (int row = 0; row < rows; ++row) {stringList.insert(position, "");}endInsertRows();return true;
}
模型首先调用beginInsertRows()函数通知其他组件行数即将改变。该函数指定要插入的第一行和最后一行的行号,以及它们父项的model索引。修改字符串列表后,它调用endInsertRows()来完成操作,并通知其他组件模型的维度发生了变化。返回true表示成功。
从模型中删除行的函数也很容易编写。要从模型中删除的行由给定的位置和行数指定。为了简化实现,我们忽略了父索引,只从字符串列表中删除相应的项。
bool StringListModel::removeRows(int position, int rows, const QModelIndex &parent)
{beginRemoveRows(QModelIndex(), position, position+rows-1);for (int row = 0; row < rows; ++row) {stringList.removeAt(position);}endRemoveRows();return true;
}
beginRemoveRows()函数总是在删除任何底层数据之前调用,并指定要删除的第一行和最后一行。这允许其他组件在数据不可用之前访问数据。删除行之后,模型发出endRemoveRows()来完成操作,并让其他组件知道模型的维度已经更改。
下一个步骤
我们可以使用QListView类以垂直列表的形式显示该模型或任何其他模型提供的数据。对于string list模型,这个视图还提供了一个默认编辑器,以便对项目进行操作。我们在视图类中检查标准视图类可用的可能性。
模型子类化参考文档更详细地讨论了QAbstractItemModel子类的需求,并提供了在不同类型的模型中启用各种特性必须实现的虚函数的指南。
Model/View Programming | Qt Widgets 5.15.17
相关文章:

Qt Model/View之Model
在检查如何处理选择之前,您可能会发现检查模型/视图框架中使用的概念很有用。 基本概念 在模型/视图架构中,模型提供了一个标准接口,用于视图和委托访问数据。在Qt中,标准接口由QAbstractItemModel类定义。无论数据项如何存储在…...

如何在 Vue 3 中使用 Element Plus
在 Vue 3 中使用 Element Plus 是一个相对直接的过程,因为 Element Plus 是为 Vue 3 设计的 UI 组件库。以下是在 Vue 3 项目中集成和使用 Element Plus 的基本步骤: 1. 安装 Element Plus 首先,你需要在你的 Vue 3 项目中安装 Element Plu…...

【TVM 教程】在 Relay 中使用 Pipeline Executor
Apache TVM 是一个端到端的深度学习编译框架,适用于 CPU、GPU 和各种机器学习加速芯片。更多 TVM 中文文档可访问 → Apache TVM 中文站tvm.hyper.ai/ 作者:Hua Jiang 本教程介绍如何将「Pipeline Executor」与 Relay 配合使用。 import tvm from t…...

使用mingw64 编译 QT开发流程
1. 安装QT5 QT5.12.12 安装时选择mingw的开发包 2. 使用qtdesigner 进行ui设计 生成ui文件 3. 将ui文件转换为.h 文件 uic mywindow.ui -o ui_mywindow.h代码中指向生成的 UI 对象的地方 要改成这个Form 4. 编译 创建mainwindow.cpp #include "mainwindow.h"…...

品读 Java 经典巨著《Effective Java》90条编程法则,第3条:用私有构造器或者枚举类型强化Singleton属性
《Effective Java》中的第3条编程法则主要是针对在开发过程如何实现单例模式,作者 Joshua Bloch 在书中给出了3种单例模式的实现方式:私有构造器和公有静态域、私有构造器和公有静态方法、枚举式。 什么是单例模式? 单例模式是一种设计模式…...

如何在Flask中处理表单数据
在Flask中处理表单数据是一个常见的任务,它涉及从客户端接收数据并在服务器端进行解析和处理。Flask本身不直接提供表单验证的功能,但它可以与WTForms等库结合使用来简化表单处理过程。不过,即使没有WTForms,你仍然可以直接通过Fl…...

9月12日的学习
练习 #include "widget.h" #include "ui_widget.h" QListWidgetItem *p; Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget),socket(new QTcpSocket(this))//给客户端指针实例化空间及关联父组件 {ui->setupUi(this);//初始化,ui-…...

Java架构师未来篇大模型
目录 1. 大模型的定义2 大模型相关概念区分3 大模型的发展历程4. 大模型的特点5 大模型的分类6 大模型的泛化与微调7 大模型岗位需求8 理解大模型8.1 生活中的比喻8.2 大模型的定义9 大模型工作9.1 数据的积累9.2 模型的训练9.3 预测和应用10 大模型的实际应用10.1 语言处理10.…...

11.5.软件系统分析与设计-面向对象的程序设计与实现
面向对象的程序设计与实现 设计模式 Java代码 C代码...

中电金信:金融级数字底座“源启”:打造新型数字基础设施 筑牢千行百业数字化转型发展基石
近期,金融级数字底座“源启”登录中国电子《最轻大国重器》融媒体报道。从数字底座到数智底座,从金融行业到千行百业,“源启”用数智化转型的中国电子解决方案,为全球企业转型及安全发展提供强大动能。 立足中国电子科技创新成果&…...

IDEA怎么让控制台自动换行
IDEA怎么让控制台自动换行 操作流程 菜单>File>Settings>Editor>General>Console>勾选Use soft wraps in console 换行效果...

大模型笔记02--基于fastgpt和oneapi构建大模型应用平台
大模型笔记02--基于fastgpt和oneapi构建大模型应用平台 介绍部署&测试部署fastgptoneapi服务部署向量模型m3e和nomic-embed-text测试大模型 注意事项说明 介绍 随着大模型的快速发展,众多IT科技厂商都开发训练了各自的大模型,并提供了各具特色的AI产…...

linux-用户与权限管理-组管理
在 Linux 系统中,用户、组与权限管理是保障系统安全的重要机制。用户和组的管理不仅涉及对系统资源的访问控制,还用于权限的分配和共享。组管理在 Linux 中尤其重要,它能够帮助管理员组织用户并为不同的组分配特定权限,从而控制用…...

Day23_0.1基础学习MATLAB学习小技巧总结(23)——句柄图形
利用空闲时间把碎片化的MATLAB知识重新系统的学习一遍,为了在这个过程中加深印象,也为了能够有所足迹,我会把自己的学习总结发在专栏中,以便学习交流。 参考书目:《MATLAB基础教程 (第三版) (薛山)》 之前的章节都是…...

同步io和异步io
同步 I/O 和异步 I/O 是处理输入输出操作的两种不同策略,它们各有优缺点,适用于不同的场景。下面是它们的主要区别: 同步 I/O 定义:在同步 I/O 模型中,发起 I/O 操作的线程会被阻塞,直到操作完成。换句话说…...

AI基础 L19 Quantifying Uncertainty and Reasoning with Probabilities I 量化不确定性和概率推理
Acting Under Uncertainty 1 Reasoning Under Uncertainty • Real world problems contain uncertainties due to: — partial observability, — nondeterminism, or — adversaries. • Example of dental diagnosis using propositional logic T oothache ⇒ C av ity • H…...

C++ 关于时间的轮子
时间字符串转chrono::system_clock std::chrono::system_clock::time_point parse_date(const std::string& date_str) {std::tm tm {};std::istringstream ss(date_str);ss >> std::get_time(&tm, "%Y-%m-%d"); // 假设日期字符串格式为YYYY-MM-DDr…...

阿里达摩院:FunASR - onnxruntime 部署
阿里达摩院:FunASR - onnxruntime 部署 git clone https://github.com/alibaba/FunASR.git 切换到 onnxruntime cd FunASR/runtime/onnxruntime1下载 onnxruntime wget https://isv-data.oss-cn-hangzhou.aliyuncs.com/ics/MaaS/ASR/dep_libs/onnxruntime-linux-x64-1.14.0.t…...

SpringMvc注解
SpringMvc注解 1 SpringMcv基础环境搭建 注:如果已经有SpringMvc项目直接跳过这个就可以了 1 新建项目 2.修改文件为packaging 为war包 <packaging>war</packaging> <?xml version"1.0" encoding"UTF-8"?> <pr…...

队列的基本概念及顺序实现
队列的基本概念 队列的定义 队列(Queue)简称队,也是一宗操作受限的线性表,只允许在表的一段进行插入,而在表的另一端进行删除。向队列中插入元素成为入队或进队;删除元素成为出队或离队。 特性:先进先出 (Fir…...

Leetcode 最长连续序列
算法流程: 哈希集合去重: 通过将数组中的所有元素放入 unordered_set,自动去除重复元素。集合的查找操作是 O(1),这为后续的快速查找提供了保证。 遍历数组: 遍历数组中的每一个元素。对于每个元素,首先检…...

linux网络编程——UDP编程
写在前边 本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。 UDP协议简介 UDP 是一个简单的面向数据报的运输层协议,在网络中用于处理数据包,是一种无连接的…...

第四部分:1---文件内核对象,文件描述符,输出重定向
目录 struct file内核对象: 如何读写文件? 文件描述符在文件描述符表中的分配规则: 输出重定向初步解析: dup2实现复制文件描述符: struct file内核对象: struct file 是在内核空间中创建的用于描述文…...

如何在开发与生产环境中应用 Flask 进行数据库管理:以 SQLAlchemy 和 Flask-Migrate 为例
在使用 Flask 进行开发时,数据库管理是一个至关重要的环节。借助 SQLAlchemy 作为 ORM(对象关系映射)工具和 Flask-Migrate 进行数据库迁移,开发者可以高效地进行数据库管理,并在不同的环境(如开发环境和生…...

【Java零基础】Java核心知识点之:Map
HashMap(数组链表红黑树) HashMap 根据键的 hashCode 值存储数据,大多数情况下可以直接定位到它的值,因而具有很快的访问速度,但遍历顺序却是不确定的。 HashMap 最多只允许一条记录的键为 null,允许多条记录的值为 null。HashMa…...

9.12日常记录
1.extern关键字 1)诞生动机:在一个C语言项目中,需要再多个文件中使用同一全局变量或是函数,那么就需要在这些文件中再声明一遍 2)用于声明在其他地方定义的一个变量或是函数,在当前位置只是声明,告诉编译器…...

光纤的两种模式
光纤主要分为两种模式:单模光纤(Single-Mode Fiber, SMF)和多模光纤(Multi-Mode Fiber, MMF)。这两种光纤在传输特性、应用场景以及传输距离上存在显著差异。12 单模光纤 定义:单模光纤…...

SpringMVC的初理解
1. SpringMVC是对表述层(Controller)解决方案 主要是 1.简化前端参数接收( 形参列表 ) 2.简化后端数据响应(返回值) 1.数据的接受 1.路径的匹配 使用RequestMapping(可以在类上或在方法上),支持模糊查询,在内部有method附带…...

Python 基本库用法:数学建模
文章目录 前言数据预处理——sklearn.preprocessing数据标准化数据归一化另一种数据预处理数据二值化异常值处理 numpy 相关用法跳过 nan 值的方法——nansum和nanmean展开多维数组(变成类似list列表的形状)重复一个数组——np.tile 分组聚集——pandas.…...

Android Greendao的数据库复制到设备指定位置
方法如下: private void export() {// 确保您已经请求并获得了WRITE_EXTERNAL_STORAGE权限// 获取要储存的设备路径String picturesDirPath Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath();// 在公共目录下创建…...