返回首页


{S0}简介
本文介绍了一套可用于构建用户界面动态类。代码是围​​绕使用空闲池经理一个CWnd派生的控件,这有助于减少在某些UI场景中GDI资源的使用。要在行动中表现出的类,我演示MD​​I应用程序,它只是允许您打开XML文件。每个XML文件定义为一个单一的MDI子窗口的布局和UI控件的属性。虽然代码VC6,示范项目,可转换为VS 2003和VS 2005以及。UI场景
有一个共同的UI场景可能从空闲池的概念中受益的情侣。第一个例子是网络管理中的应用,使运营商能够控制许多不同类型的远程设备。每个设备都有一个可读取或近实时的参数设置。这种类型的应用的一个可能的UI模型是你的基本的MDI外壳,使您可以控制​​单个设备实例打开一个MDI子窗口。因为每个设备可能有众多的参数(几十甚至上百个),UI控件(或设备)在每个MDI子窗口组织成逻辑分组如下图所示的标签。

实施为每个设备类型的用户界面,典型的做法是创建一个单独的对话或每个选项卡的属性页的控制。这种方法是直接实现的,但它不能很好地扩展。考虑一个情况下,你需要支持200个参数设备类型。假设在设备窗口中的每个标签可容纳最多20个参数的控制布局。因此,10个选项卡或对话框,需要创建。现在,如果你认为每个参数可能需要将其自己的说明性文字标签配对,代表整个设备所需的UI控件的数量可能超过400。此外,对于某些参数,UI控件可能不能简单只要您的基本CButton的或CEdit。可以想见,第三方计ActiveX控件(您需要为您的项目使用),或总类似于Windows窗体用户控件。因此,GDI资源需要实行单一的设备窗口可能会相当高,并成为一个限制因素时,运营商需要同时打开很多这些设备上的Windows。
第二个例子是选项对话框(如在VS 2005中的"选项"对话框)。这种类型的对话,通常由一个左侧的树视图,并在右边的设置UI控件。由于在树视图中选择改变时,设置的右侧是动态变化的控制。这个UI场景实际上是非常相似的选项卡式设备窗口的第一个例子。主要区别是在选择或分组机制(例如,树与视图选择标签选择)。
{S2}CWnd的免费游泳池
的方式来减少标签设备窗口资源需求,以消除需要单独的对话框或属性页。这样就可以实现只使用一个单一的对话和实施机制,UI控件根据当前选定的选项卡显示或隐藏。相同数量的UI控件需要创建,但我们保存的需要对话框。
进一步减少资源的使用可以实现,如果我们认识到,往往在多个选项卡中的UI控件相同类型。换句话说,而不只是隐藏控件标签选择改变时,我们可以存储在一个自由,使他们当切换到不同的标签,可重复使用的池或缓存隐藏控件。这使我们能够重用"选项卡上选择的用户界面控件实例。例如,如果一个标签使用一个CButton和第二个选项卡还使用一个CButton,它应该只必要创建一个CButton的一个实例,并使用相同的用户界面的实例,这两个标签。通过这种方法,在每个设备窗口所需的UI控件可以节省显著。例如,作为一个最好的情况下,考虑10个参数分组(标签)和200个参数,每个参数代表一个TrackBar控制设备。如果我们还对每一个相应的文本标签控制的TrackBar,那么总共需要400 UI控件使用一个典型的多对话框实现。然而,如果我们从一个标签重用trackbar和标签控件下,设备窗口将需要最多20 trackbar和20个文本标签控件,从而减少资源的使用了10倍。
为了实现这一复用机制,我们首先通过定义一个CWndFreePool类,只是跟踪CWnd的实例是免费的,可用。在池中引用的每个CWnd的是搭配,显示UI控件对应的CWnd类型的字符串。例如,一个"按钮"类型的字符串表示配对的CWnd实际上是一个CButton的实例(即与BS_PUSHBUTTON风格创建的)。除了内置的MFC控件,如CButton的,空闲池,也可以参考ActiveX控件,因为Visual Studio可以生成MFC包装类是从CWnd派生的ActiveX控件。 CWndFreePool类的公共接口如下所示。

// CWndFreePool keeps references to CWnds which have been

// created but are unused (hidden). The pool maintains ownership<

/span>

// of the CWnds which are still in the pool and deletes them in

// its destructor.

class CWndFreePool

