QSqlTableModel的使用

实例功能

这边使用一个实例显示数据库 demodb 中 employee 数据表的内容,实现编辑、插入、删除的操作,实现数据的排序和记录过滤,还实现 BLOB 类型字段 Photo 中存储照片的显示、导入等操作,运行界面如下图:

image.png

在上图中,左侧数据表格是一个 QTableView 组件,设置一个 QSqlTableModel 类的变量作为数据模型后就可以显示数据表的内容。右侧的一些编辑框、下拉列表框等。界面组件通过 QDataWidgetMapper 类的实例设置为某个字段关联,自动显示字段内容。但是没有现成的组件可以通过字段映射显示图片。为此需要使用一个 QLabel 来显示图片。所以图片的导入和显示等操作需要额外实现。
QTableView 显示内容有缺省的代理组件,一般是自动使用 QLineEdit 组件。但是对于某些字段期望通过下拉列表框来输入,例如“性别”和“部门”。为此,还设计了自定义数据代理类。
工具栏上的按钮根据当前状态自动可用或禁用,特别是“保存”和“取消”两个按钮在数据有改动后可以使用,使用过之后又不可使用。

主窗口设计

Action 工具栏如下图所示,其他在上面已经说明:

image.png

以下是主窗口 MainWindow 的定义:

class MainWindow : public QMainWindow
{Q_OBJECTprivate:QSqlDatabase  DB;//数据库连接QSqlTableModel  *tabModel;  //数据模型QItemSelectionModel *theSelection; //选择模型QDataWidgetMapper   *dataMapper; //数据映射QWComboBoxDelegate   delegateSex; //自定义数据代理,性别QWComboBoxDelegate   delegateDepart; //自定义数据代理,部门void    openTable();//打开数据表void    getFieldNames();//获取字段名称,填充“排序字段”的comboBox
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();private slots:void on_currentChanged(const QModelIndex &current, const QModelIndex &previous);// QTableView的SelectionModel的行发生了变化,进行处理void on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous);///void on_actOpenDB_triggered();void on_actRecAppend_triggered();void on_actRecInsert_triggered();void on_actRevert_triggered();void on_actSubmit_triggered();void on_actRecDelete_triggered();void on_actPhoto_triggered();void on_actPhotoClear_triggered();void on_radioBtnAscend_clicked();void on_radioBtnDescend_clicked();void on_radioBtnMan_clicked();void on_radioBtnWoman_clicked();void on_radioBtnBoth_clicked();void on_comboFields_currentIndexChanged(int index);void on_actScan_triggered();private:Ui::MainWindow *ui;
};

MainWindow 类中定义了几个私有变量:

  • QSqlDatabase DB,用于加载数据库驱动和建立与数据库之间的连接。
  • QSQLTab 了 Model* tabModel,用于指定某个数据表,作为数据表的数据模型。
  • QItemSelectionModel* theSelection,作为 tabModel 的选择模型,提供 currentChange()、currentRowChanged()等信号,在 tabModel 选择的字段发生变化、当前记录发生变化时发射信号,以便应用程序控制响应。例如在 currentChanged()信号发射时,检查 tabModel 是否有数据被修改,从而更新“保存”和“取消”按钮的状态。
  • QDataWidgetMapper* dataMapper 用于实现界面组件和 tabModel 的字段之间的映射。
  • QWComboBoxDelegate 是一个自定义的基于 QComboBox 的代理类,delegateSex 和 delegateDepart 用作 tableView 中的“性别”和“部门”字段的代理组件。
  • on_currentChanged() 用于检查数据表内容是否有修改,从而更新按钮状态。
  • on_currentRowChanged() 用于在当前记录发生变化的时候,从新记录中提取图片并更新到界面。

MainWindow 的构造函数如下,主要是对 tableView 的一些显示属性设置:

MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);this->setCentralWidget(ui->splitter);//   tableView显示属性设置ui->tableView->setSelectionBehavior(QAbstractItemView::SelectItems);ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);ui->tableView->setAlternatingRowColors(true);
//    ui->tableView->resizeColumnsToContents();
//    ui->tableView->horizontalHeader()->setStretchLastSection(true);
}

打开数据表

点击“打开”按钮时将加载 SQLite 数据库驱动、打开数据库文件、连接 employee 数据表并设置显示属性,并创建 tableView 显示的代理组件,设置数据源与界面组件的映射等,代码如下:

void MainWindow::on_actOpenDB_triggered()
{//打开数据表QString aFile=QFileDialog::getOpenFileName(this,"选择数据库文件","","SQL Lite数据库(*.db *.db3)");if (aFile.isEmpty())  //选择SQL Lite数据库文件return;//打开数据库DB=QSqlDatabase::addDatabase("QSQLITE"); //添加 SQL LITE数据库驱动DB.setDatabaseName(aFile); //设置数据库名称if (!DB.open())   //打开数据库{QMessageBox::warning(this, "错误", "打开数据库失败",QMessageBox::Ok,QMessageBox::NoButton);return;}//打开数据表openTable();
}

这里需要使用 QSqlDatabase 的几个函数设置数据库登录参数,setDatabaseName()设置数据库名称,对于 SQLite 数据库,就设置为数据库文件。如果是网络型数据库,如 Oracle、MS SQL Server 等,还需要使用 setHostName() 设置数据库主机名,setUserName() 设置数据库用户名,setPassword() 设置数据登录密码。对于 SQLite 数据库只要设置数据库文件即可。
数据库连接与登录参数设置后,调用 QSqlDatabase::open() 函数打开数据库。如果成功打开再调用 openTable() 打开数据表进行相关操作。openTable() 函数代码如下:

