기존 QComboBox의 한계와 개선 방향
Qt에서 QComboBox는 사용자에게 미리 정의된 항목 중 하나를 선택하게 하는 핵심 위젯 중 하나다. 기본적으로 선택 항목을 표시하고, 클릭 시 드롭다운 리스트를 보여주는 기능을 제공하지만, UI/UX 측면에서 더 직관적인 조작을 원할 경우 확장이 필요하다. 특히 웹 인터페이스에서 흔히 볼 수 있는 'X' 버튼 클릭으로 선택 해제 기능을 네이티브 데스크톱 애플리케이션에서도 구현하고자 하는 요구가 자주 발생한다.
요구사항 분석 및 설계 전략
목표는 QComboBox의 오른쪽 끝, 기존 드롭다운 화살표 위치에 마우스 커서가 올라갔을 때 아이콘이 '×'로 변경되며, 클릭 시 현재 선택된 항목을 초기화하는 것이다. 이를 위해 다음과 같은 접근이 필요하다:
- 선택 상태에 따라 시각적 피드백 제공 (아이콘 전환)
- 마우스 입력 영역 정밀 판별
- 기본 동작 재정의 및 사용자 정의 이벤트 처리
동적 스타일 속성 기반 아이콘 전환
Qt 스타일시트는 정적 정의 외에도 setProperty()를 통해 동적으로 속성을 부여함으로써 다양한 상태를 표현할 수 있다. 아래 코드는 선택 여부에 따라 Type 속성을 설정하고, 스타일을 갱신하는 예시이다.
#include <QComboBox>
#include <QMouseEvent>
#include <QStyleOption>
class EditableComboBox : public QComboBox
{
Q_OBJECT
public:
explicit EditableComboBox(QWidget *parent = nullptr) : QComboBox(parent)
{
connect(this, &QComboBox::currentIndexChanged,
this, &EditableComboBox::updateIconType);
setFocusPolicy(Qt::StrongFocus);
}
private slots:
void updateIconType(int index)
{
const QString iconState = (index == -1) ? "arrow" : "clear";
setProperty("iconMode", iconState);
style()->polish(this); // 스타일 재적용
}
};
선택 해제 로직 구현
선택된 항목을 비우는 것은 단순히 setCurrentIndex(-1)를 호출하면 된다. 이는 Qt에서 유효하지 않은 인덱스로 해석되어 표시 텍스트를 비우는 효과를 낸다.
입력 이벤트 오버라이딩을 통한 정밀 제어
마우스 이벤트를 재정의하여, 특정 영역(드롭다운/삭제 아이콘)에서의 클릭을 감지해야 한다. Qt는 hitTestComplexControl() 함수를 통해 복합 위젯 내 하위 요소를 식별할 수 있도록 지원한다.
void EditableComboBox::mouseReleaseEvent(QMouseEvent *event)
{
QStyleOptionComboBox option;
initStyleOption(&option);
const QStyle::SubControl control = style()->hitTestComplexControl(
QStyle::CC_ComboBox, &option, event->pos(), this);
// 우클릭 무시
if (event->button() == Qt::RightButton) {
event->accept();
return;
}
// 삭제 모드에서 왼쪽 클릭이 화살표 영역에 있을 경우
if (property("iconMode").toString() == "clear" &&
event->button() == Qt::LeftButton &&
control == QStyle::SC_ComboBoxArrow) {
setCurrentIndex(-1); // 선택 해제
event->accept();
return;
}
// 그 외의 경우 기본 드롭다운 동작 수행
QComboBox::mouseReleaseEvent(event);
}
불필요한 동작 억제
기본 QComboBox는 마우스를 누르고 있을 때 드롭다운이 열리는 경우가 있는데, 이를 방지하기 위해 mousePressEvent를 가로채서 차단한다.
void EditableComboBox::mousePressEvent(QMouseEvent *event)
{
// 드래그 시 드롭다운 방지
Q_UNUSED(event);
}
CSS 기반 시각적 표현
다음과 같은 스타일시트를 적용하면, iconMode 속성에 따라 아이콘이 전환된다.
EditableComboBox[iconMode="arrow"] {
padding-right: 20px;
selection-background-color: #4a90e2;
}
EditableComboBox[iconMode="clear"] {
padding-right: 20px;
qproperty-icon: url(:/icons/close.svg); /* 또는 border-image 등 */
}
실제 프로젝트에서는 qproperty-icon 대신 border-image나 폰트 아이콘(Font Awesome 등)을 활용해도 좋다.