{

public:

    // Constructor / destructor.

    CWndFreePool();

     CWndFreePool();

    

    // Public methods.

    CWnd* GetWnd(const CString& strType);

    void  AddWnd(const CString& strType, CWnd* pWnd);

};

对照班
为了重用UI控件的实例,我们需要另一个节能控制的状态,然后再返回到空闲池,并为恢复状态,当控制是从池中再次获得也机制。要做到这一点,我们可以定义一个类层次平行的支持的MFC类,如CButton和CSliderCtrl控制。这个层次的基类是CWndControl和其公共接口,以供参考。你可以认为这些CWndControl类是为他们的MFC的简单包装。{C}
CWndControl派生类的实例可以创建应用程序代码,只需使用新营办商。但是,一个CWndFactory类也提供了允许创建给定一个字符串类型的CWndControl实例。这个工厂类被设计主要是为了让动态创建控件的XML规范。CWnd的集装箱
实际重用逻辑是实施CWndContainer类。这个类是动态UI层的心脏,因为它管理更新到空闲池,使用工厂类和调度事件。 CWndContainer可以被看作是一个helper类,以添加动态UI支持可连接到任何CDialog的。例如,在一个CDialog类,只需创建一个CWndContainer实例,并将它附加到这个指针。一旦容器被附加到对话框,CWndControl实例可以被创建,然后添加到容器中(如代码示例中的{A}所示)。
补充说,当一个CWndControl实例的容器使用其内部的尝试,并获得适当类型的现有的CWnd空闲池。如果找到的CWnd从池中删除,可见,CWndControl的属性,然后应用到这个CWnd实例。另一方面,在池中发现,如果没有合适的的CWnd,容器将使用工厂类创建一个新的CWnd实例。
当一个CWndControl实例从容器中删除,其关联的CWnd是分离的,隐蔽性,并返回空闲池重用。下面是CWndContainer类的公共接口,以供参考。
// CWndContainer manages a collection of CWndControl instances and

// is designed for attachment to a CDialog such as CControlDlg.

// When a control is added to the container, the free pool is used

// to acquire an appropriate CWnd for attachment to the control.<

/span>

// If none is available, the container will create a new CWnd for



// it by using the factory class. When a control is removed from<

/span>

// the container, its CWnd is detached and added to the free pool



// for later reuse.

class CWndContainer

{

public:

    CWndContainer();

     CWndContainer();

    

    // Attach to CDialog.

    void AttachWnd(CWnd* pWnd);

    void DetachWnd();

    

    // Set resource ID range for control CWnds.

    void SetResourceIdRange(UINT minResourceId, UINT maxResourceId);

    

    // Control management.

    void AddControl(CWndControl* pControl);

    void AddControls(const std::list<CWndControl*>& controlList);

    void RemoveControl(CWndControl* pControl);

    void RemoveAllControls();

    

    // Find controls.

    CWndControl* GetControl(const CString& controlName);

    CWndControl* GetControl(UINT resourceId);

    void         GetControls(std::list<CWndControl*>& controlList) const;



    // Message handling.

    BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra, 

                  AFX_CMDHANDLERINFO* pHandlerInfo);

};

事件处理
当MFC控件在对话框中创建动态(例如,通过使用新的,然后调用的Create()方法),可以截获这些控件的消息通过重写CDialog类的OnCmdMsg()虚方法。这就是为什么CWndContainer类也定义一个OnCmdMsg()方法。在任何带有附加CWndContainer实例的CDialog的,你可以重写对话框的OnCmdMsg()方法和简单的转发CWndContainer的OnCmdMsg()实现调用。容器的实施,将消息分派到适当的CWndControl储存容器内。这CWndControl然后发出一个CWndEvent通知它的每一个事件处理程序。
对于任何CWndControl实例,你可以添加一个或多个事件处理程序,将获得其相应的MFC控件发出的事件。事件处理程序对象实施IWndEventHandler接口如下所示。
// IWndEventHandler interface.

class IWndEventHandler

{

public:

    virtual void HandleWndEvent(const CWndEvent& ev) = 0;

};


事件的性质是封装的CWndEvent类:
// CWndEvent class.

class CWndEvent

{

public:

    // Constructor / destructor.

    CWndEvent(CWndControl* sender, const CString& text);

     CWndEvent();

    

    // Public methods.

    CWndControl* GetSender() const;

