단 한 줄의 코드로 완성하는 C++ Customer/Sales 애플리케이션
- 2020-11-09
- Posted by: Narae Kim
- Categories: Uncategorized, 기술자료
 
		다음은 데이비드 아이(David I)가 작성한 기술문서를 번역한 글입니다.
요새 노 코드(No Code), 로우코드(Low Clode) 개발에 대한 이야기가 많죠. 얼마전에는 엠바카데로 책임 관리자 아타나스 포포브가 로우 코드 개발을 주제로 기술 컨텐츠를 작성하기도 했었습니다. 아타나스 글에서는 이렇게 소개합니다. “요즘 로우코드 개발이 유행이죠. 가트너 등 많은 연구단체들이 2019년 로우코드 애플리케이션 개발 플래폼 시장 규모를 약 100억 달러로 잡고 2020년부터 2027년까지 CAGR 프로젝트가 20% 이상 성장할 것으로 예상하기도 했습니다.” 아타나스는 이 컨텐츠를 통해 델파이 개발자들에게 로우코드가 왜 중요한지를 잘 정리해주었습니다 (그리고 저는 이번 컨텐츠를 통해 C++빌더 개발자분들에게 그 중요성을 설명하고자 합니다).
이 글을 통해 단 1줄의 코드만으로 C++을 이용해 윈도우용 Customer/Sales 관리, Master/Detail/Chart 기능이 있는 Customer/Sales 관리 애플리케이션을 완성할 수 있습니다.
필요한 건 C++빌더, 몇몇 RTL (라이브바인딩, 파이어닥, TeeChart 등)입니다. 이것만으로도 윈도우용 Customer/Sales 관리 프로그램을 멋지게 완성할 수 있습니다.
활용할 항목들은 다음과 같습니다:
- IDE의 폼 디자이너
- VCL
- 필드 에디터와 파이어닥 (FireDAC) 연동
- 비주얼 라이브 바인딩
- 단 한 줄의 C++코드
- 이 단 한 줄의 소스코드 조차도 필요 없는 방법을 아시는 분이 있다면, 알려주세요! 그럼 기쁘게 업데이트 하도록 하겠습니다 ^^
 
UI 화면
C++빌더를 실행하고 File | New | C++Builder VCL application 메뉴를 선택하세요. 폼 상단에 TPanel을 하나 올려주세요. 그리고 사용할 컴포넌트들 – 체크박스(checkbox), TDBNavigator, TDBGrid 컴포넌트 2개 (하나는 고객 리스트용이고, 다른 하나는 선택한 고객에 대한 세일즈 체크용입니다), Steema 소프트웨어의 TDBChart (파이 차트를 보여줄거에요), TSplitter 컴포넌트 2개 (하나는 고객 리스트확장용, 다른 하나는 영업 정보와 파이 차트 확장용), 파이어닥 컴포넌트들 (TFDConnection, TFDQuery 3개), TDataSource 2개 – 폼 위에 배치해주세요. TPanel을 하나 더 올려볼까요? 여기에는 세일즈 정보와 파이 차트가 표시되도록 할 것입니다.

사용한 컴포넌트들과 TPanel에 올라가있는 항목들은 스트럭처(Structure) 화면에서 확인할 수 있습니다.

데이터베이스 컴포넌트와 SQL 쿼리
데이터베이스는 인터베이스 Employee.gdb 샘플을 사용해보겠습니다. 이 샘플 DB에는 Customer, Sales 테이블이 이미 포함되어 있습니다.

데이터 익스플로러(Data Explorer) 화면에서 Employee.gdb 파일 구조를 확인할 수 있습니다.

이번 예제에서 사용할 TFDQuery 컴포넌트들은 FireDAC Query Editor를 통해서 각각의 상세 내용들을 확인할 수 있습니다 – TFDQuery 컴포넌트를 마우스 오른쪽 버튼으로 클릭해서 확인할 수 있습니다 – customer 쿼리, sales by customer 쿼리, customer에 대한 sales by item type 이 각 항목들에 대한 SQL 구문을 생성하고 테스트할 수 있죠.
 
    
  
