다음은 데이비드 아이(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 그리드와 파이 차트가 각 고객을 선택했을 때 다르게 보이는 걸 확인하실 수 있겠죠?

  

번호 제목 글쓴이 날짜 조회 수
공지 [DelphiCon 요약] 코드사이트 로깅 실전 활용 기법 (Real-world CodeSite Logging Techniques) 관리자 2021.01.19 14387
공지 [UX Summit 요약] 오른쪽 클릭은 옳다 (Right Click is Right) 관리자 2020.11.16 13023
공지 [10.4 시드니] What's NEW! 신기능 자세히 보기 관리자 2020.05.27 15532
공지 RAD스튜디오(델파이,C++빌더) - 고객 사례 목록 관리자 2018.10.23 21064
공지 [데브기어 컨설팅] 모바일 앱 & 업그레이드 마이그레이션 [1] 관리자 2017.02.06 22297
공지 [전체 목록] 이 달의 기술자료 & 기술레터 관리자 2017.02.06 17932
공지 RAD스튜디오(델파이, C++빌더) - 시작하기 [1] 관리자 2015.06.30 38228
공지 RAD스튜디오(델파이,C++빌더) - 모바일 앱 개발 사례 (2020년 11월 업데이트 됨) 험프리 2014.01.16 173741
1322 [DelphiCon 요약] 델파이 코드 빠르게 작성하기 (Code Faster in Delphi) 관리자 2020.12.22 607
1321 [업데이트 서브스크립션 무료 솔루션] TWINECOMPILE – C++ 컴파일 속도를 현격하게 줄여줍니다! [1] 관리자 2020.12.18 482
1320 델파이 윈도우 앱 샘플 – BLOB 스트림을 내/외부에서 쉽게 사용하기 관리자 2020.12.15 359
1319 델파이 웹 개발: TMS WEB CORE VS. UNIGUI VS. INTRAWEB 관리자 2020.12.10 1029
1318 1PASSWORD: 델파이로 개발된 BEST 패스워드 관리 프로그램 관리자 2020.12.07 849
1317 [UX Summit 요약] 감지와 응답: 지속적 파악을 통한 실제 결과를 더 좋게 하기 (Sense & Respond: Continuously Learning Our Way to Better Outcomes) 관리자 2020.12.02 421
1316 개발. 공유. 영감. – 엠바카데로 총괄 매니저가 전하는 메세지 (2020.11) 관리자 2020.12.01 334
1315 [10.4.1 패치] 애플(APPLE) 플랫폼 지원 관리자 2020.11.30 453
1314 [델파이 게임 개발] 겟잇(GETIT)에서 ALIEN INVASION 다운로드 받기 관리자 2020.11.30 394
1313 이 달의 기술자료 - 2020년 12월 험프리 2020.11.26 361
1312 RAD스튜디오 2020 로드맵 – 자세한 내용을 확인해보세요! (PM들의 코멘터리) 관리자 2020.11.19 521
1311 [DelphiFeeds.com 리뉴얼] 새롭게, 델파이 개발자들에게 매우 유용한 뉴스 피드를 모아서 제공합니다. 관리자 2020.11.19 335
1310 RAD스튜디오 로드맵 (2020.11) 관리자 2020.11.18 388
1309 델파이 개발자용 웹 개발 기술들 비교 및 평가 (Evaluating Web Development Frameworks for Delph) file 관리자 2020.11.17 497
1308 [UX Summit 요약] 애플리케이션을 개발할 때 데스크톱부터 개발해야 하는 이유 (Why Desktop First to Develop an Application) 관리자 2020.11.17 336
1307 [10.4.1 패치] 델파이 컴파일러와 LSP 업데이트 관리자 2020.11.11 722
1306 [UX Summit 요약] 터치스크린 POS 화면 디자인 하기 (Point of Sale Screen Concept) 관리자 2020.11.11 366
1305 [UX Summit 요약] 멀티플랫폼 앱에 가장 효과적인 UX 디자인 (Effective UX Design for Multiplatform Apps) 관리자 2020.11.10 312
» 단 한 줄의 코드로 완성하는 C++ CUSTOMER/SALES 애플리케이션 관리자 2020.11.09 398