How to cast to TMenuItem in TActions Execute method? - c++builder

I have a number of related TMenuItems, in a CodeGear C++ VCL application.
Each TMenuItem is associated to the same action (TAction).
When a MenuItem is clicked, the action fires (its execute method that is).
I will need to, somehow, cast the Sender parameter in the actions OnExecute function to figure out which menuitem that was clicked.
Currently I have something like this
void __fastcall TMoleculixDesktopMainUnit::openMoleculeSelectionFormAExecute(TObject *Sender)
{
//User selected a menuitem under Molecules Menu
TAction* anItem = dynamic_cast<TAction*>(Sender);
//AminoAcidsMI is a TMenuItem
if(AminoAcidsMI == dynamic_cast<TMenuItem*>(anItem->Owner))
{
//Open molecule search form with aminoacids
MLog()<<"Looking for Amino Acids..";
}
}
But the above does not work The actions Owner is NOT the MenuItem.

Use the TAction::ActionComponent property, which specifies the component that triggered the action.
void __fastcall TMoleculixDesktopMainUnit::openMoleculeSelectionFormAExecute(TObject *Sender)
{
//User selected a menuitem under Molecules Menu
TAction* anItem = dynamic_cast<TAction*>(Sender);
if (!anItem) return;
AminoAcidsMI == dynamic_cast<TMenuItem*>(anItem->ActionComponent);
if (AminoAcidsMI)
{
//Open molecule search form with aminoacids
MLog()<<"Looking for Amino Acids..";
}
}

Related

TClientDataSet OnNewRecord vs. AfterInsert

My question is about inserting records into a table on a firebird database. The table is very simple - it has only 2 columns:
CREATE TABLE myTable
(
COL_ID CHAR(36) NOT NULL CONSTRAINT PK_COL_ID PRIMARY KEY USING INDEX IX_COL_ID,
COL_ACRONYM VARCHAR(255)
);
In my application (c++ Builder XE10) I have the following constellation:
A TDataSource connected to
A TClientDataSet connected to
A TDataSetProvider connected to
A TFDTable connected to
A TFDConnection connected to
A Firebird Database
The application does the following:
Insert a new row using TClientDataSet.Append();
Edit the newly inserted record.
Save this record using TClientDataSet.ApplyUpdates(-1);
Everything is working as expected as long as I do the 2nd step manually or by editing the data within the AfterInsert event:
__fastcall TFormMain::TFormMain(TComponent* Owner)
: TForm(Owner)
{
ClientDataSet1->Active = true;
}
UnicodeString TFormMain::GenerateGuid( void )
{
// ...some fancy code creating and returning a GUID...
}
void __fastcall TFormMain::ButtonAppendClick(TObject *Sender)
{
ClientDataSet1->Append();
}
void __fastcall TFormMain::ButtonSaveClick(TObject *Sender)
{
ClientDataSet1->ApplyUpdates(-1);
}
void __fastcall TFormMain::ClientDataSet1AfterInsert(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Whatever: this works!";
}
This works good... so far...
Due to some other changes I decided to move the the auto-creation of data into the OnNewRecord event of the TClientDataSet:
void __fastcall TFormMain::ClientDataSet1NewRecord(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Not too good...";
}
For the first moment it looked good, because the DB-controls on the GUI have been filled with the correct data. But as soon as I hit the Save Button the data disappeard and the new record has not been stored to the database - as if I cancelled the process.
Secondly I noticed, that if I change one of the columns MANUALLY before executing ApplyUpdates(),... then the record is stored.
So I simply added the following line for automatic posting:
void __fastcall TFormMain::ClientDataSet1NewRecord(TDataSet *DataSet)
{
DataSet->FieldByName( "COL_ID" )->AsString = GenerateGuid();
DataSet->FieldByName( "COL_ACRONYM" )->AsString = "Not too good...";
DataSet->Post();
}
This minor change did its job.
My question now is: WHY?
Does AfterInsert automatically post the new record?
Are records that were added by Append() automatically cancelled, when they are left unchanged after the OnNewRecord event?
regards and thanx
Herwig
As far as I know, the difference between TDataSet's OnNewRecord and AfterInsert event handlers is:
Editing fields values from the OnNewRecord will NOT flag the record as modified
Editing fields values from the AfterInsert will flag the record as modified
I guess that this is the cause of the problem

How to dynamically call a form in C++ Builder XE3?

