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

QT-模型视图结构

模型视图结构

一、模型/视图结构概述

模型/视图结构一种将数据存储和界面展示分离的编程方法。模型用于存储数据,视图组件用来显示模型中的数据。

在Qt中,模型-视图架构(Model-View Architecture)被广泛应用于数据驱动的用户界面设计中。与传统的MVC(Model-View-Controller)和MVVM(Model-View-ViewModel)模式类似,Qt的模型-视图架构也强调数据和表示的分离。Qt中的模型/视图架构主要涉及三个核心概念:模型(Model)、视图(View)和委托(Delegate)。

1、模型(Model)

模型是数据的容器。定义了数据的结构和逻辑,以及数据的访问和更新规则。

常见的模型包括QStandardItemModel(用于通用的数据存储)、QSqlTableModel(用于SQL数据库)和QFileSystemModel(用于文件系统)等。

模型的数据来源可以是内存中的字符串列表,也可以是来自于数据库表中的数据。

同一模型可以采用用不同的视图组件来展示数据,所以模型/视图结构是一种高效灵活的编程结构。

在这里插入图片描述

2、视图(View)

视图是用户界面的一部分,用于展示模型中的数据。

在Qt中,常见的视图组件有QTableViewQListViewQTreeViewQAbstractItemView的子类,它们负责从模型中获取数据,并以适当的方式显示出来。视图通过信号和槽机制与模型通信,可以监听模型的数据变化,并相应地更新UI。

3、委托(Delegate)

委托在模型-视图架构中起到中介的作用,它决定了视图中数据项的外观和行为。

委托可以自定义数据项的绘制方式和编辑行为。比如为视图与模型之间的交互提供临时的编辑器,在QTableView组件上双击一个单元格来编辑数据时,单元格里就会出现一个QLineEdit组件,这个编辑框就是代理提供的临时编辑器,修改后会被自动保存在模型里。

模型、视图和代理使用信号和槽进行通信。当数据发生变化时,模型发射信号通知视图组件;当用户在界面上操作数据时,视图组件发射信号表示操作信息;在编辑数据时,代理会发射信号告知模型和视图组件编辑器的状态。

  • Model主要负责管理数据
  • View主要用来显示数据
  • Delegate主要负责控制视图中每个项的编辑和显示行为

二、模型类

1、模型类的继承关系

模型(Model)是用来给视图提供数据的,也叫数据模型。模型的数据来源可以是类、文件、数据库等。Qt中几个主要的模型类,继承关系如下:

在这里插入图片描述

模型类功能
QFileSystemModel用于表示计算机文件系统的模型类
QStringListModel用于表示字符串列表数据的模型类
QStandardItemModel标准的基于项的模型类,每个项是一个QStandardItem对象
QSqlQueryModel用于表示数据库SQL查询结果的模型类
QSqlTableModel用于表示数据库的一个数据表的模型类
2、模型的基本结构

QAbstractItemModel是所有模型类的基类,它的子类都是以表格的层次结构展示数据;视图组件按照这种规则来存取模型中的数据,以不同的形式展示。下图是模型的3种展示形式:

在这里插入图片描述

数据模型中存储数据的基本单元都是项(item),每个项有一个行号、一个列号,一个父项。3个模型都有一个隐藏的根项(root item)。

  • 列表模型的存储结构就是一列。
  • 表格模型的存储结构是规则的二维数组。
  • 树状模型的项可以有子项。

三、视图组件

视图组件负责展示数据,它从模型获取数据并呈现给用户。当模型中的数据发生变化时,视图会自动更新显示。

Qt提供的视图组件主要有以下:

在这里插入图片描述

视图组件功能
QListView用于显示单列的列表数据,适用于一维数据的操作。
QTreeView用于显示树状结构数据,适用于树状结构数据的操作。
QTableView用于显示表格数据,适用于二维表格数据的操作。
QColumnView用多个OListView显示树状结构数据,树状结构的一层用一个QListView显示。
Undo View撤销命令视图

四、列表模型/视图

列表模型的存储结构就是一列

QStringListModel是字符串列表数据的模型类,通常与QListView组件搭配,组成模型/视图结构适合处理字符串列表数据。

我们使用QStringListModel和QListView来实现列表模型,如图所示。

在这里插入图片描述

