hur.cn - 华软网

 热门搜索

几个混淆的概念Create, PreSubClassWindow

  作者:未知    来源:网络    更新时间:2011/10/3
第一个问题:Create被调用后,流程为:PreCreateWindow----OnCreate----回到Create,然后窗口创建完成。。。

那么对于 ddx/ddv机制绑定的控件,PreCreateWindow  ,OnCreate为什么没有被调用????(我在一篇网文上看到的)




第二个问题:

在一篇网文中看到,Create被调用的时候,


PreSubclassWindow()会被调用,试图进行 提前子类化操作。。。。  


举例:一个对话框上放了一个按钮Button,   ddx/ddv机制绑定了一个CButton的变量, PreSubclassWindow() 这个函数可以做些什么?? 

当对话框上没有放按钮,而是动态创建一个按钮, myButton.Create(..............),这样的方式创建按钮,

PreSubClassWindow又做了些什么??



如果覆盖这个虚函数,比如:CXXButton::PreSubClassWindow(){.......}  我们可以在这个函数里面做些什么工作呢?


改变风格,可以在 PreCreateWindow里面搞定。。


第三个问题:对于CListCtrl控件而言,有个函数:SetExtendedStyle ,这个 函数,好多控件都有,作用是:修改风格!!

风格不是在PreCreate中指定了吗? 为什么 还可以在SetExtendedStyle中再次修改呢???





---华软 网友回答---
up up
---华软网友回复---
up up
---华软网友回复---
OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。 
在view类中,Create 是虚函数由框架调用,是用来“生成一个窗口的子窗口”。 而OnCreate 函数是用来“表示一个窗口正在生成”。 
  一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。因为在MFC里面用一种消息映射的机制来响应消息,也就是可以用函数来响应相应的消息。就拿CMainFrame类来说,当窗口创建后会产生WM_CREATE消息,我们可以在OnCreate函数里实现我们要在窗口里面增加的东西,例如按扭,状态栏,工具栏等。这些子窗口一般是定义成类中的一个成员变量,因为要保证生命周期。一般以m_开头来表示成员(member)。 
OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等,Create()负责注册并产生窗口 
Create()不是对应于消息WM_CREATE的,OnCreate()才是。Create()只用于产生窗口,像动态创建控件中的Create()一样。
---华软网友回复---
粘贴 复制 



引用 3 楼 lcy_888 的回复:
OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。 
在view类中,Create 是虚函数由框架调用,是用来“生成一个窗口的子窗口”。 而OnCreate 函数是用来“表示一个窗口正在生成”。 
  一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此……

---华软网友回复---
对于CListCtrl控件而言,有个函数:SetExtendedStyle ,这个 函数,好多控件都有,作用是:修改风格!!

风格不是在PreCreate中指定了吗? 为什么 还可以在SetExtendedStyle中再次修改呢???


试验证明, 只有在Create之后,才可以进行SetExtendedStyle, 否则程序提示错误,

为什么可以在Create之后,也就是说,创建好了窗口之后,可以修改风格
---华软网友回复---
创建好了窗口之后本来就可以修改风格,用SetWindowLong
---华软网友回复---
你好, 那么SetWindowLong 是不是可以这样理解的, 只要在创建以后,任何时刻都可以调用

比如:m_listBox.Create(..........);

m_listBox.AddString("..");

SetWindow(.....);

m_listBox.AddString("..");

我一直有个潜意识,   认为 一个窗口的风格是先指定,然后 创建之后, 那么就不能修改了,。。

想修改,可以在Create的时候,指定风格参数,或者干脆覆盖 PreCreateWindow这个虚函数。。。


以下是我的一个修改扩展风格的代码,但是毫无作用, 请大侠帮忙看看,这是什么原因???


m_listCtrl.Create(WS_CHILD|WS_VISIBLE|LVS_REPORT,
CRect(10,10,400,200), this, 1);

SetWindowLong(m_listCtrl.GetSafeHwnd(),GWL_EXSTYLE,LVS_EX_FULLROWSELECT );




m_listCtrl.InsertColumn(0,_T("姓名"),LVCFMT_LEFT,200);
m_listCtrl.InsertColumn(1,_T("年龄"),LVCFMT_LEFT,200);



m_listCtrl.InsertItem(0,"张三");

m_listCtrl.SetItemText(0,1,"12");



SetWindowLong修改了扩展风格,要求:设置成 可以选中整行,但是SetWindowLong无效。。。。

而却可以做到m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT);


这是什么原因导致的。。。

第二个问题: SetWindowLong据说是可以修改窗口对应的那个回调函数。。。。。

请问什么时候需要修改窗口过程, 比如:我的这个例子中的ListCtrl 貌似是不需要的,如果用SetWindowLong修改,那么可以修改成什么样的窗口过程。。。。

