处理GUI应用程序中的复杂规则(C ++或C#)

时间:2010-03-25 13:10:35

标签: c++ user-interface mfc logic

我正在开启一个对话框,在启用确定按钮之前必须满足几条规则。

目前,页面上的任何操作(例如输入数据或从下拉列表中选择项目(以及其他内容))都会调用一个名为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;


            }

        } 

6 个答案:

答案 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采用一组关于小部件逻辑的语句,并将它们放在一个控制器中,该控制器根据该逻辑启用和禁用小部件,以及处理初始化并将结果放入适当的变量(例如,当用户点击“确定”时)。

相关问题