ListWidget::ListWidget(QWidget *parent)      // 构造函数,parent 表示父窗口指针: QWidget(parent)                        // 调用 QWidget 的构造函数,设置父对象, ui(new Ui::ListWidget)                 // 初始化 UI 指针
{ui->setupUi(this);                       // 初始化界面(加载 .ui 文件里的控件)QStringList list = {"北京","上海","成都"}; // 创建一个字符串列表,包含 3 个城市名QStringListModel *model = new QStringListModel(this); // 创建字符串列表模型,父对象是当前窗口model->setStringList(list);              // 把字符串列表设置到模型中ui->listView->setModel(model);           // 把模型绑定到界面上的 listView 控件,显示数据
}ListWidget::~ListWidget()                    // 析构函数
{delete ui;                               // 释放 UI 内存,防止内存泄漏
}

Qt 模型/视图(Model/View)架构就是为了解耦数据和显示,让复杂数据也能灵活展示。


1. 直接把数据写到视图里

比如 QListWidget,可以直接用:

ui->listWidget->addItem("北京");
ui->listWidget->addItem("上海");
ui->listWidget->addItem("成都");

✅ 优点:

  • 简单直观,几行代码就能完成。
  • 小数据量、固定内容的情况下足够用。

❌ 缺点:

  • 数据和视图强绑定,如果数据要更新(比如从数据库查询、网络接收),你得手动清空再重新添加。
  • 如果多个视图要共享同一份数据,就没法直接复用。

2. 使用模型 + 视图(你现在用的方式)

QStringListModel *model = new QStringListModel(this);
model->setStringList(list);
ui->listView->setModel(model);

✅ 优点:

  • 数据与视图分离:数据在 model 里,view 只管显示。
  • 统一接口:数据可以来自 QStringList、数据库 (QSqlTableModel)、自定义类等,换源不用改 view 代码。
  • 支持多个视图共享同一份数据(比如一个列表和一个表格同时显示同一模型里的数据)。
  • 支持大数据/懒加载,比如上万条记录,模型可以按需加载,节省内存。

❌ 缺点:

  • 初学时显得繁琐。
  • 小项目看起来“多此一举”。

3. 总结

  • 小项目/数据固定 → 用 QListWidget 直接加 item 就行,简单方便。
  • 大项目/数据来自数据库/网络 → 用 Model + View 更合适,扩展性强。

五、表格模型/视图

QStandardItemModel模型类,主要用于处理层次化的数据结构,能够存储和管理复杂的数据集合。

QStandardItemModel可以用于多种视图组件,如QTableViewQTreeViewQListView等,以适应不同的用户界面需求。

这里我们使用QStandardItemModel和QTableView来实现如图所示:

在这里插入图片描述

#include "tablewidget.h"
#include "ui_tablewidget.h"
#include <QStandardItemModel>TableWidget::TableWidget(QWidget *parent): QWidget(parent), ui(new Ui::TableWidget)
{ui->setupUi(this);// 定义二维数组,存放表格数据(姓名、部门、薪水、奖金)QVector<QVector<QString>> arr = {{"张三","研发部","10000","2000"},{"李四","市场部","12000","1000"},{"王五","研发部","12000","2000"}};// 创建一个标准模型,用来存放数据(行列数据模型)QStandardItemModel *model = new QStandardItemModel(this);// 定义表头标题QStringList headers = {"姓名", "部门", "薪水", "奖金"};// 设置水平表头(即列标题)model->setHorizontalHeaderLabels(headers);// 遍历二维数组,把数据逐行逐列填入模型for (int row = 0; row < 3; row++)          // 遍历行{for (int col = 0; col < 4; col++)      // 遍历列{// 每个表格单元格是一个 QStandardItem 对象QStandardItem *item = new QStandardItem(arr[row][col]);// 把 item 放到模型的 (row, col) 位置model->setItem(row, col, item);}}// 把模型绑定到视图(tableView 负责显示,model 负责存数据)ui->tableView->setModel(model);
}TableWidget::~TableWidget()
{delete ui;  // 析构时释放 UI 资源
}

六、树状模型/视图

QFileSystemModel用于表示本地文件系统的目录和文件结构。

QFileSystemModel为本机的文件系统提供一个模型,结合使用QFileSystemModel和QTreeView可以以目录树的形式显示本机的文件系统。

这里我们使用QFileSystemModel和QTreeView实现树状模型,如图所示:

在这里插入图片描述

