深入浅出 Qt 中 QListView 的设计思想,并掌握大规模、高性能列表的实现方法
在大规模列表控件的显示需求中,必须解决2个问题才能获得较好的性能:
- 第一就是数据存在哪里, 避免出现数据的副本。
- 第二就是如何展示Item,如何复用或避免创建大量的Item控件。
在QListView体系里,QAbstractListModel解决的是“数据存哪”,解决的是第一个问题,而QAbstractItemDelegate解决的是数据“如何展示”,解决的是第二个问题。
因此,在大规模列表的编写代码中,高效的数据存储和高效的数据UI展示,需要用到这两个类。接下来,我们通过三个例子,循序渐进地介绍QListView,使读者掌握QListView的使用技巧和设计思想。
示例 1: 使用 QListWidget 的基本用法
QListWidget
是一个方便的控件,它内部管理了一个项目列表,并提供了一些简单的接口来添加、删除和修改这些项目。但没有对数据存储和数据展示进行过多的优化,这种方式适合于简单的应用场景,其中列表的大小不会很大,因为每个项目都会被存储为一个 QListWidgetItem
对象。
#include <QApplication>
#include <QListWidget>int main(int argc, char *argv[]) {QApplication app(argc, argv); QListWidget* listWidget = new QListWidget;for (int i = 0; i < 100; ++i) {listWidget->addItem(QString("项目 %1").arg(i));}listWidget->show(); return app.exec();
}
尽管这种方式使用起来非常简单,但它并不适合处理大量数据。因为 QListWidget
会为每个项目创建一个 QListWidgetItem
对象,这将导致大量的内存消耗。
示例 2: 使用 QListView 和 QAbstractItemDelegate(解决数据存哪的问题)
在这个示例中,我们将直接从 QAbstractListModel
派生一个Model类,而不是使用 addItem
构造大量的ItemData。这样,我们就无需存储这些数据。这个方法在处理具有可预知数据模式的大量数据时特别有用,因为它避免了冗余的数据存储和内存开销。
首先,我们定义一个 SyntheticListModel
类,它继承自 QAbstractListModel
。这个模型将根据索引动态生成数据项:
#include <QAbstractListModel>
#include <QVariant>
#include <QModelIndex>class SyntheticListModel : public QAbstractListModel {Q_OBJECTpublic:SyntheticListModel(int numItems, QObject *parent = nullptr): QAbstractListModel(parent), m_numItems(numItems) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override {// 在顶层,返回项的数量;否则返回0,因为这是一个列表,没有子项return parent.isValid() ? 0 : m_numItems;}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (index.isValid() && index.row() < m_numItems) {if (role == Qt::DisplayRole) {// 根据行号动态生成数据return QString("项目 %1").arg(index.row());}// 可以根据需要添加其他角色的处理}return QVariant(); // 无效索引或角色时返回无效的QVariant}private:int m_numItems; // 列表中项目的数量
};
然后,我们创建一个简单的 QStyledItemDelegate
,这个委托可以根据需要自定义项的显示方式:
#include <QStyledItemDelegate>
#include <QPainter>class SimpleDelegate : public QStyledItemDelegate {Q_OBJECTpublic:using QStyledItemDelegate::QStyledItemDelegate; // 继承构造函数// 重写 paint 方法以自定义项目显示方式void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {// 调用基类的 paint 方法进行默认的绘制QStyledItemDelegate::paint(painter, option, index);// 可以添加额外的绘制代码,如绘制边框、背景等}// 如果需要,可以重写 createEditor、setEditorData、setModelData 等方法以自定义编辑行为
};
最后,我们在 main
函数中创建 QListView
,并将其与我们的自定义模型和委托相连接:
#include <QApplication>
#include <QListView>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建列表视图QListView listView;// 创建模型,这里我们创建了 100000 个假数据项SyntheticListModel model(100000);// 创建委托SimpleDelegate delegate;// 将模型和委托设置到列表视图listView.setModel(&model);listView.setItemDelegate(&delegate);listView.show();return app.exec();
}
在这个示例中,我们展示了如何使用 QListView
和自定义的 QAbstractListModel
来动态生成数据,而不需要在内存中维护一份数据存储的副本。在实际业务中,数据可以直接从业务模块中获取,这样避免出现数据的两个副本。SimpleDelegate
负责定制列表项的视觉呈现,但在这个简化的例子中,我们仅使用了默认的绘制逻辑。如果需要更复杂的项显示或编辑功能,可以在委托中进一步扩展 paint
和其他相关方法。这些内容我们在示例3中展现。
示例 3: 使用 QListView 和自定义 QAbstractListModel(解决数据如何展示问题)
实例2中没有展开SimpleDelegate 的实现,在实际开发场景中,界面展示的需求往往更加复杂,特别是QListView的View模型采用的是paint函数来呈现,和其他图形界面框架(如AndroidFramework)构造一个QWidget*
控件的形式不同,paint的形式用起来更复杂,但性能天花板更高。
下面是一个使用自定义模型 LargeListModel
和委托 SimpleDelegate
的例子。在这个示例中,我们将创建一个自定义的 QAbstractListModel
类,名为 LargeListModel
,它将处理大量数据项。此外,我们还将扩展 SimpleDelegate
类来自定义 QListView
中项的视觉呈现。这个委托将负责绘制项的背景、文本和一些装饰元素,从而提供更丰富的用户界面。
首先,我们定义 LargeListModel
类,该类派生自 QAbstractListModel
:
#include <QAbstractListModel>class LargeListModel : public QAbstractListModel {Q_OBJECT
public:explicit LargeListModel(int numItems, QObject *parent = nullptr): QAbstractListModel(parent), m_numItems(numItems) {}int rowCount(const QModelIndex &parent = QModelIndex()) const override {return parent.isValid() ? 0 : m_numItems;}QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {if (!index.isValid() || index.row() >= m_numItems)return QVariant();switch (role) {case Qt::DisplayRole:// 动态生成显示的数据return QStringLiteral("Item %1").arg(index.row());// 这里可以根据需要添加对其他角色的处理default:return QVariant();}}private:int m_numItems; // 数据项的数量
};
接下来,我们将自定义 SimpleDelegate
类,以便在 QListView
中渲染更复杂的项:
#include <QStyledItemDelegate>
#include <QPainter>class SimpleDelegate : public QStyledItemDelegate {
public:using QStyledItemDelegate::QStyledItemDelegate; // 继承构造函数void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {// 保存当前的绘图状态painter->save();// 绘制项的背景if (option.state & QStyle::State_Selected) {painter->fillRect(option.rect, option.palette.highlight());} else {painter->fillRect(option.rect, option.palette.base());}// 绘制自定义内容,例如文本QString text = index.data(Qt::DisplayRole).toString();painter->drawText(option.rect, Qt::AlignLeft | Qt::AlignVCenter, text);// 还原绘图状态painter->restore();}// 如果需要项的大小不是默认值,可以重写 sizeHint 方法QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {return QSize(option.rect.width(), 50); // 设置项的高度为50}
};
最后,我们在 main
函数中创建 QListView
,设置自定义的模型和委托,并显示它们:
#include <QApplication>
#include <QListView>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建自定义模型和委托LargeListModel *model = new LargeListModel(100000); // 假设有 10 万个数据项SimpleDelegate *delegate = new SimpleDelegate();// 创建并设置 QListViewQListView listView;listView.setModel(model);listView.setItemDelegate(delegate);// 设置其他视图属性,如果需要listView.setSelectionMode(QAbstractItemView::SingleSelection);listView.setAlternatingRowColors(true); // 设置交替行颜色listView.show();return app.exec();
}
在这个示例中,LargeListModel
负责提供数据项,而 SimpleDelegate
负责自定义每个项的绘制。这种方法使得处理大量数据项时能够保持高性能,同时提供了丰富的视觉呈现和用户交互能力。通过委托的 paint
方法,我们可以绘制文本、图标、背景或任何其他图形元素来增强用户界面的视觉效果。通过重写 sizeHint
方法,我们可以为每个项定制大小,以适应不同的内容和设计需求。
这种模型-视图-委托的方法为高效地处理和展示大型数据集提供了灵活的解决方案,使得开发者可以在保持应用程序性能的同时,实现复杂且具有吸引力的用户界面。
进一步优化:处理大量动态数据
以上示例已经展示了如何使用 QListView
和自定义模型以及委托来处理静态数据。但在实际应用中,我们可能需要处理动态变化的数据集,其中项目可能会被添加、移除或更新。为了保持UI的响应性和数据的一致性,我们需要在模型中正确地处理这些变化。
数据添加示例
假设我们的 LargeListModel
需要动态添加数据,我们可以在模型中实现添加数据的逻辑,并通知视图更新:
class LargeListModel : public QAbstractListModel {// ...(省略已有代码)public:// ...(省略已有代码)// 添加新项的方法void addItem(const QString &title) {const int index = itemCount;beginInsertRows(QModelIndex(), index, index);titles.append(title);checkedItems.insert(index, false);itemCount++;endInsertRows();}// ...(省略已有代码)
};// 使用示例:
int main(int argc, char *argv[]) {QApplication app(argc, argv);// ...(省略已有代码)LargeListModel* model = new LargeListModel(0); // 初始时没有数据// ...(省略已有代码)// 动态添加数据for (int i = 0; i < 100000; ++i) {model->addItem(QString("动态项目 %1").arg(i));}// ...(省略已有代码)return app.exec();
}
在这个例子中,我们通过 addItem
方法在模型中添加新的数据项。在添加数据之前和之后,我们分别调用 beginInsertRows
和 endInsertRows
方法,这样 QListView
就会自动更新显示新添加的数据。
数据更新示例
如果我们需要更新现有数据,我们同样需要确保视图能够得到通知:
class LargeListModel : public QAbstractListModel {// ...(省略已有代码)public:// ...(省略已有代码)// 更新某项的方法void updateItem(int index, const QString &newTitle) {if(index >= 0 && index < itemCount) {titles[index] = newTitle;QModelIndex modelIndex = createIndex(index, 0);emit dataChanged(modelIndex, modelIndex);}}// ...(省略已有代码)
};
在这里,我们通过 updateItem
方法更新一条数据,并通过 dataChanged
信号告知视图特定项的数据已经改变。createIndex
方法用来创建一个指向已更新项的 QModelIndex
对象,这是发出 dataChanged
信号所必需的。
性能注意事项
处理大量数据时,以下是一些提高性能的常见做法:
- 使用
beginInsertRows
和endInsertRows
(或对应的删除和更新版本)时,请确保避免同时进行大量的单独插入或删除操作,因为这会导致视图频繁更新,从而降低性能。相反,应该批量插入或删除。 - 避免在
data
方法中执行耗时的计算。如果需要,可以将数据缓存或使用后台线程来准备数据。 - 如果列表项的大小是固定的,使用
setUniformItemSizes(true)
可以提高滚动和渲染的性能。 - 如果数据的读取是昂贵的操作,考虑实现延迟加载或数据分页,这样只有当数据真正需要显示时才读取。
一个更复杂的完整例子
刚刚我们循序渐进地了解了QListView高性能大规模列表的设计思想和实现步骤,接下来我们实现一个稍微复杂的例子,这个例子在列表的每一项中增加了一个复选框和一个按钮,表示这是一个复杂列表项的呈现。
#include <QApplication>
#include <QCheckBox>
#include <QListView>
#include <QPainter>
#include <QPushButton>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QAbstractListModel>
#include <QHash>
#include <QVariant>class LargeListModel : public QAbstractListModel {
public:LargeListModel(int numItems, QObject* parent = nullptr): QAbstractListModel(parent), itemCount(numItems) {titles.resize(itemCount); // 初始化标题数组for (int i = 0; i < itemCount; ++i) {titles[i] = QString("标题文本 %1").arg(i); // 生成初始标题文本}}int rowCount(const QModelIndex& parent = QModelIndex()) const override {if (parent.isValid()) {return 0;}return itemCount;}QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override {if (!index.isValid() || index.row() >= itemCount || index.row() < 0) {return QVariant();}switch (role) {case Qt::DisplayRole:return titles.at(index.row());case Qt::CheckStateRole:{auto it = checkedItems.find(index.row());if (it != checkedItems.end()) {return QVariant(it.value() ? Qt::Checked : Qt::Unchecked);}return QVariant(Qt::Unchecked);}case Qt::EditRole: // 处理编辑角色return titles[index.row()];default:return QVariant();}}bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override {if (!index.isValid() || index.row() >= itemCount || index.row() < 0)return false;switch (role) {case Qt::CheckStateRole:// 更新 checkedItems,记录复选框的状态checkedItems[index.row()] = (value.toBool());emit dataChanged(index, index, { role });return true;case Qt::EditRole:// 更新标题文本titles[index.row()] = value.toString();emit dataChanged(index, index, { role });return true;default:return false;}}Qt::ItemFlags flags(const QModelIndex& index) const override {if (!index.isValid())return Qt::NoItemFlags;// 添加 Qt::ItemIsEditable 以支持编辑return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable;}private:int itemCount;mutable QHash<int, bool> checkedItems; // 存储复选框的状态QVector<QString> titles; // 存储标题文本
};// 自定义委托来绘制和处理列表项
class CustomDelegate : public QStyledItemDelegate {
public:CustomDelegate(QObject* parent = nullptr) : QStyledItemDelegate(parent) {}// 绘制列表项void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override {QStyleOptionButton buttonOption;QRect buttonRect = QRect(option.rect.right() - 80, option.rect.y() + 1, 78, option.rect.height() - 2);buttonOption.rect = buttonRect;QStyleOptionButton checkboxOption;QRect checkboxRect = QRect(option.rect.x() + 5, option.rect.y() + 5, option.rect.height() - 10, option.rect.height() - 10);checkboxOption.rect = checkboxRect;checkboxOption.state |= QStyle::State_Enabled;if (index.data(Qt::CheckStateRole).toBool()) {checkboxOption.state |= QStyle::State_On;} else {checkboxOption.state |= QStyle::State_Off;}painter->save();if (option.state & QStyle::State_MouseOver) {painter->fillRect(option.rect, option.palette.light());}// 根据是否有鼠标悬停,绘制高亮背景if (option.state & QStyle::State_MouseOver) {QRect highlightRect = option.rect;painter->fillRect(highlightRect, option.palette.highlight());}// 绘制复选框QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkboxOption, painter);// 绘制按钮buttonOption.text = "按钮";QApplication::style()->drawControl(QStyle::CE_PushButton, &buttonOption, painter);// 绘制文本QRect textRect = option.rect.adjusted(checkboxRect.width() + 10, 0, -buttonRect.width() - 10, 0);painter->drawText(textRect, Qt::AlignVCenter, index.data().toString());painter->restore();}// 处理事件,如复选框的点击bool editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& index) override {if (event->type() == QEvent::MouseButtonRelease) {QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);QRect buttonRect = QRect(option.rect.right() - 80, option.rect.y() + 5, 70, option.rect.height() - 10);QRect checkboxRect = QRect(option.rect.x() + 5, option.rect.y() + 5, option.rect.height() - 10, option.rect.height() - 10);if (buttonRect.contains(mouseEvent->pos())) {// 按钮被点击qDebug() << "按钮点击,项:" << index.row();} else if (checkboxRect.contains(mouseEvent->pos())) {// 切换复选框状态bool checked = !index.data(Qt::CheckStateRole).toBool();model->setData(index, checked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole);qDebug() << "勾选checkbox,项:" << index.row();}return true; // 事件已处理}return QStyledItemDelegate::editorEvent(event, model, option, index);}// 提供项的大小提示QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override {return QSize(option.rect.width(), 34); // 调整为所需的大小}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);QListView* listView = new QListView;auto insertCount = 100000;// 构造展示10w条数据CustomDelegate* delegate = new CustomDelegate(listView);listView->setModel(new LargeListModel(insertCount));listView->setItemDelegate(delegate);// 优化性能listView->setUniformItemSizes(true);listView->setSelectionMode(QAbstractItemView::SingleSelection);listView->show();return app.exec();
}
展示效果:
结语
通过遵循上述模式和性能最佳实践,可以更好地创建强大的、响应迅速的 Qt 应用程序。
简而言之,在QListView体系里,QAbstractListModel解决的是“数据存哪”,而QAbstractItemDelegate解决的是数据“如何展示”。这种模型/视图和委托的架构是 Qt 高效数据处理的基石,使得复杂的UI设计和数据操作变得可管理和可扩展。
相关文章:

