I have a grid that I use to display few query results (cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView1; etc ...). On form close, I close the queries as well.
However, the former columns that were last displayed remain visible (when I return to that form again) How can I eliminate these traces of columns as well? I would like empty grid when I return to the form.
Edit : This is the query that I run :
procedure TForm2.cxRadioGroup1Click(Sender: TObject);
begin
case cxRadioGroup1.ItemIndex of
0: begin
with Form1.UniQuery3 do begin
Close;
sql.Clear;
sql.Add('select * from program_log');
Open;
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView1;
end;
end;
1: begin
with Form1.UniQuery4 do begin
Close;
sql.Clear;
sql.Add('select * from guests_log');
Open;
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView2;
end;
end;
end;
end;
Calling
cxGrid1DBTableView1.ClearItems;
Removes all traces of columns which are then unavailable if I want to run the query again.
The easiest way to accomplish this is to create another cxgridlevel > cxGrid1dbtableview. Then just call set this level on form show:
procedure TForm2.FormShow(Sender: TObject);
begin
cxGrid1.ActiveLevel.GridView := cxGrid1DBTableView3;
end;
Since it is assigned to nothing so will the grid display empty.
Calling cxGrid1DBTableView1.ClearItems will remove all columns. Just call it in your FormClose event handler. To recreate columns call cxGrid1DBTableView1.DataController.CreateAllItems function.
Related
I have these controls TDateTimePicker, TComboBox, Tedit and TButton. TButton is disabled by default. What I would like to achieve is to enable TButton when all the other controls are filled or not null.
With the following codes, all the 3 controls starting with TDateTimePicker when filled I don't have any issues it works as expected.
The error comes when I fill TComboxBox followed by TEdit, it enables the TButton even TDateTimePicker is not filled yet. Or vise versa, I will fill TEdit followed by TComboBox, it enables the TButton.
From the codes below, I expect the TButton will not enable unless all the 3 controls are filled.
I've been trying to figure out (all day) how this error come to happen.
I will appreciate anyone there help me figure this out.
procedure TfrmHolidays.EnableSaveButton;
begin
if (edtHolidayName.Text <> NullAsStringValue) and (cmbHolidayType.ItemIndex <> -1)and (dtpHolidayDate.Date <> 0) then
begin
btnHolidaySave.Enabled := True;
end
else
begin
btnHolidaySave.Enabled := False;
end;
end;
procedure TfrmHolidays.dtpHolidayDateChange(Sender: TObject);
begin
EnableSaveButton;
end;
procedure TfrmHolidays.cmbHolidayTypeChange(Sender: TObject);
begin
EnableSaveButton;
end;
procedure TfrmHolidays.edtHolidayNameChange(Sender: TObject);
begin
EnableSaveButton; // triggers enable btnHolidaySave button
end;
By the way, I have more code related to making TDateTimePicker a blank and I supposed there's no issues with that. I also tried nesting within If Statement each condition and I am still getting the error. Further, I tested each condition at a time and It works fine.
Updates:
Here's how I initialized the dtpHolidayDate.Date:
procedure TfrmHolidays.FormCreate(Sender: TObject);
begin
DateTime_SetFormat(dtpHolidayDate.Handle, ' ');
FDTMDateEmpty := True;
end;
procedure TfrmHolidays.dtpHolidayDateCloseUp(Sender: TObject);
begin
DateTime_SetFormat(dtpHolidayDate.Handle, PChar('MMM dd yyyy (ddd)'));
end;
procedure TfrmHolidays.dtpHolidayDateChange(Sender: TObject);
begin
FDTMDateEmpty := False;
EnableSaveButton; // same and updated procedure above
end;
As pointed out in the comments above, you do not have an initialised value for the TDateTimePicker.
What you want is to have it default to a sensible date, rather than set to 0 - that is not at all helpful to users.
I would introduce a Boolean flag that you set yourself once the TDateTimePicker has been set.
You could set this flag in the OnChange event handler.
So something like:
interface
protected
blMyDTFlag: Boolean;
...
implementation
function TfrmHolidays.dtpHolidayDateChange(Sender: TObject);
begin
Self.blMyDTFlag:=True;
end
procedure TfrmHolidays.EnableSaveButton;
begin
if (edtHolidayName.Text <> '') and
(cmbHolidayType.ItemIndex <> -1) and
(Self.dtMyDTFlag) then
btnHolidaySave.Enabled := True
else
btnHolidaySave.Enabled := False;
end;
Although not shown in the question, I can guess that you initialize the date by
dtpHolidayDate.Date := 0;
After this, testing the date against 0 will (most likely) fail because the time portion still contains the time that the control is created.
You can initialize by
dtpHolidayDate.DateTime := 0;
then you can test the date as you do.
Alternatively you can use SameDate to do the comparison.
uses
dateutils;
if (edtHolidayName.Text <> NullAsStringValue) and (cmbHolidayType.ItemIndex <> -1)
and (not SameDate(dtpHolidayDate.Date, 0)) then
I would like to retrieve a value from a TDBGrid the selected row, how can I do?
procedure TForm7.Button2Click(Sender: TObject);
var
i, j: Integer;
s: string;
begin
if DBGrid1.SelectedRows.Count>0 then
with DBGrid1.DataSource.DataSet do
for i:=0 to DBGrid1.SelectedRows.Count-1 do
begin
GotoBookmark(DBGrid1.SelectedRows.Items[i]);
for j := 0 to FieldCount-1 do
begin
if (j>0) then s:=s+', ';
s := s + FindField(Fields.Fields[j].FieldName).AsString;
end;
Listbox1.Items.Add(s);
s:= '';
end;
end;
The code below fixes a few problems with yours.
The main problems were the fact that you weren't correctly initialising s and your way of getting the fields for the selected row(s) was flawed.
The calls to DataSet.Disable/EnableControls and ListBox1.Items.BeginUpdate/EndUpdate are to speed the process up.
Also, avoid the with construct like the plague. As you can see, my use of a local DataSet variable instead involves minimal extra typing and avoids all sorts of accidental problems that can arise when you use with.
procedure TForm1.GetSelected;
var
i,
J : Integer;
s : String;
DataSet : TDataSet;
begin
if DBGrid1.SelectedRows.Count>0 then begin
DataSet := DBGrid1.DataSource.DataSet;
// with DBGrid1.DataSource.DataSet do
try
ListBox1.Items.BeginUpdate;
DataSet.DisableControls;
for i:=0 to DBGrid1.SelectedRows.Count-1 do
begin
DataSet.GotoBookmark(Pointer(DBGrid1.SelectedRows.Items[i]));
s := '';
for j := 0 to DataSet.FieldCount - 1 do
begin
if (j>0) then s:=s+', ';
s := s + DataSet.Fields[j].AsString;
//s := s + FindField(Fields.Fields[j].FieldName).AsString;
end;
Listbox1.Items.Add(s);
//s:= '';
end;
finally
DataSet.EnableControls;
ListBox1.Items.EndUpdate;
end;
end;
end;
**Update: **
You can set the current grid row as selected like this
DBGrid1.SelectedRows.CurrentRowSelected := True;
Update #2
The grid's selected rows are stored in a TBookmarkList named SelectedRow. To clear the current selections, all you need do is to call its Clear method, like so:
procedure TForm1.btnClearSelectedClick(Sender: TObject);
begin
DBGrid1.SelectedRows.Clear;
end;
Equally, if you want to clear your ListBox, you just call its Clear method, as in:
procedure TForm1.btnClearListBoxClick(Sender: TObject);
begin
ListBox1.Clear;
end;
If you are having trouble getting my code to work, try this:
In the Object Inspector, set the DBGrid Options property dgMultiSelect to True.
Place a button on your form and in its OnClick handler call GetSelected.
Compile and run. Click a row in the grid and then the button. Nothing happens. The reason is that clicking the button moves focus away from the DBGrid, so that as far as it is concerned, none of its rows is selected. Then try step 3.
Run the app again. This time press and hold the Ctrl key while you click the grid then the button. This time the selected row appears in the ListBox. With the Ctrl button still down, click another row in the grid, then the button. This time, both rows are added to the ListBox.
only a single line call is needed to retrieve a value when you know the column number. The system will automatically return values from the current row, or last line clicked or double-clicked in a grid list.
var colidx : integer; ss : string;
..
ss := DBGrid1.Fields[colidx].AsString;
this is my method to retrieve the key
procedure TfrmArticle.Button2Click(Sender: TObject);
begin
op:='M';
with frmajtArticlee do
begin
Edit1.text:=dm.ADOQueryArticle.fieldbyname('ID_prod').Value;
Edit2.text:=dm.ADOQueryArticle.fieldbyname('ref_art').Value;
Edit3.text:=dm.ADOQueryArticle.fieldbyname('code_barre').Value;
Edit4.text:=dm.ADOQueryArticle.fieldbyname('marque').asstring;
Edit5.text:=dm.ADOQueryArticle.fieldbyname('qts_art').Value;
Edit6.text:=dm.ADOQueryArticle.fieldbyname('designation').asstring;
Edit7.text:=dm.ADOQueryArticle.fieldbyname('prix_achats_ht').Value;
Edit8.text:=dm.ADOQueryArticle.fieldbyname('prix_vente_faciliter').Value;
Edit9.text:=dm.ADOQueryArticle.fieldbyname('prix_vente_cache').Value;
val_mod:=dm.ADOQueryArticle.fieldbyname('ID_prod').asstring;
val_mod:string "declare it in public "
IF YOU'RE NEED TO FIND HOW TO GET DATA OF A SELECTED ROW IN THE DBGRID, I HAD THE HINT. I USE DBGRID.SelectedField TO GET THE SELECTED FIELD AND CONVERT THE FIELD TO BE SELECTED TO BOOKMARK BY DB_GRID.SelectedField.DataSet.Bookmark
AND USE DATASET.GOTOBOOKMART TO GO TO THE SELECTED RECORD FIELD IN DBGRID DB_DATA.DataSet.GotoBookmark (DB_GRID.SelectedField.DataSet.Bookmark);
This is driving me nuts ....
I fetch the names of my databases to populate the cxComboBox1:
procedure TForm1.FormShow(Sender: TObject);
var
I: Integer;
DBList: TStringDynArray;
begin
DBList := TDirectory.GetFiles(ExtractFilePath(ParamStr(0)), '*.abs', TSearchOption.soAllDirectories);
for I := 0 to Length(DBList) - 1 do
begin
cxCombobox1.Properties.Items.Add(DBList[I]);
end;
end;
This works OK.The list of my databases show in the cxCombobox1.
In the second cxCombobox I populate the table names that belong to the database
displayed in cxCombobox1.
procedure TForm1.cxComboBox1PropertiesChange(Sender: TObject);
var
TABLES: TStringList;
i: integer;
begin
if ABSTable1.Active = True then
ABSTable1.Close;
cxComboBox2.properties.Items.Clear;
TABLES := TStringList.Create;
ABSDatabase1.DatabaseFileName:=cxCombobox1.Text;
try
ABSDatabase1.Open;
ABSDatabase1.GetTablesList(TABLES);
for i:= 0 to TABLES.Count-1 do
cxComboBox2.properties.Items.Add(TABLES[i]);
finally
TABLES.free;
end;
end;
This basically works ok. Selecting the database in the cxComboBox1 populates the cxComboBox2
with pertinent tables.
So the general idea is to open the table when selected in the cxComboBox2.
And I did :
procedure TForm1.ABSTable1BeforeOpen(DataSet: TDataSet);
begin
ABSTable1.DatabaseName:= ABSDatabase1.DatabaseName;
ABSTable1.TableName := cxComboBox2.Text;
end;
And on combobox2 change event I did:
procedure TForm1.cxComboBox2PropertiesChange(Sender: TObject);
begin
cxGrid1DBTableView1.ClearItems;
ABSTable1.Open;
cxGrid1DBTableView1.DataController.CreateAllItems;
end;
This works ok. But only when I open the tables from the selected database (combobox1)
that are displayed in the combobox2.
Say I have the table opened and then go select another database in the combobox1
I get the error "Missing ABSTable1.Tablename" !
What am I missing here? Where is my table name getting lost ?
If I replace the combobox2 on change event with a button :
procedure TForm1.cxButton2Click(Sender: TObject);
begin
if ABSTable1.Active = True then
ABSTable1.Close;
cxGrid1DBTableView1.ClearItems;
ABSTable1.Open;
cxGrid1DBTableView1.DataController.CreateAllItems;
end;
then everything works....
This happens because you call Items.Clear() in cxComboBox1PropertiesChange which raises a change event which in return results in a call to cxComboBox2PropertiesChange.
You should use Items.BeginUpdate() before any update and Items.EndUpdate() when you finished the update to avoid raising events on each updated step / item.
This is related to another question but doesn't really fit enough to include it with the original. When a Post is called, how can I get the field (or fields) that was modified to a TField?
For logging, I use the OnBeforePost event, which is called (as it says) just before the data is posted. The drawback to this, of course, is that your log table has to have fields wide enough to hold all possible content.
procedure TMyData.SomeTableBeforePost(DataSet: TDataSet);
var
i: Integer;
begin
for i := 0 to DataSet.FieldCount - 1 do
begin
// Skip calculated and lookup fields
if DataSet.Fields[i].FieldType = ftData then
begin
if DataSet.Fields[i].OldValue <> DataSet.Fields[i].NewValue then
begin
LogTable.Insert;
LogTableColumnName.AsString := DataSet.Fields[i].FieldName;
LogTableOldValue.Value := DataSet.Fields[i].OldValue;
LogTableNewValue.Value := DataSet.Fields[i].NewValue;
LogTable.Post;
end;
end;
end;
end;
I have a form with 2 grids showing records selected using master-detail option on Devart UniQuery. This working very nice showing the wanted records in detail that relates to master.
I have the option to select records (companies) using a filter. This is done by 30 buttons with a letter on each and then when pressing one I set the filter with this code
procedure TfrmJsCompanies.ButtonClick(Sender: TObject);
var
ButtonValue: char;
FilterString: string;
begin
ButtonValue := (Sender as TcxButton).Caption[1];
FilterString := ButtonValue + '%';
with grdCompaniesView1.DataController.Filter.Root do
begin
Clear;
BoolOperatorKind := fboOr;
AddItem(colCompany_Name, foLike, FilterString, FilterString);
end;
grdCompaniesView1.DataController.Filter.Active := True;
grdCompaniesView1.FilterRow.Visible := False;
ActiveControl := grdCompanies;
end;
If I do this i get the result I expect unless I first press a button that gives me master records that has detail records and there after press a button that gives me no master records - in this case the detail records from the previous selection are still shown in my detail grid
What can I do to get rid of this?
This behavior is caused by the fact that filtering is executed on the cxGrid level, but not on the DataSet level and, as a result, the DataSet is not filtered.
One way to deal with that could be:
procedure TForm1.DetailViewFilterRecord(ADataController: TcxCustomDataController; ARecordIndex: Integer;
var Accept: Boolean);
begin
Accept := MasterView.DataController.FilteredRecordCount >0;
end;
procedure TForm1.MasterViewDataControllerFilterChanged(Sender: TObject);
begin
DetailView.DataController.Refresh
end;