#include "treewidget.h"
#include "ui_treewidget.h"
#include <QFileSystemModel>
#include <QDebug>
#include <QTreeView>TreeWidget::TreeWidget(QWidget *parent): QWidget(parent), ui(new Ui::TreeWidget)
{ui->setupUi(this);// 创建一个文件系统模型 QFileSystemModel// 它会把磁盘上的文件夹和文件组织成树状结构,供 QTreeView 显示QFileSystemModel *model = new QFileSystemModel(this);// 设置模型的根路径为当前工作目录// 这样模型会从当前目录开始加载文件和文件夹信息model->setRootPath(QDir::currentPath());// 把模型绑定到 QTreeView(treeView 是界面里的树形控件)ui->treeView->setModel(model);// 设置 QTreeView 的根索引为当前工作目录// 这样树视图就不会从磁盘根目录开始,而是直接展示当前目录的内容ui->treeView->setRootIndex(model->index(QDir::currentPath()));
}TreeWidget::~TreeWidget()
{delete ui;  // 析构时释放 UI 资源
}

七、模型视图结构的相关概念

1、模型索引

数据模型中引入了模型索引(model index)的概念。通过模型能访问的每一个项都有一个模型索引。

  • 模型索引是对模型内部数据结构中单个数据项的唯一标识符,它包含了行号、列号以及可能的父索引等信息,用于精确地定位模型中的某个数据元素。
  • QModelIndex 表示模型索引的类。模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据。
#include "listwidget.h"
#include "ui_listwidget.h"
#include <QStringListModel>ListWidget::ListWidget(QWidget *parent): QWidget(parent), ui(new Ui::ListWidget)
{ui->setupUi(this);// 定义一个 QStringList(字符串列表),作为初始数据源QStringList list;list << "北京" << "上海" << "成都";// 创建一个 QStringListModel(字符串列表模型)// 它会把 QStringList 中的内容映射为可显示的数据项QStringListModel *model = new QStringListModel(this);// 将字符串列表数据加载到模型中model->setStringList(list);// 将模型绑定到界面中的 QListView(listView 是 UI 里的控件)// 这样 listView 就会显示 model 的数据ui->listView->setModel(model);// 获取模型中第 0 行,第 0 列的索引(索引从 0 开始)QModelIndex index = model->index(0, 0);// 修改指定索引的数据// Qt::DisplayRole 表示用于显示的数据,这里把 "北京" 改成了 "天津"model->setData(index, "天津", Qt::DisplayRole);
}ListWidget::~ListWidget()
{delete ui;  // 析构时释放 UI 资源
}
2、行号和列号

数据模型的基本形式是用行和列定义的表格数据,但这并不意味着底层的数据就是是用二维数组存储的,使用行和列只是为了组件之间交互方便的一种规定。通过模型索引的行号和列号就可以存取数据。

要获得一个模型索引,可以提供 3 个参数:行号、列号、父项的模型索引。例如,对于如图中的表格数据模型中的 3 个数据项 A、B、C,

在这里插入图片描述

获取其模型索引的代码是:

QModelIndex()空索引表示模型的根项或没有父项的顶级项。

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexB = model->index(1, 1, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());

在创建模型索引的函数中需要传递行号、列号和父项的模型索引。对于列表和表格模式的数据模型,顶层节点用 QModelIndex() 表示。

3、父项

当数据模型是列表或表格时,使用行号、列号存储数据比较直观,所有数据项的父项就是根项;当数据模型是树状结构时,情况比较复杂(树状结构中,项一般习惯于称为节点),一个节点可以有父节点,也可以是其他节点的父节点,在构造树状结构数据项的模型索引时,必须指定正确的行号、列号和父节点。

在这里插入图片描述

对于上图中的树状数据模型,节点 A 和节点 C 的父节点是顶层节点,获取模型索引的代码是:

QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());

但是,节点 B 的父节点是节点 A,节点 B 的模型索引由下面的代码生成:

QModelIndex indexB = model->index(1, 0, indexA);
4、项的角色

通过为一个项指定不同的角色,可以告知视图组件和代理如何展示数据。

在为模型的一个项设置数据时,可以为项设置不同角色的数据。QAbstractItemModel类定义了设置项的数据函数,原型如下:

