QMainWindow와 레이아웃을 활용한 첫 번째 GUI 구조화
by
gg582 · 2026-10-25 15:14:12 · 75 views · 3 min read
Table of contents
이전 강의에서는 QObject::connect()를 통해 시그널과 슬롯이 어떻게 이벤트를 주고받는지 확인했습니다. 단일 위젯 단위의 동작 원리를 이해했으므로, 이제 실제 데스크톱 애플리케이션의 기본 뼈대가 되는 QMainWindow와 위젯을 정돈해 배치하는 레이아웃(Layout) 시스템을 살펴보겠습니다.
1. 메인 윈도우 구조와 레이아웃 시스템
단순히 위젯의 좌표를 수동(resize, move)으로 지정하면 창 크기가 변할 때 위젯 배치가 깨집니다. Qt는 창의 크기 변화에 대응하기 위해 레이아웃 관리자와 전용 메인 윈도우 구조를 제공합니다.
QMainWindow의 구조
QMainWindow는 일반적인 데스크톱 프로그램의 표준 구조를 기본적으로 내장하고 있습니다.
- Menu Bar: 상단 풀다운 메뉴
- Toolbars: 바로가기 아이콘 툴바
- Dock Widgets: 고정 또는 분리 가능한 패널
- Status Bar: 하단 상태 알림창
- Central Widget: 위 모든 요소의 중심에 위치하는 핵심 작업 영역. 레이아웃과 일반 위젯은 반드시 이 중앙 위젯 내부에 배치되어야 합니다.
레이아웃의 역할
QVBoxLayout(수직 정렬), QHBoxLayout(수평 정렬), QGridLayout(격자 정렬)은 위젯 크기 계산과 재배치를 자동으로 처리합니다. 위젯을 레이아웃에 추가하고, 해당 레이아웃을 컨테이너 위젯에 등록하면 부모 창의 크기 변경에 맞춰 하위 위젯들이 유기적으로 크기를 조절합니다.
2. 소스 코드 구현
헤더와 구현부를 분리하여 QMainWindow를 상속받는 구조로 작성합니다. 텍스트 입력창(QLineEdit)과 버튼(QPushButton), 결과 출력 라벨(QLabel)을 수직 레이아웃(QVBoxLayout)으로 묶어 중앙 위젯에 설정합니다.
MainWindow.h
#pragma once
#include <QMainWindow>
class QLineEdit;
class QLabel;
class QPushButton;
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override = default;
private slots:
void handleInput();
private:
QLineEdit *m_lineEdit;
QLabel *m_resultLabel;
QPushButton *m_submitButton;
};
MainWindow.cpp
#include "MainWindow.h"
#include <QWidget>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QLabel>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
// 중앙 위젯 생성 및 지정
auto *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
// 내부 위젯 생성
m_lineEdit = new QLineEdit(this);
m_lineEdit->setPlaceholderText("텍스트를 입력하세요...");
m_submitButton = new QPushButton("전송", this);
m_resultLabel = new QLabel("입력 대기 중", this);
// 수직 레이아웃 생성 및 위젯 등록
auto *layout = new QVBoxLayout(centralWidget);
layout->addWidget(m_lineEdit);
layout->addWidget(m_submitButton);
layout->addWidget(m_resultLabel);
// 시그널/슬롯 연결: 버튼 클릭 및 엔터 키 입력 처리
connect(m_submitButton, &QPushButton::clicked, this, &MainWindow::handleInput);
connect(m_lineEdit, &QLineEdit::returnPressed, this, &MainWindow::handleInput);
resize(400, 200);
}
void MainWindow::handleInput() {
const QString text = m_lineEdit->text().trimmed();
if (!text.isEmpty()) {
m_resultLabel->setText("출력: " + text);
m_lineEdit->clear();
}
}
main.cpp
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char **argv) {
QApplication app(argc, argv);
MainWindow window;
window.setWindowTitle("Qt 6 QMainWindow Example");
window.show();
return app.exec();
}
3. 코드 분석
setCentralWidget(QWidget*):QMainWindow는 반드시 중앙 영역을 차지할 위젯을 요구합니다. 컨테이너 역할을 할 빈QWidget을 생성해 전달합니다.QVBoxLayout: 위젯들을 위에서 아래로 순차 배치합니다.centralWidget을 부모로 넘기면 자동으로 해당 위젯의 레이아웃 매니저로 바인딩됩니다.Q_OBJECT매크로:MainWindow.h선언부의Q_OBJECT는 Qt 메타 객체 시스템(MOC)을 활성화하여 고유 슬롯 멤버 함수(handleInput)를 시그널과 연결할 수 있게 만듭니다.
4. 빌드 설정: CMakeLists.txt
Q_OBJECT 매크로를 정상적으로 컴파일하려면 CMake에서 CMAKE_AUTOMOC 옵션을 켜야 합니다.
cmake_minimum_required(VERSION 3.16)
project(MainWindowExample LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt6 REQUIRED COMPONENTS Widgets)
add_executable(MainWindowExample
main.cpp
MainWindow.h
MainWindow.cpp
)
target_link_libraries(MainWindowExample PRIVATE Qt6::Widgets)
빌드 및 실행
mkdir -p build
cd build
cmake ..
make -j$(nproc)
./MainWindowExample
핵심 요약
- QMainWindow: 메뉴바, 툴바, 중앙 위젯 등 데스크톱 애플리케이션의 기본 뼈대를 제공합니다.
- Central Widget:
setCentralWidget()을 통해 윈도우의 중심 컨테이너를 지정해야 합니다. - Layout Manager: 절대 좌표 대신
QBoxLayout,QGridLayout등을 사용하여 창 크기 변경에 유연하게 대응합니다. - CMAKE_AUTOMOC: 클래스 내부에 시그널이나 슬롯,
Q_OBJECT매크로가 포함될 경우 메타 객체 컴파일러를 활성화해야 합니다.