FastReport (RAD Studio XE7 C++ Builder) - Как создать формулу суммы?
Я использую Embarcadero RAD Studio XE7, C++ Builder с FastReport 5. Я создаю очень простой FastReport, который складывает некоторые значения в таблицу и выводит итоги. Я не могу получить правильный синтаксис для формулы суммы, и в результате он продолжает выдавать ошибку нарушения доступа.
Чтобы воспроизвести эту проблему в RAD Studio XE7:
- Откройте RAD Studio XE7 и перейдите в Файл -> Создать -> Приложение VCL Forms - C++Builder
- Перетащите компонент TClientDataSet с именем ClientDataSet1 в форму. Перетащите компонент TfrxReport с именем frxReport1 в форму. Перетащите набор TfrxDBDataset с именем frxDBDataset1 в форму.
- Перетащите TButton с именем Button1 на форму и дважды щелкните его, чтобы создать обработчик события OnClick.
Добавьте следующие строки в обработчик событий Button1Click:
// Create a simple dataset. ClientDataSet1->FieldDefs->Clear(); ClientDataSet1->FieldDefs->Add("ID", ftInteger, 0, false); ClientDataSet1->FieldDefs->Add("Status", ftString, 10, false); ClientDataSet1->FieldDefs->Add("Created", ftDate, 0, false); ClientDataSet1->FieldDefs->Add("Volume", ftInteger, 0, false); try { ClientDataSet1->CreateDataSet(); } catch(Exception& e) { ShowMessage("ERROR: '" + e.Message + "'"); return; } ClientDataSet1->Open(); for (int i = 0; i < 10; ++i) { ClientDataSet1->Append(); ClientDataSet1->FieldByName("ID")->AsInteger = i; ClientDataSet1->FieldByName("Status")->AsString = "Code" + String(i); ClientDataSet1->FieldByName("Created")->AsDateTime = Now(); ClientDataSet1->FieldByName("Volume")->AsInteger = Random(1000); try { ClientDataSet1->Post(); } catch(Exception& e) { ShowMessage("ERROR: '" + e.Message + "'"); ClientDataSet1->Close(); return; } } // Dataset created successfully, now create Fast Report that outputs that dataset frxReport1->Clear(); frxDBDataset1->DataSet = (TDataSet*)ClientDataSet1; frxReport1->DataSets->Add(frxDBDataset1); TfrxDataPage* DataPage = new TfrxDataPage(frxReport1); DataPage->CreateUniqueName(); TfrxReportPage* Page = new TfrxReportPage(frxReport1); Page->CreateUniqueName(); // set sizes of fields, paper and orientation to defaults Page->SetDefaults(); Page->Orientation = poPortrait; TfrxReportTitle* HeaderBand = new TfrxReportTitle(Page); HeaderBand->CreateUniqueName(); HeaderBand->Top = 0; HeaderBand->Height = 20; TfrxMemoView* Memo = new TfrxMemoView(HeaderBand); Memo->CreateUniqueName(); Memo->Text = "Generic Report"; Memo->SetBounds(0, 0, 200, 20); TfrxHeader* ColumnHeaderBand; ColumnHeaderBand = new TfrxHeader(Page); ColumnHeaderBand->CreateUniqueName(); ColumnHeaderBand->Top = HeaderBand->Top + HeaderBand->Height; ColumnHeaderBand->Height = 20; TfrxMasterData* DataBand = new TfrxMasterData(Page); DataBand->Name = "DataBand"; DataBand->DataSet = frxDBDataset1; DataBand->Top = ColumnHeaderBand->Top + ColumnHeaderBand->Height; DataBand->Height = 20; TfrxMemoView* mField; for (int i = 0; i < DataBand->DataSet->FieldsCount(); ++i) { const String fieldname = ClientDataSet1->Fields->Fields[i]->FieldName; mField = new TfrxMemoView(ColumnHeaderBand); mField->CreateUniqueName(); mField->SetBounds(i * 100, 0, 100, 20); mField->Text = fieldname; mField->HAlign = haCenter; // Now do the actual data mField = new TfrxMemoView(DataBand); mField->CreateUniqueName(); mField->DataSet = DataBand->DataSet; mField->DataField = fieldname; mField->SetBounds(i * 100, 0, 100, 20); mField->HAlign = haRight; } // Now do footer band. This will hold the total TfrxBand* FooterBand = new TfrxFooter(Page); FooterBand->CreateUniqueName(); FooterBand->Top = DataBand->Top + DataBand->Height; FooterBand->Height = HeaderBand->Height; TfrxMemoView* totals = new TfrxMemoView(FooterBand); totals->Top = 0; totals->Left = 0; totals->Height = 20; totals->Align = baWidth; bool is_error = false; try { // ALL OF THESE LINES CAUSE THE ACCESS VIOLATION // Create a summation function that displays the volume total totals->Text = "Totals: [Sum(<ClientDataSet1.Volume>, MyDataBand, 1)]"; //totals->Text = "Totals: [Sum(<ClientDataSet1.'volume'>,MyDataBand,1)]"; //totals->Text = "Totals: [Sum(<ClientDataSet1.\"volume\">,MyDataBand,1)]"; //totals->Text = "Totals: [Sum(<ClientDataSet1.""volume"">,MyDataBand,1)]"; //totals->Text = "Totals: [Sum(<ClientDataSet1.''volume''>,MyDataBand,1)]"; //totals->Text = "Totals: [Sum(<ClientDataSet1.\'volume\'>,MyDataBand,1)]"; } catch(Exception& e) { ShowMessage("ERROR: '" + e.Message + "'"); is_error = true; } if (!is_error) { frxReport1->ShowReport(true); } ClientDataSet1->Close(); ShowMessage("Program complete!");
Скомпилируйте и запустите программу. Код в блоке try выдаст нарушение прав доступа. Почему это происходит? Какой правильный синтаксис для создания формулы суммы?
ОБНОВИТЬ:
Я изменил код, явно указав имя для frxDBDataset1:
frxReport1->Clear();
frxDBDataset1->DataSet = (TDataSet*)ClientDataSet1;
frxDBDataset1->Name = "frxDBDataset1"; // line added
frxReport1->DataSets->Add(frxDBDataset1);
Я также изменил строку формулы следующим образом:
totals->Text = "Totals: [Sum(<frxDBDataset1.\"Volume\">, DataBand, 1)]";
Я все еще получаю нарушение доступа, хотя.
2 ответа
Перейдите в Проект -> Параметры -> Пакеты -> Пакеты времени выполнения. Установите "Link with Runtime Packages" в значение False.
Значением по умолчанию для этого параметра является True для C++Builder, False для Delphi. Это объясняет, почему эквивалентный код работал в Delphi, но не работал в C++Builder.
Мне удалось без проблем запустить следующий связанный пример, который включает изменения, которые мы комментировали ранее.