这个功能可以改进吗?

Can this function be improved?

我想出了以下可以正常工作的函数:

bool CChristianLifeMinistryStudentMaterialDlg::EncodeText(HWND hWnd, CString strCode)
{
    bool bHandled = false;

    map<HWND, CComboBox*> mapControls;
    map<HWND, CString*> mapControlsText;

    mapControls.emplace(m_cbMaterialAssignment1.GetSafeHwnd(), &m_cbMaterialAssignment1);
    mapControls.emplace(m_cbMaterialAssignment2.GetSafeHwnd(), &m_cbMaterialAssignment2);
    mapControls.emplace(m_cbMaterialAssignment3.GetSafeHwnd(), &m_cbMaterialAssignment3);
    mapControls.emplace(m_cbMaterialAssignment4.GetSafeHwnd(), &m_cbMaterialAssignment4);

    mapControlsText.emplace(m_cbMaterialAssignment1.GetSafeHwnd(), &m_strMaterialAssignment1);
    mapControlsText.emplace(m_cbMaterialAssignment2.GetSafeHwnd(), &m_strMaterialAssignment2);
    mapControlsText.emplace(m_cbMaterialAssignment3.GetSafeHwnd(), &m_strMaterialAssignment3);
    mapControlsText.emplace(m_cbMaterialAssignment4.GetSafeHwnd(), &m_strMaterialAssignment4);

    if (mapControls.find(::GetParent(hWnd)) != mapControls.end())
    {
        UpdateData(TRUE);
        DWORD dwSel = mapControls[::GetParent(hWnd)]->GetEditSel();

        CMeetingScheduleAssistantApp::EncodeText(*mapControlsText[::GetParent(hWnd)],
                                                    strCode, LOWORD(dwSel), HIWORD(dwSel));
        UpdateData(FALSE);

        bHandled = true;
    }
    else
    {
        map<HWND, CEdit*> mapControls;
        map<HWND, CString*> mapControlsText;

        mapControls.emplace(m_editBibleReading.GetSafeHwnd(), &m_editBibleReading);
        mapControls.emplace(m_editDiscussionVideoTheme.GetSafeHwnd(), &m_editDiscussionVideoTheme);
        mapControls.emplace(m_editDiscussionVideoMaterial.GetSafeHwnd(), &m_editDiscussionVideoMaterial);

        mapControlsText.emplace(m_editBibleReading.GetSafeHwnd(), &m_strBibleReading);
        mapControlsText.emplace(m_editDiscussionVideoTheme.GetSafeHwnd(), &m_strDiscussionVideoTheme);
        mapControlsText.emplace(m_editDiscussionVideoMaterial.GetSafeHwnd(), &m_strDiscussionVideoMaterial);

        if (mapControls.find(hWnd) != mapControls.end())
        {
            UpdateData(TRUE);
            DWORD dwSel = mapControls[hWnd]->GetSel();

            CMeetingScheduleAssistantApp::EncodeText(*mapControlsText[hWnd],
                                                        strCode, LOWORD(dwSel), HIWORD(dwSel));
            UpdateData(FALSE);

            bHandled = true;
        }
    }

    return bHandled;
}

代码简单明了。但正如您所见,我可能不得不处理组合框编辑控件或常规编辑控件。结果,我有两套相似的代码。

是否可以在不使代码过于复杂的情况下合并其中的一些代码?如果有帮助,我的项目设置为 ISO C++ 17 标准。


更新

最初我想我会尝试一个 CWnd* 指针的映射。但是后来我遇到了 CComboBoxCEdit 的两个问题。

CComboBox 使用:

CEdit 使用:

通过使用 CWnd* 的单个列表,我不再知道哪个是组合控件或编辑控件。 ----

更新

我想解决的核心问题是有一个循环而不是两个。

一种可能性是为您需要的功能定义一个接口,然后定义该功能的几个实现。添加地图以从 HWND 到达您需要的对象,然后您就可以开始比赛了:

class Writer {
    virtual DWORD getSel() = 0;
    CString* data;
public:
    Writer(CString *data) : data(data) {}

    void write(CString text) {
        UpdateData(true);
        DWORD selection = getSel();
        CMeetingScheduleAssistantApp::EncodeText(*data, text, LOWORD(dwSel), HIWORD(dwSel));
        UpdateData(false);
    }

    virtual ~Writer() = default;
};

class ComboBoxWriter : public writer {
    CWnd *parent;
    DWORD getSel() override { return parent->GetEditSel();  }
public:
    ComboBoxWriter(CComboBox &dest, CString &data) : Writer(&data), parent(dest.GetParent()) {}
};

class EditCtrlWriter : public Writer {
    CEdit *ctrl;
    DWORD getSel() override { return ctrl->GetSel();  }
public:
    EditCtrlWriter(CEdit &ctrl, CString &data) : Writer(&data), ctrl(&ctrl) {}
};

