I am using C++Builder Enterprise and need some ideas.
I have a Form with a bunch of TButton
and TSpeedButton
controls on it. What I want to have happen is that, when a given button is pressed, I want to disable it and several others, while enabling several other buttons, i.e. state changes.
The issue is that I am duplicating the enable/disable code in a bunch of places. I've thought about somehow using the TNotifyEvent
delegation to alert the buttons of a state change, but I don't think that delegation technique will work in this situation. I want to avoid creating a bunch of sub-classes of TButton
/TSpeedButton
.
I also would like to try to use techniques that are available from the VCL, as in each component carries an observer list and wonder if I could leverage that somehow.
My 2 cents worth..
I have done a proof of concept for your problem, would need a lot more work but I think it is doable and should do what you want.
I will do more work on it and post if there is interest.
To find all controls of a class type on a form
--- TControlAgent->FindTControl(this, "TButton");
I added 4 buttons on a form, added code bellow to button1 click event,
TControlAgent->SetControlProperty("Enabled", "TButton", false, true, "Button3");
in this case, want controls with Enabled property whose class name is TButton, state = true or false, execute the action but but exclude control named TButton3
There result was all TButtons on the form were set to disable except for button 3
(note: the exclude option would be a lookup list of controls to be excluded from any action or be able to set a state that is not the state eg Enabled = !true or !false )
In the click event of button3 I placed the following code;
TControlAgent->SetControlProperty("Enabled", "TButton", true, true, "");
The result of this is to re-enable all the controls, this is just an idea but with with the extra work it could be possible to execute any action on any control from a single parent form for any form in a collection of forms.
I also think it could be possible to fire events, just a crazy idea...
.h file using 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 file
//---------------------------------------------------------------------------
#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);
}
}
//---------------------------------------------------------------------------