Have cxGrid expand current date - delphi

I made my grid group by date (grabbed the column name and dragged it to where it says 'group by that column'). However, when the grid is displayed all the dates are 'closed' so I must expand them to see data. That is OK but I wonder if it is possible to have current date expanded already (all other should remain closed !) so I do not have to click the expand cross?

try this, you can put the code in other event handler like a TButton for example
procedure TForm1.FormCreate(Sender: TObject);
begin
//aDBTableView1.ViewData.Expand(true); // this is how to expand all records
aDBTableView1.ViewData.Records[YourRecordNumber].Expand(true); // this is how to expand by a given record
end;
OK try the following
procedure TForm1.FormCreate(Sender: TObject);
begin
with cxGrid1DBTableView1 do
begin
DataController.DataSource.DataSet.Locate('YourDateFieldName',DateTimeToStr(Date),
[loPartialKey]);
ViewData.Records[DataController.FocusedRowIndex].Expand(True);
end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
intLoop,
vValue: Variant;
begin
for intLoop := 0 to self.cxGrid1DBTableView1.DataController.RowCount - 1 do
begin
if self.cxGrid1DBTableView1.ViewData.Rows[IntLoop] is TcxGridGroupRow then
begin
if TcxGridGroupRow(cxGrid1DBTableView1.ViewData.Rows[IntLoop]).Level = cxGrid1DBTableView1MyDate.GroupIndex then
begin
vValue:=TcxGridGroupRow(cxGrid1DBTableView1.ViewData.Rows[IntLoop]).Value ;
if vValue = Date() then
begin
TcxGridGroupRow(cxGrid1DBTableView1.ViewData.Rows[intLoop]).Expand(False);
end;
end;
end;
end;
end;

Related

How to cast selected TListViewItem from "OnItemClick" event, on assigning to multiple buttons?

i have an application with 2 TButton, 1 TListView. I would like display the value or content(Text) of TListViewItem inside the TButton(s) in a way that the content of the first TButton can't be the same with the 2nd one.
Steps =>>
When I click on the 1st TButton, I can select the Item text in the TListView and save it as new TButton text.
When I click on the 2nd TButton, I can select another item text in the same TListView, and it is saved as Text in the 2nd TButton.
My code:
....
ListView1: TListView;
Base: TButton;
Hypo: TButton;
....
procedure TMainForm.BaseClick(Sender: TObject);
begin
ListView1.Visible := True;
end;
procedure TMainForm.HypoClick(Sender: TObject);
begin
ListView1.Visible := True;
end;
procedure TMainForm.ListView1ItemClick(const Sender: TObject;
const AItem: TListViewItem);
begin
if Assigned(ListView1.Selected) and Assigned(Base.OnClick) then
begin
Base.Text := TListViewItem(ListView1.Selected).Text;
end else
if Assigned(ListView1.Selected) and Assigned(Hypo.OnClick) then
begin
Hypo.Text := TListViewItem(ListView1.Selected).Text;
end;
ListView1.Visible := False;
end;
I used LiveBindings to fill the TListView; when i run the app and select one item it works but it's displaying the same value/content in both TLabels
If you really have 2 selected items, then you have to iterate through the whole list view
procedure TForm3.ListView1ItemClick(const Sender: TObject;
const AItem: TListViewItem);
var elvitem : TListViewItem;
i,n : integer;
begin
n:=0;
for i:=0 to ListView1.ItemCount-1 do
begin
if ListView1.Items[i].Purpose=TListItemPurpose.None then // it's an item
begin
if ListView1.Items[i].Checked then
begin
inc(n);
case n of
1 : base.text:=ListView1.Items[i].Text;
2 : begin
hypo.text:=ListView1.Items[i].Text;
break; // don't search more
end;
end;
end;
end;
end;
Here item 2 and 8 are selected with this code
procedure TForm3.FormCreate(Sender: TObject);
begin
Listview1.Items[2].Checked:=True;
Listview1.Items[8].Checked:=True;
end;
My first reaction, if your listview is livebinded then why don't you use livebindings to link your 2 labels ?
Second one is your code, you use Selected when you have the AItem parameter
so
procedure TMainForm.ListView1ItemClick(const Sender: TObject;
const AItem: TListViewItem);
begin
Base.Text:= AItem.text;
Hypo.Text:= AItem.detail;
ListView1.Visible := False;
end;
should be sufficient if it is not a DynamicAppearance type.

Delphi - Get all column names of selected row from DBGrid