深入浅出 Qt 中 QListView 的设计思想,并掌握大规模、高性能列表的实现方法
在大规模列表控件的显示需求中,必须解决2个问题才能获得较好的性能: 第一就是数据存在哪里, 避免出现数据的副本。第二就是如何展示Item,如何复用或避免创建大量的Item控件。 在QListView体系里,QAbstractListModel解…...

课设--学生成绩管理系统
欢迎来到 Papicatch的博客 文章目录 🍉技术核心 🍉引言 🍈标识 🍈背景 🍈项目概述 🍈 文档概述 🍉可行性分析的前提 🍈项目的要求 🍈项目的目标 🍈…...

MySQL性能分析
一、查看执行频率 sql执行频率,执行下述指令可以看到select,update,delete等操作的次数 show global status like Com_______; 具体我们在终端登录mysql看下,使用下述命令登录mysql,并输入命令 mysql -u 用户名 -p 上述查询,删…...

为什么要学习Flink系统管理及优化课程?
Flink系统是一种流式处理框架,能够高效地处理大规模数据流。然而,要确保Flink系统的正常运行,就需要进行系统管理和优化。系统管理是指对Flink集群的监控、调度和维护,而系统优化则是指通过调整参数和优化算法,提高Fli…...
把本机的bash构建到docker镜像里面
最近突发奇想,想把本机的bash放到docker镜像里面,接下来看操作。 获取bash以及依赖 [rootbogon ~]# cat get_lib_info.sh #!/bin/bash# 函数:显示帮助信息 show_help() {echo "Usage: $(basename "$0") -h -f <file>…...

