MFC FAQs

MFC Tree Control: How to use 'SetItemData()' and 'GetItemData()'?

Q: How to use 'GetItemData()' and 'SetItemData()'?

A: A tree control is just a visual representation of some hierarchical data structure. You use 'SetItemData()' and 'GetItemData()' to link each tree item to a node if this data structure.

Firstly you have to define a class or a structure that holds the data for each node. For example if your tree is supposed to show a file system, the structure you define will reflect all the properties of a file, like name, size, timestamp, whether it is a directory or not, access rights and so on. The tree will display only the name. Each of the trees items will be linked to an instance of such a structure.

struct node_data
{
//...
};

'SetItemData()' allows you to attach a 'DWORD' to each item and 'GetItemData()' allows you to get that 'DWORD' back. A plain 'DWORD' isn't of much use, but luckily under Windows a 'DWORD' and a pointer have the same size, so you can cast forth and back between them.

When you add an item to the tree, you attach a pointer to a 'node_data' structure to that item:

HTREEITEM hItem = m_tree.InsertItem(/*...*/);
node_data *node = new node_data();
// Fill up the new node
node->member = value; //...
// Attach the node to the item
m_tree.SetItemData(hItem, (DWORD) node);

When you handle an operation on some item of the tree (for example selection) you retrieve the node using 'GetItemData()':

// 'hItem' is a valid iten handle
node_data *node = (node_data *) m_tree.GetItemData(hItem);

// Retrieve, set or take decisions according to the nodes
// members
if(node->member == some_value)
some_action()
;

value =
node->member;
node->member = value;

 

Note: Most of the material in this article is taken from codeguru.com

 


Recommended Reading :

MFC Tree Control: How to disable an item in Tree Control?

Q: How to disable an item?

A: Tree items do not have enabled/disabled states. That means that you can stop searching for a function called 'SetItemEnabled()', because it does not exist. You have to simulate this by your own. Let's outline what you need to do in order to 'disable' an item:

  • You need to mark that item as 'disabled'. As the tree control itself doesn't help here, you need to reserve a flag in the underlaying structure of each item. You will use 'SetItemData()' and 'GetItemData()' to set and retrieve this structure for each item.
  • You need to give some visual feedback to your user that the item is disabled. The easiest solution is to use a special (grayed) icon for the item. You can refine this approach up to changing the items color or font, as presented in this CodeGuru article.
  • You need to prevent some operations on that item, like expanding, selecting, dragging it or dropping on it. We assume that for each item you have correctly set an underlaying data structure called 'CItemStruct', and this has a boolean member 'm_bDisabled'.
    //Preventing selection: (handle TVN_SELCHANGING)
    void CYourDialog::OnSelchangingTree(NMHDR* pNMHDR, LRESULT* pResult)
    {
    NM_TREEVIEW* pNMTreeView
    = (NM_TREEVIEW*) pNMHDR;
    if
    (((CItemStruct *) m_tree.GetItemData(pNMTreeView->iNewItem))->m_bDisabled)
    {
    *pResult
    = 1;
    return;
    }
    *pResult
    = 0;
    }

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC List Control: How to correctly delete items from a CListCtrl?

Q: How to correctly delete items from a CListCtrl?

A: Unlike the 'HTREEITEM' values returned from 'CTreeCtrl::InsertItem()', the integer values returned from 'CListCtrl::InsertItem()' aren't stable. In short, this means that you shouldn't store them anywhere. If you need to find an entry again, it's probably best to simply put something useful in 'LVITEM::lParam', and search for it using 'CListCtrl::GetNextItem()'.

Having said that, one can use the following piece of code to correctly delete items from a CListCtrl:

for (int nItem = 0; nItem < m_List.GetItemCount(); )
{
if (m_List.GetItemState(nItem, LVIS_SELECTED) == LVIS_SELECTED)
m_List.DeleteItem(nItem)
;
else
++nItem;
}

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC Dialog: How to start your dialog application in hidden mode?

Q: How to start your dialog application in hidden mode?

A: If you put the function 'ShowWindow(SW_HIDE)' in your 'OnInitDialog()', it won't have any effect, because 'OnInitDialog()' always finishes with calling 'ShowWindow(SW_SHOW)'. But there is a workaround for that. Create a 'BOOL' member variable into your dialog class and set it to 'FALSE' in the constructor.

class CYourDialog : public CDialog
{
...
private:
BOOL m_visible
;
};
CYourDialog::CYourDialog(CWnd* pParent /*=NULL*/)
: CDialog(CYourDialog::IDD, pParent)
{
//...
m_visible = FALSE;
}

 

