Printing listview items using fastreport in Delphi - delphi

I am looking for a simple example or a reference to print items from a listview using fastreport. For example: I have a listview that has three columns: id, name and marks. The listview has n number items each containing id, name and marks of individual students. I need to print the whole listview using fastreport in a tabular format. I googled but couldn't find an exact sample for my scope. Similarly, I couldn't find any documentation regarding this in fastreport demo. I am using Delphi XE8 with default installed fastreport version.

For demonstration purposes.
Place on the form the following components:
TButton;
TListView;
frxReport;
frxUserDataSet;
Double click on frxReport. In the Fastreport designer do
insert ReportTitle, MasterData and PageFooter bands.
Press Report => Data menu items. Check frxUserDataSet check box and press OK button.
Assign MasterData band with frxUserDataSet as double click on MasterData band and select frxUserDataSet, then press 'OK' button.
In MasterData band insert Text object (Memo).
In Memo write [element].
Designer should look like this :
Now we can write some code :
procedure TForm8.FormCreate(Sender: TObject);
var
I: Integer;
Li : TlistItem;
begin
// Just to fill some data in ListView
for I := 1 to 10 do
begin
Li := ListView1.Items.Add;
LI.Caption := 'Col ' + IntToStr(i);
end;
end;
In frxReport1 OnGetValue event write for example :
procedure TForm8.frxReport1GetValue(const VarName: string; var Value: Variant);
begin
if CompareText(VarName, 'element') = 0 then
Value := ListView1.Items[frxUserDataSet1.RecNo].Caption;
end;
And now print data
procedure TForm8.Button1Click(Sender: TObject);
begin
frxUserDataSet1.RangeEnd := reCount;
frxUserDataSet1.RangeEndCount := ListView1.Items.Count;
frxReport1.ShowReport();
end;
The result after Button1 is pressed:
Note : In this answer is used part of FastReport PrintStringList demo.

Related

How to iterate into components inside a TTabSheet

I'm trying to iterate between all components inside a TTabsheet. Problem is, inside this tab there are only a memo and a edit, but my code iterate between components in all form. What am I'm missing ?
var i : integer;
begin
with PageControl1.ActivePage do
for i := 0 to componentcount-1 do
begin
// componentcount should be 2, but actually is 95
components[i].doSomething;
end;
end;
I had something like this, where a button click caused code to traverse over all the controls that were on a tabsheet that was on a page control, using the components array. Later on I changed it to the following, that uses the controls array of the given tabsheet.
procedure TShowDocsByRank.CleanBtnClick(Sender: TObject);
var
i: integer;
begin
for i:= 0 to tabsheet1.controlcount - 1 do
if tabsheet1.controls[i] is TLabeledEdit
then TLabeledEdit (tabsheet1.controls[i]).text:= ''
else if tabsheet1.controls[i] is TComboBox
then TComboBox (tabsheet1.controls[i]).text:= '-';
end;
Perhaps 'with' might have something to do about it. You cant really tell what the return value for 'componentcount' will be (might even return number of components for the form itself?).

How to get data for FastReport (Delphi) from an TEdit?

I created a report using FastReport, but the only way I know to get data to that report is from a database, I want to get data from a TEdit and I don't want to store anything, just writing in TEdit + click on the button (fastreport.preview) + print and Done.
How can I do that ?
Please explain am new with Delphi and FastReport.
You can use the OnGetValue event of your TfrxReport component as follows:
procedure TForm1.frxReport1GetValue(const VarName: string; var Value: Variant);
begin
if(VarName = 'MyVariable') then
begin
Value := Edit1.Text;
end;
end;
Then you just need to add a memo item to the report and set its value to [MyVariable].
One possible approach is to access the TfrxReport and TfrxMemoView components at runtime. Note, that when you don't have a dataset, the Master Data band won't be printed, so you should use another band.
You may use the following code as a basic example. Just place one TfrxReportTitle band (named 'ReportTitle1') and one TfrxMemoView text object (named 'Memo1') on your TfrxReport component.
procedure TfrmMain.btnReportClick(Sender: TObject);
var
memo: TfrxMemoView;
band: TfrxReportTitle;
begin
// Get the band
band := (rptDemo.Report.FindObject('ReportTitle1') as TfrxReportTitle);
// Create a memo
memo := TfrxMemoView.Create(band);
memo.CreateUniqueName;
memo.ParentFont := True;
memo.Text := edtReport.Text;
memo.SetBounds(100, 1, 100, 16);
memo.HAlign := haLeft;
memo.AutoWidth := False;
// Use existing memo
memo := (rptDemo.Report.FindObject('Memo1') as TfrxMemoView);
memo.Text := edtReport.Text;
// Preview report
rptDemo.ShowReport(False);
end;
Notes: This is a working example, tested with FastReport 4.7.

