简体   繁体   中英

MFC MDI Designing user preferences dialog GUI layout functionality

In this instance I am not "stuck" but looking for some 'guidance' on how to perform a GUI layout mechanism that makes sense and easy to construct. I am using a TreeControl that visually "matches" Winamp's options/preferences dialog for all the settings and program options.

TO BE CLEAR: This is not something I've ever attempted and looking for user input to help me get across the finish line.

I have 6 items in the 'tree' (the 'parent') and 5 'subitems'. I have it fully constructed and I can get the data from whatever node is selected (which I'll post below images).

I am using a "do.Modal dialog" and, when I click on the tree node, I want the right side of the dialog to update to the needed controls for that node function. The execution of controls through "show" and "hide" to me seems pretty easy. The issue I have is the how to do the visual "static" controls in the resource editor when each "node paged" controls may or may not sit on top of each other visually during design time . During run time, when each node is selected on the nodes controls will be active but during design time, I may have controls sitting on top of each other and will be a logistical nightmare trying to sort out their positions etc.

How do I resolve that aspect of building it? I think of it as a select: 'node' show: 'option page controls' so I get the logic; I'm just wondering if I should have separate "popup" pages and call those … or deal with the controls directly. Does that makes sense?

I've done some searching on how to do this, but the examples are all over the place and I figured asking here makes the most sense. I'm sure there are multiple ways to do this, I'm just looking for the shortest path and easiest to maintain and possibly expand on the options in the future.

The examples of the dialog and the source code I'm using:

我的设置对话框

Winamp 的用户首选项对话框

Here is the initialization code:

BOOL CSettingsDlg::OnInitDialog()
{
    CDialog::OnInitDialog();

    // TODO:  Add extra initialization here

    HTREEITEM hParent, hToolbars, hColorScheme, hTabStyles, hPowerUser,
        hResetApp;
                
    //HTREEITEM hCompany, hLevel, hLevelNext; // Used in core example, not needed here

    hParent = m_TreeCtrl.InsertItem((L"Preferences"), TVI_ROOT);
    hToolbars = m_TreeCtrl.InsertItem((L"Toolbars"), hParent);
    hColorScheme = m_TreeCtrl.InsertItem((L"Color Scheme"), hParent);
    hTabStyles = m_TreeCtrl.InsertItem((L"Tab Styles"), hParent);
    hPowerUser = m_TreeCtrl.InsertItem((L"Power User"), hParent);   
    hResetApp= m_TreeCtrl.InsertItem((L"Reset All Options"), hParent);
    
    m_TreeCtrl.Expand(hParent, TVE_EXPAND);
    m_TreeCtrl.SelectItem(hParent);
    GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Preferences Settings"));

    return TRUE;  // return TRUE unless you set the focus to a control
                  // EXCEPTION: OCX Property Pages should return FALSE
}

Here is the dialog framework that I'm starting from scratch with just to arrive here:

void CSettingsDlg::OnTvnSelchangedTree1(NMHDR *pNMHDR, LRESULT *pResult)
{

    //LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
    //SetDlgItemInt(IDC_TXT_TREE1, m_TreeCtrl.GetItemData(pNMTreeView->itemNew.hItem));
    //*pResult = 0;

    HTREEITEM sel = m_TreeCtrl.GetSelectedItem();
    CPoint point;
    CString str;
    GetCursorPos(&point);
    m_TreeCtrl.ScreenToClient(&point);
    UINT flags = 0;
    HTREEITEM hitItem = m_TreeCtrl.HitTest(point, &flags);
    if (hitItem && sel != hitItem)
    {
        sel = hitItem;
        m_TreeCtrl.SelectItem(sel);     
        str = m_TreeCtrl.GetItemText(sel);
        //MessageBox((LPCTSTR)str);  // Just to verify.  
    }

    if (str == "Preferences")
    {
        this->SetWindowText(_T("Preferences Settings"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Preferences Settings"));
    }

    if (str == "Toolbars")
    {
        this->SetWindowText(_T("Toolbars Settings"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Toolbars Settings"));
    }

    if (str == "Color Scheme")
    {
        this->SetWindowText(_T("Color Scheme"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Color Scheme Settings"));
    }

    if (str == "Tab Styles")
    {
        this->SetWindowText(_T("Tab Styles Settings"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Tab Styles Settings"));
    }

    if (str == "Power User")
    {
        this->SetWindowText(_T("Power User Settings"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Power User Settings"));
    }

    if (str == "Reset All Options")
    {
        this->SetWindowText(_T("Reset All Settings"));
        GetDlgItem(IDC_SETTINGS_CAPTION)->SetWindowText(_T("Reset All Settings"));
    }
    
    *pResult = 0;

}

So as shown, you can see that I have the ability to change the static caption to the "active" page node that is selected from the tree. I'm looking to solve the best way to handle the GUI elements that will go on the right side....

Some controls for example will be:

Color scheme Node: 5 check boxes for theme changing

Toolbars Node: Radio button for Docked or Floating

Power User Node: Checkbox to disable user warning within program operation

Tab Styles Node: Radio buttons to select flat, 3d, whatever.

and when the user "selects" whatever it writes it to the registry and then I call the function to read the data blah blah blah...

So that is where I'm at. Does anyone have any suggestions on a course of action, so I don't paint myself into a corner?

Although I can't actually speak for how the authors of the "Winamp" software implemented their UI, I would suggest that you consider using a property sheet for your case, where each set of controls can be implemented as separate property pages , each of which will be defined (both in the resource script and in the C++ code) in ways very similar to individual modal dialog boxes.

The 'classic' property sheet has a horizontal row of tabs (normally, at the top of the sheet) to select each page, as shown in the sample below. Indeed, some sources/platforms refer to a property sheet as a "tabbed dialog".

在此处输入图像描述

However, the new(ish) CMFCPropertySheet class allows you to replace that tab control with one of several other options, which will show as separate 'panes' (on the left-hand side of the sheet). To use one of these alternative styles, call the SetLook() member function in your constructor override with the CMFCPropertySheet::PropSheetLook_Tree enum value. The example shown in the link is not exactly what you have shown in your question, but the CMFCPropertySheet and CMFCPropertyPage classes allow many, many customizations to their appearance and style.

I have never actually used the PropSheetLook_Tree style, but the image below shows "one I made earlier" with the PropSheetLook_OutlookBar style.

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM