FastReports - programatically set text in a text object field - delphi

I am trying to pass the content of AdvOfficeStatusBar1.Panels[0] to a Memo 4 of the frxreport1. The AdvOfficeStatusBar1.Panels[0] is date type (psDate). So before I open the report I would like the Memo to display my statusbar date.

I found out this by myself :
procedure TForm1.cxButton1Click(Sender: TObject);
var
Memo: TfrxMemoView;
Component: TfrxComponent;
begin
Component := frxReport1.FindObject('Memo4');
if Component is TfrxMemoView then
begin
Memo := Component as TfrxMemoView;
Memo.Text := AdvOfficeStatusBar1.Panels[0].Text;
frxReport1.ShowReport;
end;
end;

You can set the text of a fastreport memo from code like this:
procedure SetMemo(aReport: TfrxReport; aMemoName: string; aText: string);
var
memo: TfrxMemoView;
begin
memo := aReport.FindObject(aMemoName) as TfrxMemoView;
if memo <> nil then
memo.Text := aText;
end;

In C# language you can use the following:
report2.RegisterData(dt, "DataTable1");
TextObject t1 = (TextObject)report2.FindObject("Text1");
t1.Text = "I love Kurdistan!";

Related

listview and custom font color per item with delphi

I am trying to find a way so when I add an item to a TListView I can assign its own text color (by matching its name with a name I am entering into an edit box). I got it working, sort of, but the issue is when I add more then 2 items the font colors are changed for all of the items.
Here is my test code:
procedure TMainForm.ListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
if Edit2.Text = Item.Caption then // match my name with item name
begin
Sender.Canvas.Font.Color := Font.Font.Color; // assign from font dialogue
Sender.Canvas.Font.Style := Font.Font.Style; // assign from font dialogue
end;
end;
Does anyone have any ideas?
You are not resetting the ListView's Canvas.Font parameters for list items that do not match your text.
procedure TMainForm.ListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
if Edit2.Text = Item.Caption then
begin
Sender.Canvas.Font.Color := Font.Font.Color;
Sender.Canvas.Font.Style := Font.Font.Style;
end else begin
// add this...
Sender.Canvas.Font.Color := Sender.Font.Color;
Sender.Canvas.Font.Style := Sender.Font.Style;
end;
end;
That being said, if you know the colors you want to use ahead of time, a different way to set per-item colors is to derive a new class from TListItem and add your own Font property to it, then you can use that during drawing.
type
TMyListItem = class(TListItem)
private
fFont: TFont;
procedure FontChanged(Sender: TObject);
procedure SetFont(AValue: TFont);
public
constructor Create(AOwner: TListItems); override;
destructor Destroy; override;
property Font: TFont read fFont write SetFont;
end;
constructor TMyListItem.Create(AOwner: TListItems);
begin
inherited;
fFont := TFont.Create;
fFont.OnChange := FontChanged;
end;
destructor TMyListItem.Destroy;
begin
fFont.Free;
inherited;
end;
procedure TMyListItem.FontChanged(Sender: TObject);
begin
Update;
end;
procedure TMyListItem.SetFont(AValue: TFont);
begin
fFont.Assign(AValue);
end;
// OnCreateItemClass event handler
procedure TMainForm.ListCreateItemClass(Sender: TCustomListView; var ItemClass: TListItemClass);
begin
ItemClass := TMyListItem;
end;
procedure TMainForm.ListCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
Sender.Canvas.Font := TMyListItem(Item).Font;
end;
...
var
Item: TMyListItem;
begin
...
Item := TMyListItem(List.Items.Add);
Item.Caption := ...;
if Edit2.Text = Item.Caption then
Item.Font := Font.Font // assign from font dialogue
else
Item.Font := List.Font; // assign from listview
...
end;
if Edit2.Text = Item.Caption then // match my name with item name
begin
Sender.Canvas.Font.Color := Font.Font.Color; // assign from font dialogue
Sender.Canvas.Font.Style := Font.Font.Style; // assign from font dialogue
end;
The problem is what happens when the if condition is False. You don't specify font color and style, and so the state of the canvas remains what it was previously. You need to do the following:
For each item in the list you must remember that items color and style.
When ListCustomDrawItem is called you must specify the canvas color and style to the the value that you remembered in step 1.

How can I make a SearchBox visible when I open the list of a ComboBox in Delphi