Now override the 'WM_WINDOWPOSCHANGING' message handler. Your code should look something like this to hide the dialog:

void CYourDialog::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
if(!m_visible)
{
lpwndpos->flags &
= ~SWP_SHOWWINDOW;
}
CDialog::OnWindowPosChanging(lpwndpos)
;
}

To make the dialog again visible, use the following code:

//...
m_visible = TRUE;
ShowWindow(SW_SHOW);
//...

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC Dialog: How to enable/disable the 'Close' button of your dialog at run-time?

Q: How to enable/disable the 'Close' button of your dialog at run-time?

A:

BOOL bEnable = TRUE; // To enable
BOOL bEnable = FALSE; // To disable
UINT menuf = bEnable ? (MF_BYCOMMAND) : (MF_BYCOMMAND | MF_GRAYED | MF_DISABLED);
CMenu* pSM = GetSystemMenu(FALSE);
if
(pSM)
{
pSM->EnableMenuItem(SC_CLOSE, menuf)
;
}

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC Dialog: How to add a minimize/maximize button into your dialog?

Q: How to add a minimize/maximize button into your dialog?
A:

  • At design time: use the dialogs properties in the resource editor.
  • At runtime: override the 'OnCreate()' function like this:
  • int CYourDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    if(CDialog::OnCreate(lpCreateStruct) == -1)
    return -1;
    // TODO: Add your specialized creation code here
    SetWindowLong(this->m_hWnd,
    GWL_STYLE,
    GetWindowLong(
    this->m_hWnd, GWL_STYLE) | WS_MINIMIZEBOX | WS_MAXIMIZEBOX);
    return
    0;
    }
Note: Most of the material in this article is taken from codeguru.com
Recommended Reading :

MFC Doc/View: How to modify the default 'Open' dialog?

Q: How to modify the default 'Open' dialog?

A:

  • Delete or comment the following line added in message map of CWinApp-derived class by the AppWizard:
    ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
  • Using ClassWizard map yourself ID_FILE_OPEN command

  • Write this code in ID_FILE_OPEN handler function:

  • void CMyApp::OnFileOpen()
    {
    LPCTSTR pszFilter
    =
    _T("Bitmap files (*.bmp;*.dib;*.rle)|*.bmp;*.dib;*.rle|")
    _T(
    "JPEG files (*.jpg;*.jpeg;*.jpe;*.jfif)|*.jpg;*.jpeg;*.jpe;*.jfif||");
    CFileDialog dlgFile(TRUE, NULL, NULL,
    OFN_HIDEREADONLY,
    pszFilter,
    AfxGetMainWnd())
    ;
    if
    (IDOK == dlgFile.DoModal())
    {
    OpenDocumentFile(dlgFile.GetPathName())
    ;
    }
    }

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC General: How to process command line arguments in a MFC application?

Q: How to process command line arguments in a MFC application?

A:

  • Derive a class from CCommandLineInfo, say 'CCustomCommandLineInfo'
    class CCustomCommandLineInfo : public CCommandLineInfo
  • Add virtual method 'ParseParam()'
    {
    virtual void ParseParam(const char* pszParam, BOOL bFlag, BOOL bLast);
    }
  • In 'ParseParam()', check the 'pszParam' passed. Note, that 'ParseParam()' will be called as many times as the tokens being used while launching the command line. So, if you call 'Yourapp.exe /e /o /whatever', you will see 3 calls to 'ParseParam()' each with "/e", "/o", "/whatever".
    class CCustomCommandLineInfo : public CCommandLineInfo
    {
    CCustomCommandLineInfo()
    {
    m_bExport
    = m_bOpen = m_bWhatever = FALSE;
    }

    //for convenience maintain 3 variables to indicate the param passed.
    BOOL m_bExport; //for /e
    BOOL m_bOpen; //for /o
    BOOL m_bWhatever; //for /whatever

    //public methods for checking these.
    public:
    BOOL IsExport() {
    return m_bExport; };
    BOOL IsOpen() { return m_bOpen; };
    BOOL IsWhatever() { return m_bWhatever; };

    virtual void
    ParseParam(const char* pszParam, BOOL bFlag, BOOL bLast)
    {
    if(0 == strcmp(pszParam, "/o"))
    {
    m_bOpen
    = TRUE;
    }
    else if(0 == strcmp(pszParam, "/e"))
    {
    m_bExport
    = TRUE;
    }
    else if(0 == strcmp(pszParam, "/whatever"))
    {
    m_bWhatever
    = TRUE;
    }
    }
    }
    ;
  • Instantiate an object of this class in 'InitInstance()' and parse it like below.
    BOOL CYourApp::InitInstance()
    {
    // Do all the stuff you want to do, like registering document tempates etc.

    CCustomCommandLineInfo oInfo;
    ParseCommandLine(&oInfo);
    // ....
    }

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC General: How to change frame and caption window styles at run-time?