void MainWindow::openTable()
{//打开数据表tabModel=new QSqlTableModel(this,DB);//数据表tabModel->setTable("employee"); //设置数据表tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);//数据保存方式,OnManualSubmit , OnRowChangetabModel->setSort(tabModel->fieldIndex("empNo"),Qt::AscendingOrder); //排序if (!(tabModel->select()))//查询数据{QMessageBox::critical(this, "错误信息","打开数据表错误,错误信息\n"+tabModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);return;}//字段显示名tabModel->setHeaderData(tabModel->fieldIndex("empNo"),Qt::Horizontal,"工号");tabModel->setHeaderData(tabModel->fieldIndex("Name"),Qt::Horizontal,"姓名");tabModel->setHeaderData(tabModel->fieldIndex("Gender"),Qt::Horizontal,"性别");tabModel->setHeaderData(tabModel->fieldIndex("Height"),Qt::Horizontal,"身高");tabModel->setHeaderData(tabModel->fieldIndex("Birthday"),Qt::Horizontal,"出生日期");tabModel->setHeaderData(tabModel->fieldIndex("Mobile"),Qt::Horizontal,"手机");tabModel->setHeaderData(tabModel->fieldIndex("Province"),Qt::Horizontal,"省份");tabModel->setHeaderData(tabModel->fieldIndex("City"),Qt::Horizontal,"城市");tabModel->setHeaderData(tabModel->fieldIndex("Department"),Qt::Horizontal,"部门");tabModel->setHeaderData(tabModel->fieldIndex("Education"),Qt::Horizontal,"学历");tabModel->setHeaderData(tabModel->fieldIndex("Salary"),Qt::Horizontal,"工资");tabModel->setHeaderData(tabModel->fieldIndex("Memo"),Qt::Horizontal,"备注"); //这两个字段不再tableView中显示tabModel->setHeaderData(tabModel->fieldIndex("Photo"),Qt::Horizontal,"照片");theSelection=new QItemSelectionModel(tabModel);//关联选择模型
//theSelection当前项变化时触发currentChanged信号connect(theSelection,SIGNAL(currentChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentChanged(QModelIndex,QModelIndex)));
//选择行变化时connect(theSelection,SIGNAL(currentRowChanged(QModelIndex,QModelIndex)),this,SLOT(on_currentRowChanged(QModelIndex,QModelIndex)));ui->tableView->setModel(tabModel);//设置数据模型ui->tableView->setSelectionModel(theSelection); //设置选择模型ui->tableView->setColumnHidden(tabModel->fieldIndex("Memo"),true);//隐藏列ui->tableView->setColumnHidden(tabModel->fieldIndex("Photo"),true);//隐藏列//tableView上为“性别”和“部门”两个字段设置自定义代理组件QStringList strList;strList<<"男"<<"女";bool isEditable=false;delegateSex.setItems(strList,isEditable);ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("Gender"),&delegateSex); //Combbox选择型strList.clear();strList<<"销售部"<<"技术部"<<"生产部"<<"行政部";isEditable=true;delegateDepart.setItems(strList,isEditable);ui->tableView->setItemDelegateForColumn(tabModel->fieldIndex("Department"),&delegateDepart); //Combbox选择型//创建界面组件与数据模型的字段之间的数据映射dataMapper= new QDataWidgetMapper();dataMapper->setModel(tabModel);//设置数据模型dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit);////    dataMapper->setItemDelegate(new QSqlRelationalDelegate(this)); //含有外键的
//界面组件与tabModel的具体字段之间的联系dataMapper->addMapping(ui->dbSpinEmpNo,tabModel->fieldIndex("empNo"));dataMapper->addMapping(ui->dbEditName,tabModel->fieldIndex("Name"));dataMapper->addMapping(ui->dbComboSex,tabModel->fieldIndex("Gender"));dataMapper->addMapping(ui->dbSpinHeight,tabModel->fieldIndex("Height"));dataMapper->addMapping(ui->dbEditBirth,tabModel->fieldIndex("Birthday"));dataMapper->addMapping(ui->dbEditMobile,tabModel->fieldIndex("Mobile"));dataMapper->addMapping(ui->dbComboProvince,tabModel->fieldIndex("Province"));dataMapper->addMapping(ui->dbEditCity,tabModel->fieldIndex("City"));dataMapper->addMapping(ui->dbComboDep,tabModel->fieldIndex("Department"));dataMapper->addMapping(ui->dbComboEdu,tabModel->fieldIndex("Education"));dataMapper->addMapping(ui->dbSpinSalary,tabModel->fieldIndex("Salary"));dataMapper->addMapping(ui->dbEditMemo,tabModel->fieldIndex("Memo"));//    dataMapper->addMapping(ui->dbPhoto,tabModel->fieldIndex("Photo")); //图片无法直接映射dataMapper->toFirst();//移动到首记录getFieldNames();//获取字段名称列表,填充ui->groupBoxSort组件//更新actions和界面组件的使能状态ui->actOpenDB->setEnabled(false);ui->actRecAppend->setEnabled(true);ui->actRecInsert->setEnabled(true);ui->actRecDelete->setEnabled(true);ui->actScan->setEnabled(true);ui->groupBoxSort->setEnabled(true);ui->groupBoxFilter->setEnabled(true);
}

数据模型的创建和属性设置

首先创建 QSqlTableModel 类型的私有变量 tabModel,并且在创建时制定了数据库连接,然后用 setTable() 来指定数据表;setSort() 函数设置排序字段和排序方式,函数原型如下:

void QSqlTableModel::setSort(int column, Qt::SortOrder order);

第一参数是排序的列号,第二个参数是枚举类型,表示排序方式。Qt::AscendingOrder 表示升序,Qt::DescendingOrder 表示降序。
QSqlTableModel::setEditStrategy()函数用于设置编辑策略,参数是枚举类型 QSqlTableModel::EditStrategy,取值如下:

  • QSqlTableModel::OnFieldChange,字段变化时马上更新数据库。
  • QSqlTableModel::OnRowChange,当前行变化时自动更新数据库。
  • QSqlTableModel::OnManualSubmit,所有修改暂时缓存,手动调用 submitAll() 保存修改,或调用 revertAll() 函数取消所有未保存的修改。