【数据分析】推断统计学及Python实现
各位大佬好 ,这里是阿川的博客,祝您变得更强 个人主页:在线OJ的阿川 大佬的支持和鼓励,将是我成长路上最大的动力 阿川水平有限,如有错误,欢迎大佬指正 Python 初阶 Python–语言基础与由来介绍 Python–…...

探索交互的本质:从指令到界面的演进与Linux基础指令的深入剖析
目录 1.指令 vs 界面//选读 1.1交互的需求 满足需求的第一阶段-指令 满足需求的第二阶段-界面 1.2 指令 和 界面交互 区别 2.操作系统介绍 2.1 举例说明 驱动软件层 2.2 为什么要有操作系统? 0x03 为什么要进行指令操作? 3.Linux基本指令 l…...
uniapp vue分享功能集成
分享必须通过button设置open-type"share"拉起 <view class"img horizontal center" style"margin-right: 20rpx;"><image class"img" :src"src" click"onTapClick(xxx)" style"z-index: 1;" …...

软件工程实务:软件产品
目录 1、软件产品的基本概念 2、软件工程是什么? 为什么产生软件工程? 软件工程是做什么的? 3、定制软件和软件产品的工程比较 4 、软件产品的运行模式 5、软件产品开发时需要考虑的两个基本技术因素 6、产品愿景 7、软件产品管理 8、产品原型设计 9、小结…...

