基于Windows系统用C++做一个点名工具

embedded/2024/11/22 16:13:19/

目录

一、前言        

二、主要技术点

三、准备工作

四、主界面

1.绘制背景图

2、实现读取花名册功能

3.实现遍历花名册功能

4.实现储存功能

4.1创建数据库

4.2存储数据到数据库表

4.3读取数据库表数据


一、前言        

        人总是喜欢回忆过去,突然回忆起大学时光来,我的计算机老师是用自己做的点名工具,来抽人回答问题的。那么本次的主题就是做一个点名工具,咱们在点名的基础上加一个存储功能,在多次抽取的情况下进行存储。

二、主要技术点

Sqlite数据的增删改查、GDI/GDI+绘制、COM接口、文件数据读取、定时器。

三、准备工作

1.SQLite数据库操作工具

适用于 SQLite 的 DB 浏览器

2.SqLiteCpp第三方库

GitHub - SRombauts/SQLiteCpp:SQLiteC++ (SQLiteCpp) 是一个智能且易于使用的 C++ SQLite3 包装器。

3.一个.txt格式的花名册

四、主界面

主界面包含三个控件:静态文本控件、按钮控件、编辑框控件。分别用于响应选择本地花名册文件、遍历花名册名单、显示花名册名单。

1.绘制背景图

映射WM_PAINT消息进行绘制,可以使用GDI或者GDI+方法。

MESSAGE_HANDLER(WM_PAINT, OnPaint)

GDI的方法:

    LRESULT CRandomDlg::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){PAINTSTRUCT ps;HDC hdc = BeginPaint(&ps);HDC hdcMem = CreateCompatibleDC(hdc);if (lstrlen(m_picPath) != 0){HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, m_picPath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);HBITMAP oldBitmap = (HBITMAP)SelectObject(hdcMem, hBitmap);BITMAP bitmap;GetObject(hBitmap, sizeof(bitmap), &bitmap);SetStretchBltMode(hdc, STRETCH_HALFTONE);   //设置位图拉伸模式,解决模糊问题StretchBlt(hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,ps.rcPaint.bottom - ps.rcPaint.top, hdcMem, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);SelectObject(hdcMem, oldBitmap);DeleteObject(hBitmap);}EndPaint(&ps);DeleteDC(hdcMem);return 0;}

GDI+方法:

#include <gdiplus.h>
using namespace Gdiplus;LRESULT CRandomDlg::OnPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){PAINTSTRUCT ps;HDC hdc = BeginPaint(&ps);if (lstrlen(m_picPath) != 0){Graphics gh(hdc);RectF rect(ps.rcPaint.left, ps.rcPaint.top,ps.rcPaint.right - ps.rcPaint.left,ps.rcPaint.bottom - ps.rcPaint.top);Image* image = Image::FromFile(m_picPath);gh.DrawImage(image, rect);}EndPaint(&ps);return 0;}

如果你写代码所使用的框架没有初始化GDI+,那么需要我们手动初始化和释放:

//初始化GDI+
ULONG_PTR gdiplusToken;   
GdiplusStartupInput gdiplusStartupInput;GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
//释放GDI+
GdiplusShutdown(gdiplusToken);

2、实现读取花名册功能

映射WM_COMMAND消息。

MESSAGE_HANDLER(WM_COMMAND, OnCommand)