表头设置

QSqlTableModel::setHeaderData() 函数用于设置每个字段的表头数据,主要是设置显示标题。如果不进行表头设置,在 TableView 里显示时将显示字段名作为表头。例如,设置“Name”字段的显示标题为“姓名”的代码如下:

tabModel->setHeaderData(tabModel->fieldIndex("Name"), Qt::Horizontal, "姓名");

这里需要注意第一个参数是字段的序号,使用 fieldIndex() 函数可以自动识别序号。

选择模型和信号的作用

为数据模型创建一个选择模型的代码如下:

theSelection = new QitemSelectionModel(tabModel);

选择模型的作用是当用户在 TableView 组件上操作时,获取当前选择的行、列信息,并且在选择的单元格变化时发射 currentChanged() 信号,在当前行变化时发射 currentRowChanged() 信号。为 currentChanged() 信号编写槽函数 on_currentChanged(),获取 tabModel->isDirty() 函数的值,根据是否有未提交的修改,更新工具栏按钮状态。槽函数 on_currentChanged() 代码如下:

void MainWindow::on_currentChanged(const QModelIndex &current, const QModelIndex &previous)
{//更新actPost和actCancel 的状态Q_UNUSED(current);Q_UNUSED(previous);ui->actSubmit->setEnabled(tabModel->isDirty()); //有未保存修改时可用ui->actRevert->setEnabled(tabModel->isDirty());
}

为 currentRowChanged() 信号编写槽函数 on_currentRowChanged(),用于在当前行变化时,从新的记录里提取 Photo 字段的内容,并将图片在 QLabel 组件中显示出来。on_currentRowChanged() 的代码如下:

void MainWindow::on_currentRowChanged(const QModelIndex &current, const QModelIndex &previous)
{Q_UNUSED(previous);
// 行切换时的状态控制ui->actRecDelete->setEnabled(current.isValid());ui->actPhoto->setEnabled(current.isValid());ui->actPhotoClear->setEnabled(current.isValid());if (!current.isValid()){ui->dbLabPhoto->clear(); //清除图片显示return;}dataMapper->setCurrentIndex(current.row()); //更细数据映射的行号int curRecNo=current.row();//获取行号QSqlRecord  curRec=tabModel->record(curRecNo); //获取当前记录if (curRec.isNull("Photo"))  //图片字段内容为空ui->dbLabPhoto->clear();else{QByteArray data=curRec.value("Photo").toByteArray();QPixmap pic;pic.loadFromData(data);ui->dbLabPhoto->setPixmap(pic.scaledToWidth(ui->dbLabPhoto->size().width()));}
}

添加、插入与删除记录

工具栏上有“添加”,“插入”和“删除”三个按钮用于记录操作。添加按钮的槽函数如下:

void MainWindow::on_actRecAppend_triggered()
{//添加记录tabModel->insertRow(tabModel->rowCount(),QModelIndex()); //在末尾添加一个记录QModelIndex curIndex=tabModel->index(tabModel->rowCount()-1,1);//创建最后一行的ModelIndextheSelection->clearSelection();//清空选择项theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);//设置刚插入的行为当前选择行int currow=curIndex.row(); //获得当前行tabModel->setData(tabModel->index(currow,0),2000+tabModel->rowCount()); //自动生成编号tabModel->setData(tabModel->index(currow,2),"男");
// 插入行时设置缺省值,需要在primeInsert()信号里去处理
}

QSqlTableModel::insertRow(int row)函数在数据模型的 row 行前插入一行记录,如果 row 大于等于总函数,就在最后一行添加。使用代码如下:

void MainWindow::on_actRecInsert_triggered()
{//插入记录QModelIndex curIndex=ui->tableView->currentIndex();tabModel->insertRow(curIndex.row(),QModelIndex());theSelection->clearSelection();//清除已有选择theSelection->setCurrentIndex(curIndex,QItemSelectionModel::Select);
}