I'm using the following code to display the values of every column from a row I select in my DBGrid, to a Memo.
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
Memo1.Clear;
with DBGrid1 do
begin
for i:=0 to FieldCount-1 do
Memo1.Lines.Add(Fields[i].AsString);
end;
end;
Anyone have any ideas how to also get the column names, before the value?
For example 1st column is named ID, the 1st value shown on the memo is the ID value (let's say 15) - I'd like it to be ID:15 (column_name:column_value)
if you need column name and values
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
Memo1.Clear;
with DBGrid1 do
begin
for i:=0 to Columns.Count-1 do
Memo1.Lines.Add(Columns[i].FieldName+':'+ Columns[i].Field.AsString);
end;
end;

How to repeat the procedure of a button

I have developed two procedures of two buttons to for task 1 and task 2. Do you know how to create the new button which can repeat the procedures of two previous buttons to perform task 1 + 2 in assigned number of times ?
Extract the tasks into separate methods:
procedure TForm1.DoTask1;
begin
....
end;
procedure TForm1.DoTask2;
begin
....
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DoTask1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DoTask2;
end;
And then add a new button with OnClick handler like this:
procedure TForm1.Button3Click(Sender: TObject);
var
i: Integer;
begin
for i := 1 to N do
begin
DoTask1;
DoTask2;
end;
end;

Reassigning a datasource at run-time

I did some searching and only found more unanswered questions. :)
Using D5pro.
I want to reassign the DataSource to a TDBGrid at run time. I have seven identical structured DataSets and depending on a button click I want the appropriate DataSet displayed in the grid.
I have tried everything and I cannot get it to show the next DataSet. It sticks with the first one assigned at start up. I am getting to overkill approaches and still nothing is working. Here's where I am at the moment.
procedure SetSource(var aSrc : TDataSource);
begin
aSrc.DataSet.Close;
dbgridShowData.DataSource:=aSrc;
aSrc.DataSet.Open;
aSrc.DataSet.First;
aSrc.DataSet.Refresh;
end;
Where am I going wrong?
Thanks
You can change the Dataset shown by a DBGrid quite easily at runtime quite easily. There two approaches:
1: use a single DataSource assigned to DBGrid.DataSource and change the DataSource.DataSet to the desired DataSet. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet3;
end;
2: use a DataSource for each DataSet and change DBGrid.DataSource to the desired DataSource. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
DataSource2.DataSet := DataSet2;
DataSource3.DataSet := DataSet3;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource3;
end;
If you define the columns of the DBGrid, the structure of the DataSets will need to be the the same, or you will have to change the column definitions when you change the Dataset displayed.
I prefer using a DataSource per DataSet because it is more flexible.
You probably need to change the DataSource.DataSet instead:
procedure SetDataFromDataSet(const aDataSource: TDataSource;
const aNewDataSet: TDataSet);
begin
aDataSource.DataSet.Close;
aDataSource.DataSet := aNewDataSet;
if not aNewDataSet.Active then
aNewDataSet.Open;
end;
Sample use:
SetDataFromDataSet(DataSource1, CustomerQuery);
You may not want to close and open datasets globally like this, though. It's probably better to do that from the calling code. Of course, that would depend on what you need for your app.
Tested with Delphi5 pro.
procedure TForm1.setDataSourceDataSet(var newDataSource:TDataSource);
begin
if DBgrid1.DataSource = nil then begin
DBgrid1.DataSource:=newDataSource;
end else begin
if DBgrid1.DataSource.Name = newDataSource.Name then exit;
DBGrid1.DataSource.Enabled:=False;
DBgrid1.DataSource:=newDataSource;
end;
If DBgrid1.DataSource.DataSet.active=False then DBgrid1.DataSource.DataSet.active:=True;
DBGrid1.DataSource.Enabled:=True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource1);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource2);
end;
The secret lies in:
DBGrid1.DataSource.Enabled:=False;
...making changes...
DBGrid1.DataSource.Enabled:=True;
Tested with D5Pro

How can I filter the contents of a combo box based on what's been typed?