处理静态文本控件被点击时的通知消息STN_CLICKED,以此来弹出选择窗口选择花名册文件。我们使用IFileDialog接口来打开一个shell窗口进行文件选择,获取选择文件的路径之后通过CreateFile()函数打开文件,再通过ReadFile()函数读取其内容:

 LRESULT CRandomDlg::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){int wmId = LOWORD(wParam);int messageId = HIWORD(wParam);switch (messageId){case STN_CLICKED:{if (wmId == IDC_CHOOSESTATIC){IFileDialog* pFileDialog = NULL;//创建IFileDialog接口实例HRESULT hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pFileDialog));if (SUCCEEDED(hr)){IShellItem* pItem = nullptr;DWORD dwOptions;hr = pFileDialog->GetOptions(&dwOptions);//设置窗口选项pFileDialog->SetOptions(dwOptions | FOS_FORCEFILESYSTEM | FOS_PATHMUSTEXIST | FOS_FILEMUSTEXIST);//设置窗口标题pFileDialog->SetTitle(L"请选择文件:");//设置筛选器COMDLG_FILTERSPEC fileSpec[] ={{ L"文本文件", L"*.txt"},};pFileDialog->SetFileTypes(1, fileSpec);hr = pFileDialog->Show(GetWindow(IDD_RANDOMDIALOG));//获取用户选择if (SUCCEEDED(hr)){hr = pFileDialog->GetResult(&pItem);if (SUCCEEDED(hr)){//获取选择文件的路径hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &m_pszFilePath);HANDLE hFile = CreateFile(m_pszFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);if (hFile != INVALID_HANDLE_VALUE){//打开文件读取内容DWORD size = GetFileSize(hFile, NULL);if (size != INVALID_FILE_SIZE){nameVec.clear();char* pBuffer = new char[size + 1];memset(pBuffer, 0, size + 1);DWORD dwBytesRead = 0;WCHAR tmp[100] = { 0 };if (ReadFile(hFile, pBuffer, size, &dwBytesRead, NULL)){splitString(pBuffer);if (nameVec.empty())MessageBox(L"所选文件没有内容!", L"Warning", MB_OK | MB_ICONWARNING);else{stringToLPCWSTR(*nameVec.begin(), tmp);SetDlgItemText(IDC_NAMESTATIC, tmp);}}}CloseHandle(hFile);}elseMessageBox(L"CreateFile Error!", L"Error", MB_OK | MB_ICONERROR);}else{MessageBox(L"GetResult Error!", L"Error", MB_OK | MB_ICONERROR);}}// 释放资源pFileDialog->Release();CoTaskMemFree(m_pszFilePath);m_pszFilePath = nullptr;}else{MessageBox(L"CoCreateInstance Error!", L"Error", MB_OK | MB_ICONERROR);}
}

效果图:

3.实现遍历花名册功能

我们通过响应按钮被按下的通知消息BN_CLICKED,来开始遍历花名册。将选中的名字显示在主窗口上,再用定时器来延迟3秒之后清除显示,通过AnimateWindow()函数将显示和清除动作加上动画效果。

LRESULT CRandomDlg::OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled){int wmId = LOWORD(wParam);int messageId = HIWORD(wParam);switch (messageId){case BN_CLICKED:{if (wmId == IDC_STOPBUTTON){//响应开始/停止按钮isStop = !isStop;BOOL errorFlag = FALSE;HANDLE handlePro = GetCurrentProcess();SetUserObjectInformation(handlePro, UOI_TIMERPROC_EXCEPTION_SUPPRESSION, &errorFlag, sizeof(BOOL));if (isStop){SetDlgItemText(IDC_STOPBUTTON, L"开始");KillTimer(ID_SHOWNAME);WCHAR tmpStr[100] = { 0 };stringToLPCWSTR(nameVec.at(index), tmpStr);choosedVec.push_back(tmpStr);HWND hwnd = GetDlgItem(IDC_POPSTATIC);::SetWindowText(hwnd, tmpStr);AnimateWindow(hwnd, 300, AW_ACTIVATE | AW_HOR_POSITIVE);  //动态显示窗口SetTimer(ID_POPNAME, 3000, PopNameProc);}else{if (nameVec.empty()){MessageBox(L"未选择抽奖名单或者名单为空", L"Warning", MB_OK | MB_ICONWARNING);isStop = TRUE;return FALSE;}::ShowWindow(GetDlgItem(IDC_POPSTATIC), SW_HIDE);SetDlgItemText(IDC_STOPBUTTON, L"停止");SetTimer(ID_SHOWNAME, 50, ShowNameProc);InvalidateRect(0, 1);UpdateWindow();}}
}

效果图:

4.实现储存功能

存储方式有很多种,我们本次是使用储存到数据库的方法。使用第三方库SqliteCPP操作sqlite数据库。

4.1创建数据库

我们需要在程序初始化时创建一个数据库文件,并且创建储存数据的表。

创建表指令:

CREATE TABLE 表名 (列名1 列1对应值的类型,……, 列名n 列n对应值的类型)

try{//创建数据库文件if (!PathFileExists(L"C\\ToolBox"))CreateDirectory(L"C:\\ToolBox", NULL);SQLite::Database db("C:\\ToolBox\\TB.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);//创建表string sql = R"(CREATE TABLE IF NOT EXISTS RANDOM (id INTEGER PRIMARY KEY NOT NULL,name TEXT NOT NULL,week INTEGER NOT NULL,todayDate TEXT NOT NULL))";db.exec(sql);}catch (const exception& e){MessageBoxA(NULL, e.what(), "Create table failed!", MB_OK | MB_ICONERROR);}

4.2存储数据到数据库表

我们在第3点中响应按钮消息,将抽中的名单暂时存储到一个vector容器中,再统一保存到本地数据库。

插入数据指令 :

 INSERT INTO 表名 (列名1,……,列名n)VALUES (列名1 对应的值,……,列名n对应的值)

try {SQLite::Database db("C:\\ToolBox\\TB.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);string sql;for (int i = 0; i < choosedVec.size(); i++){sql = "INSERT INTO RANDOM (name, week, todayDate) VALUES (?,?,?)";SQLite::Statement query(db, sql);query.bind(1, UnicodeToUtf8(choosedVec.at(i)));query.bind(2, m_curWeek);query.bind(3, UnicodeToUtf8(m_curDate));query.exec();}nameVec.clear();choosedVec.clear();if (m_staticFont != NULL)DeleteObject(m_staticFont);if (m_titleFont != NULL)DeleteObject(m_titleFont);if (m_bkBrush != NULL)DeleteObject(m_bkBrush);}catch (const exception& e){MessageBoxA(NULL, e.what(), "Store to DB failed!", MB_OK | MB_ICONERROR);return 0;}

注意:sqlite数据库默认的编码模式是UTF-8,所以当我们上传的数据是字符串格式时且编译器设置的字符集非UTF8格式,那么需要先转换为UTF-8格式再上传,否则数据库存储的数据可能就是乱码了。

再储存完成之后我们可以使用事先准备的数据库工具来打开创建的数据库,以此查看数据:

4.3读取数据库表数据

我们可以在程序中读取数据库中储存的数据,读取数据指令:

SELECT 列名 FROM 表名        读取表中某一列的数据

SELECT * FROM 表名                读取整个表的数据

                    WCHAR date[50] = { 0 };GetNowDateString(date);wstring total;try{SQLite::Database db(L"C:\\ToolBox\\TB.db", SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE);SQLite::Statement query2(db, "SELECT name FROM RANDOM WHERE todayDate = ?");query2.bind(1, UnicodeToUtf8(date));while (query2.executeStep()){wstring data;UTF8ToUniocde(query2.getColumn(0).getString().c_str(), data);total += data + L";";}if (!total.empty()){MessageBox(hWnd, total.c_str(), L"上期中奖名单", MB_OK);}else{MessageBox(hWnd, L"暂无数据", L"Tip", MB_OK | MB_ICONINFORMATION);}}catch (const exception& e){MessageBoxA(NULL, e.what(), "GetData failed!", MB_OK | MB_ICONERROR);return FALSE;}

效果图:


http://www.ppmy.cn/embedded/139655.html

相关文章

ElasticSearch7.x入门教程之索引概念和基础操作(三)

文章目录 前言一、索引基本概念二、索引基本使用elasticsearch-head插件Kibana使用 总结 前言 要想熟悉使用ES的索引&#xff0c;则必须理解索引相关的概念&#xff0c;尤其是在工作当中。 在此记录&#xff0c;方便开展工作。 一、索引基本概念 尽量以通俗的话语。 1、集群…

hive3.1.2编译spark3安装包

此安装包是《去破解站长》在公司真实生产环境所使用的安装包。 引言&#xff1a;Hive引擎包括&#xff1a;默认MR、tez、sparkDownload:www.qupojie.com 1、Hive on Spark 1、Hive onSpark&#xff1a;Hive既作为存储元数据又负责SQL的解析优化&#xff0c;语法是HQL语法&…

react学习篇--创建项目

前言 随着技术的更新迭代&#xff0c;需要学习了解更多的前端框架&#xff0c;下面就开始逐渐分析react的学习之旅。 一、react是什么&#xff1f; React是用于构建用户界面的JavaScript库。 二、使用步骤 1.确认是否已下载node node -v2.全局安装create-react-app npm …

QA RockyLinux8.8、双网卡、ping 8.8.8.8失败。

关键字&#xff1a; 仅主机网络、NAT网络、路由优先级、nmcli 环境&#xff1a; RockyLinux8.8最小版本安装&#xff0c;网卡配置如下所示&#xff1a; ens160: 连仅主机(用于本地SSH登陆) 10.0.0.0/24 ens224: 连NAT(有于上外网)、10.0.2.0/24&#xff08;网关:10.0.2.2)…

translation1

农历&#xff08;the lunar calendar&#xff09;起源于数千年前的中国&#xff0c;根据太阳和月亮的运行规律制定。长期以来&#xff0c;农历在农业生产和人们日常生活中发挥着重要作用。古人依据农历记录日期、安排农活&#xff0c;以便最有效地利用自然资源和气候条件&#…

AI社媒引流工具:解锁智能化营销的新未来

在数字化浪潮的推动下&#xff0c;社交媒体成为品牌营销的主战场。然而&#xff0c;面对海量的用户数据和日益复杂的运营需求&#xff0c;传统营销方法显得力不从心。AI社媒引流王应运而生&#xff0c;帮助企业在多平台中精准触达目标用户&#xff0c;提升营销效率和效果。 1.…

项目实战(webshop)

一、搭建靶场webshop(www.example1.com) 二、信息收集 1、获取IP winR→cmd→ping www.example1.com→显示出ip(192.168.51.128) 注&#xff1a;TTL为IP包的生存时间&#xff0c;拿到TTL我们可以大概的判断一下目标机器的操作系统&#xff0c;但不是很准确&#xff0c;因为…

FastAdmin接口传参获取获取不同语言的相应。

1.在application\config.php 里开启多语言 // 是否开启多语言lang_switch_on > true,// 默认全局过滤方法 用逗号分隔多个default_filter > ,// 默认语言default_lang > zh-cn,// 允许的语言列表allow_lang_list > [zh-cn, en], …