删除数据的代码如下:

void MainWindow::on_actRecDelete_triggered()
{//删除当前记录QModelIndex curIndex=theSelection->currentIndex();//获取当前选择单元格的模型索引tabModel->removeRow(curIndex.row()); //删除最后一行
}

在插入或删除记录操作没有提交之前,TableView 的左侧表头会记录编辑状态;在保存记录之后,标记会消失,删除的记录也会从 TableView 里删除。

保存和取消修改

当前 demo 在打开数据表的时候,将编辑策略设置为 OnManualSubmit,即手动提交修改。当前数据模型的数据被修改后,不管是直接修改字段值,还是插入或删除记录,在未提交修改前,QSqlTableModel::isDirty() 函数返回 true,利用这个函数在自定义槽函数 on_currentChanged() 里修改 actSubmit 和 actRevert 两个 Action 的使能状态。“保存”和“取消修改”的槽函数代码如下:

void MainWindow::on_actRevert_triggered()
{//取消修改tabModel->revertAll();ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);
}void MainWindow::on_actSubmit_triggered()
{//保存修改bool res=tabModel->submitAll();if (!res)QMessageBox::information(this, "消息", "数据保存错误,错误信息\n"+tabModel->lastError().text(),QMessageBox::Ok,QMessageBox::NoButton);else{ui->actSubmit->setEnabled(false);ui->actRevert->setEnabled(false);}
}

数据遍历

工具栏上的“涨工资”按钮用于将数据表内所有记录的 salary 字段内容增加 10%,演示了记录遍历的功能,代码如下:

void MainWindow::on_actScan_triggered()
{//涨工资,记录遍历if (tabModel->rowCount()==0)return;for (int i=0;i<tabModel->rowCount();i++){QSqlRecord aRec=tabModel->record(i); //获取当前记录float salary=aRec.value("Salary").toFloat();salary=salary*1.1;aRec.setValue("Salary",salary);tabModel->setRecord(i,aRec);}// 索引方式刷新记录,速度一样
//    float   salary;
//    for (int i=0;i<tabModel->rowCount();i++)
//    {
//        salary=tabModel->data(tabModel->index(i,10)).toFloat();
//        salary=salary*1.1;
//        tabModel->setData(tabModel->index(i,10),salary);
//    }if (tabModel->submitAll())QMessageBox::information(this, "消息", "涨工资计算完毕",QMessageBox::Ok,QMessageBox::NoButton);
}

记录排序

QSqlTableModel 的 setSort() 函数设置数据表根据某个字段按照升序或降序排列,实际上就是设置了 SQL 的 ORDER BY 语句。这里在打开数据表的时,调用了 getFieldNames() 函数将数据表的所有字段名添加到界面上的“下拉框”。“排序字段”、“下拉框列表”、“升序”和“降序”的操作如下:

void MainWindow::on_comboFields_currentIndexChanged(int index)
{//选择字段进行排序if (ui->radioBtnAscend->isChecked())tabModel->setSort(index,Qt::AscendingOrder);elsetabModel->setSort(index,Qt::DescendingOrder);tabModel->select();
}
void MainWindow::on_radioBtnAscend_clicked()
{//升序tabModel->setSort(ui->comboFields->currentIndex(),Qt::AscendingOrder);tabModel->select();
}void MainWindow::on_radioBtnDescend_clicked()
{//降序tabModel->setSort(ui->comboFields->currentIndex(),Qt::DescendingOrder);tabModel->select();
}

记录过滤

QSqlTableModel 的 setFilter() 函数设置记录过滤条件,实际上就是 SQL 语句中的 WHERE。界面上的“数据过滤”分组框里有三个 RadioButton;分别为“男”、“女”和“全部显示”,对应的参函数如下:

void MainWindow::on_radioBtnMan_clicked()
{tabModel->setFilter(" Gender='男' ");
//    tabModel->select();
}void MainWindow::on_radioBtnWoman_clicked()
{tabModel->setFilter(" Gender='女' ");
//    tabModel->select();
}void MainWindow::on_radioBtnBoth_clicked()
{tabModel->setFilter("");
}

