DBGrid에서 체크박스로 멀티셀렉트 하기

저 개인적으로는 그리드 컴포넌트로는 서드파티인 DevExpress의 cxGrid를 주로 사용하기 때문에, 간단한 로직 검증 테스트 목적 외에는 TDBGrid를 잘 사용하지 않습니다. 하지만 제가 지원하는 여러 사이트들 중에는 업무용 기본 그리드 컴포넌트로 TDBGrid를 사용하고 있는 경우가 종종 있습니다. 지난주 제가 기술지원을 하고 있는 사이트들 중 한곳에서, DBGrid에서 체크박스로 멀티셀렉트를 할 수 있도록 기능 구현을 해달라는 부탁을 받았습니다.

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

TDBGrid

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

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

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

TImpDBGrid

소스파일은 다음과 같습니다.

CheckDBGrid.pas

실제로 써보기 전에 이게 실제로 어떻게 보이고 동작하는지 궁금하실 수 있으니 데모 실행 파일도 첨부합니다. (각각 델파이7, 델파이XE4에서 컴파일한 것입니다)

CheckDBGridDemo_7.zip CheckDBGridDemo_XE4.zip

이 그리드는 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의 멀티셀렉트 기능을 그대로 오버라이드한 만큼, 기본적인 멀티셀렉트 코드와 동일하게 작성하면 됩니다. 즉 다음과 같이 작성할 수 있습니다.

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

답글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다.