HotProp Control

Environment: VS6/.NET, Windows 98/Me/2000 and XP

New features

Version 1.8
- Minor bugs fixed

Version 1.7
- Showing and hiding properties
- Bar style properties

Version 1.6
- Support for custom drawn properties
- New property types: button and enum

Version 1.5
- Improved appearance, including rolling menus, flat style, gradient fill and XP-like item highlighting
- New splitter window included

Overview

The HotProp Control was designed for applications that need a flexible, modeless property window. There are many traditional solutions, similar to the property list in Visual Basic. HotProp has a much more modern look, and it has also an improved functionality. You don't have to select an item and click once again to open the combo or edit the property. HotProp doesn't have any focus and item selection; instead, it uses the hot tracking technique. A border is drawn when you place the mouse above an item and you can open the popup list, toggle the item, or start in-place editing with just a single mouse click. The control also supports keyboard shortcuts for each property.

There are six types of properties available:

  • toggle—the user can switch between two values, eg. No and Yes
  • list—there is a number of options, which can be selected using a popup list
  • enum—similar to list, but there is no stringarray object (useful for owner drawn properties)
  • button—simple button, which can be pressed
  • string—any string can be entered (with a specified length limit)
  • integer—a number in a specified range can be entered

Each property has an identifier. It can be any number, provided that it's unique for each property diplayed at the same time. The identifier is passed as the first argument to most of the functions. The name of the property is what is displayed on its bar, it can have an underscored mnemonic marked with the '&' sign. The control has an image list; images can be displayed to the left of each property's name.

Properties have two values, a number and a string, connected to each other. The string is always what is displayed in the control. The numeric value is 0 or 1 for a toggle, index of the selected option for a list and the entered value for an integer propetry. When the numeric value is set, the string is updated automatically (either to display proper option for a toggle/list, or the formatted number). A negative value can be given, causing the string to be cleared (it's meant to be an undefined state of a property).

Properties can be added at the bottom or inserted after a specified one. You can remove individual properties or all at once. Remember that these operations don't update the control to avoid flickering when you remove and add many properties. You have to call Update() after you add or remove properties to let the control update its size and redraw itself. You don't have to call it when you change properties (name, value, state etc.). The name and image index of each property can be changed.

Each type of property has specific information that you can change by using the following functions:

  • toggle—the negative and positive strings can be changed by using SetPropToggle()
  • list—the options are stored in a CStringArray object that can be retrieved using GetPropStringArray() and modified whenever you need
  • enum—the number of entries in the list can be changed with SetPropLimit()
  • string—the maximum length of text can be specified with SetPropLimit() (default is 1000)
  • integer—the min and max value can be changed with SetPropLimits() (default is 0 to 1000)

Note that the value of the property is not changed automatically when you call these functions.

Another useful feature of HotProp is the ability to lock or disable individual properties. A locked property is read-only and a small lockpad appears to the right of its bar. When a property is disabled, its name and icon is grayed and no value is displayed.

In version 1.6, some basic grouping abilities have been added. You can hide and show individual properties and whole ranges of properties instead of creating and removing them every time. Hidden properties still remember their values and can be modified. Some properties may have a special "bar" style, useful for separating groups of items.

Project & Settings

Add the following files to your project:

  • HotPropCtrl.cpp/.h
  • HPDynEdit.cpp/.h
  • HPPopList.cpp/.h (these are needed by the control)
  • HCSplitWnd.cpp/.h (if you use CHPSplitWnd)

Link your application with msimg32.lib. The control uses the GradientFill function from msimg32.dll.

Some visual settings of the control can be changed by commenting out the macros in HotPropCtrl.h. The OfficeXP-like style can be used either when Windows XP is detected (default style otherwise) or on all systems (or never).

Using in a Splitter Window

The simplest way of creating the HotProp control is to create a static splitter window with the application's view in one pane and the control in the other pane. It doesn't hide the view and it's much simplier than using control bars, so I used this method in the demo program. I wrote a class extending the standard splitter window—CHPSplitWnd. It can be used in the static mode only. It can display the contents of views when dragging instead of a black stripe (depending on system settings), and uses standard system cursors. If the splitter contains two views (vertical or horizontal), both views are resized proportionally when the window size is changed.

  1. Add the splitter window to CMainFrame. You can use the original CSplitterWnd instead of my class.
  2.    CHPSplitWnd m_wndSplitter;
  3. Create the OnCreateClient() virtual function to create static splitter, like this:
  4. BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT lpcs,
                                     CCreateContext* pContext )
    {
       if (!m_wndSplitter.CreateStatic(this, 1, 2))
          return FALSE;
    
       m_wndSplitter.SetInitialRatio(0.75);    // left pane is 75%
                                               // wide
    
       if (!m_wndSplitter.CreateView( 0, 0,
                                     RUNTIME_CLASS(CHotPropView),
                                     CSize(100, 100),
                                     pContext)
          || !m_wndSplitter.CreateView( 0, 1,
                                       RUNTIME_CLASS(CHotPropCtrl),
                                       CSize(100, 100),
                                       pContext))
       {
          m_wndSplitter.DestroyWindow();
          return FALSE;
       }
    
       return TRUE;
    }
    
  5. You can add a public method to CMainFrame for easy access to the HotProp control from your view:
  6. CHotPropCtrl& CMainFrame::GetHotProp()
    {
       return *((CHotPropCtrl*)m_wndSplitter.GetPane(0, 1));
    }
    
  7. Since the control is not a view, the framework doesn't destroy it automatically. You have to do it manually; for example, in OnDestroy():
  8. void CMainFrame::OnDestroy()
    {
       GetHotProp().DestroyWindow();
    
       CFrameWnd::OnDestroy();
    }
    
  9. Once the control is created, you need to init the image list. It's best to do it in main frame's OnCreate. The images should be 16 x 16 pixels. You can call GetImageList() and init the list manually or use the following function to load the bitmap:
  10.    GetHotProp().LoadImages(IDB_IMAGES, RGB(255,0,255));

