请问关于CImageList的Create()函数

quaddamage 2006-09-01 04:18:19
CImageList mImageList;
mImageList.Create(16, 16, ILC_COLOR | ILC_MASK , 20, 20);

现在的问题是:只有传入ILC_COLOR才能返回成功, ILC_COLOR8, ILC_COLOR16等宏貌似都没有被定义,我直接传入0x00000008或者0x00000010也不行。说是什么无效的句柄。
我用的是WinCE3.0
...全文
111 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
quaddamage 2006-09-06
  • 打赏
  • 举报
回复
色郎中 2006-09-01
  • 打赏
  • 举报
回复
bang
ding
从VC++项目中的菜单资源建立结构相同的自绘弹出式菜单,原理和步骤如下: (1)CMenu::LoadMenu读入菜单资源; (2)CImageList::Create读入工具栏位图; (3)CMenu::CreatePopupMenu和CMenu::AppendMenu拷贝菜单资源,建立弹出式菜单。其中CMenu::AppendMenu第1个参数设置成MF_OWNERDRAW(自绘), 第四个参数设置成一个附加结构的指针,包括菜单项文字和位图索引等信息。通过这个结构,在自绘制时,可以获取对应的菜单项文字和位图位置索引,其中位图保存在第(2)步中的CImageList变量中; (4)在对右鼠标键的响应函数里,使用CMenu::TrackPopupMenu启动显示弹出式菜单; (5)在弹出式菜单的拥有者窗口(CxxxView)里,处理WM_MEASUREITEM消息和WM_DRAWITEM消息,分别调用CMenuEx::MeasureItem和CMenuEx::DrawItem, 分别用来定义菜单项的尺寸,对菜单项进行自绘; (6)在自绘函数CMenuEx::DrawItem里,通过每个菜单项的附加结构lpDIS->itemData,获得其文字和位图索引,然后分别使用CDC::DrawText和CImageList::Draw,画出该菜单项的文字和位图,从而实现自绘制。 程序在VC6下编译通过。 没有处理的地方:如果菜单项状态是checked或者radio,程序没做处理。另外,弹出式菜单的激活/禁止时,不会自动触发其拥有者窗口的ON_UPDATE_COMMAND_UI宏。不过,可以处理owner窗口的WM_INITMEMUPOPUP消息(在弹出式菜单的每个子菜单弹出时,都会发出此消息),为每个子菜单项单独生成一个CCmdUI对象,调用其CCmdUI::DoUpdate函数,来手动触发ON_UPDATE_COMMAND_UI宏中对应的消息处理函数,使得菜单项能够根据应用环境进行激活和禁止。详见博客: http://oliver.zheng.blog.163.com/blog/static/14241159520143210595266/
封面 1 内容简介 2 目录 4 第1章 综述 10 1.1 本书结构 10 1.2 本书约定 11 第2章 C++重点回顾 12 2.1 类、对象与实例 12 2.2 构造函数 12 2.3 匿名实例 13 2.4 虚函数 14 2.5 异常处理 16 第3章 基本概念与基础MFC类 19 3.1 什么是Win32 API 19 3.2 控制台模式的应用程序 19 3.3 基本数据类型 20 3.4 什么是Unicode 23 3.5 使用MFC类库 24 第4章 窗口程序的基本概念 34 4.1 文字终端与GUI界面 34 4.2 组成要素 35 第5章 创建第一个窗口程序 41 5.1 使用Visual C++ 41 5.2 示例程序 46 5.3 增加资源文件 50 5.4 用MFC Application Wizard产生程序(丢失部分) 59 第6章 窗口的产生与处理 61 6.1 窗口类 (丢失) 61 6.2 产生CWnd 对象 61 6.3 处理消息 63 6.4 关闭窗口 66 6.5 窗口位置与尺寸 68 6.6 窗口的状态与样式 73 6.7 工作区显示 75 6.8 有滚动条 的窗口 77 6.9 CWnd与句柄 80 6.10 窗口文本 81 第7章 对话框 82 7.1 基础知识 82 7.2 编辑器与列表框的字符串交换 86 7.3 消息框 99 7.4 多页对话框 102 7.5 通用对话框 107 第8章 键盘、鼠标与时间 114 8.1 消息与输入焦点 114 8.2 键盘的消息 115 8.3 鼠标 118 8.4 特殊的状况 123 8.5 示例:模拟打字程序 125 8.6 计时器消息与时间 132 8.7 设计鼠标光标 133 第9章 菜单、工具栏与快捷键 135 9.1 菜单 135 9.2 快捷键 150 9.3 工具栏与状态栏 153 第10章 文档、视图与框架窗口 162 10.1 “文档/视图”模型 162 10.2 文档、视图与框架窗口间的关系 165 10.3 CDocument类 174 10.4 CView类 182 10.5 CScrollView类 183 10.6 SDI框架窗口CFrameWnd 185 10.7 示例:拉线绘图 186 10.8 MDI 197 10.9 MDI化的LineArt 205 10.10 多视图类的MDI 212 10.11 拆分式窗口(Splitter Window) 220 10.12 更多不同的View类 231 第11章 文档视图模式与MFC Application Wizard 238 11.1 SDI项目 238 第12章 控件 248 12.1 静态类 248 12.2 按钮 251 12.3 滚动条CScrollBar 267 12.3.1 CScrollBar::Create() 267 12.3.2 样式 268 12.3.3 成员函数 268 12.3.4 通知消息 269 12.3.5 示例:多线程动画 271 12.4 列表框 278 12.5 编辑控件 283 12.6 组合框 286 12.7 数据交换与校验 291 第13章 设备上下文与基本绘图工具 299 13.1 概述 299 13.2 设备上下文类CDC 299 13.3 CWindowDC与CClientDC 304 13.4 画笔与画刷 305 13.5 基本绘图函数 308 13.6 色彩与调色板 312 13.7 使用调色板 316 13.8 字体与文本输出 318 13.9 示例:时钟 330 第14章 位图 336 14.1 简介 336 14.2 CBitmap类 338 14.3 设备无关位图类(DIB) 340 14.4 处理DIB的示例 344 第15章 打印与坐标系 368 15.1 打印 368 15.2 比例、原点与方向 375 15.3 更大的灵活性 380 15.4 打印预览 382 第16章 通用控件 383 16.1 概述 383 16.2 CSliderCtrl 387 16.3 CSpinButtonCtrl 390 16.4 CHeaderCtrl 391 16.5 CAnimateCtrl 394 16.6 CProgressCtrl 397 16.7 CTreeCtrl、CTreeView与CImageList 397 16.8 CListCtrl与CListView 415 16.9 示例:程序管理器 434 16.10 CIPAddressCtrl 437 第17章 使用ActiveX控件 439 17.1 ActiveX控件的由来 439 17.2 使用ActiveX控件 440 17.3 设计ActiveX容器 442 第18章 进程、线程与内存 447 18.1 Win32的内存管理 447 18.2 Process简介 451 18.2.1 产生子进程 452 18.2.2 与process有关的信息 455 18.2.3 结束process 456 18.3 Thread简介 456 18.3.1 产生Child Thread 457 18.3.2 Thread的信息 457 18.3.3 终止Thread 457 18.4 同步(Synchronization) 457 18.4.1 Critical Section 459 18.4.2 等待对象的状态改变 462 18.4.3 Mutex 463 18.4.4 Event 465 18.5 进程间通信(IPC) 468 18.5.1 共享内存与文件映射 468 18.6 CWinThread 471 18.6.1 GUI Thread与非GUI Thread 471 18.6.2 利用CWinThread产生Thread的流程 471 18.6.3 其他的CWinThread成员 472 第19章 Profile与Registry 473
一个好用的ODBC数据库类CMYODBC --- VC数据库开发之一