I'm building an application in which Im populating menus using DB. I can create menu items but im having trouble linking "On Click" event to particular forms. I have stored names of the forms classes in my DB and trying to use RTTI to bind them at runtime. Following is the snippet of my code that Im trying to run.
__fastcall TfrmMainMDI::TfrmMainMDI(TComponent *Owner)
: TForm(Owner)
{
// Register 2 form classes
RegisterClass(__classid(TfrmSecurity));
RegisterClass(__classid(TfrmPassword));
}
Now when I try to run following code to call the form it gives "Access violation" error.
TForm *frm = (TForm*)TFormClass(FindClass(formName));
UnicodeString str = frm->Name;
frm->Show();
Do this:
TForm *frm = 0;
Application->CreateForm( TFormClass(FindClass(formName)), &frm );
Then if frm is not null,
frm->Show();
TForm *frm = new TForm(this);
if( frm != NULL )
{
frm->ShowModal();
//or
frm->Show();
}

Prevent selection of a particular item in spark list

I have a Spark List which has a custom itemRenderer for rendering each item in the List.
I wish to prevent an item in that list from being selected (based on some custom logic) by the user.
What is the best way I can achieve this?
Here's how my List is defined:
<s:List id="myList" itemRenderer="com.sample.MyItemRenderer" />
and of course, I have a item renderer defined as the class com.sample.MyItemRenderer.
The selection of items is handled by the list alone as far as I know, so I would say that you can manage it from there. I would have a field on the Objects that are in the list called "selectable" or something like that and when the list item is changing check to see if the new item is actually selectable and if it isn't then you can either have it clear the selection or reset to the previous selection. You can accomplish that by reacting to the "changing" event on the list component and calling "preventDefault" on the IndexChangeEvent as follows:
protected function myList_changingHandler(event:IndexChangeEvent):void {
var newItem:MyObject = myList.dataProvider.getItemAt(event.newIndex) as MyObject;
if(!newItem.selectable) {
event.preventDefault();
}
}
// Jumping ahead ...
<s:List id="myList" changing="myList_changingHandler(event)" // ... continue implementation
The relevant part of the MyObject class is as follows:
public class MyObject {
private var _selectable:Boolean;
public function MyObject(){
}
public function set selectable(value:Boolean):void {
_selectable = value;
}
public function get selectable():Boolean {
return _selectable;
}
}

How to make my ListBox not to call SelectionChanged event, when I assign ItemSource of my list

I have a combobox, that I populate from a web service:
public Configure()
{
InitializeComponent();
WebServiceSoapClient ws = new WebServiceSoapClient();
ws.GetTypesCompleted += new EventHandler<GetTypesCompletedEventArgs>(OnGetTypeCompleted);
ws.GetTypesAsync();
}
void OnGetTypeCompleted(object sender, GetTypesCompletedEventArgs e)
{
if (e.Result != null)
{
List<CodeTableItem> source = e.Result.ToList<CodeTableItem>();
lstType.ItemsSource = source;
lstType.SelectedIndex = -1;
}
}
So when I set the ItemSource property, SelectionChanged event gets fired with SelectedIndex = 0, but user hasn't made this selection yet and I need this list to have no selected value, so I'm setting SelectedIndex to -1, as you can see. As a result, SelectionChanged is called twice.
Can I make it be called only when user selects the item?
Thanks!
I'm using Silverlight 3 and VS 2008
Instead, modify your code so that the SelectionChange event handler isn't defined until after the itemssource and selected index are set.
void OnGetTypeCompleted(object sender, GetTypesCompletedEventArgs e)
{
if (e.Result != null)
{
List<CodeTableItem> source = e.Result.ToList<CodeTableItem>();
lstType.ItemsSource = source;
lstType.SelectedIndex = -1;
lstType.SelectionChanged += new SelectionChangedEventHandler(lstType_SelectionChanged);
}
}
In our application we implemented some code that would set a boolean flag based on the Control.LeftMouseButtonUp() event. When this has been set, it would mean that the user has interacted with the field, and so we can handle the SelectionChanged with different behaviour.
Over the development lifetime of our application this approach was essential so that default bindings would trigger our SelectionChanged logic when we didn't want it to.
If you are an MVVM purist, you'll need to expose the VM as a member variable and then set the bool flag in the VM.
HTH,
Mark

C# .net windows application - Printing Text Box Values

I have two text boxes when i input in these text boxes , by clicking the print button , it should directly printed with the connected printer. can anybody help me how should i do this?
The example below is a basic idea of using/inheriting the PrintDocument class:
using System.Drawing.Printing;
public class PrintDoc : PrintDocument
{
// there are other properties you can enter here
// for instance, page orientation, size, font, etc.
private string textout;
public string PrintText
{
get { return textout; }
set { textout = value; }
}
// you will also need to add any appropriate class ctor
// experiment with the PrintDocument class to learn more
}
Then from your form's button event, call something like:
public void PrintDocument()
{
//instance PrintDocument class
PrintDoc printer = new PrintDoc();
//set PrintText
printer.PrintText = myTextBox.Text;
printer.Print(); // very straightforward
}

Resources