Using in a Modeless Window

You can create the HotProp control as a child of a modeless dialog, a property page, docking control bar, and so forth. All you have to remember is that the CHotPropCtrl object has to be allocated on the heap, since it deletes itself in PostNcDestroy().

  1. Add a pointer to the parent window's class:
  2.    CHotPropCtrl* m_pHotProp;
  3. Add the following code to your window's OnCreate() or OnInitDialog():
  4.    m_pHotProp = new CHotPropCtrl;
       m_pHotProp->CreateEx( WS_EX_STATICEDGE,
                             NULL,
                             NULL,
                             WS_VISIBLE|WS_CHILD,
                             CRect(...position...),
                             this,
                             ...control ID...);
    

    In this case, the control is destroyed automatically with the parent window. Don't delete it manually.

Interaction with the View

HotProp control is designed for SDI and MDI applications. By default, the control sends the notification to the active view. You can change this by overriding the NotifyView() virtual function. The notification is sent whenever a property is changed by the user (or a button property is clicked).

  1. To handle notifications, add the following line to your view's header file:
  2.    afx_msg void OnHotPropUpdate(int nID, int nValue);
  3. Add the following entry to the message map:
  4.    ON_MESSAGE(HPCM_UPDATE, OnHotPropUpdate)
  5. Implement OnHotPropUpdate(), which gets the identifier of the property that was changed and its new numeric value. You can safely modify any properties in the message handler. If you add or remove properties, don't forget about calling Update().
  6. void CYourView::OnHotPropUpdate(int nID, int nValue)
    {
       CHotPropCtrl& prop =
          ((CMainFrame*)AfxGetMainWnd())->GetHotProp();
    
       // apply changes to the document
    }
    
  7. To handle keyboard mnemonics, you can create a WM_CHAR handler in your view's class. Pass the character to the ProcessKey() function.
  8. void CYourView::OnChar( UINT nChar,
                            UINT nRepCnt,
                            UINT nFlags ) 
    {
       CHotPropCtrl& prop =
          ((CMainFrame*)AfxGetMainWnd())->GetHotProp();
       prop.ProcessKey(nChar);
    }
    

