Click here to Skip to main content
15,867,977 members
Articles / Desktop Programming / MFC
Article

An Adaptable Property List Control

Rate me:
Please Sign up or sign in to vote.
4.68/5 (11 votes)
25 Apr 2003 209.1K   1.7K   83   37
An object properties list control than can change based on the objects state.
  • Download demo project - 45 Kb
  • Download source files - 19 Kb

    Sample Image - PropertyListCtrl.gif

    Introduction

    In an application I was developing, there was a need to implement some kind of user interface for changing an objects properties for different types of objects. Some objects properties are static, but there are objects whose properties are changing, reflecting their actual state. So I decided to create a Microsoft Visual Basic like control that can display different property items according to an objects state.

    Lets take a simple example. I need to describe the properties of individual items of a form. The items can display simple text, but also a concrete representation from a database. If the item displays only simple text, I do not need to edit the other parameters (object properties) that specify data field and display format.

    In the sample screen above, the Data and Data format categories will be removed from the properties list when the Data binding item is set to no.

    How it works

    The CPropertyListCtrl class implements the neccessary utility for presenting property items and user interaction.

    The CInPlaceEditImp and CInPlaceComboBox classes implement in place controls for editing item values for strings and for list items or enumerations respectively.

    The property data item classes allow for property data item manipulations.

    The CPropertyItemString and CPropertyItemList are classes for basic editing of property data values.

    The CPropertyItemCategory class contains property items of one category.

    The CPropertyItemManager is a container for all the property categories of an object.

    The CPropertyItemManagerAdaptable class supports the mechanism of adaptibility.

    How to use it

    1. Include the source files into your project.
    2. If you need to you can define your own property list item values (enumerations) derived from the class CPropertyItemList and / or implement your own custom property item value derived from the base class CPropertyItem.
    3. Implement your CPropertyItemManager derived property item manager that describes the property items of your object. If the property items can change according to the objects state, derive your property item manager from the class CPropertyItemManagerAdaptable.
    4. Use the CPropertyListCtrl control in your dialog or view and manipulate its property item manager with the SetPropertyItemManager method.

    How to implement your own property item value class

    Derive it from the base class CPropertyItem and implement its get/set methods and its virtual methods:

    • virtual void DrawValue(CDC* pDC, CRect& rect)<BR>// for drawing a property item value into the CPropertyListCtrl dc context.
    • virtual void CreateInPlaceControl(CWnd* pWndParent, CRect& rect, CWnd*& pWndInPlaceControl)
      // for creating its own suitable in place control for editing its value.
    • virtual void SetData(CWnd* pWndInPlaceControl)
      // for setting its value after the end of editing by an in place control.
    /////////////////////////////////////////////////////////////////////////////
    // CMyPropertyItem
    
    class CMyPropertyItem : public CPropertyItem
    {
    	CMyPropertyItem(const CMyPropertyItem& d);
    	CMyPropertyItem& operator=(const CMyPropertyItem& d);
    
    protected:
    	DECLARE_DYNAMIC(CMyPropertyItem)
    
    public:
    	CMyPropertyItem(MyDataType myData = INI_VALUE);
    	virtual ~CMyPropertyItem();
    
    	// Attributes
    	MyDataTyp& GetData() const;
    	void SetData(MyDataType& myData);
    
    	// Operations
    	virtual void DrawValue(CDC* pDC, CRect& rect);
    	virtual void CreateInPlaceControl(CWnd* pWndParent, <BR>                                     CRect& rect, CWnd*& pWndInPlaceControl);
    	virtual void SetData(CWnd* pWndInPlaceControl);
    
    	// Data
    private:
    	MyDataType m_myData;
    };

    And define its GET_ITEM... and SET_ITEM... macros that are used in a conjuction with the BEGIN_ITERATE_PROPERTY_ITEMS macros. For a better understanding of these look at how they are implemented in the CPropertyItemString or CPropertyItemList classes.

    How to define your own property list item value class

    You can use the predefined macros for implementing classes representing property list item values. In this examle the CMyCustomPropertyItemList is defined with two property items.

    /////////////////////////////////////////////////////////////////////////////
    // CMyCustomPropertyItemList
    
    BEGIN_LIST_ITEM_DATA_TYPE(CMyCustomPropertyItemList)
    	LPCTSTR_STRING_ITEM_DATA(_T("A string value here")),
    	ID_STRING_ITEM_DATA(IDS_STRING_VALUE_FROM_RESOURCES)
    END_LIST_ITEM_DATA_TYPE(CMyCustomPropertyItemList)

    Or you can implement your own class, derived from the CPropertyItemList class, overriding its virtual LPCTSTR GetItemData(int nItem) const function.

    /////////////////////////////////////////////////////////////////////////////
    // CMyOwnPropertyItemList
    
    class CMyOwnPropertyItemList : public CPropertyItemList
    {
    	....
    public:
    	virtual LPCTSTR GetItemData(int nItem) const;
    }

    How to implement your own property item manager class

    In order for the CPropertyListCtrl control to know what items to display, you have to implement your own property item manager describing the property items of your object. If your object property items are static you simply derive your property item manager from the class CPropertyItemManager and in the constructor declare the items using predefined macros :

    /////////////////////////////////////////////////////////////////////////////
    // CMyStaticPropertyItemManager
    
    CMyStaticPropertyItemManager::CMyStaticPropertyItemManager()
    {
     ////////////////////////////////////////////////////////////General 	
     BEGIN_PROPERTY_TAB(_T("General"), true)
        PROPERTY_ITEM(ID_PD_NAME, CPropertyItemString,<BR>                  _T("Name"), true)
        PROPERTY_ITEM(ID_PD_DESCRIPTION, CPropertyItemString,<BR>                  _T("Description"),true)
        PROPERTY_ITEM(ID_PD_BIND_DATA, CPropertyItemListYesNo, <BR>                  _T("Data binding"), true)
     END_PROPERTY_TAB()
    <BR><BR> <BR> <BR> ///////////////////////////////////////////////////////////////////////
     // Data<BR> BEGIN_PROPERTY_TAB(_T("Data"), true)
        PROPERTY_ITEM(ID_PD_DB_NODE, CPropertyItemString, <BR>                  _T("Db data node"), true)
        PROPERTY_ITEM(ID_PD_HISTORY, CPropertyItemListYesNo, <BR>                  _T("History"), true)
     END_PROPERTY_TAB()
    }

    You also need to implement get/set methods for accessing property item values of your object. For simple reference access you can use predefined macros.

    bool CMyStaticPropertyItemManager::SetData(const CObject* pData)
    {
    	const CMyData* pMyData = static_cast <const CMyData* > (pData);
    
    	BEGIN_ITERATE_PROPERTY_ITEMS()
    		SET_ITEM_STRING(ID_PD_NAME, pMyData->m_strName)
    		SET_ITEM_STRING(ID_PD_DESCRIPTION, pMyData->m_strDescription)
    		SET_ITEM_LIST(ID_PD_BIND_DATA, pMyData->m_bBindDatabaseData)
    		SET_ITEM_STRING(ID_PD_DB_NODE, pMyData->m_strDbTableColumn)
    		SET_ITEM_LIST(ID_PD_HISTORY, pMyData->m_bCreateHistoryData)
    	END_ITERATE_PROPERTY_ITEMS()
    
    	return true;
    }
    
    bool CMyStaticPropertyItemManager::GetData(CObject* pData) const
    {
    	CMyData* pMyData = static_cast <CMyData* > (pData);
    
    	BEGIN_ITERATE_PROPERTY_ITEMS()
    		GET_ITEM_STRING(ID_PD_NAME, pMyData->m_strName)
    		GET_ITEM_STRING(ID_PD_DESCRIPTION, pMyData->m_strDescription)
    		GET_ITEM_LIST(ID_PD_BIND_DATA, pMyData->m_bBindDatabaseData)
    		GET_ITEM_STRING(ID_PD_DB_NODE, pMyData->m_strDbTableColumn)
    		GET_ITEM_LIST(ID_PD_HISTORY, pMyData->m_bCreateHistoryData)
    	END_ITERATE_PROPERTY_ITEMS()
    
    	return true;
    }

    If you want to implement an adaptable property item manager derive it from the class CPropertyItemManagerAdaptable and define a virtual void OnDataChanged(CPropertyItem* pPropertyItem, CPropertyListCtrl* pWndPropertyListCtrl, int nIndex) method for changing a property items state:

    void CMyAdaptablePropertyItemManager::OnDataChanged(CPropertyItem* <BR>          pPropertyItem, CPropertyListCtrl* pWndPropertyListCtrl, int nIndex)
    {
       bool bDoChecking = false;
    
       switch(pPropertyItem->GetPropertyID())
       {
         case ID_PD_BIND_DATA:
         {
          // Yes/No item
          bool bEnableTabs;
          static_cast <CPropertyItemList*>(pPropertyItem)->GetData(bEnableTabs);
    
          // Enable/Disable tabs 1
          CPropertyItemCategory* pPropertyItemTab = GetCategoryTab(1);
    
          if(pPropertyItemTab->SetEnabled(bEnableTabs))
    	bDoChecking = true;
    			
          // Enable/Disable tabs 2
          int nItemType;
          static_cast<CPropertyItemList*>(pPropertyItemTab->GetPropertyItem(<BR>                                       ID_PD_DATA_TYPE))->GetData(nItemType);
    
          pPropertyItemTab = GetCategoryTab(2);
    
          if(pPropertyItemTab->SetEnabled(bEnableTabs && nItemType < 4))
            bDoChecking="true;" 
          } 
          break;
          case ID_PD_DATA_TYPE: { // Enumerate item 
          { 
            int nItemType; 
            static_cast<CPropertyItemList*>(pPropertyItem)->GetData(nItemType);
    
    	// For items 4 (Form) and 5 (Macro) disable tab #2, for others enable
    	CPropertyItemCategory* pPropertyItemTab = GetCategoryTab(2);
    	bDoChecking = pPropertyItemTab->SetEnabled(nItemType <4); 
           } 
           break; 
           default: 
           return; 
         } 
         if(bDoChecking) 
           CheckState(pWndPropertyListCtrl, nIndex, <BR>                  pPropertyItem->GetPropertyID());
    }

    Things to Improve

  • Eliminate flicker while showing in place controls.
  • Add further edit controls.
  • If you have any other suggested improvements, please let me know so that I can incorporate them into the next release. If you want to see how I have used this control in my projects, take a look at http://welcome.to/StefanBelopotocan.
  • License

    This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

    A list of licenses authors might use can be found here


    Written By
    Software Developer (Senior)
    Slovakia Slovakia
    This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

    Comments and Discussions

     
    GeneralNice work,thanks... Pin
    ucc80130-Jan-06 5:45
    ucc80130-Jan-06 5:45 
    GeneralScrolling with InPlaceComboBoxImp Pin
    Urban Olars13-Jun-04 10:47
    Urban Olars13-Jun-04 10:47 
    GeneralRe: Scrolling with InPlaceComboBoxImp Pin
    Urban Olars29-Jun-04 10:07
    Urban Olars29-Jun-04 10:07 
    AnswerRe: Scrolling with InPlaceComboBoxImp Pin
    BadJerry16-Jun-15 1:22
    BadJerry16-Jun-15 1:22 
    QuestionExcellent - Can it be used in a commercial app? Pin
    prcarp4-Jun-04 10:33
    prcarp4-Jun-04 10:33 
    Questionexcellent ! Will it improve ? Pin
    Gilles Diawara1-Apr-04 7:55
    Gilles Diawara1-Apr-04 7:55 
    Questionhow can I insert a control into the item? Pin
    Anonymous3-Nov-03 22:36
    Anonymous3-Nov-03 22:36 
    GeneralProblems using the control Pin
    simbakid23-May-03 5:57
    simbakid23-May-03 5:57 
    GeneralRe: Problems using the control Pin
    Stefan Belopotocan25-May-03 0:04
    Stefan Belopotocan25-May-03 0:04 
    GeneralRe: Problems using the control Pin
    simbakid26-May-03 23:01
    simbakid26-May-03 23:01 
    GeneralRe: Problems using the control Pin
    simbakid27-May-03 23:25
    simbakid27-May-03 23:25 
    Generalprograming the addition of the control Pin
    Manuel D. Jiménez23-Jan-03 6:49
    Manuel D. Jiménez23-Jan-03 6:49 
    GeneralRe: programing the addition of the control Pin
    Stefan Belopotocan23-Jan-03 21:55
    Stefan Belopotocan23-Jan-03 21:55 
    GeneralThanks, but... Pin
    Manuel D. Jiménez23-Jan-03 22:49
    Manuel D. Jiménez23-Jan-03 22:49 
    QuestionHow to use this control in docking control like workspace Pin
    Guo Yabing20-Dec-02 13:05
    Guo Yabing20-Dec-02 13:05 
    AnswerRe: How to use this control in docking control like workspace Pin
    Stefan Belopotocan23-Jan-03 21:48
    Stefan Belopotocan23-Jan-03 21:48 
    GeneralBug when more than 256 items Pin
    Mephisto7716-Oct-02 21:09
    Mephisto7716-Oct-02 21:09 
    GeneralDynamic property item insertion Pin
    27-Mar-02 5:41
    suss27-Mar-02 5:41 
    GeneralAnother properties control Pin
    14-Jan-02 3:53
    suss14-Jan-02 3:53 
    GeneralAdvertising? Pin
    David Wulff10-Feb-02 15:02
    David Wulff10-Feb-02 15:02 
    GeneralResizing Issue Pin
    gh7-Nov-01 10:55
    gh7-Nov-01 10:55 
    QuestionHow can I update data? Pin
    Mac22-Oct-01 10:51
    Mac22-Oct-01 10:51 
    GeneralExcellent Property Control Pin
    Rod Hamilton17-Sep-01 13:23
    Rod Hamilton17-Sep-01 13:23 
    Generalgood job! Pin
    Bao Nguyen30-Jun-01 10:48
    Bao Nguyen30-Jun-01 10:48 
    GeneralRe: good job! Pin
    Manuel D. Jiménez23-Jan-03 0:16
    Manuel D. Jiménez23-Jan-03 0:16 

    General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

    Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.