DevHyun

Delphi에서 FastReport 핸들링 하기! 본문

Delphi

Delphi에서 FastReport 핸들링 하기!

D3V3L0P3R 2021. 1. 21. 18:16

 

*작업환경

- Delphi 10.3

- MSSQL

- FastReport 6.0

 

*사용 컴포넌트

- frxReport

- frxDBDataset

- AdoQuery

- AdoTable

- DataSource

- AdoConnection

: 위 컴포넌트들을 동적으로 생성해도 상관없음!

예시 ) 개발팀 팀원별 2020년 잔여 연차 리스트 뽑아보자!

 

 

1. 필요한 데이터 확인

- 잔여 연차 소모 독려를 위하여 개발팀 팀원들의 2020년 잔여 연차리스트가 필요

: 사원별 잔여 연차 리스트 테이블, 사원 정보 테이블(편의상 정규화 X)

- 각 사원들은 고유한 사번이 존재

 

[사원 정보] - Master

사번 직책 이름
1234 팀장 김팀장
5678 과장 송과장
91011 대리 박대리

 

[사원별 잔여 연차 리스트] - Detail

사번 사용연차 잔여 연차
1234 17 0
5678 12 3
91011 9 4

 

2. DB 셋팅

- ADOConnection setting

: ConnectionString 설정 후 LoginPrompt 체크 해제

 

- AdoQuery, AdoTable Connection Setting

 

- AdoQuery에 SQL문 입력

: 1이 MASTER, 2가 DETAIL로 사용될 예정

: FIELD EDITOR 에서 ADD ALL FIELD

 

- DATASOURCE 지정

: DATASOURCE1 = AdoQuery1

: DATASOURCE2 = AdoTable1

 

- AdoTable1(DETAIL)의 property - mastersource를 DATASOURCE1(MASTER)로 지정

: MASTER FIELDS 선택

: 여기서 매칭할 컬럼(사원번호)를 각각 선택 후 ADD -> OK

 

- FrxDBDataset1 은 DataSource1(MAIN) , FrxDBDataset2 는 DataSource2(Detail)  datasource로 지정

 

** 중간점검! 

 

- AdoConnection Setting

 

- AdoQuery1 : Main( SAWON 테이블 조회 쿼리)

- AdoQuery2 : Detail( HOLIDAY 테이블 조회 쿼리)

 

- AdoTable1 : TABLE NAME = HOLIDAY 

                 : MASTER SOURCE = DATASOURCE1

                 : MASTERFIELDS = SNUM

                 : INDEXFIELDNAME = SNUM

 

- DataSource1 : Dataset = AdoQuery1

- DataSource2 : Dataset = AdoTable2 = HOLIDAY 테이블

 

- FrxDBDataset1 : Dataset = DataSource1

- FrxDBDataset2 : Dataset = DataSource2

**

 

- FrxReport 편집화면 진입

: Report -> Data

: FrxDBDataset 1, FrxDBDataset2 둘다 선택

 

- Data Tree에서 확인

: Data Tree 탭이 안보일 경우 View -> ToolBars -> DataTree 클릭

 

 

 

- Master Data Section과 Detail Data Section 추가

 

 

- 사용할 Dataset 선택

 

 

- Report 화면 꾸미기

: Header는 한번만 출력

: 표현할 데이터는 DataTree에서 컬럼 별로 끌어와서 report 화면에 추가 가능(Drag & Drop)

: Master Data 는 Master Data 수 만큼 출력

: Detail Data는 Master Data와 연관된 Datail 수 만큼 출력

 

 

- 출력

 

- 끝

 

* frxReport와 frxDbDataset AdoQuery AdoTable Datasource는 생성만 해 두고

사용은 pas 파일(delphi source file)에서 동적으로 할 수 있게 변경 해볼 예정!

 

- pas파일에서 코딩해보기!

- adocennection constring setting과 report 꾸미기 작업은 수동으로 진행하였으므로 생략!

