通知一个控件另一个控件有状态改变

Notifying a control that another control has a state change

我正在使用 C++Builder Enterprise,需要一些想法。

我有一个表单,上面有一堆 TButtonTSpeedButton 控件。我想要发生的是,当按下给定按钮时,我想禁用它和其他几个按钮,同时启用其他几个按钮,即状态更改。

问题是我在很多地方复制了 enable/disable 代码。我考虑过以某种方式使用 TNotifyEvent 委托来提醒状态更改的按钮,但我认为委托技术在这种情况下不起作用。我想避免创建一堆 TButton/TSpeedButton.

的子 类

我还想尝试使用 VCL 提供的技术,因为每个组件中都有一个观察者列表,我想知道我是否可以以某种方式利用它。

我的 2 美分值..

我已经为您的问题完成了概念验证,还需要做更多的工作,但我认为它是可行的,应该可以满足您的要求。

如果有兴趣,我会做更多的工作,post。

查找表单上 class 类型的所有控件

--- TControlAgent->FindTControl(this, "TButton");

我在表单上添加了 4 个按钮,在按钮 1 的点击事件中添加了下面的代码,

TControlAgent->SetControlProperty("Enabled", "TButton", false, true, "Button3");

在这种情况下,想要 属性 名称为 TButton、状态 = true 或 false 的启用 属性 控件,执行操作但排除名为 TButton3

的控件

结果是表单上的所有 TButton 都设置为禁用,除了按钮 3

(注意:排除选项将是要从任何操作中排除的控件的查找列表,或者能够设置不是状态的状态,例如 Enabled = !true 或 !false)

在button3的点击事件中我放置了以下代码;

TControlAgent->SetControlProperty("Enabled", "TButton", true, true, "");

结果是 re-enable 所有控件,这只是一个想法,但通过额外的工作,可以从任何表单的单个父表单对任何控件执行任何操作在表格集合中。

我也认为可以触发事件,只是一个疯狂的想法...

.h 文件使用 berlin 10.1


    //---------------------------------------------------------------------------

#ifndef TControlAgentH
#define TControlAgentH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <System.TypInfo.hpp>
#include <vector>
#include <algorithm>

//---------------------------------------------------------------------------
class PACKAGE TControlAgent : public TComponent
{
private:
    std::vector<TControl*> FControls;
protected:
public:
  std::vector<UnicodeString> excludeControlNames;
    __fastcall TControlAgent(TComponent* Owner);
    TControl * __fastcall GetControl(TControl* ctrl, UnicodeString property);
    void __fastcall FindTControl(TForm *f, UnicodeString className);
  TControl* __fastcall SetControlProperty(UnicodeString property, UnicodeString className, bool state, bool exec, UnicodeString excludeControlName   );
__published:
};
//---------------------------------------------------------------------------
#endif


.cpp 文件


    //---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "TControlAgent.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
//---------------------------------------------------------------------------
// component to act as agent for other components derived from TControl
//
//  Components have properties and events, is it possible to get all TControls into a vector
//  then be able to get a property of a component then fire an event or carry out an action
//  on the component!!!!
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TControlAgent *)
{
    new TControlAgent(NULL);
}
//---------------------------------------------------------------------------
__fastcall TControlAgent::TControlAgent(TComponent* Owner)
    : TComponent(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TControlAgent::FindTControl(TForm *f, UnicodeString className)
    {
    FControls.clear();

    for(int i = 0; i < f->ControlCount; i++)
        {
        if(f->Controls[i]->ClassName() == className)  //control classes that to set as a group
            FControls.push_back(f->Controls[i]);
        }
    //note:  could have a function that appends other class names
    }
//---------------------------------------------------------------------------
TControl* __fastcall TControlAgent::SetControlProperty(UnicodeString property, UnicodeString className, bool state, bool exec, UnicodeString excludeControlName  )
    {
    PPropInfo propinfo;
    for(int i = 0; i < FControls.size(); i++)
        {
        if(FControls[i]->ClassName() == className)
            {
            propinfo = GetPropInfo(FControls[i], property);
            if (!propinfo)
                continue;
            if(exec && FControls[i]->Name != excludeControlName )
                {
                if(property == "Enabled")
                    FControls[i]->Enabled = state;
                }
            }

        }

    }
//---------------------------------------------------------------------------
namespace Tcontrolagent
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(TControlAgent)};
        RegisterComponents(L"SQLite", classes, 0);
    }
}
//---------------------------------------------------------------------------

**** 已更新 ***** TControlAgent 进度

