【发布时间】:2021-12-01 07:46:15
【问题描述】:
我有一个标准对话框资源,上面有一些无线电控件。
目前一切都以正常方式完成,因此第一个无线电被映射到int 变量。
DDX_Radio(pDX, IDC_RADIO_DISPLAY_EVERYONE, m_iDisplayMode);
DDX_Radio(pDX, IDC_RADIO_SELECT_EVERYONE, m_iSelectMode);
事情是这样的……我有这些相关的枚举:
enum class DisplayMode { Everyone = 0, Brother, Sister };
enum class SelectMode { Everyone = 0, Elders, MinisterialServants, Appointed, Custom, None };
因此,每当我需要对映射变量进行一些比较时,我都必须这样做:
示例 1:
m_iDisplayMode = to_underlying(DisplayMode::Everyone);
m_iSelectMode = to_underlying(SelectMode::None);
示例 2:
if (m_iDisplayMode == to_underlying(DisplayMode::Everyone))
bInclude = true;
else if (m_iDisplayMode == to_underlying(DisplayMode::Brother) && mapPublisher.second.eGender == Gender::Male)
bInclude = true;
else if (m_iDisplayMode == to_underlying(DisplayMode::Sister) && mapPublisher.second.eGender == Gender::Female)
bInclude = true;
to_underlying 函数是一个辅助函数,之前在 SO 上向我建议过,它非常宝贵:
template <typename E>
constexpr auto to_underlying(E e) noexcept
{
return static_cast<std::underlying_type_t<E>>(e);
}
我想知道是否可以将这些无线电控件直接映射到DisplayMode 或SelectMode 对象?因此,它不是映射到1 等,而是映射到DisplayMode::Everyone 等。这将简化此上下文中的代码并避免对所有to_underlying 调用的需要。
这是 DDX_Radio 的 MFC 源代码:
void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value)
// must be first in a group of auto radio buttons
{
pDX->PrepareCtrl(nIDC);
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
ASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
ASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON);
if (pDX->m_bSaveAndValidate)
value = -1; // value if none found
// walk all children in group
int iButton = 0;
do
{
if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
{
// control in group is a radio button
if (pDX->m_bSaveAndValidate)
{
if (::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
{
ASSERT(value == -1); // only set once
value = iButton;
}
}
else
{
// select button
::SendMessage(hWndCtrl, BM_SETCHECK, (iButton == value), 0L);
}
iButton++;
}
else
{
TRACE(traceAppMsg, 0, "Warning: skipping non-radio button in group.\n");
}
hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT);
} while (hWndCtrl != NULL &&
!(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
}
我正在尝试使用答案中的代码但收到此错误:
【问题讨论】:
-
我很确定Stan, sorry, I mean Loretta 不会喜欢这段代码。无论如何......最简单的解决方案可能是根本不将选择存储在成员变量中。相反,实现一个查询 UI 状态的函数,并将选择转换为一个作用域枚举。也可以在
DoDataExchange方法或其他一些数据交换机制中实现枚举和 UI 状态之间的自定义映射。 -
@IInspectable 如果我查询 UI 状态,那么您如何知道选择了哪个收音机? DoDateExchange 听起来很有趣。一种替代方法是我添加自己的枚举变量(未映射)并在所有单击的处理程序中手动更新该枚举。
-
该框架提供了standard DDX routines,用于在数据和 UI 之间执行双向转换。正如here 所暗示的那样,您可以实现自己的。您可以查看提供的实现以了解如何编写自定义 DDX 例程。它可能归结为执行转换的大量强制转换,但它仅限于单个函数。
-
@IInspectable 这也很有趣:codeproject.com/articles/14510/dialog-data-exchange-in-mfc
-
通过使其成为枚举类来实现,如果您的 UI 需要更改,即单选按钮顺序需要更改(技术上应该与枚举类顺序“无关”),您需要无论如何要“映射”它?这是将 UI 与枚举值紧密耦合的缺点之一(除非它们可以更改,并且它们的值永远不会在对话框之外使用,但如果不是,您可能会遇到这个问题)
标签: visual-c++ enums mfc radio-button