In my cxGrid I have a Yes/No field which is by default 'NO' . Next to that field, I have another field,a LookupComboBox field that
gets its values from another table. It is empty by default however I would like that, when the value gets changed in this
particular field, my Yes/No field should change to 'YES' (Only in the row that I am currently editing) How am I to do this ? Also Not sure where to implement the code ....OnChange,Oneditvaluechanged,Onvalidate ???
Since your grid semms to be bound on datasets one easy way would be using the fieldchange event of your selection field.
For immediate behavior you should use a TcxEditRepositoryLookupComboBoxItem with ImmediatePost instead a of a Lookupfield in your dataset (which would anyway the worse approach with at least ADO)
procedure TForm4.MainSelectionChange(Sender: TField);
begin
if Main.State in [dsEdit,dsInsert] then
if not Sender.IsNull then
MainYesNo.Value := true;
{ maybe you are looking for that instead the code above
if Main.State in [dsEdit,dsInsert] then
MainYesNo.Value := not Sender.IsNull
}
end;
Related
Most of my application's forms use 2 or more db grids : basically, the user clicks a record in main grid and get child results in a secondary grid.
All my primary DBGrids FDQueries (that is the one with SELECT) have been set on the form but none are "active", they fire on FormShow.
I noticed that, wether I write :
FDQuery1.Active := True;
or
FDQuery1.Open;
the result is the same : my rows are displayed in the main DBGrid.
Accordingly, I call Close or Active := False on FormClose.
But there must be a difference between those approaches and this is the subject of my question : what is the difference between Query.Open and Query.Active := True; ?
What should I use if there is any significant difference ?
Thanks in advance
Math, getting less and less noob as you take the time to answer my questions :)
SIDE NOTE : my INSERT and UPDATE queries are set up with a CLEAR then, SQL.ADD, then Parameters declaration and finally an ExecSQL
Active is a property, Open is a method. When Active is set to true, it calls the Open method, when it is set to false, it calls Close. Active is useful as it can be used to check whether the dataset is actually open.
if Qry.Active then DoSomething;
SIDE NOTE : my INSERT and UPDATE queries are set up with a CLEAR then,
SQL.ADD, then Parameters declaration and finally an ExecSQL
Between Active and Open is no difference.(see whosrdaddy comment) They do the same thing - The dataset becomes active and returns the result from SELECT statement.
You can also use property Active to check if the dataset is active for example:
if not MyQuery.Active then
MyQuery.Open; // or MyQuery.Active := true;
ExecSQL execute queries that do not return a cursor to data (such as INSERT, UPDATE, DELETE, and CREATE TABLE).
I have a rather strange issue about which I am having trouble finding documentation. I have a Delphi program that uses Delphi's built-in TDBMemo component, as the component needs to pull data from a field in a database. The user must also be able to edit this information, namely add information to the component's field. Text typed to the field is visible and does not disappear; however, that is not my problem.
The form gives the user the option to post pre-defined comments from a list, accessed through the equivalent of a pop-up triggered by a TBitButton; however, once the selected text is added to the TDBMemo and the user clicks anywhere, the added values disappear - again, not the typed text.
Here is the code for the assignment:
var NoteString: String;
if DBMemo1.Text <> '' then
begin
NoteString := frmSelectNoteCodeView.GetTextfromField + ' - ' + User.ID
+ ' on ' + FormatDateTime('mm/dd/yyyy', Now);
DBMemo1.Text := dbedComments.Text + #13#10 + NoteString;
end;
This is purposefully a code fragment (if the field is blank, the value is just assigned). I am posting this code fragment as I believe this is where the issue is, i.e. that a regular assignment cannot be used with TDBMemo?
Here's the thing: there are no events dealing with user clicks. Any ideas as to why the posted text disappears?
As I said in my comment, the TDBMemo is a data-aware control, meaning that it's set up to display the text of the associated field in the dataset; you can't just stuff a value into its text property, because any time the TDBMemo is told to refresh itself (via its TDatalink), it retrieves the text from the field, overwriting whatever you thought you'd assigned to it.
I'd do something like this
var
ADataSet : TDataSet;
begin
ADataSet := DBMemo1.DataSource.DataSet; //just to reduce typing
if not (ADataSet.State in [dsInsert, dsEdit) then
ADataSet.Edit;
ADataSet.FieldByName(DBMemo1.FieldName).AsString := 'your text goes here';
ADataSet.Post;
end;
Or you could leave it to the user to call Post.
Might be better if the .Post were in a finally block.
Btw, your problem arises from the tight control that Delphi's db-aware framework exerts over the on-screen display of db-aware controls. Generally, this will fight you trying to directly alter what these controls display; if you want to change dataset data, then change it, not what an associated control displays.
I have to create a program in Delphi using Access 2003 .mdb file as data repository.
The Access database has a table with a boolean (Yes/No in Access) field called "original".
I have mapped this field to a TDBCheckBox which shows checked for true and unchecked for false, and shows a half greyed check is the field has not been set.
What I want is oncreation of the field for the field to be set to false (checkbox unchecked) and save the field value as false IF the user has not explicitly set the field.
I have tried if (DVDQuery.FieldByName('Original').AsBoolean <> True) and (DVDQuery.FieldByName('Original').AsBoolean <> False )
then DVDQuery.FieldByName('Original').AsBoolean := False;
But this does not work for new records. I use a query to access the dataset as there a large number of dynamically created where statements to filter the dataset.
ANy help guidance is greatly appreciated.
Rob
Can you change the structure in the database? The proper place for default values is in the column definition. If you can update the structure, change the field to have a default value of "No". You will then never need to do any coding around this issue, and your data will be guaranteed correct even if entered directly through Access.
If you need to check the value in code, use if DVDQuery.FieldByName('Original').IsNull to determine whether the field is empty or not.
Finally, if you must change the value in code rather than as a database default, do it in the appropriate TDataset event (AfterInsert, AfterScroll, etc).
Check if the field is set a value or not in the BeforePost event of the DataSet:
procedure TForm1.DVDQueryBeforePost(DataSet: TDataSet);
begin
if DVDQuery.FieldByName('Original').IsNull then
DVDQuery.FieldByName('Original').AsBoolean := False;
if still relevant, check the status field of the field. It should be cbChecked, cbUnchecked or cbGray, which is what you are looking for.
I have a situation where I have to allow the user to update either of 2 fields of a dbgrid(connected to a CDS) persisting the last entered one. So (after user enters data) I need to get the current focused control, so that i will remove the previous field data if it has any. I also have other fields apart from these two.
It was insisted not to use any grid related events, i have to use only CDS event to achieve this.
Thanks in advance,
Vijay.
Use the field's OnChange event, and just clear the other field value if any:
Something like this:
TForm1.cdsField1Change(Sender: TField);
begin
if not Sender.IsNull then
cdsField2.Clear;
end;
TForm1.cdsField2Change(Sender: TField);
begin
if not Sender.IsNull then
cdsField1.Clear;
end;
I would like to change the behaviour of the insert button on the standard DBNavigator bar, from a dataset insert to append.
I could trap the button click in the BeforeAction event, do the append, etc; and then in the OnClick event abort the original insert, but this seems a bit of a hack. Any better ideas? I'm using D6 (500,000 kms on the clock, and still going strong...).
Thanks for any advice
Regards,
PhilW.
You could derive your own class from TDBNavigator and override BtnClick method.
Or, for a quick and dirty fix, you could change the insert button's click handler at runtime, e.g.:
type
THackDBNavigator = class(TDBNavigator);
procedure TForm1.DBNavigatorInsertClick(Sender: TObject);
var
DBNavigator: TDBNavigator;
begin
DBNavigator := ((Sender as TControl).Parent as TDBNavigator);
if Assigned(DBNavigator.DataSource) and (DBNavigator.DataSource.State <> dsInactive) then
begin
if Assigned(DBNavigator.BeforeAction) then
DBNavigator.BeforeAction(DBNavigator, nbInsert);
DBNavigator.DataSource.DataSet.Append;
if Assigned(DBNavigator.OnClick) then
DBNavigator.OnClick(DBNavigator, nbInsert);
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
THackDBNavigator(DBNavigator1).Buttons[nbInsert].OnClick := DBNavigatorInsertClick;
end;
There is no difference in most databases between insert and append. Doing an actual physical insert would mean actually moving all data, starting with the place the new row would be inserted, down the size of one row, and then writing that new row in the newly open spot. This would be very slow because of all of the disk activity.
Databases instead do an append, which writes the data to the end of the physical file, and the index order controls the way the row appears to be positioned in the correct place in the file.
So for most intents and purposes, you're probably already getting an append instead of an insert, regardless of which method you use or what the button on the DBNavigator says. It's the index that makes it appear otherwise.
You can check that for validity by creating a database without an index, and try doing both an insert and an append a few times, examining the data carefully after every operation.
#TOndrej: Great! I hadn't appreciated this technique. Thanks!
#Ken White: I understand your point, but visually to my users it makes a difference - the DBNavigator controls a DBGrid where, in the majority of cases, there is plenty of unused rows in the grid. It appears to be more consistent to have new records appear at the bottom of the grid rather then just above where ever the current record is at that moment. But thanks for your answer.
Regards,
PhilW.