    CString      GetText() const;

    void         AddProperty(const CString& name, const CString& value);

    bool         GetProperty(const CString& name, CString& value) const;

};


下面的代码示例显示如何添加动态UI支持一个CDialog类。在这个例子中,我们只需添加一个"Hello World!"按钮,一个对话框。当按下按钮时,一个消息框显示在下面的截图所示。
{S3}
对话框的包含文件中的有关变化首先出现:
// Filename: MyDlg.h



...



#include "WndEvent.h"



// Forward declarations.

class CWndContainer;

class CWndButton;



// CMyDlg class.

class CMyDlg : public CDialog, public IWndEventHandler

{

    DECLARE_DYNAMIC(CMyDlg)



public:

    CMyDlg(CWnd* pParent = NULL);

    virtual  CMyDlg();



    // IWndEventHandler overrides.

    virtual void HandleWndEvent(const CWndEvent& ev);



    ...



protected:

    virtual BOOL OnInitDialog();    

    virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,

                          AFX_CMDHANDLERINFO* pHandlerInfo);

    ...

        

private:

    CWndContainer* m_container;

    CWndButton*    m_button;

    

    ...

};



...


在这里,对话框的源文件的有关变化:
// Filename: MyDlg.cpp



#include "stdafx.h"

#include "MyDlg.h"

#include "WndContainer.h"

#include "WndControl.h"



...



CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)

    : CDialog(CMyDlg::IDD, pParent)

{

    m_button = NULL;



    // Create an instance of the container

    // and attach it to the dialog.

    m_container = new CWndContainer;

    m_container->AttachWnd(this);    

}



CMyDlg:: CMyDlg()

{

    // Detach the container from the dialog

    // and then delete it.

    m_container->DetachWnd();

    delete m_container;



    // Delete the button.

    delete m_button;

}



BOOL CMyDlg::OnInitDialog()

{

    CDialog::OnInitDialog();

    

    // Create a CWndButton and set its properties.

    m_button = new CWndButton;

    m_button->SetName(_T("Button1"));

    m_button->SetText(_T("Hello World!"));

    m_button->SetLocation(CPoint(10,10));

    m_button->SetSize(CSize(100,24));



    // Attach an event handler to the button.

    m_button->AddEventHandler(this);



    // Add the button to the container.

    m_container->AddControl(m_button);



    return TRUE;  // return TRUE unless you set the focus to a control

                  // EXCEPTION: OCX Property Pages should return FALSE

}



BOOL CMyDlg::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

    // Let the container handle the message.

    if ( m_container != NULL )

    {

        BOOL isHandled = m_container->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

        if ( isHandled )

            return TRUE;

    }

    

    return CDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);    

}



void CMyDlg::HandleWndEvent(const CWndEvent& ev)

{

    if ( ev.GetSender()->GetName() == _T("Button1") )

    {

        MessageBox(ev.GetText(), _T("CMyDlg"));

    }

}



...

控制面层
对话框的例子是相当基本的,并显示如何创建一个动态用户界面。然而,为了证明空闲池机制对资源的使用效益,我们需要一种方法CWndControl实例在运行时从容器中添加和删除。这是最好的说明使用在它控制划分成组(其中只有一组控件可以一次显示)的情况下,存在一个组选择的机制(如使用树视图或选项卡控件)。为此,我已经添加了一个类实现了"控制窗口"包含的内容,可以通过XML定义的第二层。我的这个类的主要目标是显示一个非常具体的UI方案,可用于实现资源的节约。控制面类简要介绍如下。
CTreeWnd:一个树控件的CWnd包装。用来实现在控制窗口的树视图。
CListWnd:一个列表控件的CWnd包装。用来实现在控制窗口的事件区域。
CControlDlg:这是对话框类使用CWndContainer实例。它的表面创建CWnd的控制,显示,或隐藏的实际控制。
CMarkup:从本科比的 XML解析器类。这是一个易于使用的类没有外部的依赖,它只是两个源文件(版本6.5精简版版)组成。
CControlGroup:表示"控制组",这是类似于在一个文件系统中的文件夹。一个对照组可能包含其他群体,也可能包含控件(类似于文件系统中的的文件)。
CControlXml:这是XML引擎使用CMarkup来解析XML文件,并生成对照组和控制实例。
CControlWnd:一个CWnd的派生类实现一个窗口,一个树视图的左侧,右侧的内容控制组成,和一个小的事件窗口展示事件处理。这是顶级类,它是由TestFreePool演示应用程序使用。TestFreePool应用
演示项目(TestFreePool)是我最初使用Visual Studio生成一个MDI应用程序。此应用程序只允许您打开XML文件定义为MDI子窗口的UI内容。在每个子窗口,您可以访问上下文菜单,其中包含的选项,"显示CWnd的计数"。此函数计算的实际使用水平的CChildView实例(作为资源使用情况的一个粗略估计)开始的窗口CWnd对象总数。 CChildView类是由Visual Studio生成和集成与控制面层(即CControlWnd)的MDI应用程序代码的主要点。下面的截图显示,组织示范项目是如何。

