Delphi grid with a different data type in each row, displayed dynamically - delphi

I am trying to create a Delphi grid to allow display and edit in a db grid of data that might have a different data type on each row. I would like to display a specific control for each data type, e.g. when the data type is DateTime, I want to display my custom edit control that allows typing a date in or popping up a calendar.
The data looks something like this:
Name DataType DateValue StringValue BooleanValue
---------------------------------------------------------
A Date 1/1/2007
B String asdf
C Boolean True
...and in the db, this table has a column for each possible type of value. So, there is a BooleanValue column, DateValue, etc.
What I would like to do is display a single 'Value' column in the grid that displays the appropriate edit control depending on what the 'DataType' is for that row. So, the grid should look like :
Name DataType Value
---------------------------
A Date 1/1/2007
B String asdf
C Boolean True
It seems I will need to display a different edit control (to allow the user to edit the Value column) for each row dynamically based on the value of the DataType column. I know there are more advanced grids out there that handle this sort of problem, but the powers that be will not allow anything but what is available out-of-the-box with Delphi.
Any ideas on how to make something like this work?

Personally, I would not go for editing directly inside the TDBGrid in this case, since your Table is not DB normalized (I don't use it in any case actually). I would have used a Calculated field to display the desired value in the grid, And dynamically created the TDBxxxEdits on the form for each field type (How about your own TDBTreeEdit for example, a TDBRichEdit, or a DB Image pickup editor, etc...?).
In case you do want to use your own controls on the TDBGrid, and replace the default TInplaceEdit editor, you can refer the following article: Adding components to a DBGrid, and a related article: Displaying and editing MEMO fiels in Delphi's TDBGrid

Displaying all of the data in the same column is quite easy. You can simply add a calculated string field, and change the value according to what you are storing in that row.
The editing is quite a bit more complicated. If you want to have an in-place editor, you are in for a world of hurt... I've done it, it's a pain, and takes a lot of time. If you want to display a dialog to edit the value, that's much easier. You can add a column objects to the grid and you can setup the column you have attached to the calc field to display a button. When the button is clicked you simply display the editing dialog needed for that row, and commit the edits when the dialog is closed.
There are other ways to get this done, but I would say the above would be the shortest way. Other ways may include custom draw events to display your data in one column, intercept clicks to create your own editor, etc, etc, etc...

after add calculated fields .
Sample:
procedure OnCalculate(DataSet:TDataSet);
begin
case IndexText(DataSet['ValueType'],['Date','String','Boolean']) of
0:DataSet['DateValue']:=StrToDateTime(DataSet['Value']); // also converting
1:DataSet['StringValue']:=DataSet['Value'];
2:DataSet['BooleanValue']:= MatchText(DataSet['Value'],['1','True','T','Y','Yes']);
{etc datatypes}
end;
end;

Related

How to set focus on a particular row in a TDBgrid Delphi

I want to set the focus on a specific row on a Tdbgridview.
First, I choose the criteria field ( column concerned by search ex: FisrtName) from a combo box then I type criteria in a TeditField (ex : Jack ).
Then the arrow of the Dbgrifd should point on the concerned row.
How should I do?
thanks.
The TDBGrid component (and all other TDBxxx components as well) are what Delphi defines as dataware components. This kind of component exists as a visual expression of a dataset.
So, in a TDBGrid you should not think about focusing a row of the grid, rather think about positioning a row of the grid's dataset (using the Locate method suggested by TLama, for instance). The grid will notice that the current row of its dataset has changed (because the grid is aware about the condition of the dataset) and will focus the corresponding row.
Update 1
Below you can see an example of what I said:
MyDataset.Locate('Id', 123, []);
The code above simply looks for a certain record in a dataset named MyDataset. The first parameter is the name of a existing field in the dataset. So, you have a dataset with some fields and one of those is named Id. The second parameter is the value contained in that field in the desired row and the third parameter is some options that do not apply here. Go to the Delphi docwiki for more details on the Locate method.
In other words, we are looking for a row in which the field Id has the value 123! If the dataset can find such a row, it will become the current record (or row). If there is a TDBGrid connected to a TDataSource that is connected to TMyDataset, it will automatically update to select the corresponding row, just like you wanted.

Delphi - How to get a image for a cxGrid column?

I have a TcxGrid component to show data of a MS Access table. One of this columns have a picture. The column "Properties" of this column is marked as "ButtonEdit".
I don't want to use a BlobEdit. I want to create another form, for display this picture. It will be opened by OnButtonClick() event of the grid column. But, I don't know how to get the column content (as TStream or other type), or the column name/field name in the OnButtonClick() event. I can't fix the column name, because it's a "generic" grid for show any Access table.
How can I do it?
It will be nice to understand your question better if you can post your code. But offcourse You can get column contents easily by using FieldByName method. Try to use that.
You did not say how you load the data into the grid, but to get the cell content you can use:
VarAsType(cxGrid1TableView1.DataController.Values[cxGrid1TableView1.Controller.FocusedRecordIndex,cxGrid1TableView1.Controller.FocusedColumnIndex],varString)

Generating values for dropdown ONLY for 'C' of CRUD

When choosing 'Add' in CRUD, how best to generate a list of choices to pick from a dropdown?
For U/update - just display what's there...
The field contents starts with a letter, followed by five numeric digits:{A-I,K-N,Z}#####
Each letter has a different 'max' value for the numeric part.
So when adding a new record, I'd like to offer a listbox with one of each letter and that letter's highest numeric value + 10.
So, if the max 'A' as A00120, and max 'B' B00030 (etc) the listbox would have A00130 and B00040.. etc
Save the user having to figure out which is 'next' when generating a new record.
? Thanks,
Mark
This time I'll not be able to come up with ready to use solution, but I must say - everything is possible with ATK4. You just have to customize and extend it to fit your needs :)
Speaking about your question above - I guess you have to split it in multiple parts.
First part is about how to show select box on Create and readonly or disabled field on Update. I guess you can make some custom Form field or pin some action to existing Form Field hook. Not sure exactly what's better in this case.
Second one is about data structure. I believe that this field actually should be 2 fields in DB and maybe (only maybe) merged together in ATK model with addExpression() just for user interface needs to display these 2 fields as one field easily in UI. Maybe such concatenated field will be useful also for searching, but definitely not as only one field stored in DB. Imagine how hard it'll be for DB engine to find max value if such field. Store it like type = letter, num = number and then search like SELECT max(num)+10 FROM t WHERE type='A'
Finally Third part is about how to generate this next number. I read your question 3 times and came to conclusion that actually you don't have to show this +10 numeric value in UI at all if it's hardly predefined anyway. Actually that'll not work correctly if this will be multi-user system which I guess it will. Instead just show simple select box with letters {A-I,K-N,Z} and calculate this next value exactly before inserting data in DB. That can be done using models insert hook. This will be much more appropriate solution and will be better for UI and also more stable because calculated in model not incorrectly in UI part.

How to display all data from 2 related tables in a dbgrid with sql

I'm new to delphi and have created an SQL query which displays the results of a search entered by the user through an edit box (showing data from 2 related tables) in a dbGrid.
The dbgrid displays no data until a search has been made and then the results of that search are displayed, however i was wondering whether it was possible to show all the related data in the dbgrid as if it were a table and the search then simply selects from it?
thanks
You could display all the data in the table. Then write an onExit event handler for your edit box which would look something like this (assuming that the string which you are entering in the edit box is supposed to match the value in the 'name' field of the query)
query.locate ('name', edit1.text, [loPartialValue]);
This will cause the dbgrid's cursor to jump to the first line which matches the string in the edit box.
Instead of using the OnExit event, you could also use the OnChange event of the edit box, but this would mean a search after every key stroke.
Your question was a bit vague so it's difficult to give a specific answer.

Benefit of using DBComboBox over CombBox?

So I'm messing around with a new project in Delphi 2009 and the default components that can be dropped onto a form for accessing data consist of a SQLConnection, DataSource and SQLQuery. If I add a simple select to the query component, say:
select name from customers
and then drop a DBComboBox on the form and link it up with the DataSource I get a single record in the combo box. After using Google for half and hour to figure out what I was doing wrong it looks like you have to manually add some code to your project which loops through the dataset and adds all the records to the drop down box. Something like:
while not SQLQuery.eof do
begin
DBComboBox.items.add(SQLQuery.fieldbyname('name').asstring);
SQLQuery.next;
end;
And that actually sort of works, but then you get a list in the drop down which you can't actually select anything from. Regardless of the result though I'm wondering why would you even use a DBComboBox if you have to manually add the result of your query to it? Seems to me that if it doesn't automatically populate the db combo box with the result of the query then we might as well be using a non-data-aware component like tcombobox.
I guess what I'm asking is why does it work this way? Isn't the purpose of data aware drag-and-drop controls to minimize the amount of actual written code and speed development? Is there a method that I'm missing that is supposed to make this easier?
A TDBComboBox doesn't get its list of values from the database; it gets its current value from the database. Link it to a field in your dataset, and when you change the active record, the combo box's current value will change. Change the combo box's current value, and the corresponding field's value will change.
If you want to get the list of values from the database as well, then use a TDBLookupComboBox.
This is all covered in the help:
Using TDBListBox and TDBComboBox
Displaying and Editing Data in Lookup List and Combo Boxes
Defining a Lookup List Column
I think you want the TDBLookupComboBox because that allows you to lookup from a list of items where the list comes from a dataset.
In the TDBComboBox, the list is just a TStrings manually filled with data.
--jeroen
DbCombox is a dbaware version of the standard combobox component.

Resources