C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 팁&트릭
C++Builder Programming Tip&Tricks
[1166] DBGrid에서 체크박스로 멀티셀렉트 하기
박지훈.임프 [cbuilder] 14207 읽음    2015-09-05 18:52
저 개인적으로는 그리드 컴포넌트로는 서드파티인 DevExpress의 cxGrid를 주로 사용하기 때문에, 간단한 로직 검증 테스트 목적 외에는 TDBGrid를 잘 사용하지 않습니다. 하지만 제가 지원하는 여러 사이트들 중에는 업무용 기본 그리드 컴포넌트로 TDBGrid를 사용하고 있는 경우가 종종 있습니다. 지난주 제가 기술지원을 하고 있는 사이트들 중 한곳에서, DBGrid에서 체크박스로 멀티셀렉트를 할 수 있도록 기능 구현을 해달라는 부탁을 받았습니다.

멀티셀렉트 기능 자체는 기본 TDBGrid에도 있습니다. Options 속성의 dgMultiSelect 플래그를 True로 설정하면 되죠. 이 모드에서는, DBGrid에서 컨트롤 혹은 시프트 키와 마우스/키보드 조합으로 여러 로우를 선택할 수 있는데, 문제는 이때의 UI가 일반적인 사용자들이 익숙한 멀티셀렉트와 많이 달라서 생소해보이는 것입니다.



보시다시피 멀티셀렉트된 로우들은 그리드 왼쪽의 인디케이터 영역에 까만색 점으로 표시되고, 현재 활성 로우는 화살표 비슷한 꺾쇠 표시로 나타납니다. 통상적인 사용자들은 이 표시를 멀티셀렉트된 상태라고 쉽게 인식하지 못하고, 또 체크박스의 경우와 달리 각 로우의 인디케이터 영역을 클릭하더라도 컨트롤키를 함께 누르지 않은 상태에서는 그냥 다른 로우 선택을 모두 해제하고 해당 로우만 선택한 상태가 되어버립니다. 전반적으로 사용자가 멀티셀렉트 기능이라고 기대할 수 있는 것과는 너무 다른 UI죠.

그래서, TDBGrid를 기반으로, 체크박스 UI 방식으로 멀티셀렉트를 할 수 있도록 개선해보기로 했습니다. 구현 방법에 대해서는... TDBGrid에서 체크박스 선택 기능을 위해서는, 그리드에 연결된 데이터셋에 데이터 타입이 아닌 Calc 타입의 필드를 추가하고(선택상태 저장), 그 필드가 연결된 그리드 컬럼에서는 OnDrawDataCell 이벤트를 이용해서 체크박스를 오너드로우로 그려넣는 방법이 가장 간단합니다. 하지만 이렇게 필드를 추가하고 이벤트 핸들러를 작성하는 방식을 사용할 경우, 각 화면마다 모두 데이터셋에 필드를 추가하고 일일이 이벤트핸들러를 작성해줘야 하기 때문에, 그리드를 사용한 화면이 아주 많을 경우(제게 이 기능을 요청한 사이트의 경우 시스템의 화면 갯수가 7000개가 넘고 대부분 DBGrid를 사용했습니다) 그러면 기존 화면들을 변경하기 위한 작업량이 대단히 많아지고 향후 유지보수에도 불리하게 되죠. 또한 데이터셋에 필드를 추가, 삭제, 순서바꿈 등을 할 때마다 일일이 수정해줘야 하게 됩니다. (물론 필드 자체의 값이 True/False의 boolean 값인 경우에는 이 방법을 써야겠지만, 그건 그리드 로우의 멀티셀렉트 목적이 아니라 데이터셋의 데이터 필드 자체를 체크박스로 표시하고 싶을 때여서, 완전히 다른 경우죠)

그래서, 저는 기본 DBGrid에서처럼 인디케이터 영역을 이용하는 방법을 '오버라이드'해서, 인디케이터 영역에 검은 점 대신 체크박스를 표시하고, 그 체크박스를 클릭해서 선택/비선택 토글할 수 있도록 구현해보기로 마음먹었습니다. 하는 김에, 거기에 통상적인 체크박스 UI에서 흔히 볼 수 있는 것처럼 타이틀 영역에 전체선택/전체해제를 위한 체크박스도 만들어넣기로 했습니다. 작업을 해보니 예상했던 것보다는 조금 더 복잡했는데, 어쨌든 그럭저럭 구현을 완료하고 하루 정도 테스트를 해봤는데, 지금까지 보기로는 꽤 잘 동작하는 것 같습니다. 구현된 컴포넌트는 다음과 같이 나타납니다.



소스파일과 데모 실행 파일들은 첨부 파일로 올립니다. (각각 델파이7, 델파이XE4에서 컴파일한 것입니다)