TFDQuery들을 마우스 오른쪽 버튼으로 클릭하면 필드 에디터를 가져올 수 있습니다. 여기에는 각 쿼리들에서 가져온 컬럼 값들이 포함되어 있습니다.
 
   
  
각 쿼리 결과 데이터를 TDBGrid, TDBChart와 연동합니다. TDataSource 컴포넌트 속성들도 아래와 같이 설정합니다.
 
  
customer (master), sales (detail) 쿼리들을 연결하기 위해서는 오브젝트 인스펙터(Object Inspector)에서 SalesQuery에 대한 MasterFields 속성과 MasterSource를 설정해줍니다. SalesByItemTypeForCustomerQuery 도 동일한 방법으로 진행해주세요.
 
  
비주얼 라이브 바인딩 (Visual Live Bindings)
데이터베이스 연동과 UI에서 쿼리 결과값 연동을 해보겠습니다. C++빌더에서 자체 제공하는 기능인 비주얼 라이브 바인딩 기술을 사용하면 매우 쉽습니다. 라이브바인딩은 데이터를 바인딩할 수 있는 표현식 기반의 프레임워크입니다. 직접 눈으로 보면서 (또는 코드로도 가능) 객체들간의 연동 또는 객체와 데이터셋 필드 연동이 가능합니다. 라이브바인딩은 객체들의 속성들과 연계되어 있는 바인딩 표현식들을 사용해 다른 객체들과 연동이 가능합니다. 라이브바인딩 표현식들은 단방향, 양방향 모두 가능합니다.
라이브바인딩 디자이너는 연동하고자 하는 항목에서 할 수 있습니다. 해당 항목을 마우스 오른쪽 버튼으로 클릭하면 팝업 메뉴가 뜨면서 “Bind Visually…”를 클릭하면 됩니다.

그럼 해당 폼에 포함되어 있는 비주얼/논비주얼 컴포넌트들까지 모두 폼 아래 화면에 나타납니다. 각 객체(object) 오른쪽 아래에 있는 “…”를 클릭해 바인딩 식에 필요한 속성 목록을 불러올 수 있습니다.

이 예제에서는 Checked 속성과 CheckedState를 사용해보려고 합니다. 마우스를 CheckedState 속성과 각 쿼리의 Active 속성을 드래그해서 연결해줍니다. 실행될 때 바인딩 표현식에 따라 각 SQL 쿼리가 실행됩니다.
라이브바인딩 디자이너를 줌 인/아웃도 할 수 있습니다. 보기에 너무 복잡하면 바인딩 일부를 레이어를 생성해 숨겨 놓을 수도 있고, 디자인 화면을 비트맵 파일로 저장할 수도 있습니다.

Steema 사의 TeeChart를 활용한 파이 차트(Pie Chart) – Customer Sales by Item Type 차트로 표현하기
C++빌더에는 TeeChart 컴포넌트 기본 세트가 이미 포함되어 있습니다. 필요하다면 Steema Software 홈페이지를 통해서 더 많은 기능을 제공하는 에디션으로 업그레이드도 할 수 있습니다.

개발 화면 우측 하단에 보면 팔레트(Palette) 화면이 있습니다. 여기서 TeeChart Std 모음 중 TDBChart 컴포넌트를 마우스 오른쪽 버튼으로 클릭해보세요. 그럼 다양한 컴포넌트 에디터 항목들을 확인할 수 있습니다.

“Edit Chart…” 항목을 클릭해봅시다. 그럼 세 가지 탭이 나오는 화면이 나올텐데 그 중 “Series”를 클릭합니다. 이 예제에서는 파이 차트를 사용할텐데요. 만약 “Series”를 클릭해서 파이 차트가 보이지 않는다면 ‘Add…’ 버튼을 클릭해서 추가해주세요. 참고로 파이(Pie) 차트는 TeeChart 스탠다드 에디션에 포함되어 있는 항목입니다.

DBChart1을 열어서 좌측 메뉴 중 Series 아래에 ‘Series 1’이 보이시죠? 이걸 클릭하고 ‘Data Source’ 탭을 선택하세요. 이제 데이터셋(Dataset)을 “SalesByItemTypeForCustomerQuery”로 설정하고 Labels 값은 ITEM_TYPE으로, Pie는 SUM 으로 설정해줍니다.