一、引言
感觉MFC的CRecordset类不是很好用,因为我们要想使用的话必须为每个查询从CRecordset类派生出一个新类,或者进行动态数据交换。在VC知识库第六期上面有一篇介绍"单独使用CRecordset"文章,可是上面的CRecordset打开方式只能使用CRecordset::forwardOnly,游标只能向前滚动,而且用这种方式,你根本无法从打开的记录集中获得本次查询得到了有多少列。有一次在应用的时候,我只好通过捕获CRecordset::GetFieldValue()的异常来得到查询的结果有多少列。为了使用的方便,我自己写了一个数据库类CMYODBC,它是用ODBC API写的,它支持各种sql语句,支持事务处理。它最好的地方在于,对于查询的记录集实现了动态绑定,这是通过类CODBCSet来实现的。要说明的是,这两个类可以说比较简单,两个类的代码量很少,所以建议感兴趣的朋友看一下它的代码,下图是本代码运行效果图:



二、原理
其实无论是使用ODBC API还是使用ORACLE的OCI(对于ORACLE的OCI感兴趣的朋友,欢迎一起探讨,OCI的功能很强大,支持动态绑定,支持pl/sql,它的类的封装和CMYODBC很相似,用它来代替ODBC编程,可以解决ODBC的效率问题)其过程都很相似,一般分为以下几个过程:
1 初始化工作环境
2 连接数据源
3 操作数据源
4 检索结果集
5 更新结果集
6 事务处理
7 断开连接,释放各种句柄