bool  QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role= Qt::EditRole)
QStandardItemModel model;                       // 创建模型
QModelIndex index = model.index(0, 0);          // 获取第0行第0列的索引(假设已有数据)// 修改显示文本(默认 role 是 EditRole)
model.setData(index, "新文本", Qt::EditRole);// 设置提示信息(鼠标悬停时显示)
model.setData(index, "这是提示信息", Qt::ToolTipRole);// 设置前景色(文字颜色为红色)
model.setData(index, QColor("red"), Qt::ForegroundRole);// 设置背景色(背景为黄色)
model.setData(index, QColor("yellow"), Qt::BackgroundRole);// 设置勾选框为已选中
model.setData(index, Qt::Checked, Qt::CheckStateRole);

其中,index是项的模型索引,value是要设置的数据,role是设置数据的角色。角色参数role用枚举类型Qt::ItemDataRole的枚举值表示:

枚举值角色数据类型含义
Qt::DisplayRoleQString界面上显示的字符串,例如单元格显示的文字
Qt::DecorationRoleQIcon、QColor在界面上起装饰作用的数据,如图标
Qt::EditRoleQString界面上适合在编辑器中显示的数据,一般是文字
Qt::ToolTipRoleQString项的toolTip字符串
Qt::FontRoleQFont项的字体,如单元格内文字的字体
Qt::TextAlignmentRoleQt::Alignment项的对齐方式,如单元格内文字的对齐方式
Qt::BackgroundRoleQBrush项的背景色,如单元格的背景色
Qt::ForegroundRoleQBrush项的前景色,如单元格的文字颜色
Qt::CheckStateRoleQt::CheckState项的复选状态

在获取一个项的数据时也可以指定角色,以获取不同角色的数据。QAbstractItemModel定义了函数data(),可以返回一个项的不同角色的数据,原型:

QVariant QAbstractItemModel::data(const QModelIndex &index, int role = Qt::DisplayRole)
QStandardItemModel model;                       // 创建模型
model.setItem(0, 0, new QStandardItem("北京")); // 在第0行第0列放一个数据QModelIndex index = model.index(0, 0);          // 获取第0行第0列的索引// 取出显示的文本(默认 role 是 DisplayRole)
QString text = model.data(index, Qt::DisplayRole).toString();  
qDebug() << "显示文本:" << text;// 取出编辑角色的数据(其实等价于 DisplayRole)
QString editText = model.data(index, Qt::EditRole).toString();
qDebug() << "编辑文本:" << editText;// 如果之前设置过 ToolTipRole
QString tooltip = model.data(index, Qt::ToolTipRole).toString();
qDebug() << "提示信息:" << tooltip;

📌 总结:

  • setData()写入数据
  • data()读取数据
  • role 决定读/写哪种用途的数据(显示、编辑、提示、颜色、勾选状态等)。

模型索引和项角色使用案例:

#include "standardmainwindow.h"
#include "ui_standardmainwindow.h"
#include <QTreeView>
#include <QStandardItemModel>
#include <QDebug>StandardMainWindow::StandardMainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::StandardMainWindow)
{ui->setupUi(this);QTreeView *view = new QTreeView(this);             // 创建一个树形视图控件view->resize(200, 300);                            // 设置视图大小QStandardItemModel *model = new QStandardItemModel(this); // 创建标准项模型,用于存储树形数据QStandardItem *root = model->invisibleRootItem();  // 获取不可见的根节点,所有顶级节点都挂在它下面QStandardItem *item0 = new QStandardItem;          // 创建第一个子节点item0->setData("节点A", Qt::EditRole);             // 设置显示文本(等价于 setText)item0->setData("提示信息", Qt::ToolTipRole);       // 设置提示信息(鼠标悬停显示)root->appendRow(item0);                            // 把节点A挂到根节点下QStandardItem* item1 = new QStandardItem;          // 创建第二个子节点item1->setData("节点B", Qt::EditRole);             // 设置显示文本item1->setData(QIcon(":/image/1_2.png"), Qt::DecorationRole); // 设置图标root->appendRow(item1);                            // 把节点B挂到根节点下QStandardItem *item2 = new QStandardItem;          // 创建第三个子节点item2->setData("节点C", Qt::EditRole);             // 设置显示文本item2->setData(QColor("red"), Qt::BackgroundRole); // 设置背景色为红色item2->setCheckable(true);                         // 设置为可勾选item2->setData(Qt::Checked, Qt::CheckStateRole);   // 设置勾选状态为“已勾选”root->appendRow(item2);                            // 把节点C挂到根节点下view->setModel(model);                             // 将模型绑定到视图,数据就会显示出来// ========== 测试获取各个节点的数据 ==========QModelIndex index0 = model->index(0, 0, QModelIndex()); // 获取第 0 行节点(节点A)qDebug() << "节点A的文本:" << model->data(index0, Qt::EditRole).toString();          // 输出显示文本qDebug() << "节点A的提示文字:" << model->data(index0, Qt::ToolTipRole).toString();  // 输出提示信息QModelIndex index1 = model->index(1, 0, QModelIndex()); // 获取第 1 行节点(节点B)qDebug() << "节点B的文本:" << model->data(index1, Qt::EditRole).toString();        // 输出显示文本qDebug() << "节点B的装饰:" << model->data(index1, Qt::DecorationRole);             // 输出装饰(图标)qDebug() << "节点B的字体:" << model->data(index1, Qt::FontRole).toString();        // 输出字体(未设置,默认空)QModelIndex index2 = model->index(2, 0, QModelIndex()); // 获取第 2 行节点(节点C)qDebug() << "节点C的文本:" << model->data(index2, Qt::EditRole).toString();        // 输出显示文本qDebug() << "节点C的背景色:" << model->data(index2, Qt::BackgroundRole);           // 输出背景色qDebug() << "节点C的勾选状态:" << model->data(index2, Qt::CheckStateRole);         // 输出勾选状态
}StandardMainWindow::~StandardMainWindow()
{delete ui;                                         // 析构时释放 UI 资源
}

