我正在开启一个对话框,在启用确定按钮之前必须满足几条规则。
目前,页面上的任何操作(例如输入数据或从下拉列表中选择项目(以及其他内容))都会调用一个名为ProcessEvent()的函数 - 此函数处理所有逻辑,并启用或禁用“确定”按钮。
我的问题是我发现难以使规则简洁易懂。
有些规则可以通过对话框上的另一个操作来否定,我现在已经结束了if else语句到处或者难以阅读和跟随&延伸。
下面的代码是问题的简化,但很好地证明了这一点。如何更好地处理这个问题(如果可能的话)
bool CWorkstation::ProcessEvent(void)
{
UpdateData();
CharCount = GetDlgItemInt(IDC_CharCount, NULL, FALSE); //get latest
if ( IsDlgButtonChecked(IDC_USEDBNAME))
{
if (!IsDlgButtonChecked(IDC_MAXDBNAME))
{
EnableNext(TRUE);
}
}
if (IsDlgButtonChecked(IDC_MAXDBNAME) && CharCount)
{
if (IsDlgButtonChecked(IDC_USEXMLNAME))
{
if ( PrefixName.IsEmpty() )
{
EnableNext(FALSE);
}
else
{
EnableNext(TRUE);
}
}
}
if (IsDlgButtonChecked(IDC_USEXMLNAME) && PrefixName.GetLength() > 1)
{
EnableNext(TRUE);
}
if ( IsDlgButtonChecked(IDC_WSAUTONAME) || IsDlgButtonChecked(IDC_RENAMEIFDUP))
{
// TRACE("IDC_WSAUTONAME is Checked\n");
if ( IsDlgButtonChecked(IDC_USEXMLNAME) && PrefixName.GetLength() > 1 )
{
if ( IsDlgButtonChecked(IDC_IDC_USESHORTNAME) )
{
EnableNext(TRUE);
}
else if ( IsDlgButtonChecked(IDC_USELONGNAME) )
{
EnableNext(TRUE);
}
else
{
EnableNext(FALSE);
}
}
if ( !IsDlgButtonChecked(IDC_USEPREFIX) )
{
if ( IsDlgButtonChecked(IDC_IDC_USESHORTNAME) || IsDlgButtonChecked(IDC_USELONGNAME) )
{
EnableNext(TRUE);
}
}
return false;
}
}
答案 0 :(得分:6)
我会将if / else语句拆分为多个函数,并对发送给EnableNext的参数执行& =。你应该只调用一次EnableNext。
所以,例如:
// in CWorkStation::ProcessEvent
bool enableNext = true; // start with true
enableNext &= Condition1(); // of course pick better names than Condition1
enableNext &= Condition2(); // this is just for an example
EnableNext(enableNext);
Condition1()可能是:
bool Condition1()
{
return (IsDlgButtonChecked(IDC_USEDBNAME)
&& !IsDlgButtonChecked(IDC_MAXDBNAME));
}
等等。
这里发生的是enableNext变量以true开头。然后,每个& =你这意味着如果任何ConditionX()函数返回false,则enableNext将结束为false。如果所有条件都成立,那么最终才会成真。
答案 1 :(得分:1)
这个问题可以通过听众的概念来解决。
您可以使每个GUI组件都具有isEnabled()
方法,该方法根据某些条件检查其条件。当任何改变任何组件状态的操作被调用时,在每个GUI组件上调用isEnabled()
。
这样您就可以拥有以下声明:
bool CheckBoxComponent::isValid() {
return isNameFilled() && isEmailChecked();
}
bool OkButton::canSend() {
return checkBoxName->isValid() && isEmailChecked();
}
然后,在创建GUI组件时,您可以通过监听器将它们中的每一个连接起来。
通过这种方式,您可以获得它们所属的每个组件的规则,并且您没有大量的if语句。
答案 2 :(得分:0)
尝试将规则制定为状态机可能会有所帮助,但如果这是实际的,则取决于它们的性质。在该方法中,每当用户填写对话框中的某个字段,或选中复选框或其他任何字段时,您都会相应地更新状态机的状态。如果您有,可以使用Boost.Statechart来实现它。
答案 3 :(得分:0)
在这种情况下,我倾向于通过(例如)默认启用按钮使其尽可能简单,如果设置(或不设置)任何其他条件,则禁用它;这限制了“if”条件中“else”的不同情况。
答案 4 :(得分:0)
将您的条件重新设置为正确的布尔语句,正确缩进所有条件并添加一些注释。恕我直言,你不应该隐藏一次性使用方法的真实检查。如果你想评论代码,对它进行评论但不为此目的创建方法,它只会混淆事物,你的条件不会变得更简单:
EnableNext(
// condition 1
IsDlgButtonChecked(IDC_USEDBNAME) && !IsDlgButtonChecked(IDC_MAXDBNAME)
// condition 2
|| IsDlgButtonChecked(IDC_MAXDBNAME) && CharCount
&& IsDlgButtonChecked(IDC_USEXMLNAME) && !PrefixName.IsEmpty()
// condition 3
|| IsDlgButtonChecked(IDC_USEXMLNAME) && PrefixName.GetLength() > 1
// and so on
)
这样很明显你似乎两次检查相同的条件USEXMLNAME && !PrefixName().IsEmpty()
。现在也很明显,EnableNext
总是被调用。
答案 5 :(得分:0)
虽然它可能比您想要的解决方案有点“重”,但您可能需要查看Adobe的Adam and Eve库。 Eve处理小部件布局,Adam采用一组关于小部件逻辑的语句,并将它们放在一个控制器中,该控制器根据该逻辑启用和禁用小部件,以及处理初始化并将结果放入适当的变量(例如,当用户点击“确定”时)。