大家都知道在使用CDatabase时候,如果要执行的是select语句的话,那么要通过CRecordset来检索结果集,而CRecordset类要我们先选择表等来先进行绑定,这样我们使用的时候很不方便,其实我们根本不需要这样做,而且我们也不需要知道这次执行的是关于那个数据库那张表的sql语句,因为在执行完SQLExecDirect()后,可以通过调用SQLNumResultCols() 、SQLColAttribute()等函数来获得执行的结果的很多属性,如这次执行的结果集是多少列、每列的字段名、列的类型等,然后根据类型可以动态分配内存,然后在用这些内存去绑定,最后能过SQLFetch()来得到结果集。在CMYODBC这个类里是通过CODBCSet类应用上面的原理来实现自动绑定的。

下面介绍一下类CMYODBC的使用方法:
1  通过调用ConnectDB(const char *cpServerName, const char *cpUserName, const char *cpPassword)函数来联接数据库。其中的参数意义如下:
cpServerName-----ODBC数据源名
cpUserName-------用户名
cpPassword-----口令

2  通过调用ExeSqlDirect(const char *cpSqlStmt)函数可以执行一些操作数据源的语句,如修改、删除语句等。其中的参数意义如下: cpSqlStmt------你要执行的sql语句,如delete from emp where deptno < 20

3  如果要执行事务的话,调用ExecTrans(CStringList &strSqlList)函数,其中的参数 strSqlList表示你要执行的一系列sql语句。

4 如果要执行select语句的话,通过下面的步骤:
I 声明一个CODBCSet 对象,如 CODBCSet rSet;
II然后调用函数PrepareSql(const char *cpSql, CODBCSet &rset),其中的参数的意义如下:
cpSql----代表要执行的select语句
rset-----表示一个CODBCSet的引用,你要把上面声明的对象传递进去。
III调用FetchData()函数来取得结果集。

5 通过调用函数DisConnect()断开和数据源的连接。

三、实例练习

下面就通过上面的例子一起来看一下这个类到底怎么样,为了方便,我建了一个简单的access数据库test.mdb,在这个数据库中也只有一张表emp,它有三个字段。在下面的工程的InitInstance ()中,通过代码为它自动建立了一个叫做"daliu"的ODBC数据源。

步骤一:
新建一个基于对话框的工程,命名为demo1,打开stdafx.h文件,加入#include 从例子中把MyODBC.h,MyODBC.cpp, ODBCSet.h, ODBCSet.cpp复制到这个工程的目录下,并且加入到工程中,方法是菜单project->add to project->files,选择这四个文件就可以了。复制test.mdb文件,把它加入到这个工程的debug目录下。也可以是其它的目录,只要和你的执行程序在同一个目录就可以了。

步骤二:
参照上面的对话框,在上面加入按钮和一个ClistCtrl控件,在classwizard上面关联控件的变量ClistCtrl关联m_list控件,为三个EDIT分别关联CString类型的m_strID,m_strName,m_strJob.

步骤三:
在CDemo1App::InitInstance()的最上面,加入下面的代码,实现自动ODBC数据源的增加。

char path[MAX_PATH] = {''\0''};
GetModuleFileName(NULL,path,MAX_PATH);//得到执行文件名
m_strExePath.Format("%s", path);
int iPosition;
iPosition = m_strExePath.ReverseFind(''\\'');
m_strExePath = m_strExePath.Left(iPosition + 1);
CString strAccessPath = m_strExePath + "test.mdb";//得到这个数据库文件的路径
int iLen = strAccessPath.GetLength();
char cpConfig[MAX_PATH];
//由于在这个联结串中有靠\0来分开数据源每个配置信息项的,所以只好用下面的笨方法了。
strcpy(cpConfig, "DSN=daliu\0");
strcpy(cpConfig + 10, "DBQ=");
strcpy(cpConfig + 14, strAccessPath);
strcpy(cpConfig + 14 + iLen, "\0");
strcpy(cpConfig + 15 + iLen, "DEFAULTDIR=");
strcpy(cpConfig + 15 + iLen + 11, m_strExePath);
strcpy(cpConfig + 25 + iLen + m_strExePath.GetLength(), "\0\0");

