这个功能可以改进吗?
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*
指针的映射。但是后来我遇到了 CComboBox
和 CEdit
的两个问题。
CComboBox
使用:
::GetParent(hWnd)
GetEditSel()
CEdit
使用:
hWnd
GetSel()
通过使用 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;
}
我想出了以下可以正常工作的函数:
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*
指针的映射。但是后来我遇到了 CComboBox
和 CEdit
的两个问题。
CComboBox
使用:
::GetParent(hWnd)
GetEditSel()
CEdit
使用:
hWnd
GetSel()
通过使用 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;
}