网站模板 登陆,个人品牌网站建设,网站开发软件三剑客,it运维服务作者#xff1a;小蜗牛向前冲 名言#xff1a;我可以接受失败#xff0c;但我不能接受放弃 如果觉的博主的文章还不错的话#xff0c;还请点赞#xff0c;收藏#xff0c;关注#x1f440;支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录
一、项目案例
二… 作者小蜗牛向前冲 名言我可以接受失败但我不能接受放弃 如果觉的博主的文章还不错的话还请点赞收藏关注支持博主。如果发现有问题的地方欢迎❀大家在评论区指正 目录
一、项目案例
二、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、基本函数
1sqlite3_open打开或创建数据库文件。
int sqlite3_open(const char* filename, sqlite3** db);filename数据库文件的路径。db指向 sqlite3* 类型的指针用于返回数据库连接对象。 2sqlite3_close关闭数据库连接。
int sqlite3_close(sqlite3* db);3sqlite3_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如果有错误返回错误消息。
4sqlite3_prepare_v2准备执行 SQL 语句用于查询
int sqlite3_prepare_v2(sqlite3* db, const char* sql, int nByte, sqlite3_stmt** stmt, const char** tail);b数据库连接对象。sqlSQL 语句。nByteSQL 语句的最大字节数-1 表示字符串的长度。stmt返回的 sqlite3_stmt* 指针用于后续执行查询。tailSQL 语句中的尾部部分通常为 NULL。
5sqlite3_step执行 SQL 语句例如查询。
int sqlite3_step(sqlite3_stmt* stmt);查询操作 sqlite3_step 在查询操作中用于逐行获取结果集。当查询成功时sqlite3_step 会返回 SQLITE_ROW表示当前有数据可以获取。当查询结束时即没有更多的数据行时它返回 SQLITE_DONE表示查询完成。 非查询操作 对于插入、更新、删除等 SQL 操作sqlite3_step 会在第一次执行时完成操作返回 SQLITE_DONE表示操作已完成。
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);8sqlite3_finalize 释放准备好的 SQL 语句对象。
int sqlite3_finalize(sqlite3_stmt* stmt);stmt要释放的 sqlite3_stmt 对象。
9sqlite3_errmsg获取数据库连接的错误信息。
const char* sqlite3_errmsg(sqlite3* db);10sqlite3_changes获取上次操作影响的行数适用于插入、删除、更新操作。
int sqlite3_changes(sqlite3* db);11sqlite3_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文件完成函数的编写
#includepch.h
#includeMyDll.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::vectorUserData result);void QueryData(const std::string key, const std::string values, std::vectorUserData 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 dataBasestd::endl;return true;}//1、打开数据库//返回SQLITE_OK0成功打开数据库。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_pDBnullptr){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::vectorUserData 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_castconst char*(sqlite3_column_text(query_stmt, 0)));user.userId std::string(reinterpret_castconst 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::vectorUserData 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_castconst char*(sqlite3_column_text(query_stmt, 0)));user.userId std::string(reinterpret_castconst 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_castWPARAM(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_castHCURSOR(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
#includeListCtrl.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::vectorUserData 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::vectorUserData 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
#includeListCtrl.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::vectorUserData 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::vectorUserData 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::vectorUserData result;UpdateData(true);g_pDB-QueryDataAll(result);ListCtrl ListCtrl(result); // 将查询结果传递给目标对话框ListCtrl.DoModal();
}//取消
void QueryData::OnBnClickedButton7()
{// TODO: 在此添加控件通知处理程序代码CDialogEx::OnCancel();
}主要代码就这些了具体细节大家自己完善吧