带侧边栏布局:带导航的网页
目录 任务描述 相关知识 HTML(HyperText Markup Language) CSS(Cascading Style Sheets): 编程要求 任务描述 在本关中,你的任务是创建一个带侧边栏和导航的网页布局。这种布局通常用于网站或应用程序,其中侧边栏…...
react学习-redux快速体验
1.redux是用于和react搭配使用的状态管理工具,类似于vue的vuex。redux可以不和任何框架绑定,独立使用 2.使用步骤 (1)定义一个reducer函数(根据当前想要做的修改返回一个新的状态) (2࿰…...

基于flask的网站如何使用https加密通信-问题记录
文章目录 项目场景:问题1问题描述原因分析解决步骤解决方案 问题2问题描述原因分析解决方案 参考文章 项目场景: 项目场景:基于flask的网站使用https加密通信一文中遇到的问题记录 问题1 问题描述 使用下面的命令生成自签名的SSL/TLS证书和…...

记C#优化接口速度过程
前提摘要 首先这个项目是接手的前一任先写的项目,接手后,要求对项目一些速度相对较慢的接口进行优化,到第一个速度比较慢的接口后,发现单接口耗时4-8秒,是的,请求同一个接口,在参数不变的情况下…...

windows环境如何运行python/java后台服务器进程而不显示控制台窗口
1.通常我们在windows环境下使用Java或Python语言编写服务器程序,都希望他在后台运行,不要显示黑乎乎的控制台窗口: 2.有人写了一个bat文件: cd /d D:\lottery\server && python .\main.py 放到了开机自启动里,可是开机的…...

记周末百度云防御CC攻击事件
今天一早,收到百度智能云短信提醒,一位客户的网站遭遇了CC攻击。 主机吧赶紧登陆客户网站查看,是否正常,看是否需要通知客户。 结果打开正常,看情况并没什么影响,那就等攻击结果了再看吧。 下午的时候&am…...
vue中v-bind控制class和style
当使用v-bind指令控制class和style时,可以通过动态绑定的方式根据不同的条件来添加或移除class,以及改变元素的样式。 1. 控制class 通过v-bind:class可以动态绑定class属性。可以使用对象语法、数组语法或者计算属性来实现。 对象语法:使用…...
【面试经典150题】【双指针】392. 判断子序列
题目链接 https://leetcode.cn/problems/is-subsequence/?envTypestudy-plan-v2&envIdtop-interview-150 题解思路 首先如果s的长度大于t的长度,那么s肯定不是t的子序列如果s的长度等于t的长度,那么st的情况下s才是t的子序列如果s的长度小于t的长…...

禁用PS/Photoshop等一系列Adobe旗下软件联网外传用户数据操作
方案一: 下载火绒杀毒,在联网请求上禁用Adobe软件的联网请求,甚至还可以额外发现哪些是它要想要偷偷摸摸干的。 方案二: 最后注意: 用盗版软件只是获得了使用权!...
C语言猜输赢游戏
目录 开头游戏的程序游戏的流程图结尾 开头 大家好,我叫这是我58,现在,请你看一下下面的游戏程序。 游戏的程序 #define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <Windows.h> int main() {int i 1;int ia 0…...
Rust 异步 trait 的实现困难
在 Rust 中,异步编程是使用 async/await 语法来实现的。与传统的同步编程不同,异步编程涉及到的特性较多,其中一个重要的特性是异步 trait。 异步 trait 是具有异步方法的 trait。在 Rust 中,trait 方法默认是同步的,…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
今日科技热点速览
🔥 今日科技热点速览 🎮 任天堂Switch 2 正式发售 任天堂新一代游戏主机 Switch 2 今日正式上线发售,主打更强图形性能与沉浸式体验,支持多模态交互,受到全球玩家热捧 。 🤖 人工智能持续突破 DeepSeek-R1&…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

Springboot社区养老保险系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,社区养老保险系统小程序被用户普遍使用,为方…...
多模态图像修复系统:基于深度学习的图片修复实现
多模态图像修复系统:基于深度学习的图片修复实现 1. 系统概述 本系统使用多模态大模型(Stable Diffusion Inpainting)实现图像修复功能,结合文本描述和图片输入,对指定区域进行内容修复。系统包含完整的数据处理、模型训练、推理部署流程。 import torch import numpy …...
比较数据迁移后MySQL数据库和OceanBase数据仓库中的表
设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...