封装一个sqlite3动态库
作者:小蜗牛向前冲
名言:我可以接受失败,但我不能接受放弃
如果觉的博主的文章还不错的话,还请
点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正
目录
一、项目案例
二、sqlite3数据库
2.1、sqlite3数据库的介绍
2.2、sqlite3数据库的常用函数
2.2.1、基本函数
2.2.2、sqlite3_exec于sqlite3_prepare_v2 + sqlite3_step的区别在哪里
2.3、sqlite3在MFC中的使用
三、动态库的制作过程
3.1、创建一个动态库的项目
3.2、生成三件套文件
3,3、使用生成的动态库
四、项目实现细节
4.1、封装sqlite3动态库
4.2、实现项目界面各类点击操作
一、项目案例
功能要求用 sqlite3 数据库,
实现一个学生信息管理系统。
1. 添加学生、删除学生
2. 按条件进行升序降序 查询数据库中的学生信息
3. 封装成一个类来实现
效果演示
为了完成这个功能,首先我要在本地下载好sqlite3数据库。 会有如下文件:
在include中包含:
在lib中包含(x64平台):
其次,就是写一个DataBases的动态库,主要包含了对sqilit3:打开数据库,建表,插入,查询,删除接口的封装。写完后,我就要进行编译,成功我们需要动态库文件。这里最为关键的是.dll文件(动态链接库)。这里我们将我们需要的文件,重新用一个文件包含起来DATABASE文件夹。
在include中包含:
在lib中包含(x64平台):
- dDataBases.dll
- 这是一个 动态链接库(DLL) 文件,包含了程序的可执行代码和函数,其他程序可以通过调用它提供的接口来使用其中的功能。
- dDataBases.exp
- 这是一个 导出文件(Exports File),包含了 DLL 中导出的函数和符号信息,通常是链接过程中的一部分。它帮助链接器在构建时找到 DLL 中的符号。
- dDataBases.lib
- 这是一个 静态库(Object File Library) 文件,它包含了程序或 DLL 的目标代码(即编译后的代码)。该文件通常在构建 DLL 时生成,它可以被其他程序链接到以调用 DLL 中的函数。
- dDataBases.pdb
- 这是一个 程序调试数据库(Program Debug Database) 文件,包含了调试信息,如源代码行号、变量名、函数名称等。它帮助调试器在运行时进行符号解析,以便进行调试。
最后,我们就是要在MFM,基于对话框,去实现界面的各种逻辑 。
为了完成这个项目,我们需要知道下面的知识点。
二、sqlite3数据库
2.1、sqlite3数据库的介绍
SQLite 是一个轻量级的关系型数据库管理系统(RDBMS),与其他常见的数据库(如 MySQL 或 PostgreSQL)不同,SQLite 不需要一个独立的服务器进程来运行,它直接将数据库文件嵌入到应用程序中,因此特别适合资源受限的环境。
我们可以理解为sqlite3就是一个库(文件),我们要引用他,只要包含他的头文件就好。
2.2、sqlite3数据库的常用函数
2.2.1、基本函数
1)sqlite3_open打开(或创建)数据库文件。
int sqlite3_open(const char* filename, sqlite3** db);
filename
:数据库文件的路径。db
:指向sqlite3*
类型的指针,用于返回数据库连接对象。
2)sqlite3_close关闭数据库连接。
int sqlite3_close(sqlite3* db);
3)sqlite3_exec执行一条 SQL 语句(可以是查询、插入、更新等)。
int sqlite3_exec(sqlite3* db, const char* sql, int (*callback)(void*, int, char**, char**), void* data, char** errMsg);
db
:数据库连接对象。sql
:要执行的 SQL 语句。callback
:处理查询结果的回调函数(如果是查询操作时使用)。data
:回调函数的自定义参数。errMsg
:如果有错误,返回错误消息。
4)sqlite3_prepare_v2准备执行 SQL 语句(用于查询)
int sqlite3_prepare_v2(sqlite3* db, const char* sql, int nByte, sqlite3_stmt** stmt, const char** tail);
b
:数据库连接对象。sql
:SQL 语句。nByte
:SQL 语句的最大字节数(-1 表示字符串的长度)。stmt
:返回的sqlite3_stmt*
指针,用于后续执行查询。tail
:SQL 语句中的尾部部分(通常为 NULL)。
5)sqlite3_step执行 SQL 语句(例如查询)。
int sqlite3_step(sqlite3_stmt* stmt);
-
查询操作:
sqlite3_step
在查询操作中用于逐行获取结果集。当查询成功时,sqlite3_step
会返回SQLITE_ROW
,表示当前有数据可以获取。- 当查询结束时(即没有更多的数据行时),它返回
SQLITE_DONE
,表示查询完成。
-
非查询操作:
- 对于插入、更新、删除等 SQL 操作,
sqlite3_step
会在第一次执行时完成操作,返回SQLITE_DONE
,表示操作已完成。
- 对于插入、更新、删除等 SQL 操作,
6) sqlite3_column_int获取查询结果中某一列的整数值。
int sqlite3_column_int(sqlite3_stmt* stmt, int col);
stmt
:查询语句对象。col
:列的索引(从 0 开始)。
7) sqlite3_column_text获取查询结果中某一列的文本值。
const char* sqlite3_column_text(sqlite3_stmt* stmt, int col);
8)sqlite3_finalize 释放准备好的 SQL 语句对象。
int sqlite3_finalize(sqlite3_stmt* stmt);
stmt
:要释放的sqlite3_stmt
对象。
9)sqlite3_errmsg获取数据库连接的错误信息。
const char* sqlite3_errmsg(sqlite3* db);
10)sqlite3_changes获取上次操作影响的行数(适用于插入、删除、更新操作)。
int sqlite3_changes(sqlite3* db);
11)sqlite3_busy_timeout设置数据库的忙等待超时时间(如果数据库被锁定时,设置重试时间)。
int sqlite3_busy_timeout(sqlite3* db, int milliseconds);
db
:数据库连接对象。milliseconds
:超时时间(毫秒)。
2.2.2、sqlite3_exec于sqlite3_prepare_v2 + sqlite3_step的区别在哪里
sqlite3_exec
、sqlite3_prepare_v2
和 sqlite3_step
都是 SQLite 中用于执行 SQL 语句的函数。
对于sqlite3_exec他马上执行一条SQL语句,运用在简单场景中。
sqlite3_prepare_v2
和 sqlite3_step
是一种更细粒度的执行方式,通常用于处理复杂的 SQL 查询和需要逐步执行的场景。
sqlite3_prepare_v2他是将SQL语句准换为sqlite3_stmt语句对象。sqlite3_step就是执行sqlite3_prepare_v2准备好的SQL语句。
2.3、sqlite3在MFC中的使用
这里首先我们要先下载好sqlite3得到他的sqlite3.dll动态库文件和sqlite3.h头文件。
我们将需要的四个文件放到sq3目录下
其次。在 MFC 项目中配置 SQLite3
1)点击项目属性->C/C++->常规->附加包含目录,进行配置
2) 在打开的属性页中选择 链接器 -> 常规 -> 附加库目录 -> 编辑
在打开的属性页中选择 链接器 -> 输入 -> 附加依赖项 -> 编辑 ,输入“sqlite3.lib”,点击确定。
这样就完成配置了 ,这里我们包含一下sqlite3.h看报不报错误,没有报错就是配置成功了,注意我们这里需要相对引用找到这个头文件。
三、动态库的制作过程
3.1、创建一个动态库的项目
点击动态链接库建立项目
项目创建完成后,会有framework和pch的.h文件和.cpp文件。
framework.h
主要用作项目的全局头文件,包含必要的MFC库和公共头文件。
pch.h
和 pch.cpp
提供预编译头机制,加速编译过程,提高开发效率。
上面的文件都是编译器生成的,这些都是辅助文件,真正的动态库文件,要我们自己添加,如下我添加了MyDll.h和MyDll.cpp的文件。
3.2、生成三件套文件
MyDll.这个是我们动态库的头文件
一般都用定义下面的电
#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport) // 导出
#else
#define MYDLL_API __declspec(dllimport) // 导入
#endif
上面是我们要导入和导出动态库的基本代码。
MYDLL_API这个宏是为了管理动态库的导入和导出,当那个类或者函数要导出,就要加上这个宏。
这里我们简单导入一个类
#pragma once#ifdef MYDLL_EXPORTS
#define MYDLL_API __declspec(dllexport) // 导出
#else
#define MYDLL_API __declspec(dllimport) // 导入
#endif//这里表示这个类要导出
class MYDLL_API MyDll
{
public:int addNum(int num);
};
在.cpp文件,完成函数的编写
#include"pch.h"
#include"MyDll.h"//每次都加10
int MyDll::addNum(int num)
{return 10 + num;
}
完成这些后就可以编译程序了。
编译成功后,需要找到三件套, 打开文件所在目录。
找到第一个文件MyDll.h文件,新建立一个文件夹,用来存放这三件套。
拿到.h文件后我们再去找lib和dll ,在x64文件中。注意这个x64文件,指的是上一个目录下的的x64->Debug,我们就能拿导MyDll.dll和MyDll.lib文件
将这三个文件都放入,新建立的文件夹中
1. MyDll.dll
这是动态链接库文件(DLL)。它包含了你编写的代码,并且可以被其他程序调用。通过导出函数,其他程序可以使用该 DLL 中提供的功能。这个文件是编译项目后生成的。
2. MyDll.h
这是头文件(Header file)。头文件包含了声明外部函数或类的接口,在其他项目中使用 DLL 时,程序会包含这个头文件来获取函数声明和类定义。通常,头文件中会使用
__declspec(dllexport)
或__declspec(dllimport)
来声明导出/导入的函数。3. MyDll.lib
这是静态库文件,用于在编译时链接到目标程序。在使用 DLL 的项目中,MyDll.lib 提供了符号信息,使得链接器能够正确链接到 DLL 中的函数。它不包含代码本身,只是一个包含函数地址的引用文件,在链接时会告诉程序去加载相应的 DLL 文件。
3,3、使用生成的动态库
这里我们创建项目后,就简单规划出一个简单界面,进行演示:
然后执行下面的操作
(1)将动态链接库的头文件复制到MFC程序里面,可以打开MFC程序的“cpp”文件的所在位置,然后就把MyDll.h放在这
然后在“解决方案管理器”新建一个“筛选器”,名为“自定义库”
再往“自定义库”里面添加现有项,将刚刚的“MyDll.h”添加进来
(2)在MyDll.h”所在的目录新建一个文件夹“Tlib”用来放“MyDll.h.lib”
目前所作的准备,都是为了编译的时候能用上MyDll里的东西,还有需要最后一步,我们就可以将MyDll完全导入MFC程序,那就是包含头文件“MyDl.h”和导入指定路径的"MyDl.lib",在MFCDLLDlg.cpp操作
#include "MyDll.h"//导入头文件,#pragma comment(lib,"Tlib/MyDll.lib")//指定路径,导入静态链接库
(3)之后就可以在界面上按钮的函数里面使用“MYDll”了,双击按钮,进入该函数
void CMFCDLLDlg::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码MyDll dll;int ret = dll.addNum(10);CString str;str.Format(_T("%d"), ret); // 将整数转换为字符串m_text.SetWindowText(str); // 设置到控件中
}
最关键是我们这里使用了MyDll类
这样我成功调用了,自己写的动态库
四、项目实现细节
好了,上面我们学习完成如何在MFC中使用sqlite3和制作动态库,下面我们就可以完成我们的项目了。
4.1、封装sqlite3动态库
1)在完成封装之前我们要完成项目的配置
在VC++目录上,配置好外部包含目录,和库目录。
我们配置外部包含目录是为了让编译器知道sqlite.h头文件在哪里位置,让编译器在链接的时候找到相关的头文件。
库目录,这里一般包含的是库文件(.lib和.dll),在编译时,编译器生成的是目标文件(.obj),但最终的链接阶段需要将目标文件与静态库或动态库链接在一起,以生成可执行文件或动态链接库。通过配置库目录,链接器就能找到正确的库文件进行链接。
在链接器的输入配置附加依赖项目,是为了指定在链接阶段需要链接的额外库文件。这对于使用外部库(例如 SQLite)非常重要,因为它告诉链接器在生成最终可执行文件时,应该包含哪些库文件,
对了,上面这些内容是你安装了sqlite3的情况下,并且有他的一下配置文件。
下面实现DataBases.h
#pragma once#ifdef DATABASES_EXPORTS
#define DATABASES_API __declspec(dllexport)
#else
#define DATABASES_API __declspec(dllimport)
#endif
#include <string>
#include "sqlite3.h"
#include <vector>
#include <atlstr.h>//封装用户数据struct DATABASES_API UserData
{std::string userName;std::string userId;int age;double grades;
};//这个类是从dll导出的
class DATABASES_API DataBases
{
public://构造函数DataBases();bool openDataBases(const char* path);void CreateDable();void InsertData(std::string& name,std::string& id,int age,double grades);void QueryDataAll(std::vector<UserData>& result);void QueryData(const std::string& key, const std::string& values, std::vector<UserData>& result);void DeleteData(const std::string& byid, bool byname);
private:std::string m_strUserName;std::string m_strUserId;int m_iAge;double m_dGrades;sqlite3* m_pDB;//指向数据库char* m_cErr_msg;//错误信息
};extern DATABASES_API int nDataBases;DATABASES_API int fnDataBases(void);
实现 DataBases.cpp文件
#include "pch.h"
#include "framework.h"
#include "DataBases.h"
#include <iostream>
#pragma comment(lib,"sqlite3.lib")// 这是导出变量的一个示例
DATABASES_API int nDataBases = 0;// 这是导出函数的一个示例。
DATABASES_API int fnDataBases(void)
{return 0;
}//构造函数
DataBases::DataBases():m_iAge(0),m_dGrades(0), m_cErr_msg(nullptr), m_pDB(nullptr)
{}//打开数据库,并且建立好表
bool DataBases::openDataBases(const char* path)
{if (m_pDB != nullptr){//数据库已经打开std::cout << "open dataBase"<<std::endl;return true;}//1、打开数据库//返回SQLITE_OK(0):成功打开数据库。int ret = sqlite3_open(path, &m_pDB);if (ret != SQLITE_OK){std::cout << "failed open dataBase" << std::endl;return false;}//sqlite3_exec这个函数是为了执行SQL语句//int sqlite3_exec(// sqlite3* db, // 数据库连接对象// const char* sql, // 要执行的 SQL 语句// int (*callback)(void*, int, char**, char**), // 回调函数(可选)// void* data, // 回调函数的参数(可选)// char** errMsg // 错误信息(如果发生错误)// );if (sqlite3_exec(m_pDB, CREATE_TABLE, nullptr, nullptr, &m_cErr_msg) != SQLITE_OK){std::cout << "SQL error:" << m_cErr_msg;//记得释放掉,m_cErr_msg,当SQL出现错误的时候,sqlite3_exec() 函数动态分配了内存来存储这些错误信息sqlite3_free(m_cErr_msg);//关闭数据库sqlite3_close(m_pDB);return false;}return true;
}//建表
void DataBases::CreateDable()
{if (m_pDB==nullptr){return;}if (sqlite3_exec(m_pDB, CREATE_TABLE, nullptr, nullptr, &m_cErr_msg) != SQLITE_OK){std::cout << "SQL error:" << m_cErr_msg;//记得释放掉,m_cErr_msg,当SQL出现错误的时候,sqlite3_exec() 函数动态分配了内存来存储这些错误信息sqlite3_free(m_cErr_msg);//关闭数据库sqlite3_close(m_pDB);return;}
}//插入
void DataBases::InsertData(std::string& name, std::string& id, int age, double grades)
{m_strUserName = name;m_strUserId = id;m_iAge = age;m_dGrades = grades;sqlite3_stmt* stmt;//sqlite3_prepare_v2() 是一个更底层的 API,用于将 SQL 语句编译成可执行的语句句柄(sqlite3_stmt)。//这个 API 适用于需要重复执行的 SQL 语句、带有占位符(?)的参数化查询//int sqlite3_prepare_v2(// sqlite3 * db, // 数据库连接对象// const char* sql, // 要执行的 SQL 语句// int nByte, // SQL 语句的字节数(-1表示自动计算)// sqlite3_stmt * *ppStmt, // 输出:编译后的 SQL 语句的句柄// const char** pzTail // 输出:未解析的 SQL 部分(适用于多个 SQL 语句)//);//执行插入操作if (sqlite3_prepare_v2(m_pDB, INSERT_DATA, -1, &stmt, nullptr) != SQLITE_OK){std::cout << "Failed to prepare statement!" << std::endl;sqlite3_close(m_pDB);return;}//int sqlite3_bind_text(//sqlite3_stmt* stmt, // 已准备好的 SQL 语句句柄// int index, // 占位符的位置(从 1 开始)// const char* value, // 要绑定的文本值// int n, // 绑定的文本的长度(-1 表示直到遇到 NULL 字符)// void (*destructor)(void*) // 指向析构函数的指针,用于释放值的内存(可选)// );//绑定参数//SQLITE_STATIC:表示数据在绑定时已经是静态的,SQLite 不需要再管理它的生命周期。sqlite3_bind_text(stmt, 1, m_strUserName.c_str(), -1, SQLITE_STATIC);sqlite3_bind_text(stmt, 2, m_strUserId.c_str(), -1, SQLITE_STATIC);sqlite3_bind_int(stmt, 3, m_iAge);sqlite3_bind_double(stmt, 4, m_dGrades);//插入if (sqlite3_step(stmt) != SQLITE_DONE){std::cout << "Execution failed!" << std::endl;}sqlite3_finalize(stmt); // 释放资源
}//查询
void DataBases::QueryDataAll(std::vector<UserData>& result)
{sqlite3_stmt* query_stmt;if (sqlite3_prepare_v2(m_pDB, QUERY_DATA, -1, &query_stmt, nullptr) != SQLITE_OK){std::cout << "Failed to prepare statement!" << std::endl;sqlite3_close(m_pDB);return;}//SQLITE_ROW 表示 查询结果中有一行数据while (sqlite3_step(query_stmt) == SQLITE_ROW){UserData user;user.userName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(query_stmt, 0)));user.userId = std::string(reinterpret_cast<const char*>(sqlite3_column_text(query_stmt, 1)));user.age = sqlite3_column_int(query_stmt, 2);user.grades = sqlite3_column_double(query_stmt,3);//保存结果result.push_back(user);}//释放查找的资源sqlite3_finalize(query_stmt);
}void DataBases::QueryData(const std::string& key, const std::string& values, std::vector<UserData>& result)
{sqlite3_stmt* query_stmt;// 动态构建查询语句std::string sqlQuery = "select UserName, Id, Age, Grades from User_Info where ";if (key == "UserName"){sqlQuery += "UserName = ?";}else if (key == "Id"){sqlQuery += "Id = ?";}else{std::cout << "Invalid search criterion!" << std::endl;return;}// 准备查询的SQL语句if (sqlite3_prepare_v2(m_pDB, sqlQuery.c_str(), -1, &query_stmt, nullptr) != SQLITE_OK){std::cout << "Failed to prepare statement!" << std::endl;return; // 不再关闭数据库连接,因为数据库连接可能会在其他地方继续使用}// 绑定参数,根据 key 类型绑定不同类型的值if (key == "UserName"){sqlite3_bind_text(query_stmt, 1, values.c_str(), -1, SQLITE_STATIC);}else if (key == "Id"){// 假设 "Id" 是整数类型,你可以根据实际情况调整int id = std::stoi(values); // 将 string 转换为整数sqlite3_bind_int(query_stmt, 1, id);}// 查询结果while (sqlite3_step(query_stmt) == SQLITE_ROW){UserData user;user.userName = std::string(reinterpret_cast<const char*>(sqlite3_column_text(query_stmt, 0)));user.userId = std::string(reinterpret_cast<const char*>(sqlite3_column_text(query_stmt, 1)));user.age = sqlite3_column_int(query_stmt, 2);user.grades = sqlite3_column_double(query_stmt, 3);// 保存结果result.push_back(user);}// 如果没有查询到任何数据,输出提示if (result.empty()){std::cout << "No matching records found." << std::endl;}// 释放查询语句的资源sqlite3_finalize(query_stmt);
}//根据id或者name删除数据
void DataBases::DeleteData(const std::string& identifier,bool byname)
{sqlite3_stmt* stmt;const char* sql;if (byname){sql = "delete from user_info where UserName = ?";}else{sql = "delete from user_info where Id = ?";}//准备SQL语句if (sqlite3_prepare_v2(m_pDB, sql, -1, &stmt, nullptr) != SQLITE_OK){std::cout << "Failed to prepare delete statement!" <<std::endl;sqlite3_close(m_pDB);return;}sqlite3_bind_text(stmt, 1, identifier.c_str(), -1, SQLITE_STATIC);//执行删除if (sqlite3_step(stmt) != SQLITE_DONE){std::cout << "Execution failed!" << std::endl;}else{std::cout << (byname ? "User " : "ID ") << identifier << " deleted successfully!" << std::endl;}// 释放资源sqlite3_finalize(stmt);
}
4.2、实现项目界面各类点击操作
前面我们封装sqlite3的动态库,具体咋使用的,参考上面制作动态库的制作,哪里,进行配置,才可以使用我们封装的动态库。
下面就是在我们的界面项目中使用动态库,实现学生管理系统了。
MainDlgDlg.cpp,这里实现主窗口的逻辑
// MainDlgDlg.cpp: 实现文件
//#include "pch.h"
#include "framework.h"
#include "MainDlg.h"
#include "MainDlgDlg.h"
#include "afxdialogex.h"
#include <Windows.h>#ifdef _DEBUG
#define new DEBUG_NEW
#endif#include "AddData.h"
#include "QueryData.h"
#include "DelData.h"// 用于应用程序“关于”菜单项的 CAboutDlg 对话框class CAboutDlg : public CDialogEx
{
public:CAboutDlg();// 对话框数据
#ifdef AFX_DESIGN_TIMEenum { IDD = IDD_ABOUTBOX };
#endifprotected:virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持// 实现
protected:DECLARE_MESSAGE_MAP()
};CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);
}BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()// CMainDlgDlg 对话框CMainDlgDlg::CMainDlgDlg(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_MAINDLG_DIALOG, pParent),m_bRed(true)
{m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}void CMainDlgDlg::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_SHOW, m_Text);
}BEGIN_MESSAGE_MAP(CMainDlgDlg, CDialogEx)ON_WM_SYSCOMMAND()ON_WM_PAINT()ON_WM_CLOSE()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BUTTON1, &CMainDlgDlg::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON2, &CMainDlgDlg::OnBnClickedButton2)ON_BN_CLICKED(IDC_BUTTON3, &CMainDlgDlg::OnBnClickedButton3)ON_BN_CLICKED(IDC_BUTTON4, &CMainDlgDlg::OnBnClickedButton4)ON_WM_CTLCOLOR()//这个宏帮助处理控件的 颜色设置
END_MESSAGE_MAP()// CMainDlgDlg 消息处理程序
//定义一个全部数据库变量
DataBases* g_pDB = nullptr;
BOOL CMainDlgDlg::OnInitDialog()
{CDialogEx::OnInitDialog();// 将“关于...”菜单项添加到系统菜单中。// IDM_ABOUTBOX 必须在系统命令范围内。ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);ASSERT(IDM_ABOUTBOX < 0xF000);CMenu* pSysMenu = GetSystemMenu(FALSE);if (pSysMenu != nullptr){BOOL bNameValid;CString strAboutMenu;bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);ASSERT(bNameValid);if (!strAboutMenu.IsEmpty()){pSysMenu->AppendMenu(MF_SEPARATOR);pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);}}// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动// 执行此操作SetIcon(m_hIcon, TRUE); // 设置大图标SetIcon(m_hIcon, FALSE); // 设置小图标// TODO: 在此添加额外的初始化代码m_Text.SetWindowTextW(TEXT("未连接"));if (g_pDB == nullptr) {g_pDB = new DataBases();}return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}void CMainDlgDlg::OnSysCommand(UINT nID, LPARAM lParam)
{if ((nID & 0xFFF0) == IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else{CDialogEx::OnSysCommand(nID, lParam);}
}// 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。void CMainDlgDlg::OnPaint()
{if (IsIconic()){CPaintDC dc(this); // 用于绘制的设备上下文SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);// 使图标在工作区矩形中居中int cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// 绘制图标dc.DrawIcon(x, y, m_hIcon);}else{CDialogEx::OnPaint();}
}//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMainDlgDlg::OnQueryDragIcon()
{return static_cast<HCURSOR>(m_hIcon);
}//链接数据库void CMainDlgDlg::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码if (g_pDB->openDataBases("UserData.db")){m_Text.SetWindowTextW(TEXT("已连接"));m_bRed = false;Invalidate();AfxMessageBox(_T("链接成功"));}else{m_Text.SetWindowTextW(TEXT("未连接"));m_bRed = true;Invalidate();AfxMessageBox(_T("链接失败"));}
}//添加数据
void CMainDlgDlg::OnBnClickedButton2()
{// TODO: 在此添加控件通知处理程序代码if (m_bRed == true){AfxMessageBox(_T("请先链接数据库"));}else{AddData AD;AD.DoModal();}
}//查询数据库
void CMainDlgDlg::OnBnClickedButton3()
{// TODO: 在此添加控件通知处理程序代码if (m_bRed == true){AfxMessageBox(_T("请先链接数据库"));}else{QueryData QD;QD.DoModal();}
}//删除数据
void CMainDlgDlg::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码if (m_bRed == true){AfxMessageBox(_T("请先链接数据库"));}else{DelData DD;DD.DoModal();}
}
//当我们关闭窗口的时候条用,释放资源
void CMainDlgDlg::OnClose()
{if (g_pDB != nullptr) {delete g_pDB;g_pDB = nullptr;}CDialogEx::OnOK();
}
HBRUSH CMainDlgDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);// TODO: 在此更改 DC 的任何特性if (TRUE == m_bRed){pDC->SetTextColor(RGB(255, 0, 0));//红色}else{pDC->SetTextColor(RGB(0, 255, 0));//绿色}// TODO: 如果默认的不是所需画笔,则返回另一个画笔return hbr;
}
addData.cpp,这里实现数据的添加
// AddData.cpp: 实现文件
//#include "pch.h"
#include "MainDlg.h"
#include "AddData.h"
#include "afxdialogex.h"// AddData 对话框IMPLEMENT_DYNAMIC(AddData, CDialogEx)AddData::AddData(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DIALOG1, pParent), m_strName(_T("")), m_strId(_T("")), m_iAge(0), m_dGrades(0)
{}AddData::~AddData()
{
}void AddData::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT1, m_strName);DDX_Text(pDX, IDC_EDIT2, m_strId);DDX_Text(pDX, IDC_EDIT3, m_iAge);DDX_Text(pDX, IDC_EDIT4, m_dGrades);
}BEGIN_MESSAGE_MAP(AddData, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &AddData::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON5, &AddData::OnBnClickedButton5)
END_MESSAGE_MAP()// AddData 消息处理程序//添加数据
void AddData::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码UpdateData(true);//将控件中的数据传输到成员变量中去//CT2A是将 CString(宽字符字符串) 转换为 const char*(ANSI 字符串)。std::string strname = CT2A(m_strName.GetString(), CP_UTF8);std::string strid = CT2A(m_strId.GetString(), CP_UTF8);;g_pDB->InsertData(strname, strid, m_iAge, m_dGrades);UpdateData(false);//成员变量->控件AfxMessageBox(_T("添加成功"));
}//取消按键
void AddData::OnBnClickedButton5()
{// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();
}
DelData.cpp,这里实现数据的删除
// DelData.cpp: 实现文件
//#include "pch.h"
#include "MainDlg.h"
#include "DelData.h"
#include "afxdialogex.h"
#include"ListCtrl.h"// DelData 对话框IMPLEMENT_DYNAMIC(DelData, CDialogEx)DelData::DelData(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DIALOG3, pParent), m_strName(_T("")), m_strId(_T(""))
{}DelData::~DelData()
{
}void DelData::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT1, m_strName);DDX_Text(pDX, IDC_EDIT2, m_strId);
}BEGIN_MESSAGE_MAP(DelData, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &DelData::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON4, &DelData::OnBnClickedButton4)ON_BN_CLICKED(IDC_BUTTON6, &DelData::OnBnClickedButton6)ON_BN_CLICKED(IDC_BUTTON7, &DelData::OnBnClickedButton7)
END_MESSAGE_MAP()// DelData 消息处理程序//按照名字删除
void DelData::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码UpdateData(true);std::string str_delname = CT2A(m_strName.GetString(), CP_UTF8);g_pDB->DeleteData(str_delname, true);AfxMessageBox(_T("删除成功"));
}//按照ID删除
void DelData::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码UpdateData(true);std::string str_delId = CT2A(m_strId.GetString(), CP_UTF8);g_pDB->DeleteData(str_delId, true);AfxMessageBox(_T("删除成功"));
}void DelData::OnBnClickedButton6()
{// TODO: 在此添加控件通知处理程序代码std::vector<UserData> result;UpdateData(true);g_pDB->QueryDataAll(result);ListCtrl ListCtrl(result); // 将查询结果传递给目标对话框ListCtrl.DoModal();
}void DelData::OnBnClickedButton7()
{// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();
}
ListCtrl.cpp,这里实现list Control控件,制作数据库的查询结果显示界面
// ListCtrl.cpp: 实现文件
//#include "pch.h"
#include "MainDlg.h"
#include "ListCtrl.h"
#include "afxdialogex.h"
#include <algorithm>// ListCtrl 对话框IMPLEMENT_DYNAMIC(ListCtrl, CDialogEx)ListCtrl::ListCtrl(const std::vector<UserData>& data, CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DIALOG4, pParent),m_data(data),m_bAgeFlag(false),m_bGraFlag(false)
{}ListCtrl::~ListCtrl()
{
}void ListCtrl::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Control(pDX, IDC_LIST5, m_List);
}
//转格式UTF8格式转为CString风格
CString ListCtrl::UTF8ToCString(const std::string& utf8Str)
{int wideLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, NULL, 0);if (wideLen <= 0) return CString("");wchar_t* wideStr = new wchar_t[wideLen];MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, wideStr, wideLen);CString result(wideStr);delete[] wideStr;return result;
}
//
BOOL ListCtrl::OnInitDialog()
{CDialogEx::OnInitDialog();// 设置ListCtrl的扩展样式m_List.SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);//设置标题m_List.InsertColumn(0, _T("UserName"), LVCFMT_LEFT, 100);m_List.InsertColumn(1, _T("Id"), LVCFMT_LEFT, 100);m_List.InsertColumn(2, _T("Age"), LVCFMT_LEFT, 50);m_List.InsertColumn(3, _T("Grades"), LVCFMT_LEFT, 50);AdjustListCtrlColumns();//将查询到的结果进行填充for (size_t i = 0; i < m_data.size(); ++i){const UserData& user = m_data[i];// 插入第一列(用户名)int index = m_List.InsertItem(i, UTF8ToCString(user.userName));// 插入其他列m_List.SetItemText(index, 1, UTF8ToCString(user.userId));m_List.SetItemText(index, 2, UTF8ToCString(std::to_string(user.age)));m_List.SetItemText(index, 3, UTF8ToCString(std::to_string(user.grades)));}return TRUE; // 返回TRUE以启用对话框
}//调整控件
void ListCtrl::AdjustListCtrlColumns()
{// 获取 CListCtrl 控件的客户区宽度CRect rect;m_List.GetClientRect(&rect);int totalWidth = rect.Width(); // 控件的总宽度// 计算每列的宽度int columnWidth = totalWidth / 4;// 设置每列的宽度,假设你有 4 列for (int i = 0; i < 4; ++i){m_List.SetColumnWidth(i, columnWidth); // 设置第 i 列的宽度}
}BEGIN_MESSAGE_MAP(ListCtrl, CDialogEx)ON_WM_CLOSE()ON_BN_CLICKED(IDC_BUTTON1, &ListCtrl::OnBnClickedAge)ON_BN_CLICKED(IDC_BUTTON3, &ListCtrl::OnBnClickedGrades)
END_MESSAGE_MAP()// ListCtrl 消息处理程序//年龄排序
void ListCtrl::OnBnClickedAge()
{// TODO: 在此添加控件通知处理程序代码std::sort(m_data.begin(), m_data.end(), [this](const UserData& a, const UserData& b) {if (m_bAgeFlag){return a.age < b.age;//升序}else{return a.age > b.age;//减序}});m_bAgeFlag = !m_bAgeFlag;// 清空 CListCtrlm_List.DeleteAllItems();//重新布局界面for (int i = 0; i < m_data.size(); ++i){const UserData& user = m_data[i];// 插入第一列(用户名)int index = m_List.InsertItem(i, UTF8ToCString(user.userName));// 插入其他列m_List.SetItemText(index, 1, UTF8ToCString(user.userId));m_List.SetItemText(index, 2, UTF8ToCString(std::to_string(user.age)));m_List.SetItemText(index, 3, UTF8ToCString(std::to_string(user.grades)));}
}//成绩排序
void ListCtrl::OnBnClickedGrades()
{// TODO: 在此添加控件通知处理程序代码std::sort(m_data.begin(), m_data.end(), [this](const UserData& a, const UserData& b) {if (m_bGraFlag){return a.grades < b.grades;//升序}else{return a.grades > b.grades;//减序}});m_bGraFlag = !m_bGraFlag;// 清空 CListCtrlm_List.DeleteAllItems();//重新布局界面for (int i = 0; i < m_data.size(); ++i){const UserData& user = m_data[i];// 插入第一列(用户名)int index = m_List.InsertItem(i, UTF8ToCString(user.userName));// 插入其他列m_List.SetItemText(index, 1, UTF8ToCString(user.userId));m_List.SetItemText(index, 2, UTF8ToCString(std::to_string(user.age)));m_List.SetItemText(index, 3, UTF8ToCString(std::to_string(user.grades)));}
}void ListCtrl::OnClose()
{CDialogEx::OnOK();
}
QueryData.cpp ,这里实现查询数据界面的逻辑。
// QueryData.cpp: 实现文件
//#include "pch.h"
#include "MainDlg.h"
#include "QueryData.h"
#include "afxdialogex.h"
#include"ListCtrl.h"// QueryData 对话框IMPLEMENT_DYNAMIC(QueryData, CDialogEx)QueryData::QueryData(CWnd* pParent /*=nullptr*/): CDialogEx(IDD_DIALOG2, pParent), m_strName(_T("")), m_strId(_T(""))
{}QueryData::~QueryData()
{
}void QueryData::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);DDX_Text(pDX, IDC_EDIT1, m_strName);DDX_Text(pDX, IDC_EDIT2, m_strId);
}BEGIN_MESSAGE_MAP(QueryData, CDialogEx)ON_BN_CLICKED(IDC_BUTTON1, &QueryData::OnBnClickedButton1)ON_BN_CLICKED(IDC_BUTTON4, &QueryData::OnBnClickedButton4)ON_BN_CLICKED(IDC_BUTTON6, &QueryData::OnBnClickedButton6)ON_BN_CLICKED(IDC_BUTTON7, &QueryData::OnBnClickedButton7)
END_MESSAGE_MAP()// QueryData 消息处理程序//姓名查询
void QueryData::OnBnClickedButton1()
{// TODO: 在此添加控件通知处理程序代码std::vector<UserData> result;UpdateData(true);std::string strname = CT2A(m_strName.GetString(), CP_UTF8);g_pDB->QueryData("UserName", strname, result);ListCtrl ListCtrl(result); // 将查询结果传递给目标对话框ListCtrl.DoModal();
}//id查询
void QueryData::OnBnClickedButton4()
{// TODO: 在此添加控件通知处理程序代码std::vector<UserData> result;UpdateData(true);std::string strid = CT2A(m_strId.GetString(), CP_UTF8);g_pDB->QueryData("UserName", strid, result);ListCtrl ListCtrl(result); // 将查询结果传递给目标对话框ListCtrl.DoModal();
}//查询所有
void QueryData::OnBnClickedButton6()
{// TODO: 在此添加控件通知处理程序代码std::vector<UserData> result;UpdateData(true);g_pDB->QueryDataAll(result);ListCtrl ListCtrl(result); // 将查询结果传递给目标对话框ListCtrl.DoModal();
}//取消
void QueryData::OnBnClickedButton7()
{// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();
}
主要代码就这些了,具体细节大家自己完善吧
相关文章:
封装一个sqlite3动态库
作者:小蜗牛向前冲 名言:我可以接受失败,但我不能接受放弃 如果觉的博主的文章还不错的话,还请点赞,收藏,关注👀支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录 一、项目案例 二…...
1.攻防世界 unserialize3(wakeup()魔术方法、反序列化工作原理)
进入题目页面如下 直接开审 <?php // 定义一个名为 xctf 的类 class xctf {// 声明一个公共属性 $flag,初始值为字符串 111public $flag 111;// 定义一个魔术方法 __wakeup()// 当对象被反序列化时,__wakeup() 方法会自动调用public function __wa…...
DeepSeek能做分析吗?从需求规约到分析类图的实验
DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 今天我们来尝试DeepSeek能不能帮我们从需求转到分析。 给定一个用例规约,我们让它按照面向对象分析设计方法,出一个分析类图。过程如下: 可以帮助提…...
九.Spring Boot使用 ShardingSphere + MyBatis + Druid 进行分库分表
文章目录 前言一、引入依赖二、创建一个light-db_1备用数据库三、配置文件 application-dev.yml四、创建shardingsphere-config.yml完整项目结构 五、测试总结 前言 在现代化微服务架构中,随着数据量的不断增长,单一数据库已难以满足高可用性、扩展性和…...
RNN复兴!性能反超Transformer,训练速度提升1300倍!
在最新的顶会论文中,RNN的改进创新更是层出不穷。Bengio团队提出的minLSTM和minGRU,通过去除隐藏状态的依赖和简化门控机制,显著减少了参数量和计算量。这些模型可以使用并行扫描算法进行训练,大大加快了训练速度。例如࿰…...
C语言第18节:自定义类型——联合和枚举
1. 联合体 C语言中的联合体(Union)是一种数据结构,它允许在同一内存位置存储不同类型的数据。不同于结构体(struct),结构体的成员各自占有独立的内存空间,而联合体的所有成员共享同一块内存区域…...
2025年二级建造师报名流程图解
2025年二级建造师报名时间!附报名流程! ⏰️已公布25年二建考试时间的省份如下: ️4月19日、20日考试的城市有:贵州 ️5月10日、11日考试的城市有:湖北、陕西、宁夏、甘肃、福建、浙江、江西、黑龙江、河南、湖南、…...
AWTK fscript 中的 TCP/UDP 客户端扩展函数
fscript 是 AWTK 内置的脚本引擎,开发者可以在 UI XML 文件中直接嵌入 fscript 脚本,提高开发效率。本文介绍一下 fscript 中的 TCP/UDP 客户端扩展函数。 1.iostream_tcp_create 创建 TCP 客户端输入输出流对象。 原型 iostream_tcp_create(host, por…...
用php tp6对接钉钉审批流的 table 表格 明细控件 旧版sdk
核心代码 foreach ($flows[product_list] as $k>$gift) {$items_list[] [[name > 商品名称, value > $gift[product_name] ?? ],[name > 规格, value > $gift[product_name] ?? ],[name > 数量, value > $gift[quantity] ?? ],[name > 单位, v…...
【DuodooBMS】给PDF附件加“受控”水印的完整Python实现
给PDF附件加“受控”水印的完整Python实现 功能需求 在实际工作中,许多文件需要添加水印以标识其状态,例如“受控”“机密”等。对于PDF文件,添加水印不仅可以增强文件的可识别性,还可以防止未经授权的使用。本代码的功能需求是…...
前缀和算法篇:解决子数组累加和问题
前缀和算法篇:解决子数组累加和问题 1.前缀和原理 那么在介绍前缀和的原理之前,那么我们先来说下前缀和最基本的一个应用场景,那么就是如我们标题所说的子数组累加和问题,那么假设我们现在有一个区间为[L,R]的数组,那…...
大语言模型多代理协作(MACNET)
大语言模型多代理协作(MACNET) Scaling Large-Language-Model-based Multi-Agent Collaboration 提出多智能体协作网络(MACNET),以探究多智能体协作中增加智能体数量是否存在类似神经缩放定律的规律。研究发现了小世界协作现象和协作缩放定律,为LLM系统资源预测和优化…...
vue项目使用vite和vue-router实现history路由模式空白页以及404问题
开发项目的时候,我们一般都会使用路由,但是使用hash路由还是history路由成为了两种选择,因为hash路由在url中带有#号,history没有带#号,看起来更加自然美观。但是hash速度更快而且更通用,history需要配置很…...
【Linux】从一台windows电脑访问局域网下另一台linux电脑详细操作步骤
以下是在Windows电脑B上访问Linux电脑A的文件并使用bash终端的详细步骤: 一、在Linux电脑A上配置SSH服务(用于终端操作) 安装SSH服务 sudo apt update && sudo apt install openssh-server启动SSH服务并设置开机自启 sudo systemctl …...
Makefile的用法及算法应用
编译的过程 算法:解决特定问题的求解步骤 算法的设计 1.正确性 语法正确合法的输入能得到合理的结果对非法的输入,给出满足要求的规格说明对精心选择,甚至刁难的测试都能正常运行,结果正确 2.可读性,便于交流&…...
Elasticsearch:15 年来致力于索引一切,找到重要内容
作者:来自 Elastic Shay Banon 及 Philipp Krenn Elasticsearch 刚刚 15 岁了!回顾过去 15 年的索引和搜索,并展望未来 15 年的相关内容。 Elasticsearch 刚刚成立 15 周年。一切始于 2010 年 2 月的一篇公告博客文章(带有标志性的…...
MongoDB 扩缩容实战:涵盖节点配置、服务启动与移除操作
#作者:任少近 文章目录 一、扩容在245节点上配置配置config server:配置mongos启动config server安装工具mongosh添加245新节点到副本集配置分片副本集启动路由并分片 二、缩容Conf server上去掉server4shard上去掉server4mongos上去掉server4 一、扩容…...
Bitmap在数仓中的应用
一、背景 在数据仓库的日常工作中,我们经常需要面对海量数据的存储和高效查询问题。尤其是,当业务对性能的要求越来越高、数据量持续增长时,传统的处理方式往往显得笨拙而低效。而这时候,Bitmap(位图)作为…...
C++病毒(^_^|)(2)
第二期 声明: 仅供损害电脑,不得用于非法。损坏电脑,作者一律不负责。此作为作者原创,转载请经过同意。 直接上代码 #include <bits/stdc.h> #include <windows.h> using namespace std; HHOOK g_hHook;void lrud(…...
Linux 内核架构入门:从基础概念到面试指南*
1. 引言 Linux 内核是现代操作系统的核心,负责管理硬件资源、提供系统调用、处理进程调度等功能。对于初学者来说,理解 Linux 内核的架构是深入操作系统开发的第一步。本篇博文将详细介绍 Linux 内核的架构体系,结合硬件、子系统及软件支持的…...
leetcode-495.提莫攻击
leetcode-495.提莫攻击 文章目录 leetcode-495.提莫攻击一.题目描述二.代码提交三.解释 一.题目描述 二.代码提交 #include <vector> using namespace std;int findPoisonedDuration(vector<int>& timeSeries, int duration) {int total 0;for (int i 0; i …...
mysql 参数max_connect_errors研究
1.在server端设置max_connect_errors3,超过3次连接错误就block mysql> set global max_connect_errors3; Query OK, 0 rows affected (0.00 sec) mysql> show variables like max_connect_errors; --------------------------- | Variable_name | Value…...
vscode无法ssh连接远程机器解决方案
远程服务器配置问题 原因:远程服务器的 SSH 服务配置可能禁止了 TCP 端口转发功能,或者 VS Code Server 在远程服务器上崩溃。 解决办法 检查 SSH 服务配置:登录到远程服务器,打开 /etc/ssh/sshd_config 文件,确保以下…...
sql盲注获取数据库的表名、列名和具体数据
1.时间盲注 获取表名 sql id1 AND IF(ASCII(SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schemaDATABASE() LIMIT 1),1,1))97, SLEEP(5), 0) 获取列名 sql id1 AND IF(ASCII(SUBSTRING((SELECT column_name FROM information_schema.col…...
清华大学新闻与传播学院沈阳团队出品的《DeepSeek:从入门到精通》104页PDF
前言 本机运行DeepSeek R1大模型文章如下: Windows电脑本地部署运行DeepSeek R1大模型(基于Ollama和Chatbox)【保姆级万字教程】在Windows计算机部署DeepSeek大模型,给在实验室无外网的同事们用(基于Ollama和OpenWebUI…...
使用sublime_text中,TAB键无效怎么解决???
如果你也有这样的困扰,请你跟着我下面的步骤操作 点击首选项(如下图所示) 找到下面这段代码并注释掉 { “keys”:[“tab”], “args”:{“action”:“expand_abbreviation”}, “command”:“run_emmet_action”, “context”:[ { “key”:“…...
Java IO流详解
1. IO概述 IO(Input/Output)即输入和输出,指的是设备或环境之间进行数据的输入或输出。例如,键盘是输入设备,显示器是输出设备。在Java中,输入输出问题通过流(Stream)对象来解决。以…...
智慧农业-虫害及生长预测
有害生物防控系统是一个综合性的管理体系,旨在预防和控制对人类生活、生产甚至生存产生危害的生物。这些生物可能包括昆虫、动物、植物、微生物乃至病毒等。 一、系统构成 1、监测预警系统:利用智能传感器、无人机、遥感技术等手段,实时监测…...
ASIL D要达到多少fit
ASIL(Automotive Safety Integrity Level,汽车安全完整性等级)D是ISO 26262标准中最高等级的安全要求,其对应的随机硬件故障概率目标(以FIT表示)需满足以下要求: ASIL D的FIT目标 根据 ISO 262…...
与传统光伏相比 城电科技的光伏太阳花有什么优势?
相比于传统光伏,城电科技的光伏太阳花有以下优势: 一、发电效率方面 智能追踪技术:光伏太阳花通过内置的智能追踪系统,采用全球定位跟踪算法,能够实时调整花瓣(即光伏板)的角度,确…...
2025年SEO工具有哪些?老品牌SEO工具有哪些
随着2025年互联网的发展和企业线上营销的日益重要,SEO(搜索引擎优化)逐渐成为了提高网站曝光率和流量的重要手段。SEO的工作不仅仅是简单地通过关键词优化和内容发布就能够实现的,它需要依赖一系列专业的SEO工具来帮助分析、监测和…...
深入解析与解决 Oracle 报错:ORA-29275 部分多字节字符20250213
🛠️ 深入解析与解决 Oracle 报错:ORA-29275 部分多字节字符 引言 🌟 在与 Oracle 数据库打交道的日常工作中,你是否遇到过 ORA-29275: partial multibyte character 这个令人头疼的错误?这个错误通常与字符编码、数…...
HTML应用指南:利用GET请求获取全国海底捞门店位置信息
随着新零售业态的快速发展,门店位置信息的获取变得越来越重要。作为餐饮服务行业的先锋,海底捞不仅在服务质量上持续领先,还积极构建广泛的门店网络,以支持其不断增长的用户群体。为了更好地理解和利用这些数据,本篇文…...
数据流图和数据字典
在面向结构的分析和设计阶段,**数据流图(Data Flow Diagram, DFD)和数据字典(Data Dictionary)**是两个非常重要的工具,它们分别从不同的角度描述系统的功能和数据结构,帮助开发团队更好地理解和…...
Ubuntu 22.04 LTS 安装MinerU
1. 检测是否已安装nvidia驱动 nvidia-smi 如果看到类似如下的信息,说明已经安装了nvidia驱动,可以跳过步骤2 Note CUDA Version 显示的版本号应 > 12.1,如显示的版本号小于12.1,请升级驱动 2. 安装驱动 如没有驱动&#…...
OPEN CODER : THE OPEN COOKBOOK FOR TOP -TIER CODE LARGE LANGUAGE MODELS
Abstract 大型语言模型(LLMs)在代码领域已经成为不可或缺的工具,包括代码生成、推理任务和代理系统等多个方面。虽然开放获取的代码LLMs的性能越来越接近专有模型,但适合严格科学研究的优质代码LLMs,特别是那些具有可…...
C语言中printf()函数,格式输出符
在 C 语言中,printf() 函数的格式输出符(格式说明符)用于控制输出的格式和数据类型。以下是常见的格式说明符及其用法: 基本格式符 打印各种类型的值 格式输出符数据类型说明%dint输出有符号十进制整数%uunsigned int输出无符号…...
EasyRTC嵌入式WebRTC视频通话SDK支持Web浏览器、Linux、ARM、Android、iOS
随着互联网技术的飞速发展,实时通信(RTC)已经成为现代应用中不可或缺的一部分。无论是视频会议、在线教育、远程医疗,还是社交娱乐,实时通信技术都在其中扮演着重要角色。 然而,WebRTC技术在PC和移动端的支…...
【JS球球大作战项目实战】+在线体验
个人名片: 🐼作者简介:一名大三在校生,喜欢AI编程🎋 🐻❄️个人主页🥇:落798. 🐼个人WeChat:hmmwx53 🕊️系列专栏:🖼️…...
PHP高效、轻量级表格数据处理库 OpenSpout ,很好用
OpenSpout 是一个高效、轻量级的 PHP 库,用于处理电子表格文件(如 Excel 和 CSV)。它支持读取和写入大型文件,且内存占用低。本文将详细介绍如何安装和使用 OpenSpout。 目录 安装 基本使用 高级功能 参考文档 安装 OpenSp…...
数据库第三次作业
第一题: 学生表:Student (Sno, Sname, Ssex , Sage, Sdept) 学号,姓名,性别,年龄,所在系 Sno为主键 课程表:Course (Cno, Cname,) 课程号,课程名 Cno为主键 学生选课表:S…...
Mac 下使用多版本 Node
一、导读 使用 n 实现 Mac 下 Nodejs 的多版本切换,需要先安装一个版本的 Node.js,然后使用 npm 安装 n,再通过 n 管理 node 的多版本切换。 二、使用 npm 全局安装 n sudo npm install -g n 三、根据需求安装指定版本的 node sudo -E n…...
【油猴脚本/Tampermonkey】DeepSeek 服务器繁忙无限重试(20250214优化)
目录 一、 引言 二、 逻辑 三、 源代码 四、 添加新脚本 五、 使用 六、 BUG 七、 优化日志 1.获取最后消息内容报错 2.对话框切换无法正常使用 一、 引言 deepseek演都不演了,每次第一次提问就正常,后面就开始繁忙了,有一点阴招全…...
安全测试|SSRF请求伪造
前言 SSRF漏洞是一种在未能获取服务器权限时,利用服务器漏洞,由攻击者构造请求,服务器端发起请求的安全漏洞,攻击者可以利用该漏洞诱使服务器端应用程序向攻击者选择的任意域发出HTTP请求。 很多Web应用都提供了从其他的服务器上…...
Redisson介绍和入门使用
一、什么是Redisson? Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。 官网地址…...
TUSB422 MCU 软件用户指南
文章目录 TUSB422 MCU 软件用户指南 目录表格图表1. 介绍2. 配置2.1 通用配置2.2 USB-PD 3.0 支持2.3 VDM 支持 3. 代码 ROM/RAM 大小优化4. 通过 UART 调试4. 移植到其他微控制器 TUSB422 MCU 软件用户指南 摘要 本文档是 TUSB422 微控制器基于 Type-C 端口控制(…...
归并排序 和 七大算法的总结图
目录 什么是递归排序: 图解: 递归方法: 代码实现: 思路分析: 非递归方法: 思路: 代码实现: 思路分析: 什么是递归排序: 先将数据分解成诺干个序列࿰…...
MySQL调用存储过程和存储函数
【图书推荐】《MySQL 9从入门到性能优化(视频教学版)》-CSDN博客 《MySQL 9从入门到性能优化(视频教学版)(数据库技术丛书)》(王英英)【摘要 书评 试读】- 京东图书 (jd.com) MySQL9数据库技术_夏天又到了…...
类与对象(OOP)
类(Class) 类是对象的模板或蓝图,用来描述对象的属性和行为。 动态与静态是同一张图像,最终效果也是相同 类的组成分别由: 属性(成员变量):描述对象的状态。 方法(成员方法):描述对象的行为。 构造函数:用于创建对象…...
接入 SSL 认证配置:满足等保最佳实践
前言 随着信息安全形势的日益严峻,等保(信息安全等级保护)要求成为各行业信息系统必须遵守的标准。在数据库领域,OpenGauss作为一款高性能、安全、可靠的开源关系型数据库,也需要满足等保要求,确保数据的安…...