Custom Drawn Properties

Properties of all types can be custom drawn. It means that instead of drawing the text value, HotProp calls the DrawCustomItem() virtual function. You can override it in your class to implement drawing. By default, it sends a HPCM_DRAWCUSTOM message to the active view, so you don't need to subclass anything.

Use SetCustomProp() to make a property custom drawn. You should give it a non-zero code that is passed to your drawing procedure. Giving it a code of 0 restores the standard way of drawing. If several properties are drawn the same way, you can assign them the same code. You should only draw the value itself; the control handles the background and frames for you. You can use GetImageList() if you want to draw images.

Custom drawn properties can be used with lists—the items are drawn using the same function. If you don't need a string array associated with the property, you can use the enum type instead of a list. Just set the number of entries and draw whatever you need.

  1. Add the following line to the header file of your view:
  2.    afx_msg void OnHotPropDrawCustom( int nCustom,
                                         CHotPropCtrl::CustomItem*
                                         pItem);
    
  3. Add the following entry to the message map:
  4.    ON_MESSAGE(HPCM_DRAWCUSTOM, OnHotPropDrawCustom)
  5. Implement OnHotPropUpdate(), which gets the custom code and a stucture containing the DC, item rectangle, identifier, and values to use. They are not always the current values of the property—the list uses custom drawing on all items.

    void CYourView::OnHotPropDrawCustom( int nCustom,
                                         CHotPropCtrl::CustomItem*
                                         pItem)
    {
       CHotPropCtrl& prop =
          ((CMainFrame*)AfxGetMainWnd())->GetHotProp();
       CDC& dc = *pItem->m_pDC;
       CRect rcItem = pItem->m_rcRect;
    
       switch (nCustom)
       {
          // draw item
       }
    }
    

Visit the author's home page at http://www.mimec.w.pl.

Downloads

Download demo project - 57 Kb
Download source - 18 Kb