procedure TForm3.Button1Click(Sender: TObject);
var
    sql :string;
begin
	// 쿼리 컴포넌트와 커넥션 연결
    adoquery1.Connection := ADOConnection1;
    adoquery2.Connection := ADOConnection1;

	// 쿼리 컴포넌트 open
    sql := ' SELECT * FROM TEST..SAWON ';
    adoquery1.SQL.Text := sql;
    adoquery1.open;

	// adoquery2 컴포넌트는 사실 필요 없어보이지만 추후에 
       Holiday 테이블과 다른 테이블을 조인하여 SELECT 한 뒤에 임시 테이블로 생성하는 용도로 쓸 예정
       임시테이블로 생성한 뒤에 AdoTable 컴포넌트에서 사용할 예정.
       
    sql := ' SELECT * FROM TEST..HOLIDAY ';
    adoquery2.SQL.Text := sql;
    adoquery2.open;
    
    // datasource 셋팅
    datasource1.DataSet := ADOQuery1;
    
    // ado table 셋팅
    ADOTable1.Connection := ADOConnection1;
    ADOTable1.TableName := 'HOLIDAY';

    datasource2.DataSet := ADOTable1;

    ADOTable1.MasterSource := DataSource1;
    adotable1.MasterFields := 'SNUM';
    adotable1.IndexFieldNames := 'SNUM';

	// frxDBDataSet 셋팅
    frxDBDataset1.DataSet := ADOQuery1;
    frxDBDataset2.DataSet := ADOTable1;

	// 리포트 출력!
    frxReport1.PrintOptions.ShowDialog := False;  //출력 시 진행 묻는 부분 없애기
    frxReport1.ShowProgress            := False;  //출력 시 진행 프로그래스바 없애기
    frxReport1.PrintOptions.Printer    := 'FinePrint';
    frxReport1.PrepareReport;
    frxReport1.Print;
end;

 

** 최종 **

- fastreport와 frxdbdataset은 공용모듈 폼에 생성했음.

- fasreport 셋팅은 미리 한 상태.

 

- FrxReport 편집화면 진입
: Report -> Data
: FrxDBDataset 1, FrxDBDataset2 둘다 선택

- Data Tree에서 확인
: Data Tree 탭이 안보일 경우 View -> ToolBars -> DataTree 클릭


- Master Data Section과 Detail Data Section 추가

- 사용할 Dataset 선택

- Report 화면 꾸미기
: Header는 한번만 출력
: 표현할 데이터는 DataTree에서 컬럼 별로 끌어와서 report 화면에 추가 가능(Drag & Drop)
: Master Data 는 Master Data 수 만큼 출력
: Detail Data는 Master Data와 연관된 Datail 수 만큼 출력

 

- 아래는 공용모듈에 함수로 생성한 코드

: 조금 다를순 있음..흐름만 참고 하시길 ㅎㅎ

procedure Print(sql, sql2: string;);
var
    AdoConnection1 : TAdoconnection;
    Query1, Query2 : TAdoQuery;
    Table : TAdoTable;
    DS1,DS2 : TDataSource;
    sql3 : string;