We have a combo box with more than 100 items.
We want to filter out the items as we enter characters in combo box. For example if we entered 'ac' and click on the drop down option then we want it to display items starting with 'ac' only.
How can I do this?
Maybe you'd be happier using the autocompletion features built in to the OS. I gave an outline of how to do that here previously. Create an IAutoComplete object, hook it up to your combo box's list and edit control, and the OS will display a drop-down list of potential matches automatically as the user types. You won't need to adjust the combo box's list yourself.
To expand on Rob's answer about using the OnChange event, here is an example of how to do what he suggests.
procedure TForm1.FormCreate(Sender: TObject);
begin
FComboStrings := TStringList.Create;
FComboStrings.Add('Altair');
FComboStrings.Add('Alhambra');
FComboStrings.Add('Sinclair');
FComboStrings.Add('Sirius');
FComboStrings.Add('Bernard');
FComboStrings.Sorted := True;
ComboBox1.AutoComplete := False;
ComboBox1.Items.Text := FComboStrings.Text;
ComboBox1.Sorted := True;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(FComboStrings);
end;
procedure TForm1.ComboBox1Change(Sender: TObject);
var
Filter: string;
i: Integer;
idx: Integer;
begin
// Dropping down the list puts the text of the first item in the edit, this restores it
Filter := ComboBox1.Text;
ComboBox1.DroppedDown := True;
ComboBox1.Text := Filter;
ComboBox1.SelStart := Length(Filter);
for i := 0 to FComboStrings.Count - 1 do
if SameText(LeftStr(FComboStrings[i], Length(ComboBox1.Text)), ComboBox1.Text) then
begin
if ComboBox1.Items.IndexOf(FComboStrings[i]) < 0 then
ComboBox1.Items.Add(FComboStrings[i]);
end
else
begin
idx := ComboBox1.Items.IndexOf(FComboStrings[i]);
if idx >= 0 then
ComboBox1.Items.Delete(idx);
end;
end;
My brief contribution working with objects in the combobox:
procedure FilterComboBox(Combo: TComboBox; DefaultItems: TStrings);
function Origin: TStrings;
begin
if Combo.Tag = 0 then
begin
Combo.Sorted := True;
Result := TStrings.Create;
Result := Combo.Items;
Combo.Tag := Integer(Result);
end
else
Result := TStrings(Combo.Tag);
end;
var
Filter: TStrings;
I: Integer;
iSelIni: Integer;
begin
if(Combo.Text <> EmptyStr) then
begin
iSelIni:= Length(Combo.Text);
Filter := TStringList.Create;
try
for I := 0 to Origin.Count - 1 do
if AnsiContainsText(Origin[I], Combo.Text) then
Filter.AddObject(Origin[I], TObject(Origin.Objects[I]));
Combo.Items.Assign(Filter);
Combo.DroppedDown:= True;
Combo.SelStart := iSelIni;
Combo.SelLength := Length(Combo.Text);
finally
Filter.Free;
end;
end
else
Combo.Items.Assign(DefaultItems);
end;
You can handle the combo box's OnChange event. Keep a master list of all items separate from the UI control, and whenever the combo box's edit control changes, adjust the combo box's list accordingly. Remove items that don't match the current text, or re-add items from the master list that you removed previously.
As Rob already answered, you could filter on the OnChange event, see the following code example. It works for multiple ComboBoxes.
{uses}
Contnrs, StrUtils;
type
TForm1 = class(TForm)
ComboBox1: TComboBox;
ComboBox2: TComboBox;
procedure FormCreate(Sender: TObject);
procedure ComboBoxChange(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
FComboLists: TList;
procedure FilterComboBox(Combo: TComboBox);
end;
implementation
{$R *.dfm}
procedure TForm1.ComboBoxChange(Sender: TObject);
begin
if Sender is TComboBox then
FilterComboBox(TComboBox(Sender));
end;
procedure TForm1.FilterComboBox(Combo: TComboBox);
function Origin: TStrings;
begin
if Combo.Tag = 0 then
begin
Combo.Sorted := True;
Result := TStringList.Create;
Result.Assign(Combo.Items);
FComboLists.Add(Result);
Combo.Tag := Integer(Result);
end
else
Result := TStrings(Combo.Tag);
end;
var
Filter: TStrings;
I: Integer;
begin
Filter := TStringList.Create;
try
for I := 0 to Origin.Count - 1 do
if AnsiStartsText(Combo.Text, Origin[I]) then
Filter.Add(Origin[I]);
Combo.Items.Assign(Filter);
Combo.SelStart := Length(Combo.Text);
finally
Filter.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FComboLists := TObjectList.Create(True);
// For Each ComboBox, set AutoComplete at design time to false:
ComboBox1.AutoComplete := False;
ComboBox2.AutoComplete := False;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FComboLists.Free;
end;

Resources