下载ZIP文件中包括一个发布版本的TestFreePool应用程序。如果你想自己建立示范项目,请注意,我已经排除了两个源文件,Markup.h和Markup.cpp从zip文件中,由于许可限制。请下载从CMarkup 源代码,然后放在建设与Visual Studio之前Markup.h和Markup.cpp TestFreePool项目文件夹中的文件。如果您是使用VS 2005转换和建立示范项目,您也可能遇到Markup.cpp,725线的一个编译错误C2440。为了解决这个问题,你可以只添加(_TCHAR *)适当投以避免错误。
下图说明了每个演示应用程序的MDI子窗口的窗口层次结构。
{五}XML文件
在TestFreePool文件夹中,有三个示例演示应用程序可以通过打开的XML文件。下表介绍了每个文件还给出了一个指示,以实现资源的节约使用空闲池机制(基于总CWnd的计数)。 XML格式的选择是相当武断的 - 它基本上允许你定义一个控制组的层次结构,其中每个组可以包含零个或更多的儿童群体,零个或更多的控制。文件名说明 最大的CWnd计数不使用空闲池的情况下预计的CWnd计数 Example1.xml显示每个所支持的UI控件类型。30 41Example2.xml显示12个控制组,每组包含10个标签和10个按钮。27259Example3.xml从2005年的VS选项"对话框中显示3页。3048
注意Example1.xml最大的CWnd计数可能会有所不同,取决于如何配置您的系统(因为支持的控件之一是微软WebBrowser2 ActiveX控件)上的Internet Explorer。
下面是一个该Example2.xml文件的截图演示应用程序加载。
{中六}摘要
这篇文章的目的是演示如何动态创建UI在某些情况下,同时尽量减少资源的使用。只有有限的一组控件和属性的代码来说明这个概念,是不打算例如一个通用或完整的XML表单库等,目前支持,并且是非常简单的事件处理机制。 XML的支持,增加一条,作为一个便捷的方法,演示和测试,但不是我想要的东西,以目前的主要焦点。源代码可能会更对你有用,但如果你能适应自己的特定的应用需求。例如,您可能要添加支持MFC控件,甚至是你自己的自定义控件。在示范项目的文件夹,其中概述加入新的控制支持的步骤有一个文本文件。历史2007年1月6日,日初步修订。

回答

评论会员:yunchenran 时间:2011/12/07
当我使用的代码从]和控制在"AddingNewControls.txt"中提到的文件,我发现,一旦本集团已改变,各组的ListCtrl的是相同的!这真的让我疯了。
请告诉我如何在一组不同的,从其他群体的ListCtrl的。
我的代码如下:

void CComboListCtrl::OnContextMenu(CWnd* /*pWnd*/, CPoint point)

{

	CMenu obMenu;

	obMenu.LoadMenu(IDR_LIST_POPUP); 

 

	CMenu* pPopupMenu = obMenu.GetSubMenu(0);

	ASSERT(pPopupMenu); 

	

	// Get the cursor position

	CPoint obCursorPoint = (0, 0);

	

	GetCursorPos(&obCursorPoint);

 

	if (0 >= this->GetSelectedCount())

	{

		pPopupMenu->EnableMenuItem(ID_LST_DELETE, MF_BYCOMMAND | MF_GRAYED | MF_DISABLED); 

	}

	else

	{

		pPopupMenu->EnableMenuItem(ID_LST_DELETE, MF_BYCOMMAND | MF_ENABLED);

	}

 

	// Track the popup menu

	pPopupMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON, obCursorPoint.x,obCursorPoint.y, this);

 

	//*pResult = 0;

}


