<<出现问题的自绘组合框>>的分析和修正
2015-06-21 23:25
387 查看
<<出现问题的自绘组合框>>http://download.csdn.net/detail/wxf041041/7414585
在csdn下载中, 有一个demo, 描述了自绘CComboBox出现的问题.下载了Demo看了一下,是参考别的工程, 写的Demo.
Debug模式下报错. 报错问题比较明显, 是lpDrawItemStruct->itemID无效引起的问题.
这个Demo是去年上传的, 不知道这个问题他解决了没有, 我分析并修正了一下
修正后的工程下载点 : owerncombox_fixed_2015_0621_2314.rar
发现的问题和分析如下:
在Debug模式下, 直接运行程序, 程序报错, 并没有断言.
单步一下, 到报错时, 可以看到出错的语句为 :
void CMyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { ASSERT(lpDrawItemStruct->CtlType == ODT_COMBOBOX ); CDC dc; dc.Attach(lpDrawItemStruct->hDC); CRect rcItem(lpDrawItemStruct->rcItem); int nCount = GetCount(); CString csItem; GetLBText(lpDrawItemStruct->itemID, csItem); ///< ! 执行这句过后, 就异常了在watch窗口可以看到 lpDrawItemStruct->itemID = -1, 是个无效值, 报错的直接原因是这样
- lpDrawItemStruct 0x0016f180 {CtlType=0x00000003 CtlID=0x00000064 itemID=0xffffffff ...} tagDRAWITEMSTRUCT * CtlType 0x00000003 unsigned int CtlID 0x00000064 unsigned int itemID 0xffffffff unsigned int ///< ! 直接的报错原因 itemAction 0x00000001 unsigned int itemState 0x00001000 unsigned int
itemID无效的原因是: 填充数据后, 没有设置当前条目.
修正如下:
/// BOOL COwerncomboxDlg::OnInitDialog() /// ... m_mycom2.Create(WS_VISIBLE|WS_CHILD|CBS_DROPDOWNLIST|CBS_OWNERDRAWFIXED|CBS_HASSTRINGS, CRect(110,60,160,85),this,100); m_mycom2.AddString("1"); m_mycom2.AddString("2"); m_mycom2.AddString("3"); m_mycom2.AddString("4"); m_mycom2.AddString("5"); m_mycom2.SetCurSel(0); ///< 设置 ItemID = 0, 防止 CMyComboBox::DrawItem()中, GetLBText(lpDrawItemStruct->itemID, csItem); 报错好, 现在运行ok了, 剩下的就是完善细节.
我说下解决这类问题的思路:
* 这些问题,都是人家搞过的,找些开源的工程, 关于CComboBox自绘的, 看看人家的基本用法, 有啥区别?
从这个Demo看, 用法也是从开源工程或M$帮助中摘录出来的. e.g. codeproject上的Demo, 一般都是说明一个Demo说明一个特色, 很容易找出区别.
e.g. 人家的Demo运行正常, 我从那个Demo摘录出来的功能不正常,这区别, 应该是好找的.
* 如果找不出区别,那单步下, 看看走到哪报错了. 再看看人家正常运行的Demo, 走到相应的地方参数值都有什么区别.
然后再分析参数值为啥不同?
* 如果自己的用法和人家的用法稍有区别, 可以将自己的用法先整的和人家Demo相同, 看看运行是否正常。
总之, 就是一个做实验的过程. 不断的缩小问题的范围,这类直接报错的BUG, 是比较容易搞定的.
下面是我修正后的工程源码的预览.
//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by owerncombox.rc // #define IDM_ABOUTBOX 0x0010 #define IDD_ABOUTBOX 100 #define IDS_ABOUTBOX 101 #define IDD_OWERNCOMBOX_DIALOG 102 #define IDR_MAINFRAME 128 #define IDC_COMBO1 1000 #define IDC_MY_COMBO 1001 ///< ! 自绘控件ID还是搞一个不会和别的控件或对话框重复的值 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 129 #define _APS_NEXT_COMMAND_VALUE 32771 #define _APS_NEXT_CONTROL_VALUE 1002 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif初始化自绘控件
BOOL COwerncomboxDlg::OnInitDialog() { int iPosLeft = 0; int iPosTop = 0; int iPosRight = 0; int iPosBottom = 0; CDialog::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range. ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here /// 控件没有处理滚动条, 滚动条应该也要自己画的 /// 现在只能用键盘来滚动 iPosLeft = 110; iPosTop = 60; iPosRight = iPosLeft + 50; /// 高度应该>=5行, 否则点击下拉框时, 数据显示不出来, 设成5行后,下拉框能显示3行 iPosBottom = iPosTop + m_mycom2.getRowHeight() * 5; m_mycom2.Create( WS_VISIBLE | WS_CHILD | CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS, CRect(iPosLeft, iPosTop, iPosRight, iPosBottom), this, IDC_MY_COMBO); ///< 这里的控件ID不能和resource.h中使用过的ID冲突 m_mycom2.AddString("1"); m_mycom2.AddString("2"); m_mycom2.AddString("3"); m_mycom2.AddString("4"); m_mycom2.AddString("5"); m_mycom2.SetCurSel(0); ///< 必须在填好数据后,设置当前Item, 否则 CMyComboBox::DrawItem 处ItemId为-1, 引起无效ItemId不处理 return TRUE; // return TRUE unless you set the focus to a control }
自绘控件的.h
#if !defined(AFX_MYCOMBOBOX_H__89EA435C_83F5_43AB_BD37_19B38DB628FB__INCLUDED_) #define AFX_MYCOMBOBOX_H__89EA435C_83F5_43AB_BD37_19B38DB628FB__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // MyComboBox.h : header file // ///////////////////////////////////////////////////////////////////////////// // CMyComboBox window class CMyComboBox : public CComboBox { // Construction public: CMyComboBox(); // Attributes public: // Operations public: int getRowHeight() { return m_rowHeight; } // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMyComboBox) public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual int CompareItem(LPCOMPAREITEMSTRUCT lpData); ///< 应该重载这个函数, 因为CComboBox中有断言 virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); //}}AFX_VIRTUAL // Implementation public: virtual ~CMyComboBox(); // Generated message map functions protected: //{{AFX_MSG(CMyComboBox) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG DECLARE_MESSAGE_MAP() private: int const m_rowHeight; }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_MYCOMBOBOX_H__89EA435C_83F5_43AB_BD37_19B38DB628FB__INCLUDED_)
自绘控件的.cpp
// MyComboBox.cpp : implementation file // #include "stdafx.h" #include "owerncombox.h" #include "MyComboBox.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CMyComboBox CMyComboBox::CMyComboBox() : m_rowHeight(20) ///< 行高20ppx { } CMyComboBox::~CMyComboBox() { } BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox) //{{AFX_MSG_MAP(CMyComboBox) // NOTE - the ClassWizard will add and remove mapping macros here. //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMyComboBox message handlers void CMyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { BOOL bRowWasSelected = FALSE; int iRowCnt = 0; CString csItem; CRect rcItem; CDC dc; do { if ((NULL == lpDrawItemStruct) || (ODT_COMBOBOX != lpDrawItemStruct->CtlType)) { break; } iRowCnt = GetCount(); /// 必须判断是否为为有效的Item, 否则在GetLBText处报错 if ((lpDrawItemStruct->itemID < 0) || (lpDrawItemStruct->itemID > (iRowCnt - 1))) { break; } dc.Attach(lpDrawItemStruct->hDC); rcItem = CRect(lpDrawItemStruct->rcItem); GetLBText(lpDrawItemStruct->itemID, csItem); ///< 如果 lpDrawItemStruct->itemID 无效, 有断言 bRowWasSelected = (lpDrawItemStruct->itemState & ODS_SELECTED) ? TRUE : FALSE; if (bRowWasSelected) { dc.FillSolidRect(rcItem, RGB(238, 238, 238)); dc.SetTextColor(RGB(255, 0, 0)); } else { dc.FillSolidRect(rcItem, RGB(218, 218, 218)); dc.SetTextColor(RGB(0, 255, 0)); } dc.DrawText(csItem, csItem.GetLength(), rcItem, DT_LEFT | DT_SINGLELINE); dc.Detach(); ///< ! } while (0); } int CMyComboBox::CompareItem(LPCOMPAREITEMSTRUCT lpData) { return 0; } void CMyComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // TODO: Add your code to determine the size of specified item if (lpMeasureItemStruct->itemID == -1) { lpMeasureItemStruct->itemHeight = 16; } else { lpMeasureItemStruct->itemHeight = m_rowHeight; ///< 按照20ppx作为行高 } }
相关文章推荐
- 说说那些光说不练的事
- 读后感
- 测试与调试
- Redis 笔记与总结2 String 类型和 Hash 类型
- auto_ptr
- 赋值函数;复制函数
- 总结
- 持续集成CI之Jenkins使用指南
- 第四篇:白话tornado源码之褪去模板外衣的前戏
- 第一个JavaScript代码:JS
- CF 9A Die Roll
- CSS3 选择器——伪类选择器
- Rabbit简单例子Demo
- javascript jquery插入元素后事件会被注销
- Windows Phone 十二、设计器同步
- css选择器-属性选择器
- java&eclipse代码提示
- html + css (1)
- 重装电脑系统Win7并激活、删除其中一个系统、修复电脑 发出尖锐的 嘀嘀嘀嘀嘀 警报生声
- flask twisted 结合方案