Skip to content

Commit b917f35

Browse files
committed
readme: draft
1 parent eb23b42 commit b917f35

10 files changed

Lines changed: 273 additions & 33 deletions

Delphi/example.dat

24.5 KB
Binary file not shown.

Delphi/uData.dfm

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ object DataModule1: TDataModule1
55
Width = 740
66
PixelsPerInch = 192
77
object mdLayouts: TdxMemData
8-
Active = True
98
Indexes = <>
109
Persistent.Data = {
1110
5665728FC2F5285C8FFE3F02000000000000000D0007004C61796F7574001400
@@ -791,11 +790,11 @@ object DataModule1: TDataModule1
791790
5265663D22352220436F6E74656E743D2253797374656D2E496E743332222054
792791
7970653D2253797374656D2E5479706522202F3E0D0A20203C2F4F626A656374
793792
53746F726167653E0D0A3C2F587472615265706F7274734C61796F7574536572
794-
69616C697A65723E0D0A010B0000005400610062006C0065005200650070006F
795-
0072007400}
793+
69616C697A65723E0D0A010C0000005400610062006C00650020005200650070
794+
006F0072007400}
796795
SortOptions = []
797-
Left = 408
798-
Top = 112
796+
Left = 416
797+
Top = 104
799798
object mdLayoutsLayout: TBlobField
800799
FieldName = 'Layout'
801800
end

Delphi/uMainForm.dfm

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ object MainForm: TMainForm
1111
Font.Height = -12
1212
Font.Name = 'Segoe UI'
1313
Font.Style = []
14+
OnCreate = FormCreate
1415
TextHeight = 15
1516
object dxLayoutControl1: TdxLayoutControl
1617
Left = 0

Delphi/uMainForm.pas

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,14 @@ TMainForm = class(TForm)
2929
liShowDesigner: TdxLayoutItem;
3030
liViewReport: TdxLayoutItem;
3131
liGrid: TdxLayoutItem;
32+
procedure FormCreate(Sender: TObject);
3233
procedure btnDesignClick(Sender: TObject);
3334
procedure btnPreviewClick(Sender: TObject);
3435
procedure btnNewClick(Sender: TObject);
3536
procedure dxReport1LayoutChanged(ASender: TdxReport);
3637
private
38+
procedure LoadReportNameAndLayout;
39+
procedure SaveReportNameAndLayout;
3740
{ Private declarations }
3841
public
3942
{ Public declarations }
@@ -48,6 +51,43 @@ implementation
4851

4952
uses uData;
5053

54+
procedure TMainForm.LoadReportNameAndLayout();
55+
begin
56+
if (DataModule1.mdLayouts.RecordCount = 0) and not (DataModule1.mdLayouts.State = dsInsert) then
57+
begin
58+
ShowMessage('The database is empty');
59+
Exit;
60+
end;
61+
// Load the report name from the database
62+
dxReport1.ReportName := DataModule1.mdLayoutsName.AsString;
63+
// Load the report layout from the database
64+
dxReport1.Layout.Assign(DataModule1.mdLayoutsLayout);
65+
end;
66+
67+
procedure TMainForm.SaveReportNameAndLayout();
68+
begin
69+
// Start editing the active dataset record
70+
DataModule1.mdLayouts.Edit;
71+
// Save the report name
72+
DataModule1.mdLayoutsName.AsString := dxReport1.ReportName;
73+
// Save the report layout
74+
DataModule1.mdLayoutsLayout.Assign(dxReport1.Layout);
75+
// Finish editing and write a modified record
76+
DataModule1.mdLayouts.Post;
77+
end;
78+
79+
// Event that is called when the application starts
80+
procedure TMainForm.FormCreate(Sender: TObject);
81+
begin
82+
LoadReportNameAndLayout;
83+
end;
84+
85+
86+
// Event that is called when a user saves a report layout in the Report Designer
87+
procedure TMainForm.dxReport1LayoutChanged(ASender: TdxReport);
88+
begin
89+
SaveReportNameAndLayout;
90+
end;
5191

5292
procedure TMainForm.btnNewClick(Sender: TObject);
5393
begin
@@ -56,35 +96,24 @@ procedure TMainForm.btnNewClick(Sender: TObject);
5696

5797
procedure TMainForm.btnDesignClick(Sender: TObject);
5898
begin
59-
if (DataModule1.mdLayouts.RecordCount = 0) and not (DataModule1.mdLayouts.State = dsInsert) then
99+
if (dxReport1.ReportName = '') then
60100
begin
61-
ShowMessage('The database is empty');
101+
ShowMessage('The report is not specified');
62102
Exit;
63103
end;
64-
dxReport1.ReportName := DataModule1.mdLayoutsName.AsString;
65-
dxReport1.Layout.Assign(DataModule1.mdLayoutsLayout);
66104
dxReport1.ShowDesigner;
67105
end;
68106