调用 setFilter() 后无需 select 就可以立刻刷新记录,如果需要取消过滤条件,只要设置为空字符串即可。

参考资料:https://github.com/0voice

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479848.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

什么是代理,nodenginx前端代理详解

一. 什么是代理&#xff1f; 代理就是通过一个特殊的网络服务去访问另一网络服务的一种间接访问方式。像我们不能直接访问国外的网站&#xff0c;只能使用VPN&#xff0c;就是使用了代理 二. 前端为什么要用代理&#xff1f; 首先明确以下两个概念 &#xff08;1&#xff09…

java脚手架系列16-AI大模型集成

之所以想写这一系列&#xff0c;是因为之前工作过程中有几次项目是从零开始搭建的&#xff0c;而且项目涉及的内容还不少。在这过程中&#xff0c;遇到了很多棘手的非业务问题&#xff0c;在不断实践过程中慢慢积累出一些基本的实践经验&#xff0c;认为这些与业务无关的基本的…

网络安全中的数据科学如何重新定义安全实践?

组织每天处理大量数据&#xff0c;这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难&#xff0c;常常导致疏忽。以前&#xff0c;公司依靠 FUD 方法&#xff08;恐惧、不确定性和怀疑&#xff09;来识别潜在攻击。然而&#xff0c;将数据科学集成到网络安全中…

【算法day1】数组:双指针算法

题目引用 这里以 1、LeetCode704.二分查找 2、LeetCode27.移除元素 3、LeetCode977.有序数组的平方 这三道题举例来说明数组中双指针的妙用。 1、二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜…

open-instruct框架使用记录:只使用huggingface数据集的小部分进行训练,如何修改dataset_info.json文件

open-instruct框架 这篇笔记主要记录以下问题&#xff1a;只使用huggingface下载的数据集中的一小部分数据进行数据训练。而且我不想修改open-instruct的加载数据集的代码&#xff0c;以及脚本中的--dataset_mixer_list参数的指定等。下面是我的思路历程。 if args.dataset_na…

Jenkins升级到最新版本后无法启动

1. 场景还原 最近在web界面将jenkins升级到最新版本后&#xff0c;后台无法启动jenkins服务&#xff0c;服务状态如下&#xff1a; 运行jenkins命令提示invalid Java version jenkins --version jenkins: invalid Java version: java version "1.8.0_202" Java(TM)…

DRM(数字权限管理技术)防截屏录屏----ffmpeg安装

提示&#xff1a;ffmpeg安装 文章目录 [TOC](文章目录) 前言一、下载二、配置环境变量三、运行ffmpeg四、文档总结 前言 FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的…

Unity版本使用情况统计(更新至2024年11月)

UWA发布&#xff5c;本期UWA发布的内容是第十五期Unity版本使用统计&#xff0c;统计周期为2024年5月至2024年11月&#xff0c;数据来源于UWA网站&#xff08;www.uwa4d.com&#xff09;性能诊断提测的项目。希望给Unity开发者提供相关的行业趋势作为参考。 2024年5月 - 2024年…

Spring Aop 中对JoinPoint的理解

以下是源码中对 JoinPoint 的描述 A runtime joinpoint is an event that occurs on a static joinpoint (i.e. a location in a program). For instance, an invocation is the runtime joinpoint on a method (static joinpoint). The static part of a given joinpoint can…

C中指针在64位操作系统下为什么是4而不是8

好久没写C了&#xff0c;今天用VScode想写个Demo&#xff0c;翻了下指针资料&#xff0c;想打印下指针大小&#xff0c;发现是4&#xff0c;但是理论上64位系统不应该是8么&#xff1f; 结论就是我编的是32位程序&#xff0c;编译器按照32位编译的。 用vscode的C 插件编译运行…

使用 pycharm 新建不使用 python 虚拟环境( venv、conda )的工程