begin
	// 커넥션 동적 생성 및 셋팅
    AdoConnection1 := TAdoConnection.Create(nil);
    AdoConnection1 := '커넥션 정보';
    AdoConnection1.LoginPrompt := false;
    
    // 쿼리컴포넌트 동적 생성 및 셋팅
    Query1 := TADOQuery.Create(nil);

    With Query1 do
    begin
        CommandTimeout := 0;//10000;
        CursorLocation := clUseClient;
        CursorType     := ctKeySet;
        LockType       := ltOptimistic;
        MarshalOptions := moMarshalAll;
        ParamCheck     := False;
        Prepared       := True;
    end;

    Query1.Connection := AdoConnection1;

    Query2 := TADOQuery.Create(nil);

    With Query2 do
    begin
        CommandTimeout := 0;//10000;
        CursorLocation := clUseClient;
        CursorType     := ctKeySet;
        LockType       := ltOptimistic;
        MarshalOptions := moMarshalAll;
        ParamCheck     := False;
        Prepared       := True;
    end;

    Query2.Connection := AdoConnection1;

	// table 컴포넌트 생성(임시 테이블 생성 후 데이터 참조 용)
    Table := TADOTable.Create(nil);

	// 데이터셋 컴포넌트 생성 및 셋팅
    DS1 := TDataSource.Create(nil);
    DS2 := TDataSource.Create(nil);

	// 출력 부분을 공용모듈에서 함수로 만들었기 때문에 masetr sql문은 파라미터로 받아옴
    // master 테이블 select
    adoquery1.SQL.Text := sql;
    adoquery1.open;  // Master

	// temp 테이블 생성 전 확인
    sql3 := ' IF EXISTS(SELECT * FROM TEST SYSOBJECTS WHERE name = ''TEMP'') '
             + ' DROP TABLE TEST..TEMP ';

    adoquery2.SQL.Text := sql3;
    adoquery2.ExecSQL;  // Master

	// temp 테이블 생성
    sql2 := ' SELECT * INTO TEST..TEMP FROM (SELECT * FROM TEST..HOLIDAY AS A LEFT JOIN TEST..SAWON AS B ON A.SNUM = B.SNUM) AS A ';

    adoquery2.SQL.Text := sql2;
    adoquery2.ExecSQL;  

	// temp 테이블 select
    sql3 := ' SELECT * FROM TEST..TEMP ';
    adoquery2.SQL.Text := sql3;
    adoquery2.ExecSQL;  // Detail

	// 데이터셋 컴포넌트 셋팅 및 table 컴포넌트 셋팅
    ds1.DataSet := Query1;
    table.Connection := ADOConnection1;
    table.TableName := 'TEMP';

    ds2.DataSet := table;

	// 참조할 키 설정(연결 키)
    table.MasterSource := ds1;
    table.MasterFields := 'SNUM';
    table.IndexFieldNames := 'SNUM';
    
	// 변동 사항 있을 수도 있으니 한번 active 시켜줌
   	// 컬럼이 변동되었을 경우 active를 해주면 fastrport dbdatset refresh 되는듯?
    table.Active:= True;
    
    // frxdbdataset은 공용모듈에 컴포넌트로 올려두었음(동적 생성해도 될듯?)
    frxdbdataset1.DataSet := Query1;
    frxdbdataset2.DataSet := table;

	// fastreport
	// master,detail dataset 설정
    TfrxDBDataset(frxReport1.FindObject('MasterData1')).DataSet := frxDBDataset1.DataSet;
    TfrxDBDataset(frxReport1.FindObject('DetailData1')).DataSet := frxDBDataset2.DataSet;

    // MASTER
    TfrxMemoView(frxReport1.FindObject('오브젝트 명')).DataSet := frxDBDataset1;
    TfrxMemoView(frxReport1.FindObject('오브젝트 명')).DataField := '필드명';

    //DETAIL
    TfrxMemoView(frxReport1.FindObject('오브젝트 명')).DataSet := frxDBDataset2;
    TfrxMemoView(frxReport1.FindObject('오브젝트 명')).DataField := '필드명';

	// 출력
    frxReport1.PrintOptions.ShowDialog := False;  //출력 시 진행 묻는 부분 없애기
    frxReport1.ShowProgress            := False;  //출력 시 진행 프로그래스바 없애기
    frxReport1.PrintOptions.Printer    := '프린트명';
    frxReport1.PrepareReport;
    frxReport1.Print;
    
    // temp 테이블 삭제
    sql2 := 'DROP TABLE TEST..TEMP';    
    adoquery1.SQL.Text := sql2;
    adoquery1.ExecSQL;  

	// 동적으로 생성했던 컴포넌트 free
    Query1.Free;
    Query2.Free;
    Table.Free;
    DS1.Free;
    DS2.Free;
end;
Comments