感谢您的答复〜
评论会员:会员330898 时间:2011/12/07
您好nschan,

我创建了一个XML文件与2个对照组,其中既包含多个文本编辑框。所有的编辑框可以自动填充,这样做,m_controlDlg -> SetDlgItemText(pControl> GetResourceId(),文件名),或手动输入(见下面的代码片段)。

问题是编程填充的文本框时,我切换到其他对照组,然后回到以前的对照组只有第一个文本框保持人口,反之亦然。但是,如果文本是手动输入用户从两个对照组的所有文本框保持它们之间切换的时候。伊夫加强通过的代码,但它目前还不清楚为什么这正在发生。任何建议我在做什么错呢?

// Existing code from the TestFreePoolDemo project

void CControlWnd::HandleWndEvent(const CWndEvent& ev)

{

    if ( m_listWnd != NULL && ::IsWindow(m_listWnd->m_hWnd) )

    {

        CString 

		name = ev.GetSender()->GetName(),

		txt = ev.GetText(),

		msg;

 

        msg.Format(_T("%04d, %s, %s"), m_listWnd->GetNumItems()+1, ev.GetSender()->GetName() ev.GetText());

        m_listWnd->AddItem(msg);

		

	// Code I've added for selecting fileopen dialog

	if ( name == "fn_CSVFileB_CSV" || name == "fn_ParamFileB_XML")

	{

		updateFileTB ( ev );

	}

    }

}

 

// Open file dialog and populate text edit box with file name. Text entered manually won't go through this function

int CControlWnd::updateFileTB ( const CWndEvent& ev )

{

	CString

		mess_type = ev.GetText(),

                // Get name of file dialog button, e.g., "fn_CSVFileB_CSV"

		message = _T(ev.GetSender()->GetName()),

                // Get the name of the text edit box, e.g., "fn_CSVFileTB"

                text_edit_box = getTextEditBoxName(message); 

	...

	

	CWndControl 

		*pControl = m_controlDlg->GetControl(text_edit_box);

		

	...

	

	CFileDialog dlg (TRUE, _T (ext), _T (filter), OFN_FILEMUSTEXIST | OFN_HIDEREADONLY, (LPCTSTR)szFilters);

 

	if ( dlg.DoModal() == IDOK )

	{

                CString

                    filename = dlg.GetFileName(); // Programmatically obtain file name

		...

		// This will contain the file name from the file open dialog.

                // (pControl->GetResourceId()does return the correct ID.

		m_controlDlg->SetDlgItemText(pControl->GetResourceId(), filename);

	}

 

        return 1;

}
在任何有关如何解决这个"问题"enlightement提前感谢。