Q: How to change frame and caption window styles at run-time?
I want to remove at run-time the window caption (title bar). I called GetWindowLong to get the old style, removed the WS_CAPTION flag, then called SetWindowLong to set the new style. But this seems to have no effect. What must be done?


A: After 'SetWindowLong()' to set the new style you must call 'SetWindowPos()' with 'SWP_DRAWFRAME' or 'SWP_FRAMECHANGED' flag set.

void CMyWindow::RemoveCaption()
{
LONG nOldStyle
= ::GetWindowLong(m_hWnd, GWL_STYLE);
LONG nNewStyle = nOldStyle & ~WS_CAPTION;
::SetWindowLong(m_hWnd, GWL_STYLE, nNewStyle);
SetWindowPos(NULL, 0, 0, 0, 0,
SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE|SWP_NOACTIVATE|
SWP_DRAWFRAME)
;
}

When using MFC, an easier way to modify window styles is to call 'CWnd::ModifyStyle()' or 'CWnd::ModifyStyleEx()' respectively.

Unfortunately, the first time programmers use these functions, most of them ignore the last parameter ('nFlags'). The solution is to pass 'SWP_DRAWFRAME' or 'SWP_FRAMECHANGED'.

If 'nFlags' is not zero, 'CWnd::ModifyStyle()'/'CWnd::ModifyStyleEx()' combine it with 'SWP_NOZORDER', 'SWP_NOMOVE', 'SWP_NOSIZE', and 'SWP_NOACTIVATE' flags, then call 'SetWindowPos()'.

The example below, shows/hides the control-menu box from title bar (adds/removes 'WS_SYSMENU' style).

void CMyWindow::ShowSystemMenu(bool bShow /*=true*/)
{
if(true == bShow)
{
ModifyStyle(
0, WS_SYSMENU, SWP_FRAMECHANGED); // show
}
else
{
ModifyStyle(WS_SYSMENU,
0, SWP_FRAMECHANGED); // remove
}
}

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :

MFC General: How to prevent a resizable window to be smaller than...?

Q: How to prevent a resizable window to be smaller than...?

A: Handle 'WM_GETMINMAXINFO' message:

void CWndDerived::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// set the minimum tracking width
// and the minimum tracking height of the window
lpMMI->ptMinTrackSize.x = 200;
lpMMI->ptMinTrackSize.y = 150;
}

 

Q: My resizable window is a dialog and I do not see 'WM_GETMINMAXINFO' in the messages list of ClassWizard. What can I do?
A: Because 'WM_GETMINMAXINFO' is by default filtered by class wizard for a 'CDialog' derived class, you can add the 'ON_WM_GETMINMAXINFO()' macro and the corresponding handler function by hand, or:

  • in MFC ClassWizard select 'Class Info' tab and choose 'Window' from 'Message filter' combo.
  • go back to 'Message Maps', select your CDialog-derived class in 'Object IDs' list and then 'WM_GETMINMAXINFO' from the messages list.

Q: My application is SDI/MDI. The required minimum size is given by the view. I handled 'WM_GETMINMAXINFO' in my CView-derived class but does not work. What I'm doing wrong?

A: A view is not responsible for sizing. Handle 'WM_GETMINMAXINFO' in the corresponing frame window:

void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
// the minimum client rectangle (in that is lying the view window)
CRect rc(0, 0, 200, 150);
// compute the required size of the frame window rectangle
// based on the desired client-rectangle size
CalcWindowRect(rc);

lpMMI->ptMinTrackSize.x = rc.Width();
lpMMI->ptMinTrackSize.y = rc.Height();
}

Q: My application is SDI/MDI. I don't want to be resizable at all.

A: Set also the maximum track size:

void CChildFrame::OnGetMinMaxInfo(MINMAXINFO FAR* lpMMI)
{
lpMMI->ptMinTrackSize.x
= lpMMI->ptMaxTrackSize.x = 200;
lpMMI->ptMinTrackSize.y = lpMMI->ptMaxTrackSize.y = 150;
}

An alternative solution is to simply remove 'WS_THICKFRAME' style in 'PreCreateWindow()':

BOOL CChildFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if(!CMDIChildWnd::PreCreateWindow(cs))
return FALSE;
cs.style &= ~WS_THICKFRAME;
return TRUE;
}

Note: Most of the material in this article is taken from codeguru.com


Recommended Reading :
Syndicate content



Flights - Arizona Pools - Car Insurance - Loans