望大侠不吝赐教,多谢







引用 6 楼 lactoferrin 的回复:
创建好了窗口之后本来就可以修改风格,用SetWindowLong

---华软网友回复---
问题1,通过ddx/ddv机制绑定的控件确实不走Create消息线路,走的是subclass线路,也就是子类化机制
问题2,所有带有Pre的函数都是用于在正式进入目标函数之前进行预处理工作,有Create就没有Subclass,有Subclass就没有create,机制不同
问题3,原因很简单,当已经建立好控件之后如果想动态修改或改变控件风格就需要通过SetExtendedStyle
---华软网友回复---
向大侠,能否再帮忙解答一下,第7楼的问题, 


我刚才做了实验,发现 SetWindowLong来设置风格,果然不成功,,


SetExtenedeStyel成功了


引用 8 楼 xianglitian 的回复:
问题1,通过ddx/ddv机制绑定的控件确实不走Create消息线路,走的是subclass线路,也就是子类化机制
问题2,所有带有Pre的函数都是用于在正式进入目标函数之前进行预处理工作,有Create就没有Subclass,有Subclass就没有create,机制不同
问题3,原因很简单,当已经建立好控件之后如果想动态修改或改变控件风格就需要通过SetExtendedStyle

---华软网友回复---
SetExtendedStyle是这样做的
SendMessage(hwnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);

---华软网友回复---
关于7楼的问题
1、这里你混淆了一个概念,SetWindowLong是设置窗口属性和扩展属性的,注意这里是窗口,是所有的窗口。而SetExtenedeStyel是针对控件的,你这里也就是针对listctrl自身的一些特有属性了
2、有特殊需求的时候会自己处理窗口过程,这是一个可扩展性的问题,不过以我目前的编程经验而言从来没有用到过 
---华软网友回复---
CListCtrl是对listview窗口类的封装,listview类的自己的扩展风格要用LVM_SETEXTENDEDLISTVIEWSTYLE消息来设置。SetWindowLong是一个win32api但SetExtenedeStyle不是,SetExtenedeStyle只是对SendMessage的封装
---华软网友回复---
DDX绑定的可视控件,因为没有执行Create()所以没有PreCreateWindow(CREATESTRUCT)函数得不到执行,由于DDX绑定,会执行PreSubclassWindow()函数.
动态建立的控件,因为需要执行Create(),所以在HWND(即窗口)未形成前,会执行PreCreateWindow(CREATESTRUCT)函数,MFC在建立窗口前,AfxHookWindowCreate(),即做了一个建立钩子,发现窗口建立,会执行PreSubclassWindow()函数.

总结一下:
PreCreateWindow(CREATESTRUCT &cs)由于窗口还未建立,所以不能执行操作窗口的代码,只能对cs即窗口的样式做一些简单的修改.
PreSubclassWindow()由于窗口已经建立,所以可以对窗口进行一些初始化操作,如增加项呀,增加子控件呀等等
所以说PreCreateWindow(CREATESTRUCT &cs)基本没用,PreSubclassWindow用处很大,建议尽量用后者.
---华软网友回复---
如果是动态建立的,需要执行一些对窗口的操作,建立在OnCreate()消息处理函数中进行.
所以说:
如果是DDX出来的,用PreSubclassWindow
动态建立的,用OnCreate()

不要再想其它的了,已经足够我们用了.
---华软网友回复---
多谢楼上几位,

不过对于SetWindowLong这个函数,还是不怎么懂,以前看过一些vb代码,里面用到这个函数,  印象是用来替换窗口过程的,刚才又仔细看了这个函数的参数,第一个参数是 窗口句柄,,

意味着,11楼的第一个问题的答案, 怕是在表达上有所欠妥,    应该不是所有窗口吧,

另外:我觉得 控件也算是中特殊窗口吧



对于firefly3233兄  那晚提到的一个问题, 

Create出来的ListBox(自绘型的), 要显式添加上MeaseureItem函数,否则程序会报错。。。多次试验证明,必须要添加上,否则还真会出错。。。。。



惭愧,当时因为太晚,没有深入考虑, MeasureItem函数,这个函数是虚函数,  


我刚才把里面的代码注释掉,即:

void CMyListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
// lpMeasureItemStruct->itemHeight = 20;
}


惊奇的发现,这样子,程序依然可以运行,毫无错误。。。

这  就让我疑惑了,  CListBox拥有的虚函数,对于它的子类CMyListBox,也是可以拥有的啊

这个虚函数是public 修饰!!  我们用类向导添加这个函数, 这个函数默认是空体,什么都不 。

 既然CMyListBox拥有这个继承来的虚函数, 那么为什么又必须 要 显式的添加呢???