bool CChristianLifeMinistryStudentMaterialDlg::EncodeText(HWND hWnd, CString strCode) {
    static std::map<HWND, Writer*> controls {
        { m_cbMaterialAssignment1.GetSafeHwnd(),        new ComboBoxWriter(&m_cbMaterialAssignment1, &m_strMaterialAssignment1) },
        { m_cbMaterialAssignment2.GetSafeHwnd(),        new ComboBoxWriter(&m_cbMaterialAssignment2, &m_strMaterialAssignment2) },
        { m_cbMaterialAssignment3.GetSafeHwnd(),        new ComboBoxWriter(&m_cbMaterialAssignment3, &m_strMaterialAssignment3) },
        { m_cbMaterialAssignment4.GetSafeHwnd(),        new ComboBoxWriter(&m_cbMaterialAssignment4, &m_strMaterialAssignment4) },
        { m_editBibleReading.GetSafeHwnd(),             new EditCtrlWriter(&m_editBibleReading, &m_strBibleReading) },
        { m_editDiscussionVideoTheme.GetSafeHwnd(),     new EditCtrlWriter(&m_editDiscussionVideoTheme, &m_strDiscussionVideoTheme) },
        { m_editDiscussionVideoMaterial.GetSafeHwnd(),  new EditCtrlWriter(&m_editDiscussionVideoMaterial, &m_strDiscussionVideoMaterial) }
    };

    auto ctrl = controls.find(hwnd);

    if (ctrl == controls.end())
        return false;

    ctrl->second->write(strCode);
    return true;
}

总的来说并没有短很多(事实上,长度几乎相同),但其中相当多的长度是很容易忽略的样板。

您的 HWND 到 MFC 控件的构建映射看起来很奇怪。

MFC 肯定已经有那个映射了。看看这是否有帮助:https://docs.microsoft.com/en-us/cpp/mfc/accessing-run-time-class-information?view=msvc-160

基于对其中一个答案 (@vlad-feinstein) 的评论:

all HWND handles are unique system-wide

我决定可以采用更简单的方法来简化我的代码:

bool CChristianLifeMinistryStudentMaterialDlg::EncodeText(HWND hWnd, CString strCode)
{
    map<HWND, CWnd*> mapControls; // Use generic CWnd pointers
    map<HWND, CString*> mapControlsText;

    // Lookup map of controls
    mapControls.emplace(m_cbMaterialAssignment1.GetSafeHwnd(), &m_cbMaterialAssignment1);
    mapControls.emplace(m_cbMaterialAssignment2.GetSafeHwnd(), &m_cbMaterialAssignment2);
    mapControls.emplace(m_cbMaterialAssignment3.GetSafeHwnd(), &m_cbMaterialAssignment3);
    mapControls.emplace(m_cbMaterialAssignment4.GetSafeHwnd(), &m_cbMaterialAssignment4);
    mapControls.emplace(m_editBibleReading.GetSafeHwnd(), &m_editBibleReading);
    mapControls.emplace(m_editDiscussionVideoTheme.GetSafeHwnd(), &m_editDiscussionVideoTheme);
    mapControls.emplace(m_editDiscussionVideoMaterial.GetSafeHwnd(), &m_editDiscussionVideoMaterial);

    // Lookup map of text values
    mapControlsText.emplace(m_cbMaterialAssignment1.GetSafeHwnd(), &m_strMaterialAssignment1);
    mapControlsText.emplace(m_cbMaterialAssignment2.GetSafeHwnd(), &m_strMaterialAssignment2);
    mapControlsText.emplace(m_cbMaterialAssignment3.GetSafeHwnd(), &m_strMaterialAssignment3);
    mapControlsText.emplace(m_cbMaterialAssignment4.GetSafeHwnd(), &m_strMaterialAssignment4);
    mapControlsText.emplace(m_editBibleReading.GetSafeHwnd(), &m_strBibleReading);
    mapControlsText.emplace(m_editDiscussionVideoTheme.GetSafeHwnd(), &m_strDiscussionVideoTheme);
    mapControlsText.emplace(m_editDiscussionVideoMaterial.GetSafeHwnd(), &m_strDiscussionVideoMaterial);

    // Determine if the use clicked on a combo or edit control
    bool bIsComboControl = false;
    HWND hWndToUse = nullptr;
    if (mapControls.find(::GetParent(hWnd)) != mapControls.end())
    {
        bIsComboControl = true;
        hWndToUse = ::GetParent(hWnd);
    }
    else if (mapControls.find(hWnd) != mapControls.end())
        hWndToUse = hWnd;

    if (hWndToUse == nullptr)
        return false;

    // Process
    UpdateData(TRUE);

    // Get the correct selection from the control
    DWORD dwSel = (bIsComboControl) ?
                    ((CComboBox*)mapControls[hWndToUse])->GetEditSel() :
                    ((CEdit*)mapControls[hWndToUse])->GetSel();

    // Encode the text 
    CMeetingScheduleAssistantApp::EncodeText(*mapControlsText[hWndToUse],
                                                    strCode, LOWORD(dwSel), HIWORD(dwSel));
    UpdateData(FALSE);

    return true;
}