차트 타이틀은 “Sales by Item Type for Customer”로 입력해주겠습니다. 하단의 [Close] 버튼을 눌러 파이 차트 설정을 완료합니다.
폼 설정 완료하기
지금까지 디자인한 폼 화면을 텍스트 소스코드로 확인해볼까요? 폼 디자이너 화면에서 마우스 오른쪽 버튼을 클릭하고 “view as text”를 선택해보세요. 사용한 UI 컴포넌트들, 파이어닥(FireDAC), 티차트(TeeChart), 라이브바인딩(LiveBinding) 컴포넌트와 설정 항목들을 모두 확인할 수 있습니다.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 | object MasterDetailForm: TMasterDetailForm   Left = 0   Top = 0   Caption = ‘Customer and Orders Master Detail Using Live Bindings (C++ VCL)’   ClientHeight = 509   ClientWidth = 736   Color = clBtnFace   Font.Charset = DEFAULT_CHARSET   Font.Color = clWindowText   Font.Height = –11   Font.Name = ‘Tahoma’   Font.Style = []   OldCreateOrder = False   OnShow = FormShow   PixelsPerInch = 96   TextHeight = 13   object Splitter1: TSplitter     Left = 0     Top = 161     Width = 736     Height = 3     Cursor = crVSplit     Align = alTop     ExplicitLeft = 24     ExplicitTop = 210     ExplicitWidth = 159   end   object Panel1: TPanel     Left = 0     Top = 0     Width = 736     Height = 33     Align = alTop     TabOrder = 0     object DBNavigator1: TDBNavigator       Left = 159       Top = 4       Width = 225       Height = 23       DataSource = CustomerDataSource       VisibleButtons = [nbFirst, nbPrior, nbNext, nbLast, nbRefresh]       TabOrder = 0     end     object DatabaseActiveCheckBox: TCheckBox       Left = 24       Top = 9       Width = 97       Height = 17       Caption = ‘Database Active’       TabOrder = 1     end   end   object CustomerDBGrid: TDBGrid     Left = 0     Top = 33     Width = 736     Height = 128     Align = alTop     DataSource = CustomerDataSource     TabOrder = 1     TitleFont.Charset = DEFAULT_CHARSET     TitleFont.Color = clWindowText     TitleFont.Height = –11     TitleFont.Name = ‘Tahoma’     TitleFont.Style = []   end   object Panel2: TPanel     Left = 0     Top = 164     Width = 736     Height = 345     Align = alClient     TabOrder = 2     object Splitter2: TSplitter       Left = 305       Top = 1       Height = 343       ExplicitLeft = 208       ExplicitTop = 120       ExplicitHeight = 100     end     object SalesDBGrid: TDBGrid       Left = 1       Top = 1       Width = 304       Height = 343       Align = alLeft       DataSource = SalesDataSource       TabOrder = 0       TitleFont.Charset = DEFAULT_CHARSET       TitleFont.Color = clWindowText       TitleFont.Height = –11       TitleFont.Name = ‘Tahoma’       TitleFont.Style = []     end     object DBChart1: TDBChart       Left = 308       Top = 1       Width = 427       Height = 343       Title.Text.Strings = (         ‘Sales by Item Type for Customer’)       View3DOptions.Elevation = 315       View3DOptions.Orthogonal = False       View3DOptions.Perspective = 0       View3DOptions.Rotation = 360       Align = alClient       TabOrder = 1       DefaultCanvas = ‘TGDIPlusCanvas’       ColorPaletteIndex = 13       object Series1: TPieSeries         DataSource = SalesByItemTypeForCustomerQuery         XLabelsSource = ‘ITEM_TYPE’         XValues.Order = loAscending         YValues.Name = ‘Pie’         YValues.Order = loNone         YValues.ValueSource = ‘SUM’         Frame.InnerBrush.BackColor = clRed         Frame.InnerBrush.Gradient.EndColor = clGray         Frame.InnerBrush.Gradient.MidColor = clWhite         Frame.InnerBrush.Gradient.StartColor = 4210752         Frame.InnerBrush.Gradient.Visible = True         Frame.MiddleBrush.BackColor = clYellow         Frame.MiddleBrush.Gradient.EndColor = 8553090         Frame.MiddleBrush.Gradient.MidColor = clWhite         Frame.MiddleBrush.Gradient.StartColor = clGray         Frame.MiddleBrush.Gradient.Visible = True         Frame.OuterBrush.BackColor = clGreen         Frame.OuterBrush.Gradient.EndColor = 4210752         Frame.OuterBrush.Gradient.MidColor = clWhite         Frame.OuterBrush.Gradient.StartColor = clSilver         Frame.OuterBrush.Gradient.Visible = True         Frame.Width = 4         OtherSlice.Legend.Visible = False       end     end   end   object DatabaseConnection: TFDConnection     Params.Strings = (         ‘Database=C:\Users\Public\Documents\Embarcadero\Studio\21.0\Sampl’ +         ‘es\Data\EMPLOYEE.GDB’       ‘ConnectionDef=EMPLOYEE’)     Connected = True     LoginPrompt = False     Left = 104     Top = 64   end   object CustomerQuery: TFDQuery     AfterScroll = CustomerQueryAfterScroll     Connection = DatabaseConnection     SQL.Strings = (       ‘select * from customer’)     Left = 240     Top = 72     object CustomerQueryCUST_NO: TFDAutoIncField       FieldName = ‘CUST_NO’       Origin = ‘CUST_NO’       ProviderFlags = [pfInUpdate, pfInWhere, pfInKey]       IdentityInsert = True     end     object CustomerQueryCUSTOMER: TStringField       FieldName = ‘CUSTOMER’       Origin = ‘CUSTOMER’       Required = True       Size = 25     end     object CustomerQueryCITY: TStringField       FieldName = ‘CITY’       Origin = ‘CITY’       Size = 25     end     object CustomerQuerySTATE_PROVINCE: TStringField       FieldName = ‘STATE_PROVINCE’       Origin = ‘STATE_PROVINCE’       Size = 15     end     object CustomerQueryCOUNTRY: TStringField       FieldName = ‘COUNTRY’       Origin = ‘COUNTRY’       Size = 15     end     object CustomerQueryPOSTAL_CODE: TStringField       FieldName = ‘POSTAL_CODE’       Origin = ‘POSTAL_CODE’       Size = 12     end     object CustomerQueryON_HOLD: TStringField       AutoGenerateValue = arDefault       FieldName = ‘ON_HOLD’       Origin = ‘ON_HOLD’       FixedChar = True       Size = 1     end   end   object CustomerDataSource: TDataSource     DataSet = CustomerQuery     Left = 341     Top = 72   end   object SalesQuery: TFDQuery     MasterSource = CustomerDataSource     MasterFields = ‘CUST_NO’     DetailFields = ‘CUST_NO’     Connection = DatabaseConnection     FetchOptions.AssignedValues = [evCache]     FetchOptions.Cache = [fiBlobs, fiMeta]     UpdateOptions.AssignedValues = [uvRefreshMode]     SQL.Strings = (       ‘select * from sales’       ‘where :Cust_NO = Cust_No’)     Left = 79     Top = 240     ParamData = <       item         Name = ‘CUST_NO’         DataType = ftInteger         ParamType = ptInput         Value = 1001       end>     object SalesQueryCUST_NO: TIntegerField       DisplayLabel = ‘CUST#’       FieldName = ‘CUST_NO’       Origin = ‘CUST_NO’       Required = True     end     object SalesQueryORDER_DATE: TSQLTimeStampField       AutoGenerateValue = arDefault       DisplayLabel = ‘ORD_DATE’       DisplayWidth = 10       FieldName = ‘ORDER_DATE’       Origin = ‘ORDER_DATE’     end     object SalesQueryTOTAL_VALUE: TCurrencyField       FieldName = ‘TOTAL_VALUE’       Origin = ‘TOTAL_VALUE’       Required = True     end     object SalesQueryITEM_TYPE: TStringField       FieldName = ‘ITEM_TYPE’       Origin = ‘ITEM_TYPE’       Required = True       Size = 12     end   end   object SalesDataSource: TDataSource     DataSet = SalesQuery     Left = 184     Top = 240   end   object BindingsList1: TBindingsList     Methods = <>     OutputConverters = <>     Left = 628     Top = 69     object LinkControlToPropertyActive: TLinkControlToProperty       Category = ‘Quick Bindings’       Control = DatabaseActiveCheckBox       Track = True       Component = CustomerQuery       ComponentProperty = ‘Active’     end     object LinkControlToPropertyActive2: TLinkControlToProperty       Category = ‘Quick Bindings’       Control = DatabaseActiveCheckBox       Track = True       Component = SalesQuery       ComponentProperty = ‘Active’       InitializeControlValue = False     end     object LinkControlToPropertyActive3: TLinkControlToProperty       Category = ‘Quick Bindings’       Control = DatabaseActiveCheckBox       Track = True       Component = SalesByItemTypeForCustomerQuery       ComponentProperty = ‘Active’       InitializeControlValue = False     end   end   object SalesByItemTypeForCustomerQuery: TFDQuery     MasterSource = CustomerDataSource     MasterFields = ‘CUST_NO’     Connection = DatabaseConnection     UpdateOptions.AssignedValues = [uvRefreshMode]     SQL.Strings = (       ‘select Item_Type,sum(Total_Value) from Sales’       ‘where Cust_NO = :Cust_No’       ‘Group by Item_type’)     Left = 128     Top = 320     ParamData = <       item         Name = ‘CUST_NO’         DataType = ftInteger         ParamType = ptInput         Value = Null       end>     object SalesByItemTypeForCustomerQueryITEM_TYPE: TStringField       AutoGenerateValue = arDefault       FieldName = ‘ITEM_TYPE’       Origin = ‘ITEM_TYPE’       ProviderFlags = []       ReadOnly = True       Size = 12     end     object SalesByItemTypeForCustomerQuerySUM: TFMTBCDField       AutoGenerateValue = arDefault       FieldName = ‘SUM’       Origin = ‘”SUM”‘       ProviderFlags = []       ReadOnly = True       Precision = 18       Size = 2     end   end end | cs | 
단 한 줄의 코드로 프로젝트 완성하기
프로젝트를 한 번 저장해줍시다.