69107
procedure TMainForm.btnPreviewClick(Sender: TObject);
70108
begin
71-
if (DataModule1.mdLayoutsName.AsString = '') then
109+
if (dxReport1.ReportName = '') then
72110
begin
73111
ShowMessage('The report is not specified');
74112
Exit;
75113
end;
76-
77-
dxReport1.ReportName := DataModule1.mdLayoutsName.AsString;
78-
dxReport1.Layout.Assign(DataModule1.mdLayoutsLayout);
79114
dxReport1.ShowViewer;
80115
end;
81116

82-
procedure TMainForm.dxReport1LayoutChanged(ASender: TdxReport);
83-
begin
84-
DataModule1.mdLayouts.Edit;
85-
DataModule1.mdLayoutsLayout.Assign(dxReport1.Layout);
86-
DataModule1.mdLayoutsName.AsString := dxReport1.ReportName;
87-
DataModule1.mdLayouts.Post;
88-
end;
117+
89118

90119
end.

README.md

Lines changed: 224 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,236 @@
44
[![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183)
55
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
66
<!-- default badges end -->
7-
# DevExpress VCL Reports - Store Report Layouts in a Database
87

9-
This example stores a [report layout](https://docs.devexpress.com/VCL/dxReport.TdxReport.Layout) (XML-based template) in the BLOB field of a memory-based dataset ([TdxMemData](https://docs.devexpress.com/VCL/dxmdaset.TdxMemData) inherited from the [TDataSet](https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSet) class shipped with the standard VCL library).
8+
# DevExpress Reports for Delphi/C++Builder – Store Report Layouts in a Database
109

11-
## Testing the example
10+
This example application stores [DevExpress report layouts][TdxReport.Layout] in a database.
11+
The application allows users to create and save report layouts, modify existing layouts, and open layouts in Report Designer/Viewer.
12+
13+
14+
## Prerequisites
15+
16+
[DevExpress Reports Prerequisites][req]
17+
18+
[req]: https://docs.devexpress.com/VCL/405773/ExpressCrossPlatformLibrary/vcl-backend/reports-dashboards-app-deployment#vcl-reportsdashboards-prerequisites
19+
20+
21+
## Test the Example
22+
23+
- Run the sample app and click **New Report** to create an empty database record.
24+
- Click **Show Designer** to display the [Report Designer][dx-report-designer] dialog.
25+
- Create a report layout using tools available within the UI.
26+
- Click the hamburger button, select the **Save** option, and close the dialog.
27+
- Close the app. The [TdxMemData] component will store layout data in the [data.dat] file between sessions.
28+
- Run the sample app again. Click **View Designer** to load the saved report layout,
29+
or **View Report** to preview a layout-based report in the [Report Viewer][dx-report-viewer] dialog.
30+
31+
## Implementation Details
32+
33+
Follow the instructions in this example to store report layouts in a database of your choice,
34+
using the corresponding `TDataSet` descendant.
35+
36+
The example uses a memory-based dataset
37+
([TdxMemData] from the DevExpress library, inherited from [TDataSet], shipped with the standard VCL library).
38+
Applications in this example isolate data components in separate data modules: [uData.pas] (Delphi) and [uData.cpp] (C++Builder).
39+
40+
The instructions assume that you start with a Delphi or C++Builder project that has
41+
a configured data source for DevExpress Reports.
42+
To configure a report data source in your project, refer to the following tutorial: [Create a Table Report Using the Report Wizard][report-wizard].
43+
This example uses a SQLite sample database ([nwind.db]) as a report data source.
44+
45+
### Step 1: Create a Dataset to Store Report Layout Data
46+
47+
Follow these steps to create a memory-based dataset to store report layout data:
48+
49+
1. Create a [TdxMemData] component on a form (`mdLayouts` in the example).
50+
2. Create a [TDataSource] component on a form (`dsLayouts` in the example).
51+
Assign the `TDataSource.DataSet` value to the previously created dataset component:
52+
53+
> <img src="./images/create-bind-data-source.png" style="width: 50%" alt=""/>
54+
55+
3. Open the context menu of the dataset component and select **Field Editor…**:
56+
57+
> <img src="./images/open-context-menu.png" style="width: 50%" alt=""/>
58+
59+
4. Click **Add…** to create a BLOB field for layout data:
60+
61+
> <img src="./images/create-layout-field.png" style="width: 50%" alt=""/>
62+
63+
5. Click **Add…** to create a string field for layout name:
64+
65+
> <img src="./images/create-name-field.png" style="width: 50%" alt=""/>
66+
67+
6. (*Optional*) Preload persistent data to the dataset make layouts available in the application upon first launch.
68+
Open the context menu of the dataset component, select **Persistent Editor…**, click **Load…** and select a DAT file.
69+
70+
> <img src="./images/create-persistent-data.png" style="width: 50%" alt=""/>
71+
72+
This example has an example report layout designed to use data from the Northwind sample database.
73+
You can preload it from [example.dat].
74+
75+
Alternatively, you can use the Report Designer in further steps to import report data from files or raw string data.
76+
77+
78+
### Step 2: Supply Layout Data to TdxReport
79+
80+
Supply the [TdxReport] component with two values:
81+
report name ([TdxReport.ReportName]) and layout ([TdxReport.Layout]):
82+
83+
```pas
84+
procedure TMainForm.LoadReportNameAndLayout();
85+
begin
86+
if (DataModule1.mdLayouts.RecordCount = 0) and not (DataModule1.mdLayouts.State = dsInsert) then
87+
begin
88+
ShowMessage('The database is empty');
89+
Exit;
90+
end;
91+
// Load the report name from the database
92+
dxReport1.ReportName := DataModule1.mdLayoutsName.AsString;
93+
// Load the report layout from the database
94+
dxReport1.Layout.Assign(DataModule1.mdLayoutsLayout);
95+
end;
96+
```
97+
98+
To load a different report, assign a new report name and layout.
99+
No cleanup is required between reports.
100+
101+
<!--
102+
1. Assign report name and layout when application starts.
103+
2. Assign report name and layout when user selects a different grid row.
104+
3. (Optional) Change report name when user edits it in the grid view.
105+
-->
106+
107+
108+
### Step 3: Display Report Designer and Viewer
109+
110+
Once you have assigned name and layout to the [TdxReport] component,
111+
you can display the Report Designer and Viewer components:
112+
113+
```pas
114+
procedure TMainForm.btnDesignClick(Sender: TObject);
115+
begin
116+
// Display the Report Designer
117+
dxReport1.ShowDesigner;
118+
end;
119+
120+
procedure TMainForm.btnPreviewClick(Sender: TObject);
121+
begin
122+
// Display the Report Viewer
123+
dxReport1.ShowViewer;
124+
end;
125+
```
126+
127+
### Step 4: Store Report Layout Data in the Dataset
128+
129+
When a user edits and saves a report in the Report Designer,
130+
the value of [TdxReport.Layout] changes and an [OnLayoutChanged] event is called.
131+
Handle this event to store the updated layout in the active dataset record.
132+
133+
```pas
134+
procedure TMainForm.dxReport1LayoutChanged(ASender: TdxReport);
135+
begin
136+
// Start editing the active dataset record
137+
DataModule1.mdLayouts.Edit;
138+
// Save the report name
139+
DataModule1.mdLayoutsName.AsString := dxReport1.ReportName;
140+
// Save the report layout
141+
DataModule1.mdLayoutsLayout.Assign(dxReport1.Layout);
142+
// Finish editing and write a modified record
143+
DataModule1.mdLayouts.Post;
144+
end;
145+
```
146+
147+
### Step 6: Persist the Database State Between Application Sessions
148+
149+
This step is specific to the memory-based [TdxMemData] datasource.
150+
151+
To persist the database state when user closes the application
152+
and restore the state when user restarts the application,
153+
handle the `Create` and `Destroy` events of the data module:
154+
155+
```pas
156+
const
157+
DataFileName = 'data.dat';
158+
159+
procedure TDataModule1.DataModuleCreate(Sender: TObject);
160+
begin
161+
if FileExists(DataFileName) then
162+
mdLayouts.LoadFromBinaryFile(DataFileName)
163+
end;
164+
165+
procedure TDataModule1.DataModuleDestroy(Sender: TObject);
166+
begin
167+
if mdLayouts.RecordCount > 0 then
168+
mdLayouts.SaveToBinaryFile(DataFileName)
169+
end;
170+
```
171+
172+
173+
## Files to Review
174+
175+
- [uData.pas] (Delphi) and [uData.cpp] (C++Builder) read and store layout data in a database represented by an in-memory storage component.
176+
- [uMainForm.pas] (Delphi) and [uMainForm.cpp] (C++Builder) supply layout data from the data module to [TdxReport] and display Report Designer and Viewer.
177+
- [data.dat] persists the memory-based dataset between application sessions.
178+
- [nwind.db] contains the Northwind sample database used as a data source for report content.
12179

13-
* Run the sample app and click **New Report** to create an empty database record.
14-
* Click **Show Designer** to display the [Report Designer](https://docs.devexpress.com/XtraReports/119176/web-reporting/web-end-user-report-designer) dialog.
15-
* Create a report layout using tools available within the UI.
16-
* Click the hamburger button, select the **Save** option, and close the dialog.
17-
* Close the app. The [TdxMemData](https://docs.devexpress.com/VCL/dxmdaset.TdxMemData) component will store layout data between sessions.
18-
* Run the sample app again. Click **View Designer** to load the saved report layout, or **View Report** to preview a layout-based report in the [Report Viewer](https://docs.devexpress.com/XtraReports/401850/web-reporting/web-document-viewer) dialog.
19180

20181
## Documentation
21182

22-
* [TdxReport.Layout Property](https://docs.devexpress.com/VCL/dxReport.TdxReport.Layout)
23-
* [TdxBackendDataSetJSONConnection Component](https://docs.devexpress.com/VCL/dxBackend.ConnectionString.JSON.DataSet.TdxBackendDataSetJSONConnection)
183+
- [Introduction to VCL Reports][reports-intro]
184+
- [Tutorial: Create a table report using the Report Wizard][report-wizard]
185+
- [Use SQLite as a data source for reports (as demonstrated in the current example)][sqlite-data-source]
186+
- [Store report layouts in REPX files at design-time][reports-design-time-store]
187+
- API reference:
188+
- [TdxReport.ReportName] (internal report name that is not included in the layout)
189+
- [TdxReport.Layout] (an XML-based layout template that can be stored in the BLOB field of a database)
190+
- [TdxMemData] (used to store report layout data in application runtime and between sessions)
191+
- [TDataSet] (ancestor of the `TdxMemData`, contains generic database connection methods)
192+
- [TdxBackendDatabaseSQLConnection] (used to supply data to reports)
193+
194+
<!-- documentation links -->
195+
[reports-intro]: https://docs.devexpress.com/VCL/405469/ExpressReports/vcl-reports
196+
[report-wizard]: https://docs.devexpress.com/VCL/405760/ExpressReports/getting-started/create-table-report-using-report-wizard
197+
[sqlite-data-source]: https://docs.devexpress.com/VCL/405750/ExpressCrossPlatformLibrary/vcl-backend/database-engines/vcl-backend-sqlite-support
198+
[reports-design-time-store]: https://docs.devexpress.com/VCL/dxReport.TdxReport.Layout#string-list-editor
199+
[dx-report-viewer]: https://docs.devexpress.com/XtraReports/401850/web-reporting/web-document-viewer
200+
[dx-report-designer]: https://docs.devexpress.com/XtraReports/119176/web-reporting/web-end-user-report-designer
201+
202+
203+
<!-- reference links -->
204+
[TdxReport]: https://docs.devexpress.com/VCL/dxReport.TdxReport
205+
[TdxReport.Layout]: https://docs.devexpress.com/VCL/dxReport.TdxReport.Layout
206+
[TdxReport.ReportName]: https://docs.devexpress.com/VCL/dxReport.TdxReport.ReportName
207+
[TdxReport.ShowDesigner]: https://docs.devexpress.com/VCL/dxReport.TdxReport.ShowDesigner
208+
[TdxReport.ShowViewer]: https://docs.devexpress.com/VCL/dxReport.TdxReport.ShowViewer
209+
[TdxBackendDatabaseSQLConnection]: https://docs.devexpress.com/VCL/dxBackend.ConnectionString.SQL.TdxBackendDatabaseSQLConnection
210+
[TdxMemData]: https://docs.devexpress.com/VCL/dxmdaset.TdxMemData
211+
[OnLayoutChanged]: https://docs.devexpress.com/VCL/dxReport.TdxReport.OnLayoutChanged
212+
213+
<!-- external documentation links -->
214+
[TDataSet]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSet
215+
[TDataSource]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSource
216+
[ftString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
217+
[ftWideString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
218+
[ftBlob]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
219+
220+
<!-- in-repository links -->
221+
[uData.pas]: ./Delphi/uData.pas
222+
[uData.cpp]: ./CPB/uData.cpp
223+
[data.dat]: ./Delphi/data.dat
224+
[example.dat]: ./Delphi/example.dat
225+
[uMainForm.pas]: ./Delphi/uMainForm.pas
226+
[uMainForm.cpp]: ./CPB/uMainForm.cpp
227+
[nwind.db]: ./Delphi/nwind.db
228+
229+
230+
## More Examples
231+
232+
- [Store report layouts in REPX files][file-example]
233+
234+
[file-example]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-file
235+
236+
24237
<!-- feedback -->
25238
## Does This Example Address Your Development Requirements/Objectives?
26239

@@ -29,5 +242,3 @@ This example stores a [report layout](https://docs.devexpress.com/VCL/dxReport.T
29242
(you will be redirected to DevExpress.com to submit your response)
30243
<!-- feedback end -->
31244

32-
33-

images/create-bind-data-source.png

26.7 KB
Loading

images/create-layout-field.png

33.9 KB
Loading

images/create-name-field.png

34.2 KB
Loading

images/create-persistent-data.png

13.5 KB
Loading

images/open-context-menu.png

13.1 KB
Loading

0 commit comments

Comments
 (0)