有时候我们发现一个好玩的 demo&#xff0c;想赶快在电脑上 pip install 一下跑起来&#xff0c;发现因为 python 的 venv、conda 环境还挺费劲的&#xff0c;因为随着时间的发展&#xff0c;之前记得很清楚的 venv、conda 的用法&#xff0c;不经常使用&#xff0c;半天跑不起…

鸿蒙主流路由详解

鸿蒙主流路由详解 Navigation Navigation更适合于一次开发,多端部署,也是官方主流推荐的一种路由控制方式,但是,使用起来入侵耦合度高,所以,一般会使用HMRouter,这也是官方主流推荐的路由 Navigation官网地址 个人源码地址 路由跳转 第一步-定义路由栈 Provide(PageInfo) pag…

Flink Sink的使用

经过一系列Transformation转换操作后&#xff0c;最后一定要调用Sink操作&#xff0c;才会形成一个完整的DataFlow拓扑。只有调用了Sink操作&#xff0c;才会产生最终的计算结果&#xff0c;这些数据可以写入到的文件、输出到指定的网络端口、消息中间件、外部的文件系统或者是…

鸿蒙本地模拟器 模拟TCP服务端的过程

鸿蒙模拟器模拟TCP服务端的过程涉及几个关键步骤&#xff0c;主要包括创建TCPSocketServer实例、绑定IP地址和端口、监听连接请求、接收和发送数据以及处理连接事件。以下是详细的模拟过程&#xff1a; **1.创建TCPSocketServer实例&#xff1a;**首先&#xff0c;需要导入鸿蒙…

【VUE3】新版Vue3+ElementPlus全家桶开发视频项目实战

VUE 介绍 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于标准 HTML、CSS 和 JavaScript 构建,并提供了一套声明式的、组件化的编程模型,帮助你高效地开发用户界面。 Vue.js是一个MVVM(Model - View - ViewModel)的SPA框架。 Model:数…

Edify 3D: Scalable High-Quality 3D Asset Generation

Deep Imagination Research | NVIDIA 目录 一、Abstract 二、核心内容 1、多视图扩散模型 3、重建模型&#xff1a; 4、数据处理模块&#xff1a; 三、结果 1、文本到 3D 生成结果 2、图像到 3D 生成结果 3、四边形网格拓扑结构 一、Abstract NVIDIA 开发的用于高质量…

Python爬虫能处理动态加载的内容吗?

Python爬虫确实可以处理动态加载的内容。动态加载的内容通常是通过JavaScript在客户端执行&#xff0c;这意味着当网页首次加载时&#xff0c;服务器返回的HTML可能并不包含最终用户看到的内容。相反&#xff0c;JavaScript代码会在页面加载后从服务器请求额外的数据&#xff0…

JavaScript练习2——动态“钟”的绘制

实现效果&#xff1a; 分析需求&#xff1a; 1、需要每隔一定时间间隔执行一次绘图&#xff0c;实现旋转效果 2、需要绘制矩形框、圆形缺口框、文字 3、需要设置style 代码实现&#xff1a; 下面给出关键代码的实现&#xff0c;部分函数在之前的文章已经给出 https://blog.…

Jira使用笔记二 ScriptRunner 验证问题创建角色

背景 最近在对公司Jira工作流改造&#xff0c;收到这么一个要求&#xff1a;某些问题类型只有某些角色可以创建。本来是想通过Jira内建的权限控制来处理的。结果点到权限页面&#xff0c;心都凉透了。 好吧&#xff0c;那只能上脚本了。最终使用ScriptRunner的Simple scripte…

Java中的线程池使用详解

文章目录 Java中的线程池使用详解一、引言二、线程池的创建与使用1、线程池的创建1.1、FixedThreadPool&#xff08;固定大小线程池&#xff09;1.2、CachedThreadPool&#xff08;可缓存线程池&#xff09;1.3、SingleThreadExecutor&#xff08;单线程化线程池&#xff09;1.…