Comments

  • New version available

    Posted by Legacy on 09/05/2003 12:00am

    Originally posted by: Michal Mecinski

    The new version of this code is available on my homepage (in the Articles section):

    http://www.mimec.w.pl

    I will post it to CodeGuru, but I'm already waiting for the current updates to be published :).

    In the new version, all reported bugs are fixed and scrolling support for the pop-list is added as requested.

    Regards,
    Michal

    Reply
  • Pop list too big for screen

    Posted by Legacy on 09/04/2003 12:00am

    Originally posted by: S Johnson

    We are trying to use the List control, similar to the List demo in HotProp sample program. In some cases we have more data than can fit on a single screen. The list box grows right off the screen, you can up arrow and the selection disappears off the screen and keeps going. If you tab off it will select the data where it was. Is there any way to get this to not grow off the screen & scroll on the list? It works great if you have limited choices, but this isn't always the case.

    Reply
  • Deleting.. m_pEdit...

    Posted by Legacy on 05/22/2003 12:00am

    Originally posted by: Embistel

    In...
    void CHotPropCtrl::OnEndEdit(WPARAM bDone, LPARAM)
    may have " delete m_pEdit " but this method.. Can
    delete object before call DestoryWindow..

    Folowing code... is working...(checked by BoundChecker)

    void CHPDynEdit::OnKillFocus()
    {
    GetOwner()->SendMessage(HPEM_ENDEDIT, m_bDone);
    DestroyWindow();
    // Add this
    delete this;
    }

    hmm.. But, .. Perhaps It need another method ..
    "Object's Suicide"

    Reply
  • VC++.Net Error C2440 !!!!!!

    Posted by Legacy on 02/14/2003 12:00am

    Originally posted by: M.Abolghasemi

    Thank you for your nice code!
    But when i want to compile the demo program in VC++.Net,
    I have many errors for WM_MESSAGE such as :

    error C2440: 'static_cast' : cannot convert from 'void (__thiscall CHotPropCtrl::* )(int,CHPPopList::DrawInfo *)' to 'LRESULT (__thiscall CWnd::* )(WPARAM,LPARAM)'

    Please help me.
    Thanks

    Reply
  • HPPopList Problem....

    Posted by Legacy on 12/09/2002 12:00am

    Originally posted by: �εⓓJοΟη

    Hi again! :)
    
    I created two hotprop pane in a frame.
    ------------------------
    | | | |
    | | | |
    |Normal|Hotprop|Hotprop|
    |view |Ctrl |Ctrl |
    | 1 | 2 | 3 |
    | | | |
    |-----------------------

    And I added a 'list prop' property in the No.2 pane.
    Clicked by user, the list prop should be expanded and shows all items.
    As you know, it works well. :)

    But unfolding the list prop, I clicked the No.3 pane.
    The list didn't fold its items.
    (Clicking the No.1 pane works well!)

    So I added two lines to the beginning of the function 'OnLButtonDown' of the class 'CHotPropCtrl'.

    void CHotPropCtrl::OnLButtonDown(UINT nFlags, CPoint point)
    {
    //******** added by Redjoon **************
    if(m_nPop == -1)
    SetFocus();
    //****************************************

    if (m_bLocked || m_nPop>=0)
    {
    int nPop = m_nPop;
    ........
    ........
    ........
    }

    Please check whether the code is a proper solution or not.
    This problem is not an ordinary application either. ;)

    Reply
  • Vertical Scroll Bug!!

    Posted by Legacy on 11/26/2002 12:00am

    Originally posted by: �εⓓJοΟη

    --------------------- from the MSDN -----------------------
    
    The WM_VSCROLL message carries only 16 bits of scroll box
    position data. Thus, applications that rely solely on
    WM_VSCROLL (and WM_HSCROLL) for scroll position data
    have a practical maximum position value of 65,535.
    -----------------------------------------------------------

    I have added many props in my program and found a bug above.
    To get the 32-bit position of the scroll box, add some codes
    below to the method 'OnVScroll' of the class 'CHotPropCtrl'.

    void CHotPropCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
    .......
    .......
    .......

    case SB_THUMBTRACK:
    //*********** Bug Fixed(16bit nPos to 32bit) by Redjoon **********************
    SCROLLINFO si;
    ZeroMemory(&si, sizeof(SCROLLINFO));
    si.cbSize = sizeof(SCROLLINFO);

    if (!GetScrollInfo(SB_VERT, &si, SIF_TRACKPOS))
    return; // GetScrollInfo failed

    nPos = si.nTrackPos;
    TRACE("%u\r\n", nPos);
    //*****************************************************************************
    m_nYPos = nPos;
    break;
    ..........
    ..........
    ..........
    }

    Thank you for sharing your nice hotprop control!!!

    Reply
  • Have a BUG

    Posted by Legacy on 02/06/2002 12:00am

    Originally posted by: Mark

    Don't Delete m_pEdit&m_pList pointer;

    Reply
  • Please help me

    Posted by Legacy on 01/29/2002 12:00am

    Originally posted by: Samad

    Can you tell me that how we learn VC++ in order to create such custom controls??
    I am using VC++ for 2 years using MFC approach. I can create application programs quickly using framework and controls provided by MFC. But when it comes to create a custom control, I can't do it.
    Please tell me that how and from where we take help in order to create custom controls

    Reply
  • Roll Up/Down & Any Control Adding Support.

    Posted by Legacy on 01/28/2002 12:00am

    Originally posted by: guest

    Need!

    Best Regards.

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: August 14, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Data protection has long been considered "overhead" by many organizations in the past, many chalking it up to an insurance policy or an extended warranty you may never use. The realities of today make data protection a must-have, as we live in a data driven society. The digital assets we create, share, and collaborate with others on must be managed and protected for many purposes. Check out this upcoming eSeminar and join eVault Chief Technology …

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds