responding to dbCheckbox changes programmatically - delphi

I have a no of DBCheckboxes on a form I want to be able to check/uncheck one or more of these programmatically depending upon whether the user checks /unchecks a different DBCheckbox also on the same form I cant seem to be able to do this using the onclick event

I can't seem to be able to do this using the onclick event
The reason is the tight coupling between the state of db-aware components such as TDBCheckBox and that of the dataset they are connected to. If you attempt to interfere with this by trying to set the gui state of the component (e.g. the Checked state of a DBCheckBox), the db-aware model these components all work to will fight you every inch of the way, because you are effectively trying to subvert the mechanism by which the gui state of the component is kept in sync with the value in the corresponding dataset field.
So, as Val Marinov correctly said, the thing you need to do is to manipulate the field value instead, as in the following:
if MyDataSet.FieldByName('OtherBooleanField').AsBoolean <> RequirdValue then begin
if not (MyDataSet.State.State in [dsInsert, dsEdit]) then
MyDataSet.Edit;
MyDataSet.FieldByName('OtherBooleanField').AsBoolean := RequiredValue;
It's up to you what trigger you respond to, to execute code like this.

on clickevent of check box set the Field of appropriate checkbox

In the OnChange event of the fields change the values of the other fields that need to change.

Related

A form that is able to be Modal after it is created

I have a PopForm that I want to stay over MainForm in any case.
The cases are:
PopForm.ShowModal and PopForm.Show.
Whilst ShowModal is completely works fine, the Show method is needed to interact with MainForm for doing 'drag-drop' things.
Main duty of the PopForm is to import data from some files to a dataset on the MainForm. There is two ways: drag-drop of the concrete data (selected rows while in Show-mode) and transfering all data from PopForm (while in ShowModal-mode). All data in the PopForm stored in something like ClientDataSet. I developed methods that are alike ClientDataSet's: First, Eof, FieldByName, Next, etc. and implemented them into PopForm.
After the PopForm is closed (after setting the ModalResult), the calling procedure uses a while not PopForm.eof do PopForm.Next... to import data into MainForm's dataset or whatever would be a user-programmers method.
For showing some progress I used to recreate PopForm with Show method and show a progress form above PopForm, while a cycle is being made in the calling procedure. After that - PopForm is closed.
This works fine, but the only problem is about a Show method - I need the PopForm to be over MainForm all the time. In most cases it is, but there are some applications, that somehow doesn't follow this rule. I've tried to use PopupParent & PopupMode properties, but they make popForm to recreate again on any assignment (and as I've just found - you need to assign a CustomForm on show and then - Nil it on close, because with common TForm.Close method it won't hide no way)
There would be no any problem about that, if there would be no need to Nil PopupParent on FormClose method. The other routine is to assign
...FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
...
end;
It would work if Assigned(PopForm) return false, but it returns true.
If there is any case to discover if the Form is Freed - that may help. What do you think?
If you set your form style to fsStayOnTop the form will always stay on top unles you there is another form with same property. In that case the active one of them will be on top.
As for moving data from your PopForm which you use for importing data you could folow similar approach as it is used in creating of custom Dialogs.
Custom dialogs are usually designed like so:
You have dialog class which contains fields for dialg settings (to change hoe the dialog woul look like), and even a field for dialog output (selected FileMame/s, etc.).
Within this class there is a dialog form class which esentially is a modal form. This dialog form uses its OnClose event to automatically feed necessary information into Dialog output field before closing.

How do I define the order of a form's Controls array?

When I have a form, I can access components via TForm.Controls[]. Is it possible to change a component's index in that array from IDE? I tried to edit form as text, and change the order there, but it didn't change anything.
Changing the order of the controls within the DFM will work just fine.
Update However, that only really affects the order of the Controls[] list at Form creation when the DFM is streamed. Once the Form is up and running, the order of the Controls[] list changes dynamically if the Z-order of any of the controls changes over time, such as from calls to TControl.BringToFront() or TControl.SendToBack(). The order will also change if you change the Parent of any of the controls in the list.
So you are not really guaranteed any particular ordering at any given time.

(Delphi) how to prevent DB controls from editing the record

I have a form with a grid with data and some db controls (DBEdit for instance).
When user types inside the DBEdit, Delphi automatically set the record in edit mode. But I dont like this, I want to be able to edit a record only if I programmatically call Table.Edit;
any idea how to prevent this? of course without setting the edit control read-only. I mean a workaround in the data aware components (table) directly.
Set the AutoEdit property of your datasource to false.
DBNavigator provides a nbEdit Button.
Look up TDataSource.AutoEdit property.

Dbgrid - automatic post to database

I have a form with a query, a dataset, an editable dbgrid and an updatesql component. When I need to save the changes made in the dbgrid, I call this procedure:
procedure TEditCardDetailForm.SaveChanges;
begin
Database1.StartTransaction;
try
Query2.ApplyUpdates;
Database1.Commit;
except
Database1.Rollback;
raise;
end;
Query2.CommitUpdates;
end;
However I want the changes to be applied automatically to the database when I press Enter or go to another row after editing a cell in the dbgrid - the way it is done when I use a TTable component. Is there a way to do it?
If I understand it right (please correct me if not) you have a TQuery with CachedUpdates set to true, but want it to behave as if it would not be using cached but immediate updates. If that is the case the way you have set up your TQuery contradicts your desired behaviour. Cached updates are to be "held" on the client side until you decide to manually post them to the database by using ApplyUpdates.
In case you can set CachedUpdates to false, you only need to do following:
Link the TUpdateSQL to the TQuery via its UpdateObject property.
Write the insert, update and delete statements and assign them to the InsertSQL, ModifySQL and DeleteSQL properties of the TUpdateSQL.
I guess you already have done these two things, so putting CachedUpdates to false should do it.
You can find more information on Cached Updates for Delphi 5 here.
HTH
You have two scenarios to handle here:
save changes when changing the grid row
save changes when changing the grid column
The first one is easy to implement by calling your SaveChanges procedure in the AfterPost event of the underlying dataset (query2, a TClientDataSet?).
For the second one you only have to call query2.Post after the column has changed. This can be done in the OnDataChange event of the datasource. Make sure to check for Field <> nil and the dataset being in insert or edit mode before calling post.

What is the purpose of the 'Tag' property of Delphi VCL components?

Is there any specific purpose for the 'Tag' property of Delphi VCL components?
I have Googled a few examples using it as, for example, a 'color' property or using the value as a pointer address, but is it 'good practice' to use it, or is it considered 'bad practice' as it ties the program logic to the UI?
The "tag" property is there as a "cargo container" for whatever you might want to do with it.
Something it's often used for is in event handlers when you have a lot of similar components sharing one event handler. The event handler can find its caller and then query its tag value to get some more information about what it's supposed to be acting on.
EDIT:
Example: A calculator app might tag the number buttons with their respective numbers... silly and incomplete example, but you get the idea. The event handler could then pull the number to add into the display and accumulator right out of the tag instead of having to go figure out which button is meant to do what.
It is a place to add a piece of information to any component, even if you don't have the source for that component. It should be used carefully, because you can use it for only one purpose per component. For that reason Libraries should never use it.
I have some fundamental problems with the Tag property.
Well not exactly this property itself because it works as intended.
In general I consider using any universal/general/multi-purpose variables as a 'bad practice'.
They can be useful during debugging but are very harmful in production/mission critical environment.
They reduce code readability and understandability because nobody knows what a 'Tag' named attribute or property does. Of course you know why you are using this variable. But sooner or later you will forget (I know you will) and relying on this value makes anything more complicated.
This is why we should properly name every variable and property to help us understand what the code does.
Using Tag property is just a workaround/shortcut to avoid implementing understandable and well written code.
This is the PRACTICE and it is addictive.
Next time you need to store a new integer value bound to a component you will use the Tag property without considering any other way to store the desired values.
And storing a pointer in Tag property is a horrible idea: you have to cast this value every time you debug pointers.
Tell me: how many times did you find yourself in a situation where you wanted to store a new value in the Tag property but you realized this property is already used for a different purpose (if only there would be a 'Tag2' property in every component...).
As others have said, it's a place to put anything. Typically this comes in handy when associating two objects via an object reference or pointer. The tag happens to be perfectly sized to hold a pointer, so if you need to, say, keep an object tied to an item in a listbox, it becomes pretty straightforward.
Also it can be used for grouping purposes, say you'd want to access all components with a specific tag value, regardless of the component's type.
It's great! A freebie. I use it all the time to store one additional piece of information associated with the object.
Often I store a pointer to an associated data structure, or sometimes an integer which may be an index into some other array.
You can use it as a counter for times the object is accessed, or whatever.
The only downside is if your program uses lots of memory and you have millions of objects, those 4 bytes for each tag add up, especially if you're not using it. In that case, for your most prolific object type, you may want to create your own version without the tag.
You have 2 buttons on your form, on one you set the Tag = 1, and the other one Tag = 2. Now you assign the same OnClick event to both buttons and writhe the code like this:
procedure TForm28.Button1Click(Sender: TObject);
begin
case (Sender as TButton).Tag of
1: Caption := 'you pressed button 1';
2: Caption := 'you pressed button 2';
end;
end;
or more compact:
procedure TForm28.Button1Click(Sender: TObject);
begin
Caption := 'you pressed button ' + IntToStr((Sender as TButton).Tag);
end;
Basically,Tag will let you identify what control fired the event. Think if you have a form with dynamically created buttons... a list with users from the database, and on each record you put a button "Delete User". In this situation you can't create an event for each button, you will create one event that will assigned to all the buttons... and you can put in the Tag the userid for example. That way when you implement the event to handle all the buttons, you'll know what user to delete.
I Use tags all the time.
here are some examples;
a simple sample: you have a notebook (Like a pagecontroll without tabs)
so you can define buttons as tabs and write
NoteBook.ActivePage := TButton(Sender).Tag;
A more complicated sample;
an integer can hold 16 bitwise bolleans;
I can then check the senders up to 16 conditions to decide how to continue the pricedure
If (BitCheck (Bit2,TButton(sender).tag=True) And BitCheck(bit12,TButton(Sender).Tag=False) Then
Begin
end;
If (BitCheck (Bit9,TButton(sender).tag=True) Or BitCheck(bit14,TButton(Sender).Tag=True) Then
Begin
end;
You Get the idea

Resources