if(!SQLConfigDataSource(NULL,ODBC_ADD_SYS_DSN,
"Microsoft Access Driver (*.mdb)\0",cpConfig))//设置odbc数据源
步骤四:
设置Clistctrl控件的风格,为他加入图象资源。 首先要在CDemo1Dlg中加入#include"ODBCSet.h"#include"MyODBC.h",然后在CDemo1Dlg中添加成员变量CimageList ImageList;添加成员函数BOOL ShowData() 在CDemo1Dlg::OnInitDialog()中加入下面的代码:ImageList.Create(16,16,ILC_COLOR8,0,5);
ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));
DWORD dwStyle=GetWindowLong(m_list.GetSafeHwnd(),GWL_STYLE);
dwStyle |= LVS_REPORT;
SetWindowLongA(m_list.GetSafeHwnd(),GWL_STYLE,dwStyle);
m_list.SetExtendedStyle(LVS_EX_HEADERDRAGDROP|LVS_EX_FULLROWSELECT|LVS_EX_TRACKSELECT);
m_list.SetImageList(&ImageList, LVSIL_SMALL);

ShowData()//这个函数是用来向列表框中插入数据的。

下面我们来分析一下ShowData()函数,它是使用CMYODBC的关键。 BOOL CDemo1Dlg::ShowData()
{
int i = 0, iCount;
m_list.DeleteAllItems();//首先清空listview
iCount = m_list.GetHeaderCtrl()->GetItemCount();
for(i = 0; i < iCount; i++)
{
m_list.DeleteColumn(0);
}
for(i = 0; i < iCount; i++)
{
m_list.GetHeaderCtrl()->DeleteItem(0);
}
/*上面的代码用于清空ClistCtrl控件中项,上面的两个循环并不能合成一个,你可以试一下*/

CString strSql;
strSql = "select * from emp";//sql查询语句
CMyODBC db; //声明CMyODBC类的实例
CODBCSet set;//声明CODBCSet类的实例

/*联接数据库,由于access数据库没有设定用户和口//令,所以它们两个就用空的字符串代替*/
db.ConnectDB("daliu","", "");

/*准备sql语句,你可以跟踪一下,在这个函数中完成动态的绑定,得到共有几列,每列的名称等*/
db.PrepareSql(strSql, set);

for(i = 0; i < set.GetCols(); i++)/*set.GetCols()得到本次查询得到了几列。*/
{
m_list.InsertColumn(i, set.m_coldatafmt[i].name,LVCFMT_CENTER,80);
}
/*上面的循环用于插入列, m_coldatafmt是一个COL_DATAFMT_ODBC的结构,
在我们调用db.PrepareSql()后,它就含有了每个列的名称,字段数据类型,字段数据长度信息。*/

/*下面的循环用于向列表框中插入数据, set.m_coldata是一个COL_DATA_ODBC的结构,
当含有当前行的数据值,数据值的长度信息,这样就实现了从记录集中取数据的功能。*/
int iRow = 0;
while(db.FetchData())/*每次取回一条记录。*/
{
for(i = 0; i < set.GetCols(); i++)
{
if(i == 0)
{
m_list.InsertItem(iRow, set.m_coldata[0].value);
}
else
{
m_list.SetItemText(iRow, i, set.m_coldata[i].value);
}
}
iRow++;
}
set.Empty();/*清空记录集*/
db.DisConnect();/*断开连接*/
return TRUE;
}

下面我们再来看一个如何插入一条记录: void CDemo1Dlg::OnBtnadd()
{
UpdateData(TRUE);
CString strSql;
strSql.Format("insert into emp values(%d,''%s'',''%s'')", atoi(m_strID), m_strName, m_strJob);
CMyODBC db;
db.ConnectDB("daliu","", "");//连接数据库
db.ExeSqlDirect(strSql);//执行sql语句
db.DisConnect();//断开连接
this->ShowData();//刷新数据
}

响应其它的按钮的函数就不一一写了,和上面的都差不多,希望通过它能给我们用VC的开发数据库工程带来一些方便。

四、总结
ODBC有很多用处,例如我们可以把很多信息按照一定的格式保存在文本中(因为在商业上用别人的数据库都是要买的),然后通过ODBC把这些文本文件映射成表,这些文件的目录就成为一个数据库,这些我们就可以很方便的对这些文件的内容通过sql来操作查询,这样开发的效率会高一些,而且是在本地,速度完全可以满足。

19,504

社区成员

发帖
与我相关
我的任务
社区描述
硬件/嵌入开发 嵌入开发(WinCE)
社区管理员
  • 嵌入开发(WinCE)社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