如何实现使用LVS_ICON风格的CListCtrl自绘

simon_186 2007-03-12 11:52:35
已试过重载DrawItem函数,并设置LVS_OWNERDRAWFIXED,但没用,后来查到是LVS_OWNERDRAWFIXED只支持列表风格LVS_REPORT,所以DrawItem函数在LVS_ICON风格下没有被调用.
请问:要使用LVS_ICON,怎样实现CListCtrl的自绘
...全文
2155 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
wwt861103 2010-05-16
  • 打赏
  • 举报
回复
我之前试过,好像用CustomDraw和DrawItem都无法实现,
我是通过在OnPaint中自己绘制的,有需要可以到我的空间中去看一下!
simon_186 2007-07-25
  • 打赏
  • 举报
回复
To ghl3005(), 谢谢
结帖
lyg_zy 2007-07-03
  • 打赏
  • 举报
回复
关注中!我也考虑重新做一窗口算了.
ghl3005 2007-05-10
  • 打赏
  • 举报
回复
已经实现,
void CCAGENT::OnCustomdrawList ( NMHDR* pNMHDR, LRESULT* pResult )
{NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>( pNMHDR );

*pResult = 0;

// Request item-specific notifications if this is the
// beginning of the paint cycle.

if ( CDDS_PREPAINT == pLVCD->nmcd.dwDrawStage )
{
*pResult = CDRF_NOTIFYITEMDRAW;
}
else if ( CDDS_ITEMPREPAINT == pLVCD->nmcd.dwDrawStage )
{
// This is the beginning of an item's paint cycle.
LVITEM rItem;
int nItem = static_cast<int>( pLVCD->nmcd.dwItemSpec );
CDC* pDC = CDC::FromHandle ( pLVCD->nmcd.hdc );
COLORREF crBkgnd;
BOOL bListHasFocus;
CRect rcItem;
CRect rcText;
CString sText;
UINT uFormat;

bListHasFocus = ( m_agentList.GetSafeHwnd() == ::GetFocus() );

// Get the image index and selected/focused state of the
// item being drawn.
ZeroMemory ( &rItem, sizeof(LVITEM) );
rItem.mask = LVIF_IMAGE | LVIF_STATE;
rItem.iItem = nItem;
rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
m_agentList.GetItem ( &rItem );

// Get the rect that holds the item's icon.
m_agentList.GetItemRect ( nItem, &rcItem, LVIR_ICON );

// Draw the icon.
uFormat = ILD_TRANSPARENT;

if ( ( rItem.state & LVIS_SELECTED ) && bListHasFocus )
uFormat |= ILD_FOCUS;

m_listImage.Draw ( pDC, rItem.iImage, rcItem.TopLeft(), uFormat );


// Get the rect that bounds the text label.
m_agentList.GetItemRect ( nItem, rcItem, LVIR_LABEL ); //把这行去掉就没有文字.


// Draw the background of the list item. Colors are selected
// according to the item's state.

if ( rItem.state & LVIS_SELECTED )
{
if ( bListHasFocus )
{
crBkgnd = GetSysColor ( COLOR_HIGHLIGHT );
pDC->SetTextColor ( GetSysColor ( COLOR_HIGHLIGHTTEXT ));
}
else
{
crBkgnd = GetSysColor ( COLOR_BTNFACE );
pDC->SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));
}
}
else
{
crBkgnd = GetSysColor ( COLOR_WINDOW );
pDC->SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));
}

// Draw the background & prep the DC for the text drawing. Note
// that the entire item RECT is filled in, so this emulates the full-
// row selection style of normal lists.
pDC->FillSolidRect ( rcItem, crBkgnd );
pDC->SetBkMode ( TRANSPARENT );


// Tweak the rect a bit for nicer-looking text alignment.
rcText = rcItem;
// Draw the text.
sText = m_agentList.GetItemText ( nItem, 0 );

pDC->DrawText ( sText, CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER );



// Draw a focus rect around the item if necessary.
if ( bListHasFocus && ( rItem.state & LVIS_FOCUSED ))
{
pDC->DrawFocusRect ( rcItem );
}

*pResult = CDRF_SKIPDEFAULT; // We've painted everything.
}
}




m_agentList.SetIconSpacing(150, 150);
用他来调整图标距离 qq:1600564
simon_186 2007-03-20
  • 打赏
  • 举报
回复
没有人回了吗?分不够的话可以再加
simon_186 2007-03-19
  • 打赏
  • 举报
回复
关于这个问题,我开了个相关的帖子,大家有兴趣的话,可以去看看
http://community.csdn.net/Expert/topic/5401/5401723.xml?temp=.3764002
长尾巴的悟空 2007-03-17
  • 打赏
  • 举报
回复
加油,UP一下.
simon_186 2007-03-16
  • 打赏
  • 举报
回复
我试过了OnCustomDraw,但是还是存在问题。
已用方法:
在OnCustomDraw中只绘制图标,而不绘制文字。
结果:
文字是没有出现,但文字区域依然存在,项之间的间隙很大,而且鼠标左键单击该区域就选中了项。
我希望的效果是去掉文字区域,使各项紧密排列为一行,listctrl控件的高度就等于图标的高度。
菜牛 2007-03-13
  • 打赏
  • 举报
回复
不如自己重新做个窗口简单了。
happyness44 2007-03-13
  • 打赏
  • 举报
回复
LVS_REPORT经过重绘能达到LVS_ICON风格的效果
simon_186 2007-03-12
  • 打赏
  • 举报
回复
没有人知道怎样做吗?
非常好用的CListCtrl加强版。 从CListCtrl继承,完全兼容CListCtrl. 它有以下特性: • The background of the sorted column can be displayed in a different color (like the detailed view of Windows XP Explorer). • The header of the sorted column can display an arrow that indicates the sort direction (like the detailed view of Windows XP Explorer). • You can give the user the opportunity to hide or redisplay selected columns by just clicking on the header control with the right mouse button (see picture below). • You can hide or redisplay a selected column entirely. • In contrast to the original list view control, the first column can have the LVCFMT_CENTER or LVCFMT_RIGHT style, too. For this feature, the list view control must have the LVS_OWNERDRAWFIXED style. • The label attributes state icon, small icon, and selection can always be shown in the leftmost column, independent of the order of the columns. For this feature, the listview control must have the LVS_OWNERDRAWFIXED style. • You can supply tooltips not only for the whole item, but also for the small icon, the state icon, and each subitem label. • The extended styles LVS_EX_CHECKBOXES, LVS_EX_ONECLICKACTIVATE, LVS_EX_SUBITEMIMAGES, LVS_EX_TWOCLICKACTIVATE, and LVS_EX_UNDERLINEHOT will be supported even if the list view control has the LVS_OWNERDRAWFIXED style. • If the LVS_EX_CHECKBOXES style has been applied and a selected item will be checked/unchecked, all other selected items will be checked/unchecked, too. • If the LVS_EX_LABELTIP style has been applied, not only the partially hidden text of the item label will be unfolded but also the partially hidden text of each subitem label. Note: The LVS_EX_LABELTIP style will be supported under all operating systems. • Tooltips and expanded labels can be displayed simultaneously. • The current state of the list view control (column widths, column order, hidden columns, and sort column and direction) can be saved and restored.
一个好用的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来操作查询,这样开发的效率会高一些,而且是在本地,速度完全可以满足。

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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