Pop-up controls anywhere

Sample Image

Environment: VC6, 95/98/NT4

The CPopup class

This class allows you to display controls as popup.
A Popup control is visible only when it has the focus and it can be displayed outside its own frame.

For example, you can display a treectrl under a button. See the PopupSample application to see other uses of this class.


The CPopup class derives from CMiniFrameWnd. This is the same-based frame than floating toolbar. This class allows a CFrameWnd or a CMDIFrameWnd to keep activated when a CMiniFrameWnd becomes active. It seems to have 2 active frames at the same time.
Unlike CMiniFrameWnd, CPopup has no title and no border. It’s just a frame that contains controls called ‘popped’ controls.

The simplified class declaration

    class CPopup : public CMiniFrameWnd
        bool Display (CWnd* pControl, CWnd* pCaller, CRect& rcCaller, IPopupCtrlEvent* pEvents = NULL);

        CPopup ();
        virtual ~CPopup () {};

        void EndPopup (bool bAbort = false, bool bSetFocus = true);


How to use this

You have to create dynamic instances because destruction is automatic.
The Display method is the unique public method of the class.
After creating a CPopup object (by the CreateObject runtime method), just call this method to pop-up your control.

    bool CPopup::Display (CWnd* pControl,
                          CWnd* pCaller,
                          CRect& rcCaller,
                          IPopupCtrlEvent* pEvents = NULL);

The first parameter is the control you want to popup. You can specify listbox, listctrl, treectrl, formview, activex, …

The second parameter allows you to specify a ‘caller’. It’s used to determine the parent frame of the popup. This object will also be used at the end of popup operation to set focus on it. You can omit it by specifying NULL.

The CRect parameter is the rectangle that specifies the position of the popup in screen coordinates. It may be the rectangle of the caller (as pushbutton) or the rectangle of an item (as toolbar button). It’s not just a point because the code applies a little algorithm for best placement of the popup :
By default, the popup is at left and bottom corner of the rectangle, but if there is not enough place to display entirely the control, it can be align at the right side and/or the top side. See the comments into the code.
The size of the popup is the control size before the Display call; it’s not the rectangle size.

The last parameter is a pointer to an interface, which defines some callbacks. See description below.

The method returns a Boolean value that indicates if the popup control is correctly displayed or not. So you may just do a VERIFY() with it.

The IPopupCtrlEvent interface

    interface IPopupCtrlEvent
        virtual bool OnInit () = 0;
        virtual void OnShow () = 0;
        virtual void OnHide (bool bAbort) = 0;
        virtual int OnKeyDown (UINT nChar, UINT nRepCnt, UINT nFlags) = 0;
        virtual int OnLButtonDown (UINT nFlags, CPoint point) = 0;
        virtual int OnLButtonUp (UINT nFlags, CPoint point) = 0;
        virtual IPopupCtrlEvent* GetInterfaceOf (HWND hWnd) = 0;

Most of controls you want to popup have to implement this interface (which is not a COM interface !). It’s not absolutely necessary, but strongly recommended for correct behaviors.
This interface defines a set of callbacks called by CPopup and implemented by each ‘popped’ controls.

The OnInit callback is called at the beginning of CPopup::Display method. It allows control to modify itself before being popped.

The OnShow callback is called just after the control becomes visible. Controls can set focus on it (it’s not automatic)

The OnHide callback is called when the popup is finished but before it become invisible. The bAbort parameter informs control if the selection was cancelled (by <Escape> key for example)

The three next callbacks are called when some key and mouse events occur on the popped control. They are used to determine when the popup action is finished (by clicking on list item, by pressing <Return> key, …). See the sample application for some examples of implementation.

The last callback : GetInterfaceOf is used when you pop-up several controls at the same time (In the sample application see the CMySplitterWnd class).
With the CPopup Display method, you can declare only one control to be popped. In the case you popup a dialog (via CFormView), all controls can act to close the popup. So the GetInterfaceOf callback gives to the master popped control (the declared control) the possibility to dispatch actions to child controls.


Download demo project – 42 Kb

Download source – 4 Kb


More by Author

Must Read