显然仍在进行中,但此代码有效,创建一个带有 TPanel 的表单,向此添加 6 个 TButtons

添加一个TControl Agent,按照下面的Form代码设置OnButtonClick事件

TControlAgent代码 .h

//---------------------------------------------------------------------------

#ifndef TControlAgentH
#define TControlAgentH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <System.TypInfo.hpp>
#include <vector>
#include <algorithm>

class TControls;
class TControlGroup;

typedef void __fastcall (__closure *TControlAgentOnClick)(System::TObject *Sender, TControls *ctrl);
typedef void __fastcall (__closure *TButtonClickEvent)(System::TObject *Sender);
enum action {aEnabled, aOnClick, aChange};
enum tcontrols {tbutton, tedit, tcombo, tcheckbox};
//---------------------------------------------------------------------------
class PACKAGE TControlAgent : public TComponent
{
private:
    std::vector<TControls*> FControls;
    std::vector<TControlGroup*> FControlGroups;

    TControlAgentOnClick FClickSupliment;
    TButtonClickEvent FOnButtonClick;
    bool FButtonClickRedirect;

protected:

public:
    std::vector<UnicodeString> excludeControlNames;  // not implemented yet
    std::vector<TControlGroup*> __fastcall Groups();
    std::vector<TControls*> __fastcall Controls(int GroupIndex);
    __fastcall TControlAgent(TComponent* Owner);
    TControl * __fastcall GetControl(TControl* ctrl, UnicodeString property);
    void __fastcall FindTControl(TForm *f, UnicodeString className);
    void __fastcall FindTControl(TPanel *p, UnicodeString GroupName, bool ClearIfControlsExists);
    void __fastcall SetControlProperty(TControl *ctrl, bool state, int Action);
    int __fastcall GetGroup(String name);
    void __fastcall SetControlClickEvent(String ClassName, String GroupName, String ExcludeGroup, int tControlType);
    void __fastcall SetButtonPropValue(TButton* b, String Property, String Value, bool v);
    int __fastcall AddTControl(TControl* c, String Group);
    void __fastcall SetButtonPropValue(String Group, String ExcludeGroup,int TControlType,String Property,String GroupValue,bool GroupV,String excludeGroupValue,bool excludeGroupV);


__published:
    __property bool TButtonClick = {read = FButtonClickRedirect, write = FButtonClickRedirect };
    __property TControlAgentOnClick OnClickSuppliment={read=FClickSupliment, write=FClickSupliment};
    __property TButtonClickEvent OnButtonClick = {read = FOnButtonClick, write = FOnButtonClick };
};
//---------------------------------------------------------------------------
class TControlGroup
    {
    public:
        UnicodeString GroupName;
        std::vector<TControls*> GroupControls;
        __fastcall TControlGroup();
    };
//---------------------------------------------------------------------------
class TControls
    {
    public:
        TControl* ctrl;
        bool WantButtonOnClick;
        bool WantControlOnChange;
        bool FireStateChange;
        bool WantOnClickSupliment;
        bool state;
        __fastcall TControls();
    };

#endif

.cpp

//---------------------------------------------------------------------------

#include <vcl.h>

#pragma hdrstop

#include "TControlAgent.h"
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
//---------------------------------------------------------------------------
// component to act as agent for other components derived from TControl
//
//  Components have properties and events, is it possible to get all TControls into a vector
//  then be able to get a property of a component then fire an event or carry out an action
//  on the component!!!!
//---------------------------------------------------------------------------
struct IsCtrlGroup {
    String _name;

    IsCtrlGroup(String name) : _name(name)
        {
        }

    bool operator()(const TControlGroup * item) const
        {
        return (item->GroupName == _name);
        }
};
//---------------------------------------------------------------------------
struct IsClassName {
    String _name;

    IsClassName(String name) : _name(name)
        {
        }

    bool operator()(const TControl * item) const
        {
        return (item->ClassName() == _name);
        }
};
//---------------------------------------------------------------------------
struct IsCtrl {
    TControl* _ctrl;

    IsCtrl(TControl* ctrl) : _ctrl(ctrl) {
    }

    bool operator()(const TControls * item) const {
        return (item->ctrl->Name == _ctrl->Name);
    }
};
//---------------------------------------------------------------------------

static inline void ValidCtrCheck(TControlAgent *)
{
    new TControlAgent(NULL);
}
//---------------------------------------------------------------------------
__fastcall TControlAgent::TControlAgent(TComponent* Owner)
    : TComponent(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TControlAgent::FindTControl(TForm *f, UnicodeString className)
    {
    FControls.clear();
    TControls* ctrl;

    for(int i = 0; i < f->ControlCount; i++)
        {
        if(f->Controls[i]->ClassName() == className)  //control classes that to set as a group
            {
            TControls* ctrl = new TControls();
            ctrl->ctrl = f->Controls[i];
            ctrl->FireStateChange = false;
            ctrl->WantOnClickSupliment = false;
            FControls.push_back(ctrl);
            }
        }
        //note:  could have a function that appends other class names
    }
//---------------------------------------------------------------------------
void __fastcall TControlAgent::FindTControl(TPanel *p, UnicodeString GroupName, bool ClearIfControlsExists)
    {
    /*
    group vector[]
        --> controlsindex  vector[index]

    */
    TControlGroup* g;
    TControls* ctrl;

    int i = -1;
    int group_index = -1, controls_index = -1;

    // check if group name exists in group vector
    group_index = GetGroup(GroupName);

    //clear controls vector if exists, controls will not exist if group does not exist...
    if(ClearIfControlsExists && group_index > 0)
        FControlGroups[group_index]->GroupControls.clear();

    // if group does not exist, push new group onto vector
    if(group_index == -1)
        {
        g = new TControlGroup();
        g->GroupName = GroupName;
        FControlGroups.push_back(g);
        group_index = GetGroup(GroupName);
        }

    //group must bnow exist
    for(i = 0; i < p->ControlCount; i++)
        {
        TControls* ctrl = new TControls();
        ctrl->ctrl = p->Controls[i];
        FControlGroups[group_index]->GroupControls.push_back(ctrl);
        controls_index = FControlGroups[group_index]->GroupControls.size() -1;
        FControlGroups[group_index]->GroupControls[controls_index]->ctrl = p->Controls[i];
        }
    }
//---------------------------------------------------------------------------
int __fastcall TControlAgent::AddTControl(TControl* c, String Group)
    {
    int  index;
    TControlGroup* g;

    int group_index = GetGroup(Group);
    if(group_index == -1)
        {
        g = new TControlGroup();
    g->GroupName = Group;
        FControlGroups.push_back(g);
        group_index = GetGroup(Group);
        }

    TControls* ctrl = new TControls();
    ctrl->ctrl = c;
    FControlGroups[group_index]->GroupControls.push_back(ctrl);
    index = FControlGroups[group_index]->GroupControls.size()-1;
    return(index);

    }
//---------------------------------------------------------------------------
void __fastcall TControlAgent::SetControlClickEvent(String ClassName, String GroupName, String ExcludeGroup, int tControlType)
    {
    int group_index = GetGroup(GroupName);

    for(int i = 0; i < FControlGroups[group_index]->GroupControls.size(); i++)
        {
        if(FControlGroups[group_index]->GroupControls[i]->ctrl->ClassName() == ClassName)
            {
            switch(tControlType)
                {
                case tbutton:
                    dynamic_cast<TButton*>(FControlGroups[group_index]->GroupControls[i]->ctrl)->OnClick = FOnButtonClick;
                    break;
                case tedit:
                    break;
                case tcombo:
                    break;
                case tcheckbox:
                    break;
                }
            }
        }
    }
//---------------------------------------------------------------------------
std::vector<TControlGroup*> __fastcall TControlAgent::Groups()
    {
    return(FControlGroups);
    }
//---------------------------------------------------------------------------
std::vector<TControls*> __fastcall TControlAgent::Controls(int GroupIndex)
    {
    return(FControlGroups[GroupIndex]->GroupControls);
    }
//---------------------------------------------------------------------------
int __fastcall TControlAgent::GetGroup(String name)
    {
    int group_index =-1;
    std::vector<TControlGroup*>::iterator found = std::find_if(FControlGroups.begin(), FControlGroups.end(), IsCtrlGroup(name));
    if(found != FControlGroups.end())
         group_index =  std::distance(FControlGroups.begin(), found);
    return(group_index);
    }
//---------------------------------------------------------------------------
void __fastcall TControlAgent::SetButtonPropValue(TButton* b, String Property, String Value, bool v)
    {
    PPropInfo propinfo;
    propinfo = GetPropInfo(b, Property);
    if (!propinfo)
        return;

    if(Value.IsEmpty())
        SetPropValue(b, propinfo, v);
    else
        SetPropValue(b, propinfo, Value);

    }
//---------------------------------------------------------------------------
void __fastcall TControlAgent::SetButtonPropValue(String Group,
                                                                                                    String ExcludeGroup,
                                                                                                    int TControlType,
                                                                                                    String Property,
                                                                                                    String GroupValue,
                                                                                                    bool GroupV,
                                                                                                    String excludeGroupValue,
                                                                                                    bool excludeGroupV)
    {
    // Group can hold all TControls on a form
    // ExcludeGroup contains TControls that will be excluded from an action on the Group controls
    // Group is an existing group of TControls found on a container
    // ExcludGroup is a group that can be found on a container or added to a Group
    //  then parsed to this method in ExcludeGroup param

    int i;
    PPropInfo propinfo;
    TControl *c;
    int group_index = GetGroup(Group);
    int exclude_Group_index = GetGroup(ExcludeGroup);
    TControl* ctrl;
    for(i = 0; i < FControlGroups[group_index]->GroupControls.size(); i++)
        {
        c = FControlGroups[group_index]->GroupControls[i]->ctrl;
        //check if TControl is to be excluded

        std::vector<TControls*>::iterator found = std::find_if(FControlGroups[exclude_Group_index]->GroupControls.begin(),
                                                                                                                             FControlGroups[exclude_Group_index]->GroupControls.end(),
                                                                                                                             IsCtrl(c));

        // if found, control is in the exclude list so continue, do not apply
        // property value change
        if(found != FControlGroups[exclude_Group_index]->GroupControls.end())
            {
            c = (*found)->ctrl;
            //set property value for exclude group controls
            propinfo = GetPropInfo(c, Property);
            if(propinfo)
                {
                if(excludeGroupValue.IsEmpty())
                    SetPropValue(c, propinfo, excludeGroupV);
                else
                    SetPropValue(c, propinfo, excludeGroupValue);
                }

            continue;
            }

        //if it gets here, c is not in exclude list
        propinfo = GetPropInfo(c, Property);
        if (!propinfo)
            return;


        if(GroupValue.IsEmpty())
            SetPropValue(c, propinfo, GroupV);
        else
            SetPropValue(c, propinfo, GroupValue);

        }

    }
//---------------------------------------------------------------------------
namespace Tcontrolagent
{
    void __fastcall PACKAGE Register()
    {
        TComponentClass classes[1] = {__classid(TControlAgent)};
        RegisterComponents(L"SQLite", classes, 0);
    }
}
//---------------------------------------------------------------------------
__fastcall TControls::TControls(){}
//---------------------------------------------------------------------------
__fastcall TControlGroup::TControlGroup(){}

表单代码

.cpp

Form 有一个 TPanel,上面放置了 6 个 TButtons

@运行 TButton3 被禁用的时间

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "frmTControlTest.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TControlAgent"
#pragma resource "*.dfm"
TForm3 *Form3;
//---------------------------------------------------------------------------
__fastcall TForm3::TForm3(TComponent* Owner)
    : TForm(Owner)
    {
    int i;
    std::vector<TControls*> group_controls;
    //get ALL controls on a container
    ControlAgent1->FindTControl(p, "Group1", true);
    //create the exclude (for want of a better name) groups
    /*
    add
    edit
    save
    delete
    cancel
    exit
    */
    ControlAgent1->AddTControl(bnSave, "Group2");
    ControlAgent1->AddTControl(bnCancel, "Group2");

    ControlAgent1->AddTControl(bnAdd, "Group3");
    ControlAgent1->AddTControl(bnEdit, "Group3");
    ControlAgent1->AddTControl(bnDelete, "Group3");
    ControlAgent1->AddTControl(bnExit, "Group3");


    i = ControlAgent1->GetGroup("Group1");

    group_controls = ControlAgent1->Controls(i);

    ControlAgent1->SetControlClickEvent("TButton", "Group1", "", tbutton);

    }
//---------------------------------------------------------------------------
void __fastcall TForm3::ControlAgent1ButtonClick(TObject *Sender)
    {
    TButton* b;
    if((b = dynamic_cast<TButton*>(Sender)) == bnAdd )
        ControlAgent1->SetButtonPropValue("Group1", "Group2", tbutton, "Enabled", "", false, "", true);
    if((b = dynamic_cast<TButton*>(Sender)) == bnCancel )
        ControlAgent1->SetButtonPropValue("Group1", "Group3", tbutton, "Enabled", "", false, "", true);
    if((b = dynamic_cast<TButton*>(Sender)) == bnSave )
        {
        ControlAgent1->SetButtonPropValue("Group1", "Group3", tbutton, "Enabled", "", false, "", true);
    //Do Stuff
        }


    }
//---------------------------------------------------------------------------