子类化控件出错, 对话框上有个ListCtrl控件,与这个控件关联的是:class CAccelList : public CListCtrl出事对话框函数中:
BOOL CTestDlg::OnInitDialog()
{
CDialog::OnInitDialog(); m_ctrlList.SubclassDlgItem(IDC_LIST1, this); //这一句出错,跟进去
//跟到BOOL CWnd::SubclassWindow(HWND hWnd)就异常 // 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
return TRUE; // return TRUE unless you set the focus to a control
}
异常为:
BOOL CWnd::SubclassWindow(HWND hWnd)
{
if (!Attach(hWnd))
return FALSE; //这里有问题CAccelList类中有两个CComboBox控件class CAccelList : public CListCtrl
{
public:
CComboBox m_boxName;
CComboBox m_boxNum;
..........
protected:
virtual void PreSubclassWindow();
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);protected:
//{{AFX_MSG(CAccelList)
afx_msg void OnPaint();
afx_msg void OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct);
afx_msg void OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct);
//}}AFX_MSG DECLARE_MESSAGE_MAP()};void CAccelList::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: Add your message handler code here and/or call default
CListCtrl::OnDrawItem(nIDCtl, lpDrawItemStruct);
}
void CAccelList::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
CListCtrl::OnMeasureItem(nIDCtl, lpMeasureItemStruct);
}
void CAccelList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
lpMeasureItemStruct->itemHeight = 300; //行高}
void CAccelList::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
//自类化ComboBox控件 //发送消息给自己CRect rcWin;
GetWindowRect(&rcWin);
WINDOWPOS wp;
wp.hwnd = m_hWnd;
wp.cx = rcWin.Width();
wp.cy = rcWin.Height();
wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp); char* pszText[]={"姓名","学号","性别"};
LVCOLUMN lvc = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH}; int cx[]={100,100,100}; SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES); //第三步:设置列
for(int i=0;i<sizeof(cx)/sizeof(int);i++)
{ lvc.pszText = pszText[i];
lvc.cx = cx[i];
lvc.fmt = LVCFMT_CENTER; InsertColumn(i,&lvc);
} // 动态创建姓名一列 m_boxName.Create(WS_CHILD | WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST ,CRect(0, 17, 100, 97),this,IDD_COMBOXNAME); m_boxName.AddString(_T("张三")); m_boxName.AddString(_T("李四")); m_boxName.SetCurSel(0); m_boxName.ShowWindow(SW_SHOW); ////////////////////////////////////////
// 动态创建学号一列 m_boxNum.Create(WS_CHILD | WS_TABSTOP | WS_VSCROLL | CBS_DROPDOWNLIST ,CRect(100, 17, 200, 80),this,IDD_COMBOXNUM); m_boxNum.AddString(_T("001")); m_boxNum.AddString(_T("002"));
m_boxNum.SetCurSel(0);
m_boxNum.ShowWindow(SW_SHOW);
CListCtrl::PreSubclassWindow();
}
//跟到BOOL CWnd::SubclassWindow(HWND hWnd)就异常 就是这一句出错 ,什么原因啊?
this指针还没用创建完毕,你调用的太早了
//跟到BOOL CWnd::SubclassWindow(HWND hWnd)就异常 异常为:
BOOL CWnd::SubclassWindow(HWND hWnd)
{
if (!Attach(hWnd))
return FALSE; //这里有问题
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CTestDlg)
// DDX_Control(pDX, IDC_LIST1, m_ctrlList);
//}}AFX_DATA_MAP
}
我注释掉这一行,就没有问题了, 这是为什么啊??难道 自定义的类,不能用ddx机制
{
}
这个虚函数就有问题吧?应该是在你绑定的类上。怎么会是CWnd呢?且这个虚函数没有参数吧?
如CCtrList m_ctrlList
有没有这个成员变量?
一个控件的派生类要正常工作,首先定义类对象,这样类的构造函数会执行且生成对象,但还没HWND,这样需CreateWindow(),还要为这个对象调整位置,设置属性等,完全是在隐式状态下进行。这样有些用户会感到不爽,他们提出:如果能把一个调整好的可视化控件与这个类对象关联,这样不是很好吗?为了满足用户的需求,MFC就提供了SubclassDlgItem()和SubclassWindow这两个功能来实现。通常这样做:
1、定义类对象
2、需关联的类对象.SubclassDlgItem(要关联的控件ID,其父窗口对象)
另一种方法:
需关联的类对象.SubclassWindow(控件的HWND)这样我们可以把可视化控件的位置和属性调整好,再和相应的派生类关联,这样省了不少事。二、首先你应该明白,一个可视的控件,都是有HWND的。
这样,在执行子类化操作时,MFC就把这个HWND与生成的类对象关联起来。此后因为类对象已经有了HWND,我们不需要再用CreateWindow()来隐式的建立HWND了。所以WM_CREATE消息不会被调用,即OnCreate()不会执行,要想执行一些初始化操作,MFC提供了一个PreSubClassWindow()虚函数,你可以重载,放入你的初始化代码。三、VC中其实经常在子类化的。
因为VC是一种可视化工具,要想实现可视化功能,就要把可视的控件与存在的类相关联,以便操作这个控件。如果不是为了可视化编辑,我们完全不需要子类化,一切在程序员的脑海里,全用代码来建立、操作和消毁对象。所以为了实现可视化,VC专门做了“建立类向导”->“建立控件变量”的功能来实现子类化功能。你也可以在此进行子类化,而不用这子类化功能函数。经过这个步骤,VC自动在类中生成两段代码:[
//{{AFX_DATA(CSiceDlg)
enum { IDD = IDD_SICE_DIALOG };
CRichEditCtrl m_info;
CWargeList m_wlist;
//}}AFX_DATAvoid CSiceDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSiceDlg)
DDX_Control(pDX, IDC_INFO, m_info);
DDX_Control(pDX, IDC_WAGERLIST, m_wlist);
//}}AFX_DATA_MAP
} 第一段是定义对象,第二段是关联到控件ID。四、什么时候用SubclassDlgItem(),什么时候用SubclassWindow()
你可以这样理解:如果你知道控件ID,就用SubclassDlgItem(),如果你知道了控件的HWND,就用SubclassWindow(),作用是一样的。但你如果只知道控件的HWND,还是只能用SubclassWindow(),而不能用建立类向导->关联控件变量了。
通过上面的介绍,你知道原因了吧?
如果你做好了类,如:一个派生自CListCtrl的类CMyListCtrl,在建立类向导->成员变量,点击你要关联的ID,建立成员变量,选择种类“控件”,变量类型里会有两个项,CListCtrl、CMyListCtrl,你可选择到CMyListCtrl你的派生类上。
如果没有,自已加到这两段里://{{AFX_DATA(CSiceDlg)
enum { IDD = IDD_SICE_DIALOG };
CMyListCtrl m_mylist;//加到这里
//}}AFX_DATAvoid CSiceDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CSiceDlg)
DDX_Control(pDX, IDC_MYLIST, m_mylist);//加到这里
//}}AFX_DATA_MAP
} 这样就子类化了。当然就不必再SubclassDlgItem()了,会出错的,因为不能子类化一个已经子类化过的对象。这你应该比我还明白了吧?可以结帖了吧?
不知道你能不能再帮个忙, 我昨天看了你的快捷键的代码, 有些不懂之处, 整理成word形式,发到你邮箱里面了现在过节,也不好劳累你。。你哪天有空,帮忙解惑一下, 劳累你了
)你的邮件我刚看到, 很感谢你的回复。
节日快乐!!