I am using Delphi 10 Seattle to create multi device software (Win32) (Firemonkey).
How can I show a SearchBox only when the list is shown in a ComboBox.
I fill the ComboBox in code with ListBoxItems. See for an example below.
Now the SearchBox is displayed over a closed ComboBox.
procedure AddItems;
var
SearchBox: TSearchBox;
Item: TListBoxItem;
begin
ComboBox.Items.Clear;
SearchBox := TSearchBox.Create(ComboBox);
SearchBox.Align := TAlignLayout.Contents;
SearchBox.Parent := ComboBox;
SearchBox.Visible:=True;
Item := TListBoxItem.Create(ComboBox);
Item.Parent := ComboBox;
Item.Text := 'Item 1';
Item := TListBoxItem.Create(ComboBox);
Item.Parent := ComboBox;
Item.Text := 'Item 2';
end;
Use TComboBox events OnPopup & OnClosePopup.
Move ScrollBox declaration to private form (or frame) section and create it in OnCreate form event (or in frame constructor).
type
THeaderFooterForm = class(TForm)
procedure FormCreate(Sender: TObject);
private
FSearchBox: TSearchBox;
end;
procedure THeaderFooterForm.FormCreate(Sender: TObject);
begin
FSearchBox := TSearchBox.Create(nil);
FSearchBox.Align := TAlignLayout.Contents;
FSearchBox.Parent := ComboBox;
FSearchBox.Visible:=False;
end;
procedure THeaderFooterForm.ComboBoxClosePopup(Sender: TObject);
begin
FSearchBox.Visible:=False;
end;
procedure THeaderFooterForm.ComboBoxPopup(Sender: TObject);
begin
FSearchBox.Visible:=True;
end;

Delphi : Setting OnGetText Event Handler for fields of a dynamic query

I want to set my own procedure to OnGetText event of fields in a dynamic query
My procedure is like this :
procedure TMainFrm.MyFieldGetText(Sender: TField; var Text: String;
DisplayText: Boolean);
begin
...
end;
"...Captions" are String array constants
I set the event handler in OnAfterOpen event of ADOQuery :
procedure TImportFrm.ADOQueryAfterOpen(DataSet: TDataSet);
var
I : Integer;
begin
for I := 0 to ADOQuery.FieldCount - 1 do
ADOQuery.Fields[I].OnGetText := MainFrm.MyFieldGetText;
end;
But after opening ADOQuery , there is no Text to display , it looks like the Text value is empty !
It seems it doesn't matter what my procedure do , because when I set an empty procedure ( with no code ) , no text displayed too
what goes wrong ?
thanks ...
Try this:
procedure TMainFrm.MyFieldGetText(Sender: TField; var Text: String;
DisplayText: Boolean);
begin
if Sender.FieldName = 'XX' then
begin
Text := .... String(Sender.Value);// ( or Text := Sender.AsString);
end;
if Sender.FieldName = 'YY' then
begin
Text := .... String(Sender.Value);// ( or Text := Sender.AsString);
end;
...
end;
Thanks all
The problem was that I should mention all situations of Text and should use Sender.value instead of Text in right side ! , I changed my procedure to this and problem solved :
procedure TMainFrm.MyFieldGetText(Sender: TField; var Text: String;
DisplayText: Boolean);
begin
if Sender.AsVariant = Null then
Exit;
Text := Sender.AsString;
if MatchStr(Sender.FieldName, BooleanFieldNames) then
Text := BooleanCaptions[Sender.AsInteger];
if Sender.FieldName = 'BNStatus' then
Text := BNStatusCaptions[Sender.AsInteger];
if MatchStr(Sender.FieldName, ['FStatus', 'LStatus', 'FirstStatus']) then
Text := FLStatusCaptions[Sender.AsInteger];
if Sender.FieldName = 'PayType' then
Text := PayTypeCaptions[Sender.AsInteger];
if Sender.FieldName = 'BGType' then
Text := BGTypeCaptions[Sender.AsInteger];
if Sender.FieldName = 'Updated' then
Text := UpdatedCaptions[Sender.AsInteger];
if Sender.FieldName = 'DieUser' then
Text := DieUserCaptions[Sender.AsInteger];
if Sender.FieldName = 'LiveUser' then
Text := LiveUserCaptions[Sender.AsInteger];
if Sender.FieldName = 'NVStatus' then
Text := NVStatusCaptions[Sender.AsInteger];
if Sender.FieldName = 'BSGender' then
Text := BSGenderCaptions[Sender.AsInteger];
if Sender.FieldName = 'BSMType' then
Text := BSMTypeCaptions[Sender.AsInteger];
end;
Thanks again ...

Have cxGrid expand current date

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;

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