一般用CButton都是从工具栏中拖到Dialog上,我想动态生成CButton,用数组或者其他方式,请教如何用代码生成CButton到Dialog上,而且可以拖动,谢谢

解决方案 »

  1.   

    CButton* pbtn = new CButton;
    CRect rect(0,0,120,120);
    pbtn->Create(_T("hehe"),BS_PUSHBUTTON,rect,this,5555);
    pbtn->ShowWindow(SW_SHOW);
    记住以后要释放它
      

  2.   

    CButton* pbtn = new CButton;
    CRect rect(0,0,120,120);
    pbtn->Create(_T("hehe"),BS_PUSHBUTTON,rect,this,5555);
    pbtn->ShowWindow(SW_SHOW);
    记住用完后再delete pbtn;
      

  3.   

    你的Button是局部变量
    这个函数一完成,它就被析构了
    你应该把它设置成成员变量
      

  4.   

    不需要,把函数写到ONDRAW里就可以阿。
      

  5.   

    那样的话效率可能有点低
    同意wzhing的观点
      

  6.   

    那么显示的CButton如何再让它移动和放大缩小呢?我有这样的想法,当鼠标点击后delete当前的CButton换成一个矩形区域,然后对矩形区域进行操作,确定后取得大小,然后再show一个CButton,大家认为呢,怎么做比较好呢,谢谢
      

  7.   

    移动可以用MoveWindow
    发大缩小,可以用SetWindowPos
    因为CButton继承了windows类
      

  8.   

    MoveWindow可以让显示的CButton移动和放大缩小
      

  9.   

    是这样的,我所需要的只是Button的一些属性,比如位置信息等,用CButton只是为了方便地实现拖动和放大缩小,而不用像图形系统那样做了,这些位置信息我自己保存下来,有一个数据结构对应CButton的信息,大家认为这样做好不好,请指点。
    另外,如果我从文件读入Button属性信息,在界面显示CButton,那如果鼠标点中一个Button,我怎么知道是哪个,这如何设计?
      

  10.   

    将Button的ID连续,然后使用ON_COMMAND_RANGE。
      

  11.   

    ON_COMMAND_RANGE是什么事件啊,如何使用?
      

  12.   

    另外我还想问一下,如何传递鼠标消息呢,因为我想把工具条做成一个COM组件,存在两方面的鼠标事件,一个是在工具栏中的鼠标点击事件,一个是在绘图区的鼠标事件,这如何传递呢?
      

  13.   

    ON_COMMAND_RANGE是ON_COMMAND的范围版,都是对WM_COMMAND菜单消息的响应宏,如果使用CButton将不会生成WM_COMMAND消息,因此ON_COMMAND_RANGE没用要动态生成一个CButton控件不需要像楼上几位的大费周章,只需在你的CDialog的派生类中定义一个CButton的成员变量,再在你的CDialog的派生类的OnInitDialog(好象是这个名字,记不到了)中调用CButton成员变量的Create即可,也无需调用ShowWindow对于你的Button的属性信息,我没有看懂.你的意思是说用一个CButton控件代表一块矩形区域,到时候用鼠标拖动这个按钮控件,还可缩放?因此就可通过这个按钮控件来编辑它所代表的矩形区域?如果是这样,则你完全不应该使用CButton,而应使用一个叫做C什么Rect(真是非常抱歉,这个类的类名实在是记不起来了,你只有查MSDN了,我手边没有资料)的MFC提供的以支持OLE项目的拖放操作的类,其提供了八个小方块以拖动所画的矩形,非常方便
      

  14.   

    我的意思是这样的,自己定义一组数据结构:例如MButton,MList等,包含一些属性,因为要使得用户界面友好,所以在界面操作上调用CButton,CList与之对应,因为可以使用CButton,CList的相关方法,在取得CButton,CList的属性后,我把这些信息存到对应的MButton,MList中,这样应该方便一点(我是这样想的)。另外我还把MButton,MList等的信息存到文件,这样以后如果读文件的话,可以通过对应的MButton,MList动态生成CButton,CList。我就是不太明白如何把消息事件对应过去.
    因为MButton,MList等都是在工具栏上的(是以个com),当用户点击工具栏中的某一项时开一个MButton的链表结点,当用户在绘图区中操作时生成一个对应的CButton链表结点,我就是不知道其中的消息如何传递。我设计的数据结构是一个多层链表,在最外层的Linklist中存放MButton对象结点和CButton对象结点的指针,该指针分别指向MButton,CButton对象,以这样的形式来管理,谢谢。应该说如果是一般的MFC程序应该是比较容易的,但是现在要用COM做(我刚开始接触,有点不明白),还请各位指点,谢谢
      

  15.   

    ON_COMMAND_RANGE(IDC_BUTTON1, IDC_BUTTON2, OnButton)void CDiaDlg::OnButton(int nID)
    {
    CString str;
    str.Format("你按下的按钮ID是%d", nID);
    AfxMessageBox(str);
    }
      

  16.   

    还是不大清楚你的意思,你是说MButton(或MList)这个类中的某些成员变量的意义和一个CButton(或CListCtrl)控件中的某些属性非常巧的相同或相近,以至于你觉得使用一个CButton(或CListCtrl)控件实例来作为一个MButton(或MList)实例的表现形式比较好?
    如果是这样,则每一个MButton(或MList)的实例都对应着一个控件窗口(CButton或CListCtrl)?如果是上面的意思,且MButton(或MList)的实现又基于COM技术,则应如下:
    你肯定有一个类似IDrawingObject的接口,实现MButton(或MList)实例的COM组件都支持IDrawingObject接口(专用于显示对象)、IDrawingXXX(专用于编辑对象,由IDrawingObjectView接口调用,XXX表示具体的对象,如IDrawingObjectButton、IDrawingObjectList等)和IPersistStreamInit接口(用于序列化),实现MButton(或MList)编辑的COM组件都支持一个类似IDrawingObjectView的接口,以提供对此类数据对象的编辑。IDrawingObjectView接口应有如下类似功能函数的定义:
    HRESULT CreateControlWindow( [out] HWND *pHWnd );  // 创建提供对其相对应的数据对象的编辑窗口控件的窗口句柄,如CButton::m_hWnd、CListCtrl::m_hWnd
    HRESULT HandleNotifyMessage( [in, out] IDrawingObject, [in] WPARAM wParam, [in] LPARAM lParam );  // 因为你首先可以确定一定使用控件来编辑数据对象,而你希望能处理控件生成的通知消息,所有控件生成的通知消息(如BN_CLICKED、LVN_SELCHANGED等)都是向父窗口发送WM_NOTIFY窗口消息(其参数格式请参阅MSDN)。因此在你的框架程序中,既拥有CFrameWnd派生类的工程中,响应WM_NOTIFY消息,通过获取发送消息的控件的ID,在一个事先定义好的列表(建议使用映射,即CMap)中查找,得到其对应的IDrawingObject接口指针,调用在框架程序初始化时就以生成的IDrawingObjectView的HandleNotifyMessage函数以编辑相对应的数据对象。在HandleNotifyMessage的实现中,应该通过调用QueryInterface来获得IDrawingXXX接口指针以编辑数据对象。在此,上面的两个函数可认为是IDrawingObject类(实现IDrawingObject的COM组件的类型信息)的静态成员函数,起功能辅助作用。如果嫌麻烦,还可以如下,不过建议不要使用,因为如果如此则只能使用MFC来创建实现IDrawingObject等接口的COM组件了,且不可发生跨边界调用现象,不过程序员感觉舒畅。仍象上面一样提供接口支持,不过IDrawingObjectView不需要那两个函数了,替换为如下函数
    HRESULT GetClassRuntimeInfo( CRuntimeClass *pClass );  // 原来对CreateControlWindow的调用就可替换为对pClass的CreateObject的调用,而对原来的HandleNotifyMessage的调用则可通过在你的COM组件的工程中派生一个控件类(如从CButton、CListCtrl派生),在其中响应消息反射,在反射消息的响应中编辑与其绑定的数据对象,不过则又需要提供另一个基类,如CBase,每个派生的控件类亦从CBase派生,以支持绑定数据对象的功能(void SetDataObject( IDrawingObject *pObj ); ),而基本框架在通过pClass的CreateObject的调用或的CObject*的时候,就static_cast将CObject*转成CBase*并进行绑定,不过建议在static_cast之前应先断言一下。使用此法,上面的GetClassRuntimeInfo的声明将不能写成IDL语言,因为CRuntimeClass只是MFC定义的一个类,因此不能通过MIDL编译生成代理占位程序,因此不能跨边界调用(即只能以InProc的形式加载COM组件,当然,如果你自己编写代理占位程序则不存在这个问题)。所以原本MIDL生成的.h文件现在得自己生成,可简单的如下:
    struct IDrawingObjectView : public IUnknown
    {
        HRESULT GetClassRuntimeInfo( CRuntimeClass *pClass ) = 0;
    };
      

  17.   

    对了,我正是这个意思,多谢大侠指点(虽然有点不懂,但是我会认真学习的:)),不过还有一个地方我比较迷惑,就是我的链表的维护在那里做比较好呢,在COM中还是不在COM中维护?但我总觉得这样不妥?
      

  18.   

    不应在COM组件中,因为COM组件只是代表一个对象,而装载这个对象的容器可以是队列,链表,映射等各种数据结构,如果在COM组件中进行容器的维护,则显然有违面向对象的原则,COM组件代表的对象没有权利决定自己应放在哪种容器中,它只代表一个对象