Qt 스타일 시트(QSS)는 CSS 2.0 명세를 기반으로 구축되어 있어, Qt 프레임워크 내에서 GUI 컴포넌트의 시각적 표현을 효율적으로 제어할 수 있는 데크레이티브 언어입니다. 복잡한 렌더링 코드 수정 없이 선택자 정의와 상태 규칙을 조합하여 애플리케이션 테마를 적용할 수 있습니다.
선택자 유형 및 기본 규칙
QSS는 타겟 위젯을 식별하기 위해 ID와 클래스 기반 선택자를 제공합니다. Qt 위젯은 setObjectName() 메서드를 통해 고유 식별자를 부여받을 수 있으며, 이는 해시(#) 기호와 결합해 특정 인스턴스를 명시적으로 타겟팅합니다. 반대로 점(.) 기호는 동일한 클래스에 속한 모든 위젯에 일괄적으로 스타일을 부여할 때 사용됩니다. 컴포즈드 위젯의 내부 요소는 :: 연산자를 활용해 하위 컨트롤(Sub-control)로 분리하여 지정할 수 있습니다.
가상 상태(Pseudo-states) 및 논리 조합
사용자 인터랙션에 따른 동적 변화는 가상 상태 선택자를 통해 구현합니다. 콜론(:)으로 시작하는 상태 식별자는 마우스 오버(:hover), 버튼 클릭(:pressed), 체크(:checked) 등 위젯의 실시간 동작을 반영합니다.
/* 마우스 커서가 버튼 위에 있을 때 배경 색상 변경 */
QPushButton#actionBtn:hover {
background-color: #e63946;
}
특정 상태를 제외하거나 여러 상태를 동시에 만족하도록 규칙을 정의할 수도 있습니다. 느낌표(!) 부정 연산자를 사용하면 해당 상태가 활성화되지 않았을 때만 스타일이 적용됩니다.
/* 클릭(Pressed) 상태가 아닐 때만 테두리 두께 적용 */
QCheckBox#toggleSwitch:!pressed {
border-width: 2px;
}
가상 상태는 연달아 작성하여 논리적 조건을 결합할 수 있습니다. 예를 들어 :hover:!pressed는 마우스가 올라왔지만 아직 클릭 동작이 발생하지 않은 정확한 타이밍을 타겟팅합니다. 이러한 상태 규칙은 하위 컨트롤 선택자와 자유롭게 결합되며, 쉼표(,)를 사용해 동일한 속성 값을 공유하는 다중 선택자를 단일 블록으로 그룹화할 수 있습니다.
/* 여러 컨트롤의 상호작용 상태에 동일한 텍스트 색상 적용 */
QPushButton#navBtn:hover, QSpinBox#inputBox::down-arrow:pressed, QCheckBox#optionBox:checked {
color: #1d3557;
font-weight: bold;
}
QSS 적용 시나리오
정의된 스타일 규칙을 실제 애플리케이션에 반영하는 방법은 크게 인라인 적용과 외부 파일 로드로 나뉩니다.
1. 인라인 문자열 직접 적용
소스 코드 내부에 QSS 텍스트를 문자열 리터럴로 전달하여 즉시 적용합니다. 빠른 프로토타이핑이나 간단한 레이아웃 테스트에 적합합니다.
#include <QApplication>
#include <QMainWindow>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QMainWindow w;
w.setObjectName("mainWindow");
// 애플리케이션 레벨에서 전역 스타일 시트 설정
a.setStyleSheet(
"QMainWindow#mainWindow { background-color: #f8f9fa; } "
"QPushButton#primaryBtn { color: #ffffff; background-color: #212529; border-radius: 4px; }"
);
w.show();
return a.exec();
}
2. 외부 파일 기반 로드
대규모 프로젝트에서는 유지보수성과 리소스 관리를 위해 .qss 확장자 파일을 별도로 관리하는 것이 표준 관행입니다. QFile을 활용하여 디스크 또는 Qt 리소스 시스템(:/)에서 파일을 읽고 문자열로 변환한 후 setStyleSheet()에 인자로 전달합니다.
#include <QFile>
#include <QString>
#include <QCoreApplication>
void loadExternalStyleSheet() {
QFile styleResource(":/themes/dark_mode.qss");
if (!styleResource.open(QIODevice::ReadOnly | QIODevice::Text)) {
qWarning() << "스타일 시트 파일 로드 실패";
return;
}
QByteArray rawContent = styleResource.readAll();
styleResource.close();
QString formattedQss = QString::fromUtf8(rawContent.trimmed());
QCoreApplication::setStyleSheet(formattedQss);
}