이 그리드는 TCheckDBGrid라는 이름의 새로운 컴포넌트로 작성되어진 것입니다. 하지만 델파이에서는, 새로운 컴포넌트로 IDE에 등록하지 않고 기존에 TDBGrid 기반으로 작성된 코드에서 불러 쓸 수 있게 작성되어 있습니다. 즉 델파이에서는 interface 섹션에서 CheckDBGrid 유닛을 uses하기만 하면 기존의 TDBGrid로 작성한 소스가 런타임에서는 CheckDBGrid로 나타나서 체크박스 선택이 가능합니다. (언어의 차이로 인해, C++빌더에서는 이 TCheckDBGrid 컴포넌트를 등록하고 폼의 TDBGrid를 CheckDBGrid로 바꿔넣어야만 사용할 수 있습니다)

개발툴 버전 호환성에 대해서는, 이 그리드는 델파이6 및 C++빌더6 이후의 모든 델파이/C++빌더 버전에서 사용할 수 있도록 작성되어졌으며, 그보다 더 오래된 4, 5 버전에서는 소스 가장 위의 {$IF RTLVersion >= 23.0} 로 시작하는 코드 여섯줄을 삭제하면 사용 가능합니다. 컴파일러 디렉티브에서 RTLVersion 상수 지원이 6 버전부터 시작되었기 때문인데, 이걸 VER120과 같은 값으로 변경하면 5 이하 버전에서도 지원 가능합니다만 컴파일러 디렉티브들이 너무 구질구질해져서 RTLVersion을 쓰기로 했습니다. (여러 버전 지원을 위해 컴파일러 디렉티브들을 많이 쓰게 된 가장 이유는, 기본 TDBGrid가 XE2 버전부터 윈도우 테마를 지원하면서 관련 코드가 많이 추가되었기 때문입니다. 그런데 이게 좀 요상하게도, XE2의 RTL 버전에서는 없던 것이 업데이트 버전에서 테마 지원 코드가 추가되었기 때문에, XE2 버전에서 사용할 경우에는 반드시 모든 개발툴 업데이트를 하셔야 합니다)

멀티셀렉트된 로우들을 런타임에서 코드로 뒤질 때의 코드는, 기본 TDBGrid의 멀티셀렉트 기능을 그대로 오버라이드한 만큼, 기본적인 멀티셀렉트 코드와 동일하게 작성하면 됩니다. 즉 다음과 같이 작성할 수 있습니다.

uses CheckDBGrid;

procedure TForm31.Button1Click(Sender: TObject);
var
  sum: double;
  I: integer;
begin
  if DBGrid1.SelectedRows.Count > 0 then
  begin
    sum := 0;
    with DBGrid1.DataSource.DataSet do
    begin
      DisableControls;
      try
        for I := 0 to DBGrid1.SelectedRows.Count-1 do
        begin
          GotoBookmark(DBGrid1.SelectedRows.Items[I]);  // i 번째 선택된 레코드로 이동
          sum:= sum + ClientDataSet1.FieldByName('Salary').AsFloat;
        end;
      finally
        EnableControls;
      end;
    end;
    ShowMessage('Salary = ' + FloatToStr(sum));
  end;
end;

끝으로, 사족입니다만, 기본 DBGrid에도 이처럼 상당한 기능 추가 혹은 변경을 할 수 있습니다. 예를 들자면 각 필드 컬럼들이 체크박스로 나타나게 하거나 필드에 버튼을 추가할 수도 있고, 컬럼마다 배경색이나 폰트를 변경할 수도 있습니다(실제로 저는 일부 프로젝트에서는 이렇게 기능들을 더 추가한 컴포넌트를 개발해서 썼기도 합니다). 하지만 역시 DevExpress cxGrid와 같은 광범위한 기능 추가는 어려우므로, 아주 고급 기능들이 필요한 경우에는 서드파티 컴포넌트가 답이지요.
미스터몽키 [jungsangun]   2016-04-05 22:10 X
이렇게 소스를 오픈해 주셔서 감사합니다.
임프님 덕에 또 배우는 군요.

DBGrid의 체크박스는 저도 오랜 고민 거리였습니다.
써드파티의 DBGrid 등은  너무 기능들이 많아 무거워 보여서 싫었서  TDBGrid에 간단히 체크박스 선택 기능만 깔끔하게 구현되길 원했습니다.
그동안 많은 시행착오 끝에 NiceGrid라는 인도네시아 분이 (www.priyatna.org)
공개한 소스를 기반으로 만들어 보기도하고 임프님 말씀처럼 OnDrawDataCell 도 이용해도 보고 TStringGrid 도 체크박스 구현해보았습니다.
오픈해 주신 소스를 기반으로 좀 더 안정적으로 구현가능할 것 같네요
감사합니다.

+ -

관련 글 리스트
1166 DBGrid에서 체크박스로 멀티셀렉트 하기 박지훈.임프 14207 2015/09/05
(링크)     Delphi Tip'N Tricks > DBGrid에서 체크박스로 멀티셀렉트 하기
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.