加里
评论会员:AmHao 时间:2011/12/07
在主UI,我无法找到我可以改变的树控件的显示区域的controldlg大小,什么是我应该做的
评论会员:?pamire 时间:2011/12/07
RT { BR}
评论会员:pamire 时间:2011/12/07
#定义BEGIN_CLASS_DEFINE(theClass的)\
UILIB_API theClass的类:公共CWndControl \
{\
市民:\
theClass的(); \
虚拟〜theClass的(); \
\
常量CStringamp;常量的getText(){返回m_text;} \
无效的setText(常量CStringamp;文本); \
虚拟BOOL CreateWnd(的CWnd * pParentWnd,resourceId UINT); \
虚拟无效UpdateWnd(); \
虚拟BOOL OnCmdMsg(UINT的NID,INT nCode,无效* pExtra AFX_CMDHANDLERINFO * pHandlerInfo); \
虚拟无效SetControlSkin(); \
私人:\
CString的m_text;

#定义END_CLASS_DEFINE()}
/ / CWndLayout类 BEGIN_CLASS_DEFINE(CWndLayout);的CWnd * m_dialog;
STD:maplt; CString的,的CWnd * GT; dlgList;
END_CLASS_DEFINE()
/ / CWndButton类。 BEGIN_CLASS_DEFINE(CWndButton);END_CLASS_DEFINE()
/ / CWndRadioButton类。 BEGIN_CLASS_DEFINE(CWndRadioButton);BOOL m_checked;
无效UncheckLinkedControls(CONST CStringamp; exceptName);
市民:无效SetChecked(BOOL检查);BOOL的IsChecked()const的{返回m_checked;}
/ / IWndEventHandler覆盖。
虚拟无效HandleWndEvent(CONST CWndEventamp; EV);
END_CLASS_DEFINE()
评论会员:Marmouse 时间:2011/12/07
我有尝试添加"ES_MULTILINE | ES_WANTRETURN"dwStyle在Create()函数。但它不工作
评论会员:。nschan 时间:2011/12/07
亲爱的nschan:

为感谢你的伟大的动态UI文章,我真的很感激它。

这里是我的问题时,我想共创的std::该用户inputed的数据列表,没有任何方法,我能得到的所有文字,创建丝毫动态UI。我认为这蘑菇有一个方法做到这一点,因为它有那些控制指针列表或地图。

我尝试在我的计划,但它不工作,我得到了所有空字符串。
请给我一些建议,谢谢。

void CTest001Dlg::OnButton4() 

{         

   std::list<cwndcontrol*> controlList;

   m_controlFormWnd->m_controlDlg->GetControls(controlList);

   std::list<cwndcontrol*>::const_iterator iter =controlList.begin();

    

   // Try to show the text in all TextBox

   for (; iter != controlList.end(); iter++)

   {

	CWndControl* pControl = *iter;

	AfxMessageBox(pControl->GetText());

   }

}

此致,
评论会员:狮身人面像 时间:2011/12/07
您好,
有一件事对上面的代码我想问一下... ... CWndControl的基类是不会有getText()方法。只有一些派生的控件类有一个getText()方法。当你遍历控件列表中,你应该检查他们的类型使用GetTypeName(),如果类型是例如TextBox中,然后将它转换为(CWndTextBox *),然后再试图访问它的getText()方法。

对于CWndComboBox控制,它对应到ComboBox的下拉风格。因此它不接受文字输入真的只有选择已经添加编程的项目。

关于
评论会员:nschan 时间:2011/12/07
亲爱的nschan:

Apprecitate为您的答复。,
我明白我应该做的。
这ariticle是真的很好,谢谢。

此致,
评论会员:狮身人面像 时间:2011/12/07
我尝试执行一个所有者绘制按钮,但有问题的DrawItem方法所有的时间,我应该重写一个新的所有者绘制按钮类,以取代CButton的呢?或有其他的方式做呢?我希望你能理解我的英文不好
评论会员:。nschan 时间:2011/12/07
您好,
我没有写所有者绘制按钮... ...也许你可以看看以下链接,或张贴在C / MFC论坛的问题:

关于
评论会员:pretty_kiddy 时间:2011/12/07
感谢您的答复。第一,第二种方法不起作用,MSDN上说:"覆盖的DrawItem实施为所有者绘制的CButton的对象图纸。"这对CButton的,而不是为CButton的*.我使用CBitmapButton的绘制bitmapon按钮,但类只是从资源加载位图,而不是从磁盘,也许我必须写一个新的CImageButton {七}

另一个问题是,我可以在我的商业产品中使用您的密码?

无论如何,再次感谢你为你的伟大的工作
评论会员:。nschan 时间:2011/12/07
您好,
是的,你可以使用在一个商业化的产品的代码,因为代码是代码项目开放许可下发布(点击链接在文章中看到有关此许可证的更多细节)。

方面
评论会员:pretty_kiddy 时间:2011/12/07
您好,nschan

你的工作像一个Web form.it"完美的创意,我喜欢它。
在这里,我带一组作为一个Web窗体,但我如何访问元素?
正如"getelementbyid"或"getelementsbyname"功能或"FormName.Controls.Attrib ... ..." JavaScript中的相同?
因为我不明白"CWndControl"m_resourceId"如何工作。
你可以给我一个演示函数来访问动态控制?
谢谢你,最好的问候

修改:2008年3月14日(星期五),上午10:28
| nschan
评论会员:游客 时间:2011/12/07
您好,感谢了很多。主件看的代码将是:1)CControlWnd::BuildFromXml()此方法读取从一个给定的XML文件和所有的控制组定义。但在这一点上,他们是不会被添加到CControlDlg的实例。2)CControlWnd::UpdateControlDlg()这种方法被称为每当树控件选择在UI的变化。这使得确保属于选定组的控件添加到CControlDlg实例一旦控件被添加,你可以访问任何名称的控制。然后,一旦你控制,你可以得到它的MFC实例,如果你需要它。例如,如果你是内CControlWnd类,你可以调用:CWndControl*pControl=m_controlDlg-GT;GetControl("Button1的");(pControl=NULLpControl-GT;GetTypeName()=="按钮"){CButton的*pMfcButton=(CButton的*)(pControl-GT;GetAttachWnd());{BR}...}----{BR}关于
pretty_kiddy
评论会员:游客 时间:2011/12/07
嗨,nschan,非常感谢!imgsrc=http://www.orcode.com/upimg/2011_12_07_08_32_26_9.gif使用您的方法,我可以在CControlWnd类访问控制。我注意到,controls'name独特性,如果有相同名称的控件,它会共创第一个控制。但是,当我CControlWnd类的访问控制,它的失败。由于m_controlDlg是CControlWnd类的私有成员变量。所以,我添加了一个公共成员函数"GetControlByName"返回指针。------------------------------------------------------------------------{BR}市民:CWndControl*GetControlByName(CString的sControlName);CWndControl*CControlWnd:GetControlByName(CString的sControlName){CWndControl*pControl=m_controlDlg-GTGetControl(sControlName)返回pControl;}-------------------------------------------------------------------------{BR}代码运行成功。不过,我不知道类似这样的传输安全吗?最好的问候
iyranly
评论会员:游客 时间:2011/12/07
嗨,你说得对,名称必须是唯一的。但你也应该能够使用命名一样:FormA.Label3和FormB.Label3GetControlByName()方法看起来不错。我看不出什么错,就像长为NULL调用代码检查之前使用返回的指针。方面
nschan
评论会员:游客 时间:2011/12/07
您好,nschanimgsrc=http://www.orcode.com/upimg/2011_12_07_08_32_26_10.gif谢谢我希望有更多的交流,当我完成我的的代码。关于
iyranly
评论会员:游客 时间:2011/12/07
您好,我的应用程序上的左上角,有一个ListCtrl.It的工作原理像:首先,我加载一个XML文件的应用程序,然后使用CMarkup解析,解析"页面布局"ELEM时,我插入一个新项目的ListCtrl的,所以解析后,它包含一些PageLayouts。 我的应用程序右下角的角落,有一个ListView,我用它来预览所有页面,就像在您的demo.whentreewnd我选择一个项目,如选择在您的演示TreeItem。上述功能目前我已经实现了。现在那里是一个问题,当我SelectChange的ListCtrl的(也就是说我改变了当前组的的pageLayout),我想,以获得(喜欢的"本集团一个"的treeWnd项目)的电流组​​,并改变所有控件根据在XML文件中的相应的ELEM的说明。这是非常困难的,对我来说,我不知道从哪里开始,请帮助我!的问候,
iyranly
评论会员:游客 时间:2011/12/07
您好,这听起来像你的"页面布局"是我的"对照组"之一相同。你的ListView应该包含在一些窗口或视图,类似CControlWnd在演示。这将是主类,管理添加或删除选择改变的东西到你的ListView。有CControlWnd看:在演示UpdateControlDlg()。这种方法被称为时选择treewnd改变。控制仅仅是从对话框中删除,然后在新选定的组的添加。我知道你是不是使用相同的代码,但你可能需要做同样的事情。注意一件事,在我的演示-如CWndButton控制等简单的对象。他们是不实际的MFC控件。他们只包含一个控制信息,从XML文件中检索。当一个CWndButton被添加到控制对话框然而,这是一个实际CButton的控制是创建或重用。关于
iyranly
评论会员:游客 时间:2011/12/07
您好,谢谢你的答复。其实,我用这种方式来更新CControlDlg.In左视图显示控制(命名CPageLayoutView),当我SelectChange一个ListCtrl的项目,我发表名为WM_PAGELAYOUTVIEW_SELECTION_CHANGE消息,(当然,像您的演示WM_TREEWND_SELECTION_CHANGE),我SetNotifyWndCPageLayoutView.ok,现在的控制改变selectChange,但像你这样说时,它不改变页面的页面布局,它只是告诉我ControlDlg控制chenged,不是我指定的页页面布局改变。所以我觉得我selectChange的pageLayout项目时,我应该得到当前页的ID,并改变XML文件,然后再加载XML文件。现在,一切都OK,除了其数量是两次更改页面layout.For例如后,页面列表,当我加载XML的第一次,有5页(如在您的演示ControlGroup)在ListView(命名CInfoView),然后我选择一个页面,我会改变它的页面布局,此操作后,在CInfoView10页,0〜4个项目是原有的布局,最后5项修改后的布局。我只想它生成的最后五个项目。CControlWnd::BuildFromXml(CONSTCStringamp;XMLFILE),删除所有这样的项目:CListCtrl的ListCtrl的pInfoView-GT;GetListCtrl()listctrl.DeleteAllItems()//m_topLevelGroupsList.clear();//如果我加入这一行,它显示了五个原始布局。我应该在哪里修改代码。的问候,
nschan
评论会员:游客 时间:2011/12/07
现在是行之有效的,当我打电话CControlWnd:BuildFromXml(CONSTCStringamp;XMLFILE),我cleard像m_itemtogroupmap第一这样的地图。THX都是一样的。的问候,
iyranly
评论会员:游客 时间:2011/12/07
您好,nschan,我创建的用户界面,在SDI拆分应用程序窗口的左侧,有一个ListCtrl的,我加入了一些照片,然后我将拖动到一个ImageContainer属于正确的观点。他们中的一些在LbuttonUp过程中,我使用的CStatic::SetBitmap()函数设置当前ImageContainer位图,我需要传递一个CString对象的CImageContainer对象,CString对象持有的图片的路径,我draged.But然后一些thouble未来,,那里是我的代码的某些部分,请看看:无效CMyPhotosView::OnLButtonUp(UINTnFlags,口岸系统点){//.....{BR}//.....{BR}CMainFrame中*pMainframe=(CMainFrame中*)AfxGetApp()-m_pMainWnd;CEditPageView*pEditPageView=((CEditPageView*)pMainframe-GT;SplitterH2.GetPane(0,0)) (pDropWnd-GT;IsKindOf(RUNTIME_CLASS(CStatic的))) {//我draged图片的路径,strImageName=pDoc-GT;m_strDirImages"\\"pDoc-GT;m_vFileName[m_nDragIndex]HBITMAPm_bitmap;CString的strDropWndID;//得到ImageContainer的名字strDropWndID="ufdf";/*((CWndControl*)pDropWnd)GT;的GetName();*/{BR}//strDropWndID=((CWndImageContainer*)pDropWnd-GT;m_hWnd)-GT;的GetName();//我在这里不能得到ImageContainer的名称//MESSAGEBOX(strDropWndID)位置pos=pDoc-GT;GetFirstViewPosition()(POS!=NULL){的CView*PVIEW=pDoc-GT;GetNextView(POS);(PVIEW-GT;IsKindOf(RUNTIME_CLASS(CEditPageView)))//CEditPageView是正确的观点{CRECTrectImage;::GetWindowRect(pDropWnd-GT;m_hWnd,rectImage);CxImage图像(strImageName,CXIMAGE_FORMAT_BMP)image.Resample(rectImage.Width(),rectImage.Height())m_bitmap=image.MakeBitmap(pDropWnd-GT的GetDC()-m_hDC);(((的CStatic*)pDropWnd)-GT;SetBitmap(m_bitmap)){((CWndImageContainer*)pDropWnd)-GT;SetImage(strImageName)//((CWndImageContainer*)pDropWnd)-GT;SetImageSource(strImageName)}//UpdateXmlImageContent(strDropWndID,strImageName)}}}}的CView::OnLButtonUp(nFlags,点);在CWndImageContainer:无效CWndImageContainer:SetImage(/*const的CString的图像*/LPCSTR){//m_hbitmap=(HBITMAP)的LoadImage(NULL,形象,IMAGE_BITMAP,0,0,LR_LOADFROMFILE)//AfxMessageBox(图片);CRECTrectImage;CxImageximage(形象,CXIMAGE_FORMAT_BMP);ximage.Resample(今-GT。GetSize()CX,这种GT;GetSize()CY);m_hbitmapximage.MakeBitmap=(NULL)(m_attachWnd!=NULL){((CStatic的*))GT;SetBitmap(m_hbitmap)} m_imageSrc形象; UpdateWindow();}//m_imageSrc的CImageContainer.hereCString成员VAR是错误的。错误信息未处理的异常..(MFC42D.DLL):0xc0000005访问冲突。然后指出STRCORE.CPP:无效的CString::AllocBeforeWrite(INTnLen){(getData()方法-GT;nRefs-GT;1||nLenGT的GetData()-GT;nAllocLength)新年快乐,问候,