如果不添加,又回出错.

我开始以为, 显示添加后,必须做点什么,比如:设置一下高度,才不会出错。。

但是后来证明,什么都不做,也是不会报错的。。。。


这是怎么回事?  

难道mfc对于这个控件处理上有错误??



---华软网友回复---
up  up


15楼
---华软网友回复---
lazy_2010兄说, CListBox::MeasureItem函数的源码是个ASSERT 宏,所以,要么写成其他,要么留空,空函数体,

就不会出错。。。。。


同时就解释了为什么要显式的添加MeasureItem这个虚函数了。。。。


可以结贴了。。。。

谢谢各位
---华软网友回复---
学习了!!
---华软网友回复---
SetWindowLong()在窗口已经建立后,再修改窗口的一些属性,通常可以设置以下属性

GWL_EXSTYLE设置一个新的扩展类型
GWL_STYLE设置一个新的类型
GWL_WNDPROC设置一个新的窗口过程
GWL_HINSTANCE设置一个新的实例
GWL_ID 设置一个新的窗口标识 
GWL_USERDATA 设置一个新的数据

象:
CWnd::SetStyle() API中并没有这个函数,MFC做的,其实本质也是调用SetWindowLong来设置GWL_STYLE
CWnd:SetStyleEx()亦然。

需要了解哪个API,就看MSDN中相关的,这其实就是MSDN中介绍的
---华软网友回复---
  class="deleted_message"> 该回复于2011-10-09 09:15:07被版主删除
---华软网友回复---


对帖子设计的内容及问题进行总结一下:


一、对于动态创建的ListBox,即Create产生的, 必须显式添加MeasureItem这个虚函数。。。

因为CListBox::MeasureItem这个函数的代码为:

ASSSERT(FALSE);

如果你显式添加后,那么这个函数是一个空的函数体,不存在宏了,那么就不会报错了。。。。


二、

对于对话框上的控件,比如:ListBox而言,创建方式有两种:

一种是ddx/ddv搞定,一种是Create产生。。。



对于子控件言,其创建方法有2种:模板方式或动态创建方式。二者差别在与,
   动态创建方式(Create): MFC来创建控件,MFC可以在控件的创建过程中完成子类化操作,从而实现响应WM_CREATE等消息;
   模板方式: 对话框资源上放置的控件是由对话框创建的,MFC对控件的子类化操作是在响应WM_INITDIALOG消息时进行的;

2. 无论模板创建方式或动态创建方式,虚函数PreSubclassWindow都将被调用;
   虚函数PreSubclassWindow执行前窗口句柄(HWND)已经创建完成;

3. 根据创建方式的不同,虚函数PreCreateWindow可能不会调用到,(目前看,只有掉CWnd::Create/CreateEX时才会调用到);
   虚函数PreCreateWindow执行时窗口句柄(HWND)还未开始创建;
4. CWnd::OnCreate消息响应函数同样可能不会调用到(一是看你映射ON_WM_CREATE()了没,二是看你的创建方式(对子控件言));

--简单一句话总结大概是:
只有是模板(资源)创建方式,PreCreateWindow或OnCreate很可能不会被调用到,动态创建方式(Create)则相反;
无论何种创建方式,PreSubclassWindow总能被调用到;

子创建方法总结:  无论是以哪一种,PreSubClassWindow都会被调用,但是PreCreateWindow,OnCreate 未必会被调用。。。。

对于Create创建的控件,如果 PreCreateWindow 用处不大。。。。要做手脚,可以在OnCreate中。。。

或者可以在PreSubClassWindow中,      OnCreate是一个消息函数,响应WM_CREAET这个消息


三、对于控件而言,创建之后,是可以修改风格的。比如修改LisCtrl的风格,可以通过
其成员函数:CListCtrl::SetExtendedStyle函数搞定,,
m_listCtrl.SetExtendedStyle(LVS_EX_FULLROWSELECT);

这个函数的本质是一个SendMessage,
LVM_SETEXTENDEDLISTVIEWSTYLE

SendMessage(hwnd,LVM_SETEXTENDEDLISTVIEWSTYLE,LVS_EX_FULLROWSELECT,LVS_EX_FULLROWSELECT);

但是无法用SetWindowLong来修改风格

如:SetWindowLong(m_listCtrl.GetSafeHwnd(),GWL_EXSTYLE,LVS_EX_FULLROWSELECT );
这一句代码,无法做到可以选择 正行的效果




---华软网友回复---
  class="deleted_message"> 该回复于2011-12-07 09:35:10被版主删除        
华软声明:本内容来自网络,如有侵犯您版权请来信指出,本站立即删除。