八、QAbstractItemModel类函数接口

QAbstractItemModel是所有模型类的直接或间接父类,定义了模型的通用接口函数。

例如:插入行、删除行、设置数据的函数。

在这里插入图片描述

1、行数和列数

函数rowCount返回行数,columnCount()返回列数,两个函数的原型定义如下:

int rowCount(const QModelIndex &parent = QModelIndex());
int columnCount(const QModelIndex &parent = QModelIndex());

这两个函数中都需要传递一个参数parent,这是父项的模型索引。

  • 对于列表模型和表格模型,parent使用默认的参数QModelIndex()即可,得到的行数和列数就是模型的行数和列数。
  • 对于树状模型,parent需要设置为父节点的模型索引,函数返回的是父节点下的节点的行数和列数。
2、插入或删除行
 bool insertRow(int row, const QModelIndex &parent = QModelIndex())virtual bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex())bool removeRow(int row, const QModelIndex &parent = QModelIndex())virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex())

参数parent是父项的模型索引。对于列表模型和表格模型,parent使用默认的参数QModelIndex()即可。对于树状模型,parent需要设置为父节点的模型索引。

在使用函数insertRow()时,如果参数row的值超过了模型的行数,新增的行就添加到模型的末尾。

3、插入或删除列
 bool insertColumn(int column, const QModelIndex &parent = QModelIndex())virtual bool insertColumns(int column, int count, const QModelIndex &parent = QModelIndex())
bool removeColumn(int column, const QModelIndex &parent = QModelIndex())virtual bool removeColumns(int column, int count, const QModelIndex &parent = QModelIndex())
4、移动行或列

可以实现表格中的行或列的移动,以及目录树中的节点移动等。

参数一:源行的父项索引

参数二:源行的位置

参数三:目标行的父索引

参数四:目标位置的索引,这个索引指的是插入点,即新行将被放置在该索引之前的位置。

bool moveRow(const QModelIndex &sourceParent, int sourceRow, const QModelIndex &destinationParent, int destinationChild)
bool moveColumn(const QModelIndex &sourceParent, int sourceColumn, const QModelIndex &destinationParent, int destinationChild)
5、数据排序

函数sort()将数据按某一列排序,可以指定排序方式,默认是升序方式。

 virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder)
6、设置和读取项的数据

函数setData()为一个项设置数据,函数data()返回一个项的数据,其函数原型定义如下:

virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) 
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0

这里,我们以QStingListModelQListView模型/视图组件来演示数据模型的接口函数:

在这里插入图片描述