Grouping items inside TListView object?

I am trying to group the items inside TListView object, but I cant find the class responsible for grouping the objects, neither i were able to find such inside the documentation.
What is the class responsible about grouping items inside TListView object, and how to use it properly ?
The platform is Firemonkey ( Android/iOS) / Delphi XE6
The property I believe you're referring to is TListGroups, a collection that holds TListGroup items. There's a demo provided in the Delphi documentation.
Unfortunately, it's only available in the VCL and not FMX, as the underlying functionality is part of the Windows ListView control that TListView wraps.
The closest you can get in FMX is using TListBox and a TListBoxGroupHeader, which is covered in the Multi-Device Tutorial Using ListBox Components to Display a Table View (iOS and Android) in the docwiki:
procedure TForm1.FormCreate(Sender: TObject);
var
c: Char;
i: Integer;
Buffer: String;
ListBoxItem : TListBoxItem;
ListBoxGroupHeader : TListBoxGroupHeader;
begin
ListBox1.BeginUpdate;
for c := 'a' to 'z' do
begin
// Add header ('A' to 'Z') to the List
ListBoxGroupHeader := TListBoxGroupHeader.Create(ListBox1);
ListBoxGroupHeader.Text := UpperCase(c);
ListBox1.AddObject(ListBoxGroupHeader);
// Add items ('a', 'aa', 'aaa', 'b', 'bb', 'bbb', 'c', ...) to the list
for i := 1 to 3 do
begin
// StringOfChar returns a string with a specified number of repeating characters.
Buffer := StringOfChar(c, i);
// Simply add item
// ListBox1.Items.Add(Buffer);
// or, you can add items by creating an instance of TListBoxItem by yourself
ListBoxItem := TListBoxItem.Create(ListBox1);
ListBoxItem.Text := Buffer;
// (aNone=0, aMore=1, aDetail=2, aCheckmark=3)
ListBoxItem.ItemData.Accessory := TListBoxItemData.TAccessory(i);
ListBox1.AddObject(ListBoxItem);
end;
end;
ListBox1.EndUpdate;
end;
This produces (image from the indicated docwiki)
This is easily accomplished in FMX TListview control while using Livebindings by connecting your TListviewItem.header.break field to the fieled you want to group on (it will be a field in your db that is redundant over many records).

Strange filter behavior in DevExpress grid

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;

How do you update TStringGrid cells in Delphi XE3, Firemonkey2

I've seen this question asked as part of another question before, so know it can't just be me...if I open a new FireMonkey2 HD app, add a TButton and TStringGrid, then add this to the button on click event, NOTHING happens in the grid when I click the button!
procedure TForm33.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i:= 0 to 6 do
begin
StringGrid1.Cells[0,i] := 'Row:' + IntToStr(i);
end;
stringgrid1.UpdateColumns;
stringgrid1.SetFocus;
end;
Any ideas ?
PS I've also tried using TStringGrid.OnGetValue and it still won't show anything in the StringGrid.
Having looked further into the TStringGrid source code, C is nil so the Cells are never being set.
procedure TStringGrid.SetValue(Col, Row: Integer; const Value: TValue);
var
C: TColumn;
begin
C := Columns[Col];
if Assigned(C) then
begin
C.UpdateRowCount(RowCount);
C.SetCells(Row, Value);
end;
I appears there are no Columns in the "virgin" StringGrid, so how do you add them ? There is a r+w RowCount property but ColCount is readonly...
You must add at least a column to the TStringGrid in order to add data to the cells, you can do this in runtime
StringGrid1.AddObject(TStringColumn.Create(Self));
or in design time using the Items Designer

Resources