고객을 선택할 때마다 TeeChart 파이 차트를 자동 새로고침 해줘야겠죠? CustomerQuery AfterScroll 이벤트 핸들러에 딱 한 줄의 코드를 작성해보겠습니다.
| 1 2 3 4 5 | void __fastcall TMasterDetailForm::CustomerQueryAfterScroll(TDataSet *DataSet) {     // refresh the chart data when customer row scroll happens     DBChart1->RefreshData(); } | cs | 
이 단 한 줄의 코드만으로 SalesByItemTypeForCustomerQuery 값이 업데이트 될 때마다 파이 차트 데이터가 자동 새로고침됩니다.
MasterDetailUnit.h
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | //————————————————————————— #ifndef MasterDetailUnitH #define MasterDetailUnitH //————————————————————————— #include <System.Classes.hpp> #include <Vcl.Controls.hpp> #include <Vcl.StdCtrls.hpp> #include <Vcl.Forms.hpp> #include <Data.DB.hpp> #include <FireDAC.Comp.Client.hpp> #include <FireDAC.Comp.DataSet.hpp> #include <FireDAC.DApt.hpp> #include <FireDAC.DApt.Intf.hpp> #include <FireDAC.DatS.hpp> #include <FireDAC.Phys.hpp> #include <FireDAC.Phys.IB.hpp> #include <FireDAC.Phys.IBDef.hpp> #include <FireDAC.Phys.Intf.hpp> #include <FireDAC.Stan.Async.hpp> #include <FireDAC.Stan.Def.hpp> #include <FireDAC.Stan.Error.hpp> #include <FireDAC.Stan.Intf.hpp> #include <FireDAC.Stan.Option.hpp> #include <FireDAC.Stan.Param.hpp> #include <FireDAC.Stan.Pool.hpp> #include <FireDAC.UI.Intf.hpp> #include <FireDAC.VCLUI.Wait.hpp> #include <Vcl.DBCtrls.hpp> #include <Vcl.DBGrids.hpp> #include <Vcl.ExtCtrls.hpp> #include <Vcl.Grids.hpp> #include <Data.Bind.Components.hpp> #include <Data.Bind.DBScope.hpp> #include <Data.Bind.EngExt.hpp> #include <Data.Bind.Grid.hpp> #include <System.Bindings.Outputs.hpp> #include <System.Rtti.hpp> #include <Vcl.Bind.DBEngExt.hpp> #include <Vcl.Bind.Editors.hpp> #include <Vcl.Bind.Grid.hpp> #include <Vcl.WinXCtrls.hpp> #include <VCLTee.Chart.hpp> #include <VCLTee.Series.hpp> #include <VclTee.TeeGDIPlus.hpp> #include <VCLTee.TeEngine.hpp> #include <VCLTee.TeeProcs.hpp> #include <VCLTee.DBChart.hpp> #include <Datasnap.DBClient.hpp> #include <Datasnap.Provider.hpp> //————————————————————————— class TMasterDetailForm : public TForm { __published:    // IDE-managed Components     TFDConnection *DatabaseConnection;     TFDQuery *CustomerQuery;     TDataSource *CustomerDataSource;     TFDQuery *SalesQuery;     TDBNavigator *DBNavigator1;     TPanel *Panel1;     TSplitter *Splitter1;     TCheckBox *DatabaseActiveCheckBox;     TDBGrid *CustomerDBGrid;     TDBGrid *SalesDBGrid;     TDataSource *SalesDataSource;     TBindingsList *BindingsList1;     TLinkControlToProperty *LinkControlToPropertyActive;     TLinkControlToProperty *LinkControlToPropertyActive2;     TPanel *Panel2;     TIntegerField *SalesQueryCUST_NO;     TSQLTimeStampField *SalesQueryORDER_DATE;     TCurrencyField *SalesQueryTOTAL_VALUE;     TStringField *SalesQueryITEM_TYPE;     TSplitter *Splitter2;     TFDAutoIncField *CustomerQueryCUST_NO;     TStringField *CustomerQueryCUSTOMER;     TStringField *CustomerQueryCITY;     TStringField *CustomerQuerySTATE_PROVINCE;     TStringField *CustomerQueryCOUNTRY;     TDBChart *DBChart1;     TPieSeries *Series1;     TFDQuery *SalesByItemTypeForCustomerQuery;     TLinkControlToProperty *LinkControlToPropertyActive3;     TStringField *CustomerQueryPOSTAL_CODE;     TStringField *CustomerQueryON_HOLD;     TStringField *SalesByItemTypeForCustomerQueryITEM_TYPE;     TFMTBCDField *SalesByItemTypeForCustomerQuerySUM;     void __fastcall CustomerQueryAfterScroll(TDataSet *DataSet); private:    // User declarations public:        // User declarations     __fastcall TMasterDetailForm(TComponent* Owner); }; //————————————————————————— extern PACKAGE TMasterDetailForm *MasterDetailForm; //————————————————————————— #endif | cs | 
MasterDetailUnit.cpp
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | //————————————————————————— #include <vcl.h> #pragma hdrstop #include “MasterDetailUnit.h” //————————————————————————— #pragma package(smart_init) #pragma resource “*.dfm” TMasterDetailForm *MasterDetailForm; //————————————————————————— __fastcall TMasterDetailForm::TMasterDetailForm(TComponent* Owner)     : TForm(Owner) { } //————————————————————————— void __fastcall TMasterDetailForm::CustomerQueryAfterScroll(TDataSet *DataSet) {     // refresh the chart data when customer row scroll happens     DBChart1–>RefreshData(); } //————————————————————————— | cs | 
프로그램 실행하기
완성한 프로그램을 실행해볼까요? 제가 만든 프로그램은 아래와 같이 실행이 됩니다. 데이터 첫 부분의 두 고객에 대한 정보를 클릭했을 때의 화면입니다. customer sales 그리드와 파이 차트가 각 고객을 선택했을 때 다르게 보이는 걸 확인하실 수 있겠죠?
 
  