#include "listwidget.h"
#include "ui_listwidget.h"
#include <QStringListModel>ListWidget::ListWidget(QWidget *parent): QWidget(parent), ui(new Ui::ListWidget)
{ui->setupUi(this);list << "北京" << "上海" << "成都";              // 初始化字符串列表model = new QStringListModel(this);             // 创建字符串列表模型model->setStringList(list);                     // 把数据设置到模型ui->listView->setModel(model);                  // 视图绑定模型
}ListWidget::~ListWidget()
{delete ui;
}void ListWidget::on_btnInit_clicked()
{model->setStringList(list);                     // 恢复初始数据
}void ListWidget::on_btnClear_clicked()
{model->removeRows(0, model->rowCount());        // 清空所有行
}void ListWidget::on_btnAdd_clicked()
{model->insertRow(model->rowCount());            // 在最后插入一行QModelIndex index = model->index(model->rowCount()-1, 0); // 获取新行索引model->setData(index, "新建项");                // 设置新行的数据ui->listView->setCurrentIndex(index);           // 选中新行
}void ListWidget::on_btnInsert_clicked()
{QModelIndex index = ui->listView->currentIndex();   // 获取当前选中项索引model->insertRow(index.row());                      // 在当前行插入新行model->setData(index, "插入项", Qt::EditRole);      // 设置新行内容ui->listView->setCurrentIndex(index);               // 选中插入行
}void ListWidget::on_btnDelete_clicked()
{QModelIndex index = ui->listView->currentIndex();   // 获取当前选中项model->removeRow(index.row());                      // 删除该行
}void ListWidget::on_btnUp_clicked()
{int currentRow = ui->listView->currentIndex().row(); // 获取当前行号QModelIndex index = QModelIndex();                   // 父索引为空model->moveRow(index, currentRow, index, currentRow-1); // 向上移动一行
}void ListWidget::on_btnDown_clicked()
{int currentRow = ui->listView->currentIndex().row(); // 获取当前行号QModelIndex index = QModelIndex();                   // 父索引为空model->moveRow(index, currentRow, index, currentRow+2); // 向下移动一行
}void ListWidget::on_btnSort_clicked(bool checked)
{static int sort = 0;                                // 排序模式标志if (sort){model->sort(0, Qt::AscendingOrder);             // 升序sort = 0;}else{model->sort(0, Qt::DescendingOrder);            // 降序sort = 1;}
}void ListWidget::on_checkBox_clicked(bool checked)
{if (checked) {ui->listView->setEditTriggers(                  // 开启编辑:双击或选中QAbstractItemView::DoubleClicked |QAbstractItemView::SelectedClicked);}else {ui->listView->setEditTriggers(                  // 禁止编辑QAbstractItemView::NoEditTriggers);}
}

从上述代码可以看出,对数据的操作都是通过数据模型的接口函数来实现的。在数据模型添加和删除项后,界面组件QListView中会立刻自动将其显示出来。

http://www.dtcms.com/a/394527.html

相关文章:

  • C语言 C语句
  • 《理解Reactor网络编程模型》
  • Mirror Maze 镜面反射
  • 一个案例弄懂nfs
  • 在飞牛NAS使用Lucky做动态解析到域名?
  • 多实例 MySQL 部署
  • 使用批处理脚本快速切换 Claude API 实现多平台环境配置
  • SkyDiffusion:用 BEV 视角打开街景→航拍图像合成新范式
  • 免费下载适用于 Windows PC 的 Pixologic Zbrush 2026
  • 10.eNSP下载及安装教程(2025年9月21日)
  • Qt 实战 之 打包部署
  • QT-文件
  • 2001-2022年全国地级市高铁开通数据
  • TenstoRT加速YOLOv11——C++端加速
  • 面试技巧第三篇:嵌入式操作系统基础考点:任务、调度和中断
  • 简单使用Vanna
  • 【面板数据】各省环境保护支出统计数据集(2007-2023年)
  • 无需格式转换!FileOptimizer将文件体积压至极致的软件
  • 【论文速递】2025年第17周(Apr-20-26)(Robotics/Embodied AI/LLM)
  • Spring Framework 入门:传统 XML 配置启动方式详解
  • 构建AI智能体:四十、K-Means++与RAG的融合创新:智能聚类与检索增强生成的深度应用
  • Python 中,判断元素是否存在于列表(list)和判断键是否存在于字典(dict)
  • 如何在 Windows 上恢复已删除/未保存的 PowerPoint 文件 - 4 种快速方法
  • 【含文档+PPT+源码】基于过滤协同算法的城市旅游网站的设计与实现
  • week 2
  • Core Animation基础
  • OpenVLC解析
  • 【AI论文】ScaleCUA:借助跨平台数据扩展开源计算机使用代理(系统/工具)规模
  • NW951NW916美光固态闪存NW926NW927
  • Python 如何优雅处理 100GB 数据集——实战案例