VC++对Access数据库的操作(查询、插入、更新、删除等)
最后更新于:2022-04-01 20:35:19
Microsoft Office Access是由微软发布的关系数据库管理系统。Access数据库常应用于小型软件系统中,比如:生产管理、销售管理、库存管理等各类企业管理软件,其最大的优点是:简单易学、使用灵活。
下面我们结合实例来详细说明,在VC++ MFC中,如何使用Access数据库文件进行数据的存储,如何实现对数据库中数据的查询、插入、更新和删除等操作。
(实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8235865](http://download.csdn.net/detail/margin1988/8235865))
首先,怎样创建一个可供VC++ MFC程序使用的Access数据库,并在该数据库中创建数据表呢?
> 第一步:打开Microsoft Office Access软件,点击“空白数据库”;
> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a93f518.jpg)
> 第二步:设置预创建空白数据库的文件名和文件类型(文件名:point32.mdb,文件类型:Microsoft Office Access 2000 数据库(*.mdb));
> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a99eb5e.jpg)
> 第三步:“创建”空白数据库;
> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4aa00f6b.jpg)
> 第四步:为该数据库“设置数据库密码”(本例中密码设置为:1234);
> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4aa66061.jpg)
> 第五步:在该数据库中创建一张表,例如:TestTab(编号,姓名,性别,年龄);
> ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4aad97bb.jpg)
> 第六步:表创建完成后,保存并关闭数据库,然后将该数据库文件(point32.mdb)剪切到你的VC++程序debug或release目录中,则准备工作完成。
其次,在VC++ MFC中编写对该数据库中TestTab表进行数据查询、插入、更新、删除等操作的方法:
(1)导入才用ado方式访问Access数据库所需的DLL
~~~
#import "C:\Program Files\Common Files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")//ado访问ACCESS数据库必需
~~~
(2)在程序的入口函数中,初始化OLE以支持应用程序
~~~
AfxOleInit();
~~~
(3)获取应用程序(EXE)所在路径
~~~
CString path;//应用程序所在路径
char filepath[256];
char* pPath;
GetModuleFileName(AfxGetInstanceHandle(),filepath,256);
pPath = strrchr(filepath,'\\');
*pPath = 0;
path = filepath;
~~~
(4)**创建**数据库访问连接字符串
~~~
char* PtConnectStr;//数据库连接字符串
CString connstr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=";
connstr += path;
connstr += "\\point32.mdb";
connstr += ";Jet OLEDB:Database Password='1234'";
PtConnectStr = connstr.GetBuffer(0);
~~~
(5)**查询**TestTab表中数据方法实现
~~~
//查询表中数据,并显示在List Control控件中
void CPoint32Dlg::ReadUserInfo()
{
//select
m_list.DeleteAllItems();//清空列表
_ConnectionPtr m_pConnection;
_RecordsetPtr m_pRecordset;
try
{
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->Open(PtConnectStr,"","",adModeUnknown);
}
catch(_com_error e)
{
CString errormessage;
errormessage.Format("数据库连接失败.\r错误信息:%s",e.ErrorMessage());
//AfxMessageBox(errormessage);
MessageBox(errormessage,"连接失败",MB_ICONEXCLAMATION);
if(m_pConnection->State)
m_pConnection->Close();
return;
}
try
{
//获取数据,放在数据集中
CString cmd;
cmd.Format("SELECT * FROM TestTab");
m_pRecordset.CreateInstance("ADODB.Recordset");
m_pRecordset->Open(cmd.GetBuffer(),
_variant_t((IDispatch*)m_pConnection,true),
adOpenStatic,
adLockOptimistic,
adCmdText);
//处理数据,并显示
_variant_t varbuffer;
long index = 0;//注意:必须是long类型
int countItem = 0;
CString str;
while(!m_pRecordset->adoEOF)
{
index = 0;
//读ID号
varbuffer = m_pRecordset->GetCollect(_variant_t(index));
if(varbuffer.vt!=VT_NULL)
{
str.Format("%d",varbuffer.lVal);
m_list.InsertItem(countItem,str.GetBuffer());
}
//读其它的信息
while(index < 3)
{
index++;
varbuffer = m_pRecordset->GetCollect(_variant_t(index));
if(varbuffer.vt!=VT_NULL)
{
str = (LPCTSTR)(_bstr_t)varbuffer;
m_list.SetItemText(countItem,index,str.GetBuffer());
}
}
m_pRecordset->MoveNext();
countItem++;
}
}
catch(_com_error &e)
{
//AfxMessageBox(e.Description());
MessageBox(e.Description(),"数据库操作失败.",MB_ICONEXCLAMATION);
if(m_pRecordset->State)
m_pRecordset->Close();
if(m_pConnection->State)
m_pConnection->Close();
return;
}
if(m_pRecordset->State)
m_pRecordset->Close();
if(m_pConnection->State)
m_pConnection->Close();
}
~~~
(6)向TestTab表中**插入**数据方法实现
~~~
//向表中插入数据,并更新List Control控件中显示的数据
void CPoint32Dlg::OnBnClickedButton1()
{
//insert
_ConnectionPtr m_pConnection;
_variant_t RecordsAffected;
try
{
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->Open(PtConnectStr,"","",adModeUnknown);
}
catch(_com_error e)
{
CString errormessage;
errormessage.Format("数据库连接失败.\r错误信息:%s",e.ErrorMessage());
MessageBox(errormessage," 添加失败 ",MB_ICONEXCLAMATION);
return;
}
try
{
CString strCmd="INSERT INTO TestTab(UName,UGender,UAge) VALUES('测试者','男','30')";
for(int i=0;i<5;i++)
{
m_pConnection->Execute(strCmd.AllocSysString(),&RecordsAffected,adCmdText);
}
}
catch(_com_error &e)
{
//AfxMessageBox(e.Description());
MessageBox(e.Description()," 添加失败 ",MB_ICONEXCLAMATION);
if(m_pConnection->State)
m_pConnection->Close();
return;
}
if(m_pConnection->State)
m_pConnection->Close();
//MessageBox("添加成功!","消息");
m_update.EnableWindow(TRUE);
m_delete.EnableWindow(TRUE);
ReadUserInfo();
}
~~~
(7)**更新**TestTab表中数据方法实现
~~~
//更新表中数据,并更新List Control控件的显示
void CPoint32Dlg::OnBnClickedButton3()
{
// update
_ConnectionPtr m_pConnection;
_variant_t RecordsAffected;
try
{
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->Open(PtConnectStr,"","",adModeUnknown);
}
catch(_com_error e)
{
CString errormessage;
errormessage.Format("数据库连接失败.\r错误信息:%s",e.ErrorMessage());
MessageBox(errormessage," 修改失败 ",MB_ICONEXCLAMATION);
return;
}
try
{
CString strCmd="UPDATE TestTab SET [UGender]='女',[UAge]='20' WHERE [UName]='测试者'";
m_pConnection->Execute(strCmd.AllocSysString(),&RecordsAffected,adCmdText);
}
catch(_com_error &e)
{
//AfxMessageBox(e.Description());
MessageBox(e.Description()," 修改失败 ",MB_ICONEXCLAMATION);
if(m_pConnection->State)
m_pConnection->Close();
return;
}
if(m_pConnection->State)
m_pConnection->Close();
//MessageBox("修改成功!","消息");
ReadUserInfo();
}
~~~
(8)**删除**TestTab表中数据及重置表中自动编号主键(key)方法现实
~~~
//删除表中数据、重置自动编号(从1开始),并更新List Control控件显示
void CPoint32Dlg::OnBnClickedButton4()
{
// delete
_ConnectionPtr m_pConnection;
_variant_t RecordsAffected;
try
{
m_pConnection.CreateInstance(__uuidof(Connection));
m_pConnection->Open(PtConnectStr,"","",adModeUnknown);
}
catch(_com_error e)
{
CString errormessage;
errormessage.Format("连接数据库失败!\r错误信息:%s",e.ErrorMessage());
MessageBox(errormessage,"删除失败",MB_ICONEXCLAMATION);
return;
}
try
{
//删除表中所有数据
CString strCmd="DELETE FROM TestTab";
m_pConnection->Execute(strCmd.AllocSysString(),&RecordsAffected,adCmdText);
//重置表中自动编号ID,使其从1开始增加(必须先删除表中所有数据)
strCmd="ALTER TABLE TestTab ALTER COLUMN ID COUNTER(1,1)";
m_pConnection->Execute(strCmd.AllocSysString(),&RecordsAffected,adCmdText);
}
catch(_com_error &e)
{
//AfxMessageBox(e.Description());
MessageBox(e.Description(),"删除失败",MB_ICONEXCLAMATION);
if(m_pConnection->State)
m_pConnection->Close();
return;
}
if(m_pConnection->State)
m_pConnection->Close();
//MessageBox("删除成功!","完成");
m_insert.EnableWindow(TRUE);
m_update.EnableWindow(FALSE);
m_delete.EnableWindow(FALSE);
ReadUserInfo();
}
~~~
';
VC++图片控件(Picture Control)显示资源位图(BMP)、文件位图(BMP)、其它格式文件图片(JPG\PNG\BMP)的方法
最后更新于:2022-04-01 20:35:16
在VC++ MFC编程中,我们常使用Picture Control图片控件来显示图像。下面简单归纳几种显示不同的方式:
(实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8341525](http://download.csdn.net/detail/margin1988/8341525))
**第一种、资源位图方式显示BMP图片**
如果要显示的是一张BMP位图,则可以采用资源位图方式,具体步骤如下:
(1)将BMP文件拷贝到工程的res目录下;
(2)在对话框中添加一个Picture Control控件,例如:ID为IDC_STATIC1,Type设为Bitmap;
(3)在工程的资源视图下,右键“添加资源”,现在资源类型Bitmap,然后“导入”(1)中的文件,例如:导入后资源的ID为IDB_BITMAP1;
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a8ad1bc.jpg)
(4)为IDC_STATIC1 Picture Control控件添加Control类型变量,例如:CStatic m_resbmp;
(5)在此控件上显示来自资源中的BMP位图IDB_BITMAP1,代码如下:
~~~
HBITMAP hBitmap;
// 显示资源中的图像(仅限位图BMP)
hBitmap =(HBITMAP)LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP,0,0,
LR_LOADMAP3DCOLORS);
m_resbmp.SetBitmap(hBitmap);
~~~
**第二种、文件位图方式显示BMP图片**
如果要显示的是一张BMP位图,也可以采用文件位图的方式,具体步骤如下:
(1)将BMP文件拷贝到工程的可执行文件目录下(如:Debug目录,beixin.bmp文件);
(2)在程序中获取可执行文件目录的全路径,代码如下:
~~~
CString exepath;//exe路径
char filepath[256];
char *pPath;
GetModuleFileName(AfxGetInstanceHandle(),filepath,256);
pPath = strrchr(filepath,'\\');
*pPath = 0;
exepath = filepath;
~~~
(3)在对话框中添加一个Picture Control控件,例如:ID为IDC_STATIC2,Type设为Bitmap;
(4)为IDC_STATIC2 Picture Control控件添加Control类型变量,例如:CStatic m_filebmp;
(5)在此控件上显示来自文件的BMP位图beixin.bmp,代码如下:
~~~
// 显示文件中的图像(仅限位图BMP)
HBITMAP hBitmap;
CString filebmppath;
filebmppath.Format("%s\\beixin.bmp",exepath);//位图文件全路径
hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),_T(filebmppath),IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
m_filebmp.SetBitmap(hBitmap);
~~~
**第三种、文件图片方式显示JPG\PNG\BMP等图片**
如果要显示的是一种JPG图片、PNG图片或者BMP图片(亦可)等其他格式的静态图片,则可使用文件图片的方式,步骤如下:
(1)将图片文件拷贝到工程的可执行文件目录下(如:Debug目录,shoutao.jpg\shoutao.png\shoutao.bmp文件);
(2)在程序中获取可执行文件目录的全路径,同上(第二种(2));
(3)在对话框中添加一个Picture Control控件,例如:ID为IDC_STATIC3,Type设为Frame;
(4)为IDC_STATIC3 Picture Control控件添加Control类型变量,例如:CStatic m_fileimg;
(5)在此控件上显示来自文件的JPG\PNG\BMP图片shoutao.jpg\shoutao.png\shoutao.bmp,代码如下:
~~~
//.h文件中
CFileFind finder;
void showimg(char* imgpath);//显示不同格式图片的函数
//.cpp文件中
void CPoint34Dlg::showimg(char* imgpath)
{
// 显示文件中的图像(不限图像格式)
if (finder.FindFile(imgpath))
{
CRect rect;
m_fileimg.GetClientRect(&rect);
CImage img;
img.Load(imgpath);
CDC* pDC = m_fileimg.GetWindowDC();
img.Draw(pDC->GetSafeHdc(),rect);
ReleaseDC(pDC);
}
}
~~~
~~~
//.h文件中
CString fileimgpath;
//.cpp文件中,调用图片显示函数
srand((unsigned)time(NULL));
int rd = rand()%3;
switch (rd)
{
case 0:
fileimgpath.Format("%s\\shoutao.bmp",exepath);
break;
case 1:
fileimgpath.Format("%s\\shoutao.png",exepath);
break;
case 2:
fileimgpath.Format("%s\\shoutao.jpg",exepath);
break;
}
showimg(fileimgpath.GetBuffer());//调用
~~~
(6)这种在Picture Control控件中显示图片的方式,千万不要忘记在对话框的OnPaint()中添加窗口更新、重绘图像,否则,被对话框最小化或被遮挡后,图像不能正常显示,在OnPaint()中添加代码如下:
~~~
CDialog::OnPaint();
//对话框被最小化或被遮挡后,图像不能正常显示,需要更新、重绘窗口
UpdateWindow();
showimg(fileimgpath.GetBuffer());
~~~
效果图如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a8da4ac.jpg)
';
VC++对话框(CDialog)添加背景图片
最后更新于:2022-04-01 20:35:14
在对话框(CDialog)程序中,为了让程序看上去漂亮一些,我们可以为对话框添加一个好看的背景图片,要想完成这个目标,可以利用afx_msg BOOL**OnEraseBkgnd**(CDC* pDC) 这个函数。
下面结合实例说明(实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8337225](http://download.csdn.net/detail/margin1988/8337225)):
(1)找来一张合适的BMP格式的背景图片,将其放在工程的res目录下,然后在程序的资源视图中,将这张图片导入进来(假设导入后其ID为:IDB_BITMAP1)。
(2)在对话框的.h文件中添加函数声明:
~~~
afx_msg BOOL OnEraseBkgnd (CDC* pDC);
~~~
(3)在对话框的.cpp文件中添加其消息映射宏:
~~~
BEGIN_MESSAGE_MAP(CPoint22Dlg, CDialog)
ON_WM_ERASEBKGND()//消息映射宏
END_MESSAGE_MAP()
~~~
(4)在对话框的.cpp文件中实现该函数功能:
~~~
BOOL CPoint22Dlg::OnEraseBkgnd(CDC* pDC) //为对话框添加背景图片
{
CDialog::OnEraseBkgnd(pDC);
CBitmap m_bitmap;
m_bitmap.LoadBitmap (IDB_BITMAP1);
if (!m_bitmap.m_hObject)
return true;
CRect rect;
GetClientRect(&rect);
CDC dc;
dc.CreateCompatibleDC(pDC);
CBitmap* pOldBitmap = dc.SelectObject(&m_bitmap);
int bmw, bmh ;
BITMAP bmap;
m_bitmap.GetBitmap(&bmap);
bmw = bmap.bmWidth;
bmh = bmap.bmHeight;
int xo=0, yo=0;
/*函数从源矩形中复制一个位图到目标矩形,必要时按目前目标设备设置的模式进行图像的拉伸或压缩。*/
pDC->StretchBlt(xo, yo, rect.Width(),rect.Height(), &dc,0, 0,bmw,bmh, SRCCOPY);
dc.SelectObject(pOldBitmap);
return true;
}
~~~
';
VC++对话框(CDialog)的全屏显示及控件居中显示
最后更新于:2022-04-01 20:35:12
在编写一些软件时,我们会比较偏向于比较简洁、清新的用户界面,同时为了避免其它程序或者桌面等影响使用者的注意力等,我们通常习惯将软件界面全屏,布满整个显示屏幕,与此同时,我们也将对界面中的控件位置进行相应的调整,让它们按屏幕的大小和其在对话框中的相对位置,居中显示。
下面结合实例说明(完整实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8337049](http://download.csdn.net/detail/margin1988/8337049)):
在对话框的初始化函数OnInitDialog()中分三步作如下的操作:
(1)获取屏幕的分辨率
~~~
int nFullWidth=GetSystemMetrics(SM_CXSCREEN);
int nFullHeight=GetSystemMetrics(SM_CYSCREEN);
~~~
(2)控件居中显示
~~~
CRect c1,c2;
GetClientRect(c1); //获取窗口客户区的坐标
for (int i=IDC_BUTTON1;i<=IDC_BUTTON5;i++)
{
GetDlgItem(i)->GetWindowRect(c2); //获取窗口的边框矩形的尺寸
ScreenToClient(c2); //把屏幕上指定点的屏幕坐标转换成用户坐标
GetDlgItem(i)->SetWindowPos(NULL,(nFullWidth-c1.right)/2+c2.left, (nFullHeight-c1.bottom)/2+c2.top,0,0,SWP_NOZORDER|SWP_NOSIZE);
}
~~~
(3)对话框全屏显示(去掉了标题栏)
~~~
CRect m_FullScreenRect;
CRect WindowRect;
GetWindowRect(&WindowRect);
CRect ClientRect;
RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, CWnd::reposQuery, &ClientRect);
ClientToScreen(&ClientRect);
m_FullScreenRect.left=WindowRect.left-ClientRect.left;
m_FullScreenRect.top=WindowRect.top-ClientRect.top;
m_FullScreenRect.right=WindowRect.right-ClientRect.right+nFullWidth;
m_FullScreenRect.bottom=WindowRect.bottom-ClientRect.bottom+nFullHeight;
WINDOWPLACEMENT wndpl;
wndpl.length=sizeof(WINDOWPLACEMENT);
wndpl.flags=0;
wndpl.showCmd=SW_SHOWNORMAL;
wndpl.rcNormalPosition=m_FullScreenRect;
SetWindowPlacement(&wndpl);
~~~
';
VC++编写DLL导出函数及其调用方法
最后更新于:2022-04-01 20:35:10
DLL (Dynamic Link Library)动态链接库,是一个包含可由多个程序同时使用的代码和数据的库,DLL不是可执行文件,其优点主要有:1. 有助于节省内存;2. 有助于资源共享;3. 不需编译的软件系统升级;4. 支持多语言程序。当然,有的时候我们也可以将一些核心的或者不愿意公开提供的函数编写为DLL,从而起到隐藏和保护的作用。
下面结合实例详细说明在Visual Studio 2008 SP1 IDE中如何创建、编写和导出VC++ MFC DLL,以及如何调用生成的DLL。(完整实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8336697](http://download.csdn.net/detail/margin1988/8336697))
(1)打开Visual Studio 2008 SP1 IDE,创建VC++ MFC DLL工程,如图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a8542c7.jpg)
(2)在自动生成的“工程名.cpp”(如:FirstDLL.cpp)文件中,编写要导出的函数(注:在该项目属性中工程字符集选择了“使用多字节字符集”):
~~~
/**函数:int calculateLineNum(CString filePath)
功能:用于计算文本文件的行数
描述:只需要指定文本文件的路径,若找到,则返回其行数,若没找到,则返回0 */
extern "C" _declspec(dllexport) int calculateLineNum(CString filePath){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
CStdioFile file;
CString str;
int lineNum=0;
if (file.Open(_T(filePath),CFile::modeRead | CFile::typeText))
{
file.SeekToBegin();
while (file.ReadString(str))
{
lineNum++;
}
file.Close();
}
return lineNum;
}
~~~
(3)点击“生成解决方案”,生成了供程序调用的DLL文件和Lib文件(该例中只是导出了一个函数,不需要.h文件);
(4)生成DLL及其导出函数的调用方法:
1)将.dll和.lib文件拷贝到你的工程的目录下;
2)在程序中预定义和导入库和函数:
~~~
#pragma comment(lib, "FirstDLL.lib")
extern "C" _declspec(dllimport) int calculateLineNum(CString filePath);
~~~
3)或者,也可以在工程的属性中添加链接:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a880890.jpg)
然后,程序中就只需要这一句:
~~~
extern "C" _declspec(dllimport) int calculateLineNum(CString filePath);
~~~
4)调用DLL中的导出函数:
~~~
CString path="ReadMe.txt";
int num = calculateLineNum(path);
~~~
';
VC++中的计时器及多媒体高精度计时器
最后更新于:2022-04-01 20:35:07
Windows计时器是一个非常有用的编程元素,而且计时器的使用非常简单,我们只需要一个时间间隔参数来调用SetTimer函数设置和启动计时器,通过WM_TIMER消息的响应函数进行计时器控制,调用KillTimer函数停止计时器。
但是由于Windows是一个非实时操作系统,所以如果我们定义的时间间隔小于100ms的时候,计时器可能不会很准确。所以,对于有些时间要求比较高的情况,我们需要使用多媒体高精度计时器来完成计时,它的精度可以达到1ms。
下面结合实例详细讲述计时器和多媒体高精度计时器使用方法(完整实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/8328525](http://download.csdn.net/detail/margin1988/8328525))
⑴ 普通计时器的使用方法:
1> 在.h文件中添加计时器和消息响应函数:
~~~
int m_time;//计数器编号
afx_msg void OnTimer(UINT_PTR nIDEvent);
~~~
2> 在.cpp文件中添加WM_TIMER的消息响应宏:
~~~
int m_count=0;//计时全局计数变量
BEGIN_MESSAGE_MAP (CPoint21Dlg, CDialog)
ON_WM_TIMER() //WM_TIMER消息响应宏
END_MESSAGE_MAP ()
~~~
3> 启动计时器:
~~~
m_count = 0;
m_time = SetTimer(1,1000,NULL);
ASSERT (m_time != 0);
for (int i=0;i<10000;i++){
//uses up CPU cycles
}
if (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
~~~
4> 计数控制:
~~~
void CPoint21Dlg::OnTimer(UINT_PTR nIDEvent){
m_count++;
}
~~~
5> 停止计时器:
~~~
KillTimer (m_time);
~~~
(2) 多媒体高精度计时器的使用方法:
1> 包含相关头文件和库:
~~~
#include
#pragma comment(lib, "WINMM.LIB")
~~~
2> 设置并启用多媒体计时器:
~~~
int m_acc=0;//全局计数变量
static UINT m_nTimerID=0;//多媒体计数器编号
//自定义配置及启动多媒体计数器函数
void CPoint21Dlg::MultimediaTimer(){
TIMECAPS tc;
//获得定时器分辨率
if (timeGetDevCaps(&tc, sizeof(TIMECAPS)) != TIMERR_NOERROR){
return;
}
UINT nResolution = min(max(tc.wPeriodMin, 1), tc.wPeriodMax);
UINT nInterval = 1;
if (nInterval < nResolution){
nInterval = nResolution;
}
//设置定时最小分辨率
timeBeginPeriod(nResolution);
//设置定时器
m_nTimerID = timeSetEvent (4, nResolution,
CPoint21Dlg::CallBackFuncTimer,(DWORD)this, TIME_PERIODIC);
}
~~~
3> 计数控制:
~~~
void CALLBACK CPoint21Dlg::CallBackFuncTimer(UINT wTimerID,UINT msg,DWORD dwUser,DWORD dw1,DWORD dw2){
m_acc++;
}
~~~
4> 停止多媒体计时器:
~~~
timeKillEvent (m_nTimerID);
~~~
';
VC++中单个键盘按键的响应
最后更新于:2022-04-01 20:35:05
关于如何在VC++程序中自定义热键(或称组合键)及其响应,我在之前的博客中已经作了详细的介绍,那么当遇到的是单个键盘按键的响应时,我们又该怎么解决呢?这时,我们可以采用afx_msg BOOL PreTranslateMessage (MSG* pMsg) 这个函数很方便的实现。
但是在此之前,我们必须首先了解键盘按键对应的十进制ASCII码值,下面这张表是每个键盘按键对应的十进制ASCII码值表,会给我们带来很大的方便:
Esc | 27 | #3 | 51 | >. | 190 | M | 77 | ← | 37 |
F1 | 112 | $4 | 52 | ?/ | 191 | N | 78 | ↑ | 38 |
F2 | 113 | %5 | 53 | Ctrl | 17 | O | 79 | → | 39 |
F3 | 114 | ^6 | 54 | 左徽标 | 91 | P | 80 | ↓ | 40 |
F4 | 115 | &7 | 55 | 右徽标 | 92 | Q | 81 | Num Lock | 144 |
F5 | 116 | *8 | 56 | Alt | 18 | R | 82 | / | 111 |
F6 | 117 | (9 | 57 | Space | 32 | S | 83 | * | 106 |
F7 | 118 | _- | 189 | 鼠标右快捷键 | 93 | T | 84 | - | 109 |
F8 | 119 | += | 187 | A | 65 | U | 85 | + | 107 |
F9 | 120 | Backspace | 8 | B | 66 | V | 86 | . | 110 |
F10 | 121 | Tab | 9 | C | 67 | W | 87 | 0 | 96 |
F11 | 122 | {[ | 219 | D | 68 | X | 88 | 1 | 97 |
F12 | 123 | }] | 221 | E | 69 | Y | 89 | 2 | 98 |
PrScrn SysRq | 44 | |\ | 220 | F | 70 | Z | 90 | 3 | 99 |
Scroll Lock | 145 | Caps Lock | 20 | G | 71 | Insert | 45 | 4 | 100 |
Pause Break | 19 | :; | 186 | H | 72 | Home | 36 | 5 | 101 |
~` | 192 | “’ | 222 | I | 73 | PgUp | 33 | 6 | 102 |
)0 | 48 | Enter | 13 | J | 74 | Delete | 46 | 7 | 103 |
!1 | 49 | Shift | 16 | K | 75 | End | 35 | 8 | 104 |
@2 | 50 | <, | 188 | L | 76 | PgDn | 34 | 9 | 105 |
注:表中的阴影部分为键盘上的数字小键盘分区。
下面结合实例来详细说明(完整实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/6648153](http://download.csdn.net/detail/margin1988/6648153)):
(1)在对话框.h文件中添加函数声明:
~~~
afx_msg BOOL PreTranslateMessage(MSG* pMsg);
~~~
(2)在对话框的.cpp文件中实现该函数功能:
~~~
BOOL CPoint23Dlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN)
{
switch (pMsg->wParam)
{
case 65:
MessageBox("您按了“A键”");
break;
//其它按键响应
}
return true;//不再响应其它按键(很重要)
}
return CDialog::PreTranslateMessage(pMsg);
}
~~~
';
串口通信基础知识及VC++实现
最后更新于:2022-04-01 20:35:03
串口是计算机上一种非常通用设备通信的协议。大多数计算机包含两个基于RS232的串口。串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是由于串口通信是异步的,串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。串口通信最重要的参数是[波特](http://baike.baidu.com/view/543280.htm)率、数据位、停止位和奇偶校验。
而在VC++中实现串口通信也是一名VC程序员必须要掌握的技能。下面结合实例详细介绍在VC++中实现串口通信的过程(完整的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/6408513](http://download.csdn.net/detail/margin1988/6408513))。
在这个实例中,实现了系统中可用串口的自动检测(通过注册表信息)、打开、发送、接收、关闭等基本的操作,若将串口线的TX(发送)和RX(接收)引脚连起来,便采用了“一根线发送数据的同时用另一根线接收数据”的方式测试了发送和接收功能的可用性和正确性。该实例对于初学者学习和掌握基于VC的串口通信将会有非常大的帮助。
(1)实例中所要用的主要控件及其属性、事件设置情况:
控件 | ID | caption | 绑定变量 | 绑定事件 |
组合框 | IDC_COMBO1 | - | CComboBox m_com; | - |
按钮 | IDC_BUTTON1 | 打开 | CButton m_open; | OnBnClickedButton1() |
按钮 | IDC_BUTTON2 | 发送 | CButton m_send; | OnBnClickedButton2() |
按钮 | IDC_BUTTON3 | 关闭 | CButton m_close; | OnBnClickedButton3() |
编辑框 | IDC_EDIT1 | 发送输入 | CString m_sendstr; | - |
编辑框 | IDC_EDIT2 | 接收显示 | CString m_receivestr; | - |
MSComm | IDC_MSCOMM1 | - | CMSComm m_ctrlComm; | OnComm() |
(2)需要的硬件条件及情况说明:
需要一根串口线,一端接在PC的某个串口上,另一端的TX引脚和RX引脚用铜线连接起来,这样便形成了一个回路,数据发送通过TX引脚出去后,又从RX引脚进来,程序中便可以得到接收到的数据了,接收到的数据应该和发送的数据一致,说明串口的发送、接收操作成功了。
(3)COM组件(MSComm控件)消息响应宏定义的**重要注意点**:
~~~
BEGIN_EVENTSINK_MAP (CPoint20Dlg, CDialog)
ON_EVENT (CPoint20Dlg, IDC_MSCOMM1, 1, OnComm, VTS_NONE)
END_EVENTSINK_MAP ()
~~~
(4)从注册表中检测系统中可用串口并添加到界面组合框中:
~~~
HKEY hKey;
int rtn;
rtn = RegOpenKeyEx( HKEY_LOCAL_MACHINE, "Hardware\\DeviceMap\\SerialComm", NULL, KEY_READ, &hKey);
if( rtn == ERROR_SUCCESS) // 打开串口注册表
{
int i=0;
char portName[256], commName[256];
DWORD dwLong,dwSize;
while (1)
{
dwSize = sizeof(portName);
dwLong = dwSize;
rtn = RegEnumValue ( hKey, i, portName, &dwLong, NULL, NULL, (PUCHAR)commName, &dwSize ); // 枚举串口
if( rtn == ERROR_NO_MORE_ITEMS )
break; // commName就是串口名字
m_com.AddString(commName);// 将可用串口添加到界面组合框
i++;
}
RegCloseKey(hKey);
}
m_com.SetCurSel(0);
~~~
(5)打开并设置串口参数:
~~~
if (!m_ctrlComm.GetPortOpen())
{
char commName[256];//串口名
m_com.GetWindowText (commName, 256);
m_ctrlComm.SetCommPort(_ttoi(&commName[3]));//从串口名中得到串口号
m_ctrlComm.SetInputMode (1);
m_ctrlComm.SetSettings ("9600, n, 8, 1");
m_ctrlComm.SetPortOpen (TRUE);
m_ctrlComm.SetRThreshold (1);
m_ctrlComm.SetInputLen (0);
m_ctrlComm.GetInput ();
MessageBox(" 串口已打开 ");
}
else
MessageBox("没有发现此串口或被占用");
~~~
(6)发送数据:
~~~
if (m_ctrlComm.GetPortOpen())
{
UpdateData();
CByteArray sendArr;//欲发送的数据,需从CString转化为CByteArray型
WORD wLen;
wLen=m_sendstr.GetLength();
sendArr.SetSize(wLen);
for (int i=0;i
';
VC++中Ribbon编程架构及SDI架构多视图切换介绍
最后更新于:2022-04-01 20:35:01
在MS Visual Studio 2008 MFC中Ribbon界面风格出现了,这种界面风格给人带来耳目一新的感觉。Ribbon界面风格出现,可以说改革了传统的菜单式界面风格,常见的应用就是MS Office 2007中的Word、Excel、PowerPoint等组件中,Ribbon不仅使得功能有组织的存放,而且可以更加方便快捷地找到各个功能。但是MS Visual Studio 2008 MFC中还未加入Ribbon编程的相关组件,这意味着不会是那种想要什么控件就托到相应的位置就可以了,而是要完全通过代码来生成和控制相关的组件。值得然人欣喜的是,在MS Visual Studio 2010 MFC中,Ribbon编程相关的组件已经被添加了进来,这样一来Ribbon编程就变得容易了起来,可以达到“所见即所得”的效果了。
下面结合MS Visual Studio 2008 MFC中Ribbon编程的一个实例,详细讲述Ribbon编程的具体步骤和注意事项,同时还将提出一种SDI(单文档界面)架构程序中进行多个视图切换的方法。(完整的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/6408275](http://download.csdn.net/detail/margin1988/6408275)):
⑴ MS Visual Studio 2008 MFC中创建SDIRibbon应用程序的步骤:
1)“新建”一个Visual C++ MFC应用程序项目:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a4c3c0b.jpg)
2)“确定”后进入MFC应用程序向导,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a4db700.jpg)
3)进入到应用程序类型界面,选择“单文档”、“Office”、“Office 2007(黑色主题)”,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a51f63a.jpg)
4)进入复合文档支持,选择“无”,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a55a9d0.jpg)
5)进入文档模板字符串,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a58eea3.jpg)
6)进入数据库支持,选择“无”,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a5c2bd7.jpg)
7)进入用户界面功能,按下图所示选择后,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a606aed.jpg)
8)进入高级功能,勾去所有的高级功能,如下图,单击“下一步”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a63c47b.jpg)
9)进入生成的类,选择基类“CFormView”,单击“完成”:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a6955df.jpg)
10)完成后,直接编译运行程序,得到的界面如下入:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a6d2bcd.jpg)
(2)Ribbon界面风格的主要构成分析:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a71c423.jpg)
Ribbon应用程序的主体框架构成从大到小包含如上图中所示的三大块:分类(CMFCRibbonCategory)、面板(CMFCRibbonPanel)、元素(包括:CMFCRibbonButton、CMFCRibbonEdit等)。
(3)如何创建属于自己的Ribbon界面表现形式:
1)使用绘图、PS等工具绘制自己的按钮图标(PNG),并放在工程的res目录下,然后将其导入工程资源:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a79a9e6.jpg)
![](image/d41d8cd98f00b204e9800998ecf8427e.jpg)
2)在MainFrm.cpp文件的InitializeRibbon()函数中,仿照默认生成的代码编写自己的Ribbon界面表现形式,删除自动生成的你不需要的代码:
A.添加资源符号:
在String Table中添加分类和面板资源符号:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a7b7fe9.jpg)
![](image/d41d8cd98f00b204e9800998ecf8427e.jpg)
在Accelerator中添加元素资源快捷键:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a7cc021.jpg)
B.依次创建“分类->面板->元素”:
~~~
//创建“分类”-模块1
bNameValid = strTemp.LoadString(IDS_RIBBON_MODULAR1);
ASSERT(bNameValid);
CMFCRibbonCategory* pCategoryHomeMod1 = m_wndRibbonBar.AddCategory(strTemp,IDB_PNG3,IDB_PNG2,CSize(28,25),CSize(56,50));
//创建“面板”-用户管理和“元素”-按钮
bNameValid = strTemp.LoadString(IDS_RIBBON_USERMANAGER);
ASSERT(bNameValid);
CMFCRibbonPanel* pPanelUserManager = pCategoryHomeMod1->AddPanel(strTemp, m_PanelImages.ExtractIcon(7));//有个子图标(索引~)
CMFCRibbonButton* pBtnUserManager = new CMFCRibbonButton(ID_EDIT_USERMANAGER,_T(""), 0,0);//加载的第一个(索引)
pPanelUserManager->Add(pBtnUserManager);
~~~
3)添加相应消息响应函数,使面板元素激活可用:
~~~
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWndEx)
ON_COMMAND(ID_EDIT_USERMANAGER, OnUserManagerCommand)
ON_COMMAND(ID_EDIT_PARAMCONFIG, OnParamConfigCommand)
//消息响应宏
END_MESSAGE_MAP()
~~~
4)最终自定义的Ribbon界面表现形式如下图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a7e864b.jpg)
(4)SDI(单文档界面)架构想要实现多个视图之间的切换,需要定义一个切换视图的函数——void SwitchToForm(int nForm);该函数的实现体如下:
★声明全局变量**frmID:**
在stdafx.h中添加声明:extern int frmID;
在stdafx.cpp中添加定义:int frmID;
在C工程名.cpp中的InitInstance()中初始化:frmID = 0;
~~~
void CMainFrame::SwitchToForm(int nForm) {//进行视图切换的代码函数
if (nForm!=frmID)
{
frmID=nForm;//避免多次点击同一按钮时出现的错误,一按钮点击一次后,第二次点击不做任何处理。
CDocument* pDoc = GetActiveDocument();
CView *pOldActiveView=GetActiveView();//保存旧视图
CView *pNewActiveView=(CView*)GetDlgItem(nForm);//取得新视图
if(pNewActiveView==NULL)
{
switch(nForm){
case IDD_USERMANAGER_FORM ://视图资源符号
pNewActiveView=(CView*)new CPoint19View;
break;
case IDD_PARAMCONFIG_FORM ://视图资源符号
pNewActiveView=(CView*)new CParamConfig;
break;
}
CCreateContext context; //将文挡和视图相连
context.m_pCurrentDoc=pOldActiveView->GetDocument();
pNewActiveView->Create(NULL, NULL, WS_BORDER|WS_CHILD, CFrameWnd::rectDefault, this, nForm, &context);
pNewActiveView->OnInitialUpdate();
}
SetActiveView(pNewActiveView); //改变活动的视图
pNewActiveView->ShowWindow(SW_SHOW); //显示新的视图
pOldActiveView->ShowWindow(SW_HIDE); //隐藏旧的视图
if(pOldActiveView->GetRuntimeClass() ==RUNTIME_CLASS(CPoint19View))
pOldActiveView->SetDlgCtrlID(IDD_USERMANAGER_FORM);
else if(pOldActiveView->GetRuntimeClass() ==RUNTIME_CLASS(CParamConfig))
pOldActiveView->SetDlgCtrlID(IDD_PARAMCONFIG_FORM);
pNewActiveView->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
delete pOldActiveView; //删除旧视图
RecalcLayout();//调整框架窗口
}
}
~~~
调用方式如下:
~~~
void CMainFrame::OnUserManagerCommand(){
SwitchToForm(IDD_USERMANAGER_FORM);
}
void CMainFrame::OnParamConfigCommand(){
SwitchToForm(IDD_PARAMCONFIG_FORM);
}
~~~
';
VC++中窗口过程函数及其消息发送、响应机制介绍
最后更新于:2022-04-01 20:34:58
在VC++中,窗口过程函数是应用程序定义的一个函数,主要功能是处理发送给窗口的消息。窗口过程函数的定义是:virtual LRESULT WindowProc( UINT message, WPARAM wParam,LPARAM lParam ); 其中,message指定消息类型,wParam和lParam指定其余的消息特定信息,内容与message参数值有关。
在应用程序中窗口过程函数及其消息发送、响应机制的使用,能够方便程序集中处理各类消息,使得整个程序的架构更加合理、清晰。
下面结合实例详细讲述窗口过程函数及其消息发送、响应机制的使用方法。(完整的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4570359](http://download.csdn.net/detail/margin1988/4570359))
(1)自定义消息:
在Resource.h文件中自定义消息:
~~~
#define WM_MYMSG 2000
~~~
(2)添加窗口过程函数的声明和实现体:
1)在.h文件中添加窗口过程函数声明:
~~~
virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
~~~
2)在.cpp文件中添加窗口过程函数实现体:
~~~
LRESULT CPoint18Dlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
case WM_MYMSG:
MessageBox("WindowProc收到并处理了自定义的WM_MYMSG消息");
break;
}
return CDialog::WindowProc(message,wParam,lParam);
}
~~~
(3)发送消息的方式比较:
~~~
this->SendMessage(WM_MYMSG,0,0);
//this->PostMessage(WM_MYMSG,0,0);
//this->SendNotifyMessage(WM_MYMSG,0,0);
~~~
注:这三个函数都可以将指定的消息发送到某个窗口,但是这三种消息的发送方式存在如下的区别:**SendMessage**立即调用窗口过程函数,而且直到窗口过程函数处理完消息后才返回。**PostMessage**则是将指定的消息寄送到窗口消息队列后立即返回。对于**SendNotifyMessage**来说**,**如果窗口是调用线程创建的,**SendNotifyMessage**为该窗口调用窗口过程函数,并且等待窗口过程函数处理完消息后才返回;如果窗口是由不同的线程创建的,**SendNotifyMessage**将指定的消息传给窗口过程函数后立即返回。
';
VC++中List Control控件的使用方法介绍
最后更新于:2022-04-01 20:34:56
List Control控件是使用频率比较高的一个控件,用它可以很好的做为数据报表的工具,而且比较方便操作和响应,经常可以和数据库相互配合,它就像数据库中的一张表一样,来显示数据库中的数据。
下面结合实例从List Control的样式及列名设置、数据设置和双击响应操作等几个方面,详细介绍List Control控件的使用方法。(完整的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4570315](http://download.csdn.net/detail/margin1988/4570315))
首先,在界面中新加一个List Control控件,在其“属性”中的“View”选项中选择“Report”。其次,给该控件添加控件变量:**CListCtrl m_listctrl; **。最后,给该控件添加双击事件响应“NM_DBLCLK”。
(1)样式及列名设置
~~~
//list control控件显示样式设置
DWORD dwStyle = m_listctrl.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT; //使整行高亮
dwStyle |= LVS_EX_GRIDLINES;//网格线
m_listctrl.SetExtendedStyle(dwStyle);
m_listctrl.InsertColumn(0,"ID号",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(1,"姓名",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(2,"性别",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(3,"年龄",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(4,"联系地址",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(5,"联系电话",LVCFMT_LEFT,100);
m_listctrl.InsertColumn(6,"Email",LVCFMT_LEFT,100);
~~~
(2)数据设置
~~~
//list control控件数据设置
CString str;
for (int i=0;i<5;i++)
{
str.Format("%d",i);
m_listctrl.InsertItem(i,str.GetBuffer());
for (int j=1;j<7;j++)
{
m_listctrl.SetItemText(i,j,"你好");
}
}
~~~
(3)双击响应操作
~~~
POSITION pos = m_listctrl.GetFirstSelectedItemPosition();
int index = m_listctrl.GetNextSelectedItem(pos);
CString str;
str.Format("您双击了第%d行!",index);
if(index>=0)
MessageBox(str);
~~~
';
VC++中结构体的定义及使用
最后更新于:2022-04-01 20:34:54
结构体(struct)是由一系列具有相同类型或不同类型的数据构成的数据集合,也叫结构。结构体最最主要的意义就是**封装**,而封装的好处就是可以再次利用。掌握了结构体的定义和使用方法,对编程具有非常重要的意义。结构体的使用能够封装一些属性来组成新的类型,能够使程序内部实现模块化,能够简化程序的结构和复杂度,能够方便我们对一组数据的成组操作。另外,结构体和前面讲述的vector的配合使用更是天衣无缝,非常方便和实用。
下面将结合实例详细讲述结构体的定义和使用方法,以及与vector的结合使用。(完整的实例可以在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4570184](http://download.csdn.net/detail/margin1988/4570184))
(1)结构体的定义和基本使用
1)定义方法
~~~
typedef struct my1
{
int a;
float b;
}MOD1;
~~~
2)使用方法
~~~
MOD1 mystruct;//或者:my1 mystruct;
mystruct.a = 10;
mystruct.b = 3.14f;
~~~
(2)结构体与vector的结合使用
~~~
#include
using namespace std;
vector vec;//或者:vector< my1 > vec;
vector::iterator vecIter;//或者:vector< my1 >::iterator vecIter;
for (int i=1;i<=10;i++)
{
mystruct.a = i;
mystruct.b = (float)(3.14*i);
vec.push_back(mystruct);
}
CString str;
vecIter = vec.begin();
while(vecIter != vec.end())
{
str.AppendFormat("a=%d,b=3.14*a=%0.2f\n",(*vecIter).a,(*vecIter).b);
vecIter++;
}
MessageBox(str);
vec.clear();
~~~
';
VC++中vector矢量的使用方法及随机相关
最后更新于:2022-04-01 20:34:52
简单地说,vector矢量是一个能够存放**任意类型的对象**的动态数组,能够增加和压缩数据。正因为它非常的灵活和好用,所以vector的使用非常的广泛。掌握了vector的使用方法,将为你的编程带来非常巨大的方便,而且能够比较容易地解决很多比较复杂的问题。
vector的操作主要包括:写入数据,读数据和清除数据。下面结合实例详细介绍vector的使用方法(完整的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4570147](http://download.csdn.net/detail/margin1988/4570147))。
~~~
#include
using namespace std;
~~~
⑴ vector的基本操作
1)定义vector和其迭代器
~~~
vector vec;
vector::iterator vecIter;
~~~
2)向vector写入数据
~~~
for (int i=1;i<=10;i++)
{
vec.push_back(i);
}
~~~
3)读取vector中的数据,有两种方式
A.通过索引的方式读取:
~~~
vecIter = vec.begin();
CString str1,str2;
for (int i=0;i<10;i++)
{
str1.AppendFormat("%d ",vecIter[i]);
}
MessageBox(str1);
~~~
B.通过迭代器来读取:
~~~
vecIter = vec.begin();
while(vecIter!=vec.end())
{
str2.AppendFormat("%d-",(*vecIter));
vecIter++;
}
MessageBox(str2);
~~~
4)清空vector中的数据
~~~
vec.clear();
~~~
(2)vector实现随机顺序打乱(将上面的vec进行随机)
~~~
vector vectemp;
vector::iterator vectempIter;
srand((unsigned)time(NULL));//根据时间因子来产生随机数随机
while(vec.begin()!=vec.end())
{
vectempIter = vec.begin();
vectempIter += rand()%(vec.size());
vectemp.push_back(*vectempIter);
vec.erase(vectempIter);//移除某个位置的数据
}
~~~
';
VC++中截取字符串的方法
最后更新于:2022-04-01 20:34:49
在VC++编程中,我们有时会遇到关于截取字符串的问题,对于CString类型字符串的截取VC++中有现成的函数可供使用,主要是:CString**Mid**(int*nFirst***,**int *nCount*);和BOOL **AfxExtractSubString**(CString&rString, LPCTSTR lpszFullString, int iSubString, TCHAR chSep = 10);这两个函数。
这两个函数非常好用,而且值得一说的是,其中的**AfxExtractSubString**函数并未公开,在MSDN中也差不到相关的说明,但是在MSDN的例子里却常常出现,非常好用。下面先解释一下这两个函数:
⑴ CString**Mid**(int*nFirst***,**int *nCount*);
函数功能:此函数从目标CString对象中提取一个长度为nCount个字符的子串并返回,从nFirst(从零开始的索引)指定的位置开始。
nFirst:开始位置(索引)。
nCount:提取长度。
⑵ BOOL**AfxExtractSubString**(CString&rString, LPCTSTR lpszFullString, int iSubString, TCHAR chSep = 10);
函数功能:此函数从目标字符串lpszFullString中,根据分割标志chSep,取出第iSubString个子串,放入结果串rString中。
下面将结合一个从目标字符串中以**空格**为分割标志截取所有关键词的实例,来详细说明(完整的实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/5415583](http://download.csdn.net/detail/margin1988/5415583)):
⑴ 目标字符串:
~~~
m_str = "说 谎 鼻子 会 变 长";
~~~
⑵ 利用**Mid**函数计算目标串中关键词的个数:
~~~
int tmplen=0; // 关键词个数
for (int i=0;i
';
VC++中一些常用的数据类型之间的相互转化
最后更新于:2022-04-01 20:34:47
在编程的过程中,往往会涉及到一些常见的数据类型之间的相互转化,到网上一查,大家真是众说风云,让人甚是眼花缭乱,找了半天也找不到自己想要的答案。下面结合实例详细说明几种数据类型之间的转换方法(**完整的实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4241292](http://download.csdn.net/detail/margin1988/4241292)**):
(1)CString -> int
~~~
CString intStr="100";
int a;
a = _ttoi(intStr);
~~~
(2)int -> CString
~~~
CString aStr;
aStr.Format("%d",a);
~~~
(3)CString -> double
~~~
CString doubleStr="3.1415926";
double b;
b = atof(doubleStr.GetBuffer(0));
~~~
(4)double -> CString
~~~
CString bStr;
bStr.Format("%0.4f",b);//保留小数点后4位
~~~
(5)CString -> LPCSTR
~~~
LPCSTR lpcStr;
CString cStr;
int c=1389;
cStr.Format("%d",c);
lpcStr = _T(cStr);
~~~
(6)LPCSTR -> CString
~~~
CString dStr;
dStr = lpcStr;
~~~
(7)char* -> CString
~~~
char* cha1="你好";
CString str1;
str1 = cha1;//str1.Format("%s",cha1);
~~~
(8)CString -> char*
~~~
CString str2;
char* cha2;
str2.Format("很好");
cha2 = str2.GetBuffer(0);
~~~
(9)char -> CString
~~~
char ch = 'a';
CString str3;
str3.Format("%c",ch);
~~~
(10)string -> const char*
~~~
string s = "你好";
const char* cha3;
cha3 = s.c_str();
~~~
(11)CString -> wchar_t
~~~
wchar_t wStr[256];
CString str0;
str0 = "姓名";
MultiByteToWideChar(CP_ACP, 0, str0, -1, wStr, 256);
~~~
(12) wchar_t -> CString
~~~
wchar_t wStr[256];
CString str0;
int size;
char *ch;
size=WideCharToMultiByte(CP_ACP,0,sheet->Cell(i,1)->GetWString(),-1,NULL,0,NULL,NULL);
ch=new char[size+1];
WideCharToMultiByte(CP_ACP,0,sheet->Cell(i,1)->GetWString(),-1,ch,size,NULL,NULL);
str0.Format("%s",ch);
size = 0;
delete[] ch;
~~~
';
VC++软件界面风格简单美化
最后更新于:2022-04-01 20:34:45
为了让软件能在视觉上给用户带来一种清新的感觉,从而避免潜在的用户视觉疲劳和审美疲劳,软件一般都要经过专业的界面设计和美化。但是,我们不是也没有专业的界面设计美化人员,所以只能对软件的界面和风格进行初步的简单美化,主要是色调的搭配、图片、字体的简单美化处理等基本工作。
下面结合实例,详细介绍一下之前的软件开发中所用到的两种软件界面风格简单美化的方法:
(1)采用OnCtlColor函数,对软件的界面进行简单的美化。(**完整的实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4241231](http://download.csdn.net/detail/margin1988/4241231)**)
采用这种方式,只能对软件界面在背景颜色、控件颜色、字体等方面做简单的美化。其主要的操作步骤如下:
1)在相应的.h文件中添加OnCtlColor函数:
~~~
afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
~~~
2)在相应的.cpp文件中添加消息映射宏:
~~~
BEGIN_MESSAGE_MAP(CPoint11Dlg, CDialog)
ON_WM_CTLCOLOR()//OnCtlColor函数的消息映射宏
END_MESSAGE_MAP()
~~~
3)在相应的.cpp文件中编写OnCtlColor函数的实现体:
~~~
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
switch (nCtlColor)
{
case CTLCOLOR_STATIC: //静态文本
{
pDC->SetBkMode(TRANSPARENT);
HBRUSH B = CreateSolidBrush(RGB(191,219,255)); //控件背景颜色
pDC->SetTextColor(RGB(0,0,0)); //控件中的文字的颜色
return (HBRUSH) B;
}
break;
case CTLCOLOR_DLG : //对话框背景
{
pDC->SetBkMode(TRANSPARENT);
HBRUSH B = CreateSolidBrush(RGB(191,219,255));
pDC->SetTextColor(RGB(0,0,0));
return (HBRUSH) B;
}
break;
default:
return hbr;
break;
}
~~~
※需要注意的一点是:当对话框背景颜色和静态文本的背景色设置一样时,软件界面中的静态文本产生的阴影将消失,使得界面更加整洁。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a48ceeb.jpg)
(2)使用SkinMagic插件,对软件的整体界面风格进行改变和美化。(**完整的实例程序可在我的CSDN资源中下载**)
使用这种方式,可以改变软件的整体风格,从而也改变了软件中所有细节的风格,可以达到比较好的整体美化效果。但是,使用这种方式也有它自己的缺点,那就是虽然SkinMagic插件是一个免费的插件,但是它所提供的界面风格是相当有限的,而且这其中的界面风格比较清新好看的更是少之又少。SkinMagic插件的使用步骤如下:
1)将SkinMagicLib.h,SkinMagicTrial.lib,SkinMagicTrial.dll三个文件copy到程序目录中。
2)将SkinMagicLib.h添加到工程的“头文件”中;在工程“属性”页的“配置属性-链接器-输入”的“附加依赖项”中输入SkinMagicTrial.lib。
3)在stdafx.h中添加:
~~~
#include "SkinMagicLib.h"
#pragma comment(lib,"SkinMagicTrial.lib")
~~~
4)在"工程名App.cpp"或者"工程名.cpp"中的InitInstance()函数中添加:
~~~
VERIFY(1==InitSkinMagicLib(AfxGetInstanceHandle(),_T("Demo"),NULL, NULL));
CString str;
str.Format("%ssmf\\corona.smf",g_BasePath);
VERIFY(1==LoadSkinFile(_T(str)));
SetDialogSkin(_T("Dialog"));
~~~
5)在项目的配置属性中改为使用“使用多字节字符集”字符集,否则编译时会出现函数名无法解析的错误。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a4a0799.jpg)
';
VC++按钮控件字体设置
最后更新于:2022-04-01 20:34:43
关于按钮控件上的字体的设置,需要注意的是CFont font;变量要作为类的成员变量进行声明,而不能作为局部变量进行申明,否则字体的设置将不会产生任何效果。此外,对于按钮控件字体的设置也有不同的方法,这里主要讲述两种比较常用的设置方式:利用CreatePointFont和利用CreateFont两种。
下面结合实例详细说明(**完整的实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4241142](http://download.csdn.net/detail/margin1988/4241142)**):
在Point9Dlg.h中添加成员变量:
~~~
public:
CButton m_btn;
CButton m_btn2;
CFont font1;
CFont font2;
~~~
(1)CreatePointFont方式:
~~~
font1.CreatePointFont(190,"隶书");
m_btn.SetFont(&font1);
~~~
(2)CreateFont方式:
~~~
font2.CreateFont( 25,0,0,0,FW_NORMAL,FALSE,FALSE,0,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH | FF_MODERN,_T("隶书") ) ;
m_btn2.SetFont(&font2);
~~~
';
VC++获取系统当前时间
最后更新于:2022-04-01 20:34:40
在程序中,有的时候需要知道和获得当前的系统日期和时间,想要获得它们其实是比较简单的,主要有两种方法:SYSTEMTIME方式或者CTime方式。但是值得注意的一点是:如果你的电脑的时区设置是GMT+08:00的话,那么通过SYSTEMTIME方式获得系统时间比正确的时间慢8小时,所以需要加上8小时。下面结合实例详细说明(**完整实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4241086](http://download.csdn.net/detail/margin1988/4241086)**):
(1)SYSTEMTIME方式:
~~~
SYSTEMTIME tt;
GetSystemTime(&tt);
CString date,time;
date.Format("%4d-%02d-%02d",tt.wYear,tt.wMonth,tt.wDay);
GetDlgItem(IDC_DATE)->SetWindowText(_T(date));
time.Format("%02d:%02d:%02d",tt.wHour+8,tt.wMinute,tt.wSecond);
GetDlgItem(IDC_TIME)->SetWindowText(_T(time));
~~~
(2)CTime方式:
~~~
CTime time2;
time2 = CTime::GetCurrentTime();
date.Format("%4d-%02d-%02d",time2.GetYear(),time2.GetMonth(),time2.GetDay());
GetDlgItem(IDC_DATE2)->SetWindowText(_T(date));
time.Format("%02d:%02d:%02d",time2.GetHour(),time2.GetMinute(),time2.GetSecond());
GetDlgItem(IDC_TIME2)->SetWindowText(_T(time));
~~~
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a46defd.jpg)
';
VC++中文件读、写和其他相关操作汇总
最后更新于:2022-04-01 20:34:38
在软件设计中,对文件系统的利用往往是必不可少的,它能帮助我们存储许多比较重要的数据,保存过程数据和备份数据,以备软件出现不可预知的偶然异常时,恢复测试数据和测试过程使用。
下面结合实例来讲述文件相关的一些操作(**完整的实例程序可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/4239839](http://download.csdn.net/detail/margin1988/4239839)**):
(1)创建目录(文件夹):
1)方法1:
~~~
CString strDir;
strDir.Format("%sdir1",g_BasePath);
::CreateDirectory(_T(strDir),NULL);
~~~
2)方法2:
~~~
#include
strDir.Format("%sdir2",g_BasePath);
_mkdir(strDir);
~~~
(2)创建及写文件(不追加模式、追加模式):
1)不追加模式:
~~~
CStdioFile file;
CString str;
str.Format("%sdir1\\data1.txt",g_BasePath);
if (!file.Open(_T(str),CFile::modeCreate | CFile::modeWrite | CFile::typeText))
{
MessageBox(_T("未打开文件"));
}
else
{
for (int i=1;i<11;i++)
{
str.Format("%d-%d\n",i,i*i);
file.WriteString(str);
}
file.Close();
}
~~~
2)追加模式:
~~~
CStdioFile file;
CString str;
str.Format("%sdir1\\data2.txt",g_BasePath);
if (!file.Open(_T(str),CFile::modeCreate | CFile::modeWrite | CFile::typeText | CFile::modeNoTruncate))
{
MessageBox(_T("未打开文件"));
}
else
{
for (int i=1;i<11;i++)
{
str.Format("%d\n",i);
file.SeekToEnd();//定位至文件末尾
file.WriteString(str);
}
file.Close();
}
~~~
(3)读文件:
~~~
CStdioFile file;
CString str,str1,str2;
str.Format("%sdir1\\data1.txt",g_BasePath);
if (file.Open(_T(str),CFile::modeRead | CFile::typeText))
{
file.SeekToBegin();//定位到文件开头
while(file.ReadString(str))//读取文件中的一行
{
if(AfxExtractSubString(str1,str,0,'-'))//截取字符串
{
if(AfxExtractSubString(str2,str,1,'-'))
{
MessageBox(str1+"的平方="+str2);
}
}
}
file.Close();
}
else
MessageBox(_T("data1.txt文件打开失败"));
~~~
(4)计算文件行数:
~~~
CStdioFile file;
CString str;
str.Format("%sdir1\\data2.txt",g_BasePath);
int lineNum=0;//统计文件行数的变量
if (file.Open(_T(str),CFile::modeRead | CFile::typeText))
{
file.SeekToBegin();//定位到文件开头
while (file.ReadString(str)) //读取文件中的一行
{
lineNum++;
}
file.Close();//关闭文件
str.Format("data2.txt共计%d 行",lineNum);
MessageBox(str);
}
else
MessageBox(_T("data2.txt文件打开失败"));
~~~
(5)计算目录下文件个数:
~~~
//SDK方式统计指定目录下的文件个数
HANDLE hFind;
WIN32_FIND_DATA dataFind;
BOOL bMoreFiles=TRUE;
int iCount=0;//统计文件数的变量
CString str;
str.Format("%sdir1\\",g_BasePath);//str是指定的路径
hFind=FindFirstFile(str+"*.*",&dataFind);//找到路径中所有文件
//遍历路径中所有文件
while(hFind!=INVALID_HANDLE_VALUE&&bMoreFiles==TRUE)
{
if(dataFind.dwFileAttributes!=FILE_ATTRIBUTE_DIRECTORY)//判断是否是文件
{
iCount++;
}
bMoreFiles=FindNextFile(hFind,&dataFind);
}
FindClose(hFind);
str.Format("dir1目录下文件个数共计%d 个",iCount);
MessageBox(str);
~~~
(6)删除文件:
~~~
CFileFind finder;
CString str;
str.Format("%sdir1\\data1.txt",g_BasePath);
if (finder.FindFile(_T(str)))
{
::DeleteFile(_T(str));
}
~~~
(7)删除目录:
RemoveDirectory和_rmdir两者都只能删除空文件夹,若要删其下有文件的文件夹,需先删除其下的所有文件,再删除文件夹。
1)方法1:
~~~
CString strDir;
strDir.Format("%sdir2",g_BasePath);
::RemoveDirectory(strDir);
~~~
2)方法2:
~~~
#include
strDir.Format("%sdir1",g_BasePath);
_rmdir(strDir);
~~~
';
VC++调用Matlab编写的DLL(混合编程)
最后更新于:2022-04-01 20:34:36
有的时候,我们在VC里直接实现一个想法比较复杂或者不够理想,但是使用Matlab可以比较轻松的实现或者实现的效果比较理想,这个时候,我们可以选择混合编程的方法,将预想功能模块使用Matlab实现,在将其编译成供VC调用的DLL,从而更好地实现达到的目标。
**一.基本环境**:
1. Microsoft Visual Studio 2008 SP1(VC++);
2. MATLAB Compiler Runtime;(**MCRInstaller.exe 可在网上下载安装,已安装了Matlab的就不需安装了**)
3. OS:Windows XP。
**二. 基本方法:
1.环境准备:**
首先值得说明的是,经过不断的尝试和搜集资料,发现要想在VC++中调用MATLAB编写的DLL,必须至少要有MATLAB Compiler Runtime环境,也就是说得先安装MCRInstaller.exe(约160M),当然,直接安装MATLAB R2009a(约4.0G)也可以。显然,如果您仅仅想用VC++调用MATLAB编写的DLL,安装MCRInstaller.exe 就足够了,安装完之后看一下系统环境变量的Path里是否已经添加了其路径,如果没有需手动添加,一般会有的。
**2.调用细节步骤:**
(1)将MATLAB生成的:*.h、*.lib、*.dll 三个文件拷贝到当前项目的目录下。
(2)设置VC++项目的属性:
首先,在“配置属性->C/C++->常规”的“附加包含目录”中添加MCR的include目录的路径,我的路径是:
C:\Program Files\MATLAB\MATLAB Compiler Runtime\v713\extern\include 。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a3eb381.gif)
其次,在“配置属性->链接器->常规”的“附加库目录”中添加MCR的lib库路径,我的路径是:
C:\Program Files\MATLAB\MATLAB Compiler Runtime\v713\extern\lib\win32\ microsoft。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a414938.gif)
最后,在“配置属性->链接器->输入”的“附加依赖项”中添加DLL中和程序中所依赖的lib库名称。如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a431343.gif)
(3)VC++程序中的调用:(**详细的实例可在我的CSDN资源中下载:[http://download.csdn.net/detail/margin1988/3677489](http://download.csdn.net/detail/margin1988/3677489)**)
首先,包含所使用到的头文件,其次,正式调用。例如(我的libdrawAMResults DLL用于绘图):
~~~
#include "libdrawAMResults.h"
#include "mclmcrrt.h"
#include "mclcppclass.h"
//初始化MCR
if(!mclInitializeApplication(NULL,0) )
{
MessageBox(_T("Could not initialize MCR!"));
}
//初始化lib
if(!libdrawAMResultsInitialize())
{
MessageBox(_T("Could not initialize libdrawAMResults!"));
}
//上面的初始化可以放在程序中的InitInstance()函数中。
try
{
mwArray a(3,3,mxDOUBLE_CLASS);
//double ha[9]={0,0.953,-0.544,1.189,0.177,-0.358,0.358,1.811,-0.358};
//a.SetData(ha,9);
a(1,1) = 0; a(1,2) = 1.189; a(1,3) = 0.358;
a(2,1) = 0.953; a(2,2)=0.177; a(2,3) = 1.811;
a(3,1) = -0.544; a(3,2)=-0.358; a(3,3) = -0.358;
//上面两种方式初始化mwArray,得到的矩阵才是一样。
}
catch (const mwException& e)
{
MessageBox(_T("mwException!"));
}
~~~
最后,结果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-08-31_57c6b4a4513ed.gif)
';