I would like to change DBgrid row value with outside data, how to achieve that?
For example i would like to add Tedit value into dbgrid selected row column(for example 5) via button click.
Also, i would like to add value from 1 dbgrid to another dbgrid.(Add to an existing number, not replace).
Suppose you have a dataset connected to db-aware controls like TDBEdit and TDBGrid via a TDataSource. Delphi's db-aware controls are basically the default ones which come with Delphi and are displayed on the Data controls tab of its Component Palette plus any 3rd-party ones that you install. The reason they are called db-aware is because they are written so that the values they display are automatically derived from the related fields of the dataset.
Also suppose that the dataset is called Table1 and has a CustomerName field that you want to change. The simplest code which will achieve that is something like:
Table1.Edit; // put table one into dsEdit state so that field values can be changes
Table1.FieldByName('CustomerName').AsString := 'Jones';
Table1.Post; // save the change(s) to Table1
More optimal code might be
Table1.Edit;
try
Table1.DisableControls; // this prevents the db-aware controls updating on-screen while the changes are made
Table1.FieldByName('CustomerName').AsString := 'Jones';
Table1.FieldByName('CustomeCountry').AsString := 'DE#;
finally
Table1.Post;
Table1.EnableControls; // Eable screen updating od the db-aware controls again
end;
That would update the values displayed in DBEdit controls linked to the CustomerName and CustomerCountry fields and in the CustomerName and CustomerCountry cells of the current (i.e. highlighted) row in the DBGrid, because the current row in the DBGrid always tracks the current row in the connected dataset.
If you really do want to update a given column from a TEdit's text you could do that like this:
Table1.Edit;
DBGrid1.Columns[5].Field.AsString := Edit1.Text;
Table1.Post;
Related
I can't seem to get the fixed row Titles in a DBGrid to align right justified when using a FDMemtable. Whenever I set the Field alignment to taRightJustify it right justifies the data cells perfectly. However, the DBGrid titles are always left justified.
What's even more frustrating is I can set the corresponding DBGrid column title alignment to taRightJustify and it appears perfectly fine in the IDE. But when I run the program the column title shows as left justified.
Has anyone found a way to make DBGrid column titles stay right justified when using a FDMemtable?
BTW, this also happens with taCenter. The data cells align centered but the titles stay left justified.
PEBKAC
The issue was of my own making. I did not invoke the DBGrid Columns Editor and add all the fields. Instead, I was using the "Structure" pane and getting to the DBGrid columns that way. Although the Structure pane allowed me to modify the column titles this was only temporary and did not persist when the program was run.
I can't reproduce the issue using a TFDMemTable either.
I dropped a TFDMemTable, TDataSource, and TDBGrid on a new VCL application's main form, connected them as usual (the grid's datasource set to DataSource1, the datasource's DataSet set to FDMemTable1), and then added the below code to the form's OnCreate event:
procedure TForm3.FormCreate(Sender: TObject);
begin
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, True);
FDMemTable1.FieldDefs.Add('LastName', ftString, 20);
FDMemTable1.FieldDefs.Add('FirstName', ftString, 20);
FDMemTable1.FieldDefs.Add('Salary', ftCurrency);
FDMemTable1.CreateDataSet;
FDMemTable1.Active := True;
FDMemTable1.AppendRecord([1, 'Smith', 'John', 30000]);
FDMemTable1.AppendRecord([2, 'Jones', 'Jane', 40000]);
FDMemTable1.AppendRecord([3, 'Doe', 'David', 2500]);
DBGrid1.Columns[3].Alignment := TAlignment.taRightJustify;
DBGrid1.Columns[3].Title.Alignment := TAlignment.taRightJustify;
end;
It also works correctly if I set everything up at designtime. Repeat the same setup steps I used above, but instead of using the code, use the following steps:
Select FDMemTable1 in the Object Inspector. At the bottom of the OI, click the LoadFromFile link, and navigate to the BDS Samples data folder (by default, in C:\Users\Public\Public Documents\Embarcadero\Studio\17.0\Samples\Data) and select animals.fds. (No specific reason for choosing that one, except it has a numeric field we can use for testing.)
Right-click on the DBGrid, and choose Columns Editor, or click the ellipsis button on the DBGrid.Columns property in the Object Inspector. Right-click in the Columns Editor and choose Add all fields.
Select either the Size or Weight column, expand it's Title property, and set Alignment to taRightJustify.
Run the application. The column you modified in step #3 above has a right-aligned title. (Here I used the Size column.)
The code below works for me in Seattle. I'm using a TClientDataSet rather than a TFDMemTable, but I can't see that that would make any difference.
If you have persistent columns defined on your DBGrid, you can also set a column's title alignment via the Object Inspector - use it to select the column, then expand its Title node and you can set the title alignment there.
procedure TForm1.CDS1AfterOpen(DataSet: TDataSet);
var
i : Integer;
begin
for i := 0 to DBGrid1.Columns.Count - 1 do
DBGrid1.Columns[i].Title.Alignment := taRightJustify;
end;
Btw, if you think you're setting the alignment in the OI but it's getting ignored, see if you can find out why, as follows:
Make sure your form is saved, then right-click on it and select View as text. Then, in the IDE editor window, you can see whether the Alignment property is saved as you've specified in the OI. Use the editor context menu to return to viewing the form as a form.
Add an override of the form's Loaded method as I've described in a comment. With a breakpoint on the inherited in Loadeds body, you can inspect the Alignment value before and after inherited is called.
Why am I suggesting looking into Loaded? Well, it is called after a form is streamed in from the DFM and is the routine where the run-time system finishes setting up the form. Sometimes, admittedly very rarely, another component (usually a 3rd-party one) misbehaves and causes strange behaviour of the properties of other compononents.
I am using the cxGrid. I have a field (column) in my grid that is of boolean type (true/false) represented in the grid as a checkbox. How can I make all the checkboxes in the column checked (or unchecked) on button click ?
it looks like this :
Now I would like, on button click, to turn those 3 checkboxes checked BEFORE I save everything..
DATA on the left(USERS) comes from a table, the data on the right is from a query. The SAVE of everything goes to a separate LOG table.
When I hit 'Check all' button,the result :
I could run the update query : update MYFIELD set SELECTED = '2';
but I am more interested in manipulating the grid itself.Something simple...
You will have to add a button or pop up menu somewhere on your form to accept the check all 'command', or maybe even place a checkbox in your column header. Then go through your underlying dataset and set all field values. Don't forget a DisableControls/EnableControls.
added an extra field to my table (boolean type) and changed its property in the cxGrid to that of a checkbox.Then on button click:
with uniquery1 do begin
Active:=False;
sql.Clear;
SQL.Add('update users set selected = 0'); //or '1'
execSql;
end;
Uniquery1.Refresh;
this I found was the easiest way ....
Is it possible to get the row number that is displayed from the underlying dataset in the top-most row of a DBGrid, without that top-most row being the currently selected row, when the number of records in the underlying dataset is greater than the number of rows displayed in the DBGrid, and the DBGrid has been scrolled.
Here's my problem. From a drag/drop event handler attached to the DBGrid I can determine which visible row of the DBGrid the drop event is associated with using MyGrid.MouseCoord(X,Y).Y. When the underlying dataset contains less than or the same number of records as the number of rows displayed in the DBGrid, this value is also the row number of the associated record in the underlying dataset.
When the underlying dataset contains more records than the number of visible rows in the DBGrid, MyGrid.MouseCoord(X, Y).Y and TDataSet(MyGrid.DataSource.DataSet).RecNo are the same only when the first row of the dataset appears on the first row of the grid.
Is there some way to identify the record number in the underlying dataset (or the offset) of the top-most displayed record in a DBGrid without that DBGrid row being selected? I know that if I actually select the top-most row of the DBGrid then I can use TDataSet(MyGrid.DataSource.DataSet).RecNo to get the current record number of the underlying dataset. However, from DBGrid.OnDragOver or DBGrid.OnDragDrop events I only have a reference to the DBGrid and the mouse coordinates (from which I can determine which row of the grid was the target of the drop).
For example, if I can determine that the DBGrid is displaying the third record in the underlying dataset in the top-most row of the grid, my problem is solved. Likewise, if I can read an underlying TField of a particular row (say, the top-most row) without that row being select, I have what I need. However, I cannot see a way to do this.
Any suggestions will be greatly appreciated.
Edit: I previously posted a blog about dragging and dropping into a DBGrid. With this new info, I can solve a previously known problem. I will be updating that blog sometime this week, and will add a link to that blog here once I have done so.
There is an additional issue. When the number of visible rows is less than the number of underlying records, we need to also accomdate calculating the drop when it occurs after the last visible row. When dropping after the last visible row, MouseCoord(x,y).Y returns -1.
Here is a modification to Uwe's code that accomplishes that end:
function TDBGridHelper.RecNoFromVisibleRow(Value: Integer): Integer;
begin
if Value = -1 then
begin
Result := DataSource.DataSet.RecNo - Row + TopRow + VisibleRowCount
end
else
begin
Result := DataSource.DataSet.RecNo - Row + TopRow + Value;
if dgTitles in Options then
Dec(Result);
end;
end;
Edit: As I mentioned in the original question, I was interested in this answer in order to fix a behavior in my code that implements drag and drop into a DBGRid. With this answer I have updated my drag and drop behavior, and I have written about this update in my blog. You can find this discussion, including links to the original blog post, at the following URL: Dragging and Dropping into a DBGrid Revisited
As long as there is only an offset between DataSet.RecNo and the visible rownumber in the grid, you might get the required information from the protected members Row and TopRow, which can be accessed by a class helper. Something like this:
function TDbGridHelper.RecNoFromVisibleRow(Value: Integer): Integer;
begin
Result := DataSource.DataSet.RecNo - Row + TopRow + Value;
if dgTitles in Options then
Dec(Result);
end;
I'm making a simple program for use in automotive parts shop. Here's how it's supposed to look: Link
The problem is the small window on the left. It should be opened when double clicked on any of the rows in DBGrid in the main window, and it should show all of the selected item's characteristics in DBEdit fields. If the Save button is clicked it should save the changes from the DBEdit fields into the database, but otherwise it should just ignore the changes.
I succeeded opening another form by double click on a field in DBGrid by using this code:
procedure TForm1.DBGrid1DblClick(Sender: TObject);
begin
if not Assigned(Form2)
then Form2 := TForm2.Create(Application);
Form2.Show;
end;
The only problem now is how to get the program to detect which row in the DBGrid is selected and then show its contents in DBEdit fields in the smaller window.
Can anyone tell me how to do this, please?
Thanks!
Just add the TDBEdits to TForm2, and connect them to the same DataSource as the DBGrid is using. They will automatically show the contents of the same row that is selected in the DBGrid, and you can edit or insert into the DataSource's DataSet and have the new or changed data appear in the DBGrid automatically.
There are many ways to achieve this. I'll describe two:
If you link the DBEdits in the little window to the same DataSource as the DBGrid's, then you are all set
OR
You can pass whatever info you want inside DBGrid1DblClick from Form1 to Form2. This option, by itself, has many possibilities.
Update
For the DataSource to be visible in Form2, unit to make Form2's unit use Form1's unit.
I got a dbGrid with X rows.
I want to update a field-value in the second row with a timer (for example, show a countdown).
Thats no problem, but I want to be able to change the selected row and keep updating the second row.
When the selection changes in the grid, the current record of the connected dataset changes as well, and thats a problem because the code in the timer points to the selected record.
How could that be solved?
Thanks!
If dataset connected to dbGrid is TClientDataSet, you can drop another TClientDataSet and clone data from grid's dataset.
Since both datasets will point to same data, you can change values in cloned dataset, and that data will show in dbGrid without tampering with dbGrids dataset.
Try this very straightforward approach:
if DataSource1.DataSet.State in dsEditModes then
DataSource1.DataSet.Post; { or Cancel, depends on your needs }
try
DataSource1.DisableControls;
Bookmark := ClientDataSet1.GetBookmark;
try
if ClientDataSet1.Locate(SecondRowId, 'Id', []) then
begin
ClientDataSet1.Edit;
ClientDataSet1['Counter'] := Counter;
ClientDataSet1.Post;
end;
ClientDataSet1.GotoBookmark(Bookmark);
finally
CLientDataSet1.FreeBookmark(Bookmark);
end;
finally
DataSource1.EnableControls;
end;