์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿ–ฅ๏ธ Qt & wxWidgets๋กœ ๋งŒ๋“œ๋Š”C++ ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๊ฐœ๋ฐœ
ํ”„๋กœ๊ทธ๋žจ๊ฐœ๋ฐœ ยท ์‘์šฉํ”„๋กœ๊ทธ๋ž˜๋ฐ

๐Ÿ–ฅ๏ธ Qt & wxWidgets๋กœ ๋งŒ๋“œ๋Š”
C++ ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๊ฐœ๋ฐœ

Windows, macOS, Linux ์–ด๋””์„œ๋“  ๋Œ์•„๊ฐ€๋Š” ์•ฑ์„ ๋งŒ๋“ค์–ด๋ณด์ž! ๐Ÿš€

์•ผ, ์†”์งํžˆ ๋งํ•ด๋ด. ์•ฑ ํ•˜๋‚˜ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ Windows์—์„œ๋งŒ ๋Œ์•„๊ฐ€๋ฉด ์–ผ๋งˆ๋‚˜ ์–ต์šธํ•ด? ๐Ÿ˜ค
์นœ๊ตฌํ•œํ…Œ ์ž๋ž‘ํ•˜๋ ค๊ณ  ๋ณด๋ƒˆ๋”๋‹ˆ "๋‚˜ Mac ์“ฐ๋Š”๋ฐ?"๋ผ๋Š” ๋ง ๋“ค์–ด๋ณธ ์  ์žˆ์ง€?
๊ทธ๋ž˜์„œ ์˜ค๋Š˜์€ C++๋กœ ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ์„ ๋งŒ๋“œ๋Š” ๋‘ ๊ฐ€์ง€ ํ•ต์‹ฌ ๋ฌด๊ธฐ, ๋ฐ”๋กœ Qt์™€ wxWidgets์— ๋Œ€ํ•ด ์™„์ „ ๊นŠ์ด ํŒŒํ—ค์ณ๋ณผ ๊ฑฐ์•ผ.

์ด ๋‘ ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ์ˆ˜์‹ญ ๋…„์˜ ์—ญ์‚ฌ๋ฅผ ๊ฐ€์ง„ ๊ฒ€์ฆ๋œ ๋„๊ตฌ๋“ค์ด๊ณ , ์ง€๊ธˆ๋„ ์ „ ์„ธ๊ณ„ ์ˆ˜๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์‹ค๋ฌด์—์„œ ์“ฐ๊ณ  ์žˆ์–ด.
VLC ๋ฏธ๋””์–ด ํ”Œ๋ ˆ์ด์–ด, Autodesk ์ œํ’ˆ๋“ค, ์‹ฌ์ง€์–ด NASA ์†Œํ”„ํŠธ์›จ์–ด์—๋„ Qt๊ฐ€ ๋“ค์–ด๊ฐ€ ์žˆ๋‹ค๊ณ  ํ•˜๋ฉด ๋ฏฟ๊ฒจ? ๐Ÿ›ธ
์ž, ๊ทธ๋Ÿผ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์‹œ์ž‘ํ•ด๋ณด์ž!


C++ ํฌ๋กœ์Šคํ”Œ๋žซํผ Qt ํฌ๋กœ์Šคํ”Œ๋žซํผ GUI ํ”„๋ ˆ์ž„์›Œํฌ 1991๋…„ ~ ํ˜„์žฌ wxWidgets ๋„ค์ดํ‹ฐ๋ธŒ ๋ฃฉ์•คํ•„ GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ 1992๋…„ ~ ํ˜„์žฌ Windows macOS Linux ํ•˜๋‚˜์˜ ์ฝ”๋“œ, ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ์‹คํ–‰! Qt์™€ wxWidgets์˜ ํฌ๋กœ์Šคํ”Œ๋žซํผ ๋งˆ๋ฒ• โœจ

๐ŸŒ ํฌ๋กœ์Šคํ”Œ๋žซํผ์ด ์™œ ์ค‘์š”ํ•œ๊ฐ€?

๋จผ์ € ์™œ ํฌ๋กœ์Šคํ”Œ๋žซํผ ๊ฐœ๋ฐœ์ด ์ด๋ ‡๊ฒŒ ์ค‘์š”ํ•œ์ง€๋ถ€ํ„ฐ ์งš๊ณ  ๋„˜์–ด๊ฐ€์ž.
2024๋…„ ๊ธฐ์ค€์œผ๋กœ ๋ฐ์Šคํฌํƒ‘ OS ์‹œ์žฅ์„ ๋ณด๋ฉด Windows๊ฐ€ ์•ฝ 72%, macOS๊ฐ€ ์•ฝ 15%, Linux๊ฐ€ ์•ฝ 4% ์ •๋„๋ฅผ ์ฐจ์ง€ํ•˜๊ณ  ์žˆ์–ด.
์ฆ‰, Windows๋งŒ ์ง€์›ํ•˜๋ฉด ์ „์ฒด ์‚ฌ์šฉ์ž์˜ 28%๋ฅผ ํฌ๊ธฐํ•˜๋Š” ๊ฑฐ์•ผ. ๊ทธ๊ฒŒ ์–ผ๋งˆ๋‚˜ ํฐ ์†์‹ค์ธ์ง€ ๋А๊ปด์ง€์ง€? ๐Ÿ’ธ

๐Ÿ’ก ํฌ๋กœ์Šคํ”Œ๋žซํผ ๊ฐœ๋ฐœ์˜ ํ•ต์‹ฌ ๊ฐ€์น˜: "Write Once, Run Anywhere" โ€” ํ•œ ๋ฒˆ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์—ฌ๋Ÿฌ OS์—์„œ ๋™์ž‘ํ•˜๋Š” ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค!

๋ฌผ๋ก  ์›น ๊ธฐ๋ฐ˜ ์•ฑ(Electron ๊ฐ™์€)๋„ ํฌ๋กœ์Šคํ”Œ๋žซํผ์„ ์ง€์›ํ•˜์ง€๋งŒ, C++ ๊ธฐ๋ฐ˜ ๋„ค์ดํ‹ฐ๋ธŒ ์•ฑ์€ ์„ฑ๋Šฅ ๋ฉด์—์„œ ์••๋„์ ์ด์•ผ.
ํŠนํžˆ ๊ทธ๋ž˜ํ”ฝ ์ฒ˜๋ฆฌ, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ, ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ ๊ฐ™์€ ๋ถ„์•ผ์—์„œ๋Š” C++ ํฌ๋กœ์Šคํ”Œ๋žซํผ ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์ง„๊ฐ€๋ฅผ ๋ฐœํœ˜ํ•ด.

๊ทธ๋ฆฌ๊ณ  ์†”์งํžˆ ๋งํ•˜๋ฉด, C++๋กœ ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๋งŒ๋“œ๋Š” ๋Šฅ๋ ฅ์€ ์ทจ์—… ์‹œ์žฅ์—์„œ๋„ ์—„์ฒญ๋‚œ ๊ฒฝ์Ÿ๋ ฅ์ด์•ผ.
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ๋„ Qt ๊ฐœ๋ฐœ์ž๋‚˜ C++ GUI ๊ฐœ๋ฐœ ๊ด€๋ จ ์˜๋ขฐ๊ฐ€ ๊พธ์ค€ํžˆ ์˜ฌ๋ผ์˜ค๋Š” ๊ฑธ ๋ณด๋ฉด ์ˆ˜์š”๊ฐ€ ์–ผ๋งˆ๋‚˜ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ์ง€. ๐Ÿ˜Ž


๐Ÿ”ต Qt ํ”„๋ ˆ์ž„์›Œํฌ ์™„์ „ ํ•ด๋ถ€

Qt์˜ ์—ญ์‚ฌ์™€ ์ฒ ํ•™

Qt(ํํŠธ๋ผ๊ณ  ์ฝ์–ด, "ํํ‹ฐ"๊ฐ€ ์•„๋‹ˆ์•ผ! ๐Ÿ˜„)๋Š” 1991๋…„ ๋…ธ๋ฅด์›จ์ด์˜ Trolltech ํšŒ์‚ฌ์—์„œ ๋งŒ๋“ค์—ˆ์–ด.
์ดํ›„ Nokia๊ฐ€ ์ธ์ˆ˜ํ–ˆ๋‹ค๊ฐ€, ์ง€๊ธˆ์€ The Qt Company๊ฐ€ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์ง€.
30๋…„์ด ๋„˜๋Š” ์—ญ์‚ฌ๋ฅผ ๊ฐ€์ง„ ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋Š” ๋‹จ์ˆœํ•œ GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋„˜์–ด์„œ ์™„์ „ํ•œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ํ”Œ๋žซํผ์œผ๋กœ ์ง„ํ™”ํ–ˆ์–ด.

Qt์˜ ํ•ต์‹ฌ ์ฒ ํ•™์€ "๋ชจ๋“  ๊ฒƒ์„ Qt ์•ˆ์—์„œ"์•ผ.
GUI๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋„คํŠธ์›Œํ‚น, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ๋ฉ€ํ‹ฐ๋ฏธ๋””์–ด, 3D ๊ทธ๋ž˜ํ”ฝ, ์›น ์—”์ง„๊นŒ์ง€ Qt ํ•˜๋‚˜๋กœ ๋‹ค ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์–ด.
์ด๊ฒŒ Qt์˜ ๊ฐ€์žฅ ํฐ ๊ฐ•์ ์ด์ž, ๋•Œ๋กœ๋Š” ๋‹จ์ ์ด ๋˜๊ธฐ๋„ ํ•ด(๋ฌด๊ฑฐ์›Œ์ง€๊ฑฐ๋“  ๐Ÿ˜…).

Qt์˜ ํ•ต์‹ฌ ๊ฐœ๋…: Signal & Slot

Qt๋ฅผ ์ฒ˜์Œ ๋ฐฐ์šธ ๋•Œ ๊ฐ€์žฅ ๋จผ์ € ๋งŒ๋‚˜๋Š” ๊ฐœ๋…์ด ๋ฐ”๋กœ Signal & Slot ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด์•ผ.
์ด๊ฑด Qt๊ฐ€ C++ ํ‘œ์ค€์— ์—†๋Š” ์ž์ฒด์ ์ธ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ ์‹œ์Šคํ…œ์„ ๊ตฌํ˜„ํ•œ ๊ฑฐ์•ผ.
์‰ฝ๊ฒŒ ๋งํ•˜๋ฉด ์ด๋ ‡๊ฒŒ ์ƒ๊ฐํ•ด๋ด:

๐Ÿ“ก Signal = "์•ผ, ๋ญ”๊ฐ€ ์ผ์–ด๋‚ฌ์–ด!" ๋ผ๊ณ  ์™ธ์น˜๋Š” ๊ฒƒ
๐ŸŽฏ Slot = "์•Œ๊ฒ ์–ด, ๋‚ด๊ฐ€ ์ฒ˜๋ฆฌํ• ๊ฒŒ!" ๋ผ๊ณ  ์‘๋‹ตํ•˜๋Š” ๊ฒƒ

๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๋ฉด Signal์ด ๋ฐœ์ƒํ•˜๊ณ , ๊ทธ Signal์— ์—ฐ๊ฒฐ๋œ Slot ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜๋Š” ๊ฑฐ์•ผ.
์ด ๋ฐฉ์‹์˜ ์žฅ์ ์€ ๋А์Šจํ•œ ๊ฒฐํ•ฉ(Loose Coupling)์ด์•ผ. ๋ฐœ์‹ ์ž์™€ ์ˆ˜์‹ ์ž๊ฐ€ ์„œ๋กœ๋ฅผ ์ง์ ‘ ์•Œ ํ•„์š”๊ฐ€ ์—†์–ด.

// Qt Signal & Slot ๊ธฐ๋ณธ ์˜ˆ์ œ
#include <QApplication>
#include <QPushButton>
#include <QLabel>
#include <QVBoxLayout>
#include <QWidget>

class MyWindow : public QWidget {
    Q_OBJECT  // Qt ๋ฉ”ํƒ€ ์˜ค๋ธŒ์ ํŠธ ์‹œ์Šคํ…œ ํ™œ์„ฑํ™” (ํ•„์ˆ˜!)
    
public:
    MyWindow(QWidget *parent = nullptr) : QWidget(parent) {
        // ๋ ˆ์ด์•„์›ƒ ์„ค์ •
        QVBoxLayout *layout = new QVBoxLayout(this);
        
        // ์œ„์ ฏ ์ƒ์„ฑ
        QPushButton *btn = new QPushButton("ํด๋ฆญํ•ด๋ด!", this);
        QLabel *label = new QLabel("์•„์ง ์•ˆ ๋ˆŒ๋ ธ์–ด์š”", this);
        
        layout->addWidget(btn);
        layout->addWidget(label);
        
        // Signal๊ณผ Slot ์—ฐ๊ฒฐ (ํ•ต์‹ฌ!)
        connect(btn, &QPushButton::clicked, [label]() {
            label->setText("๋ฒ„ํŠผ์ด ๋ˆŒ๋ ธ์–ด์š”! ๐ŸŽ‰");
        });
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    MyWindow window;
    window.setWindowTitle("Qt ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ");
    window.show();
    return app.exec();
}

์œ„ ์ฝ”๋“œ ๋ณด๋ฉด ์–ด๋•Œ? ์ƒ๊ฐ๋ณด๋‹ค ์ง๊ด€์ ์ด์ง€? ๐Ÿ™‚
connect() ํ•จ์ˆ˜ ํ•˜๋‚˜๋กœ ๋ฒ„ํŠผ ํด๋ฆญ๊ณผ ๋ผ๋ฒจ ํ…์ŠคํŠธ ๋ณ€๊ฒฝ์„ ์—ฐ๊ฒฐํ–ˆ์–ด.
์ด ์ฝ”๋“œ๋Š” Windows, macOS, Linux ์–ด๋””์„œ๋“  ๋™์ผํ•˜๊ฒŒ ๋™์ž‘ํ•ด. ๊ทธ๊ฒŒ Qt์˜ ๋งˆ๋ฒ•์ด์•ผ!

Qt์˜ ์ฃผ์š” ๋ชจ๋“ˆ ๊ตฌ์กฐ

Qt๋Š” ๋ชจ๋“ˆ์‹ ๊ตฌ์กฐ๋กœ ๋˜์–ด ์žˆ์–ด์„œ ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ๊ณจ๋ผ์„œ ์“ธ ์ˆ˜ ์žˆ์–ด.
์ฃผ์š” ๋ชจ๋“ˆ๋“ค์„ ์‚ดํŽด๋ณด์ž:

๋ชจ๋“ˆ๋ช…์—ญํ• ์ฃผ์š” ํด๋ž˜์Šค
Qt Coreํ•ต์‹ฌ ๊ธฐ๋Šฅ (๋ฌธ์ž์—ด, ์ปจํ…Œ์ด๋„ˆ, ์ด๋ฒคํŠธ)QString, QList, QTimer
Qt GUI๊ธฐ๋ณธ GUI ๊ธฐ๋ŠฅQWindow, QPainter, QFont
Qt Widgets๋ฐ์Šคํฌํƒ‘ UI ์œ„์ ฏQWidget, QDialog, QMainWindow
Qt Network๋„คํŠธ์›Œํฌ ํ†ต์‹ QTcpSocket, QNetworkRequest
Qt SQL๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™QSqlDatabase, QSqlQuery
Qt Multimedia์˜ค๋””์˜ค/๋น„๋””์˜คQMediaPlayer, QCamera
Qt Quick/QML๋ชจ๋˜ UI (์„ ์–ธํ˜•)QQuickView, QQmlEngine
Qt WebEngine์›น ๋ธŒ๋ผ์šฐ์ € ์—”์ง„QWebEngineView

Qt์˜ ๋นŒ๋“œ ์‹œ์Šคํ…œ: qmake vs CMake

Qt ํ”„๋กœ์ ํŠธ๋ฅผ ๋นŒ๋“œํ•  ๋•Œ ๋‘ ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ์–ด.

๐Ÿ”ง qmake (์ „ํ†ต์  ๋ฐฉ์‹)

Qt ์ „์šฉ ๋นŒ๋“œ ์‹œ์Šคํ…œ์ด์•ผ.
.pro ํŒŒ์ผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์„ค์ •ํ•˜๊ณ ,
Qt Creator์™€ ์™„๋ฒฝํ•˜๊ฒŒ ํ†ตํ•ฉ๋ผ.
๊ฐ„๋‹จํ•œ ํ”„๋กœ์ ํŠธ์—” ์—ฌ์ „ํžˆ ํŽธ๋ฆฌํ•ด.
โšก CMake (ํ˜„๋Œ€์  ๋ฐฉ์‹)

Qt 6๋ถ€ํ„ฐ ๊ณต์‹ ๊ถŒ์žฅ ๋นŒ๋“œ ์‹œ์Šคํ…œ.
๋” ๋„“์€ ์ƒํƒœ๊ณ„์™€ ํ˜ธํ™˜๋˜๊ณ ,
๋ณต์žกํ•œ ํ”„๋กœ์ ํŠธ ๊ด€๋ฆฌ์— ์œ ๋ฆฌํ•ด.
ํ˜„์—…์—์„œ ์ ์  ๋” ๋งŽ์ด ์“ฐ์—ฌ.
# CMakeLists.txt ์˜ˆ์‹œ (Qt 6 ๊ธฐ์ค€)
cmake_minimum_required(VERSION 3.16)
project(MyQtApp VERSION 1.0)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)    # MOC ์ž๋™ ์‹คํ–‰
set(CMAKE_AUTOUIC ON)    # UIC ์ž๋™ ์‹คํ–‰
set(CMAKE_AUTORCC ON)    # RCC ์ž๋™ ์‹คํ–‰

find_package(Qt6 REQUIRED COMPONENTS Core Widgets Network)

add_executable(MyQtApp
    main.cpp
    mainwindow.cpp
    mainwindow.h
)

target_link_libraries(MyQtApp PRIVATE
    Qt6::Core
    Qt6::Widgets
    Qt6::Network
)

Qt์˜ MOC (Meta-Object Compiler)

Qt๋ฅผ ์ฒ˜์Œ ๋ฐฐ์šฐ๋ฉด MOC๋ผ๋Š” ๊ฐœ๋…์—์„œ ํ•œ ๋ฒˆ์ฏค ๋ฉ˜๋ถ•์ด ์™€ ๐Ÿ˜ต
MOC๋Š” Qt์˜ Signal & Slot, Q_OBJECT ๋งคํฌ๋กœ ๊ฐ™์€ ๊ธฐ๋Šฅ์„ C++ ํ‘œ์ค€์ด ์ง€์›ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—,
Qt๊ฐ€ ์ž์ฒด์ ์œผ๋กœ ๋งŒ๋“  ์ „์ฒ˜๋ฆฌ๊ธฐ(Pre-processor)์•ผ.

๋นŒ๋“œ ๊ณผ์ •์„ ๋ณด๋ฉด:

๐Ÿ“ .h ํŒŒ์ผ (Q_OBJECT ํฌํ•จ) โ†’ MOC ์ฒ˜๋ฆฌ โ†’ moc_xxx.cpp ์ƒ์„ฑ โ†’ ์ปดํŒŒ์ผ๋Ÿฌ โ†’ ์ตœ์ข… ์‹คํ–‰ํŒŒ์ผ

์ด ๊ณผ์ •์ด ์ž๋™์œผ๋กœ ์ด๋ฃจ์–ด์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ฐœ์ž๋Š” ํฌ๊ฒŒ ์‹ ๊ฒฝ ์“ธ ํ•„์š” ์—†์–ด.
CMake์—์„œ CMAKE_AUTOMOC ON์œผ๋กœ ์„ค์ •ํ•˜๋ฉด ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ด์ค˜.
๋‹ค๋งŒ ์ด ๋•Œ๋ฌธ์— Qt ์ฝ”๋“œ๋Š” ์ˆœ์ˆ˜ C++ ํ‘œ์ค€๊ณผ 100% ํ˜ธํ™˜๋˜์ง€ ์•Š๋Š”๋‹ค๋Š” ์ ์€ ์•Œ์•„๋‘ฌ์•ผ ํ•ด.

Qt Designer์™€ Qt Creator

Qt๋Š” ๊ฐ•๋ ฅํ•œ ๊ฐœ๋ฐœ ๋„๊ตฌ๋“ค์„ ์ œ๊ณตํ•ด:

๐ŸŽจ Qt Designer: ๋“œ๋ž˜๊ทธ ์•ค ๋“œ๋กญ์œผ๋กœ UI๋ฅผ ๋งŒ๋“œ๋Š” ์‹œ๊ฐ์  ํŽธ์ง‘๊ธฐ์•ผ.
.ui ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , ์ด๊ฑธ ์ฝ”๋“œ์™€ ์—ฐ๊ฒฐํ•ด์„œ ์‚ฌ์šฉํ•ด.
๋ณต์žกํ•œ ๋ ˆ์ด์•„์›ƒ๋„ ์ฝ”๋“œ ํ•œ ์ค„ ์—†์ด ๋š๋”ฑ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

๐Ÿ› ๏ธ Qt Creator: Qt ์ „์šฉ ํ†ตํ•ฉ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ(IDE)์ด์•ผ.
์ฝ”๋“œ ํŽธ์ง‘, ๋””๋ฒ„๊น…, ํ”„๋กœํŒŒ์ผ๋ง, Qt Designer ํ†ตํ•ฉ๊นŒ์ง€ ๋‹ค ๋“ค์–ด์žˆ์–ด.
๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ , ํฌ๋กœ์Šคํ”Œ๋žซํผ ๊ฐœ๋ฐœ์— ์ตœ์ ํ™”๋˜์–ด ์žˆ์–ด.

QML๊ณผ Qt Quick: ๋ชจ๋˜ UI์˜ ์„ธ๊ณ„

Qt 5๋ถ€ํ„ฐ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋„์ž…๋œ QML(Qt Modeling Language)์€ UI๋ฅผ ์„ ์–ธํ˜•์œผ๋กœ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ์‹์ด์•ผ.
JavaScript์™€ ๋น„์Šทํ•œ ๋ฌธ๋ฒ•์œผ๋กœ ์• ๋‹ˆ๋ฉ”์ด์…˜, ํŠธ๋žœ์ง€์…˜, ๋ฐ˜์‘ํ˜• UI๋ฅผ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.

// QML ์˜ˆ์‹œ - ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ์žˆ๋Š” ๋ฒ„ํŠผ
import QtQuick 2.15
import QtQuick.Controls 2.15

ApplicationWindow {
    visible: true
    width: 400
    height: 300
    title: "QML ๋ฐ๋ชจ"
    
    Rectangle {
        id: myRect
        width: 100; height: 100
        color: "#5b8fa8"
        radius: 10
        anchors.centerIn: parent
        
        // ํด๋ฆญ ์‹œ ์ƒ‰์ƒ ๋ณ€๊ฒฝ ์• ๋‹ˆ๋ฉ”์ด์…˜
        MouseArea {
            anchors.fill: parent
            onClicked: {
                colorAnimation.start()
            }
        }
        
        ColorAnimation on color {
            id: colorAnimation
            to: "#7ab87a"
            duration: 500
        }
    }
}

QML์€ ํŠนํžˆ ๋ชจ๋ฐ”์ผ ์•ฑ์ด๋‚˜ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ UI์—์„œ ๊ฐ•๋ ฅํ•œ ์„ฑ๋Šฅ์„ ๋ฐœํœ˜ํ•ด.
Qt for Android, Qt for iOS๋„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋ฐ”์ผ๊นŒ์ง€ ์ปค๋ฒ„ํ•  ์ˆ˜ ์žˆ์–ด. ์ง„์งœ ์˜ฌ์ธ์›์ด์ง€? ๐Ÿ˜ฒ


Qt ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์กฐ๋„ Qt ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ ˆ์ด์–ด ์—ฌ๋Ÿฌ๋ถ„์ด ์ž‘์„ฑํ•˜๋Š” ์ฝ”๋“œ (C++ / QML) Qt ํ”„๋ ˆ์ž„์›Œํฌ ๋ ˆ์ด์–ด Qt Core / Qt GUI / Qt Widgets / Qt Quick / Qt Network ... Qt ํ”Œ๋žซํผ ์ถ”์ƒํ™” ๋ ˆ์ด์–ด (QPA) ํ”Œ๋žซํผ๋ณ„ ์ฐจ์ด๋ฅผ ์ˆจ๊ฒจ์ฃผ๋Š” ๋งˆ๋ฒ•์˜ ๋ ˆ์ด์–ด โœจ Windows Win32 API / DirectX macOS / iOS Cocoa / Metal Linux / Android X11 / Wayland / OpenGL ๐Ÿ”‘ ํ•ต์‹ฌ ํฌ์ธํŠธ QPA ๋ ˆ์ด์–ด ๋•๋ถ„์— ๊ฐœ๋ฐœ์ž๋Š” ํ”Œ๋žซํผ๋ณ„ ์ฐจ์ด๋ฅผ ์‹ ๊ฒฝ ์“ธ ํ•„์š” ์—†์–ด! Qt๊ฐ€ ์•Œ์•„์„œ ๊ฐ OS์— ๋งž๋Š” ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ํ•ด์ค˜ ๐Ÿ˜Š

๐ŸŸข wxWidgets ์™„์ „ ํ•ด๋ถ€

wxWidgets์˜ ์—ญ์‚ฌ์™€ ์ฒ ํ•™

wxWidgets(์›๋ž˜ ์ด๋ฆ„์€ wxWindows์˜€์–ด, ๋งˆ์ดํฌ๋กœ์†Œํ”„ํŠธ์˜ ํ•ญ์˜๋กœ ์ด๋ฆ„์„ ๋ฐ”๊ฟจ๋‹ค๋Š” ์ฐ์ด ์žˆ์–ด ๐Ÿ˜‚)๋Š”
1992๋…„ Julian Smart๊ฐ€ ๋งŒ๋“  ์˜คํ”ˆ์†Œ์Šค C++ GUI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์•ผ.

wxWidgets์˜ ํ•ต์‹ฌ ์ฒ ํ•™์€ Qt์™€ ์™„์ „ํžˆ ๋‹ฌ๋ผ.
Qt๊ฐ€ "์šฐ๋ฆฌ๊ฐ€ ๋‹ค ๋งŒ๋“ค์–ด์ค„๊ฒŒ"๋ผ๋ฉด, wxWidgets๋Š” "๊ฐ OS์˜ ๋„ค์ดํ‹ฐ๋ธŒ ์œ„์ ฏ์„ ๊ทธ๋Œ€๋กœ ์จ"์•ผ.
์ด๊ฒŒ ๋ฌด์Šจ ๋ง์ด๋ƒ๋ฉด:

๐Ÿ–ฅ๏ธ Windows์—์„œ ์‹คํ–‰ํ•˜๋ฉด: Win32 ๋„ค์ดํ‹ฐ๋ธŒ ๋ฒ„ํŠผ, ๋ฉ”๋‰ด, ๋‹ค์ด์–ผ๋กœ๊ทธ ์‚ฌ์šฉ
๐ŸŽ macOS์—์„œ ์‹คํ–‰ํ•˜๋ฉด: Cocoa ๋„ค์ดํ‹ฐ๋ธŒ ์œ„์ ฏ ์‚ฌ์šฉ
๐Ÿง Linux์—์„œ ์‹คํ–‰ํ•˜๋ฉด: GTK+ ๋„ค์ดํ‹ฐ๋ธŒ ์œ„์ ฏ ์‚ฌ์šฉ

์ด ๋ฐฉ์‹์˜ ์žฅ์ ์€ ์™„๋ฒฝํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฃฉ์•คํ•„(Look & Feel)์ด์•ผ.
Windows ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋ฉด "์•„, ์ด๊ฑฐ Windows ์•ฑ์ด๋„ค"๋ผ๊ณ  ๋А๋ผ๊ณ ,
Mac ์‚ฌ์šฉ์ž๊ฐ€ ๋ณด๋ฉด "์ด๊ฑฐ ์™„์ „ Mac ์•ฑ ๊ฐ™์€๋ฐ?"๋ผ๊ณ  ๋А๋ผ๋Š” ๊ฑฐ์•ผ.
Qt๋Š” ์ž์ฒด ๋ Œ๋”๋ง ์—”์ง„์„ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Ÿฐ ์™„๋ฒฝํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋А๋‚Œ์„ ๋‚ด๊ธฐ๊ฐ€ ์–ด๋ ค์›Œ.

wxWidgets ๊ธฐ๋ณธ ๊ตฌ์กฐ

wxWidgets ์•ฑ์˜ ๊ธฐ๋ณธ ๊ตฌ์กฐ๋ฅผ ์‚ดํŽด๋ณด์ž:

// wxWidgets ๊ธฐ๋ณธ ์•ฑ ๊ตฌ์กฐ
#include <wx/wx.h>

// 1. ์•ฑ ํด๋ž˜์Šค ์ •์˜ (wxApp ์ƒ์†)
class MyApp : public wxApp {
public:
    virtual bool OnInit() override;
};

// 2. wxIMPLEMENT_APP ๋งคํฌ๋กœ๋กœ ์ง„์ž…์  ์„ค์ •
wxIMPLEMENT_APP(MyApp);

// 3. ๋ฉ”์ธ ํ”„๋ ˆ์ž„ ํด๋ž˜์Šค (wxFrame ์ƒ์†)
class MyFrame : public wxFrame {
public:
    MyFrame();
    
private:
    // ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์„ ์–ธ
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    
    // ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ” ์„ ์–ธ
    wxDECLARE_EVENT_TABLE();
};

// 4. ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ” ์ •์˜
wxBEGIN_EVENT_TABLE(MyFrame, wxFrame)
    EVT_MENU(wxID_EXIT, MyFrame::OnExit)
    EVT_BUTTON(wxID_ANY, MyFrame::OnHello)
wxEND_EVENT_TABLE()

// 5. ์•ฑ ์ดˆ๊ธฐํ™”
bool MyApp::OnInit() {
    MyFrame *frame = new MyFrame();
    frame->Show(true);
    return true;
}

// 6. ํ”„๋ ˆ์ž„ ์ƒ์„ฑ์ž
MyFrame::MyFrame()
    : wxFrame(nullptr, wxID_ANY, "wxWidgets ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ",
              wxDefaultPosition, wxSize(400, 300))
{
    // ๋ฉ”๋‰ด๋ฐ” ์ƒ์„ฑ
    wxMenuBar *menuBar = new wxMenuBar();
    wxMenu *fileMenu = new wxMenu();
    fileMenu->Append(wxID_EXIT, "์ข…๋ฃŒ\tCtrl+Q");
    menuBar->Append(fileMenu, "ํŒŒ์ผ");
    SetMenuBar(menuBar);
    
    // ํŒจ๋„๊ณผ ๋ฒ„ํŠผ ์ƒ์„ฑ
    wxPanel *panel = new wxPanel(this);
    wxButton *btn = new wxButton(panel, wxID_ANY, "์•ˆ๋…•ํ•˜์„ธ์š”!",
                                  wxPoint(150, 100));
    
    // ์ƒํƒœ๋ฐ”
    CreateStatusBar();
    SetStatusText("์ค€๋น„๋จ");
}

void MyFrame::OnHello(wxCommandEvent& event) {
    wxMessageBox("์•ˆ๋…•ํ•˜์„ธ์š”! wxWidgets ์•ฑ์ด์—์š” ๐ŸŽ‰",
                 "์ธ์‚ฌ", wxOK | wxICON_INFORMATION);
}

void MyFrame::OnExit(wxCommandEvent& event) {
    Close(true);
}

Qt์™€ ๋น„๊ตํ•˜๋ฉด ์ข€ ๋” ์ „ํ†ต์ ์ธ C++ ์Šคํƒ€์ผ์ด์ง€? ๐Ÿค”
์ด๋ฒคํŠธ ํ…Œ์ด๋ธ” ๋ฐฉ์‹์€ MFC(Microsoft Foundation Classes)๋ฅผ ์จ๋ณธ ์‚ฌ๋žŒ์ด๋ผ๋ฉด ์ต์ˆ™ํ•  ๊ฑฐ์•ผ.
๋ฌผ๋ก  wxWidgets๋„ ๋žŒ๋‹ค ํ•จ์ˆ˜๋ฅผ ์ด์šฉํ•œ ํ˜„๋Œ€์ ์ธ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ์„ ์ง€์›ํ•ด:

// ํ˜„๋Œ€์ ์ธ wxWidgets ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ (Bind ๋ฐฉ์‹)
btn->Bind(wxEVT_BUTTON, [](wxCommandEvent& event) {
    wxMessageBox("๋žŒ๋‹ค๋กœ ์ฒ˜๋ฆฌํ–ˆ์–ด์š”! ๐Ÿ˜Ž");
});

wxWidgets์˜ ๋ ˆ์ด์•„์›ƒ ์‹œ์Šคํ…œ: Sizer

wxWidgets์—์„œ UI ๋ ˆ์ด์•„์›ƒ์„ ์žก์„ ๋•Œ Sizer๋ฅผ ์‚ฌ์šฉํ•ด.
Sizer๋Š” ์œ„์ ฏ๋“ค์˜ ํฌ๊ธฐ์™€ ์œ„์น˜๋ฅผ ์ž๋™์œผ๋กœ ๊ด€๋ฆฌํ•ด์ฃผ๋Š” ์‹œ์Šคํ…œ์ด์•ผ.

// wxWidgets Sizer ์˜ˆ์ œ
wxPanel *panel = new wxPanel(this);

// ์ˆ˜์ง ๋ฐ•์Šค Sizer ์ƒ์„ฑ
wxBoxSizer *vSizer = new wxBoxSizer(wxVERTICAL);

wxStaticText *label = new wxStaticText(panel, wxID_ANY, "์ด๋ฆ„์„ ์ž…๋ ฅํ•˜์„ธ์š”:");
wxTextCtrl *textCtrl = new wxTextCtrl(panel, wxID_ANY);
wxButton *okBtn = new wxButton(panel, wxID_OK, "ํ™•์ธ");

// Sizer์— ์œ„์ ฏ ์ถ”๊ฐ€
// (์œ„์ ฏ, ๋น„์œจ, ํ”Œ๋ž˜๊ทธ, ์—ฌ๋ฐฑ)
vSizer->Add(label, 0, wxALL | wxEXPAND, 10);
vSizer->Add(textCtrl, 0, wxALL | wxEXPAND, 10);
vSizer->Add(okBtn, 0, wxALL | wxCENTER, 10);

panel->SetSizer(vSizer);
vSizer->Fit(this);  // ์ฐฝ ํฌ๊ธฐ๋ฅผ ๋‚ด์šฉ์— ๋งž๊ฒŒ ์กฐ์ •

wxWidgets์˜ ์ฃผ์š” ์œ„์ ฏ๋“ค

์œ„์ ฏ ํด๋ž˜์Šค์„ค๋ช…๋Œ€์‘ Qt ํด๋ž˜์Šค
wxButton์ผ๋ฐ˜ ๋ฒ„ํŠผQPushButton
wxTextCtrlํ…์ŠคํŠธ ์ž…๋ ฅ/ํŽธ์ง‘QLineEdit / QTextEdit
wxListBox๋ชฉ๋ก ๋ฐ•์ŠคQListWidget
wxTreeCtrlํŠธ๋ฆฌ ๋ทฐQTreeWidget
wxGrid๊ทธ๋ฆฌ๋“œ/ํ‘œQTableWidget
wxNotebookํƒญ ์ปจํŠธ๋กคQTabWidget
wxDialog๋‹ค์ด์–ผ๋กœ๊ทธ ์ฐฝQDialog
wxFileDialogํŒŒ์ผ ์„ ํƒ ๋Œ€ํ™”์ƒ์žQFileDialog
wxSlider์Šฌ๋ผ์ด๋”QSlider
wxGauge์ง„ํ–‰ ํ‘œ์‹œ์ค„QProgressBar

wxWidgets ๋นŒ๋“œ ์„ค์ •

wxWidgets๋Š” CMake๋ฅผ ํ†ตํ•ด ์‰ฝ๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด:

# wxWidgets CMakeLists.txt ์˜ˆ์‹œ
cmake_minimum_required(VERSION 3.16)
project(MyWxApp)

set(CMAKE_CXX_STANDARD 17)

# wxWidgets ์ฐพ๊ธฐ
find_package(wxWidgets REQUIRED COMPONENTS core base)
include(${wxWidgets_USE_FILE})

add_executable(MyWxApp WIN32
    main.cpp
    myframe.cpp
    myframe.h
)

target_link_libraries(MyWxApp ${wxWidgets_LIBRARIES})
โœ… ํŒ: Windows์—์„œ wxWidgets๋ฅผ ๋นŒ๋“œํ•  ๋•Œ vcpkg๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ํ›จ์”ฌ ํŽธํ•ด!
vcpkg install wxwidgets ๋ช…๋ น์–ด ํ•˜๋‚˜๋กœ ์„ค์น˜ ์™„๋ฃŒ!

Qt vs wxWidgets ๋ Œ๋”๋ง ๋ฐฉ์‹ ๋น„๊ต Qt ๋ฐฉ์‹ Qt ์ž์ฒด ๋ Œ๋”๋ง ์—”์ง„ (OpenGL / Vulkan / Metal ๊ธฐ๋ฐ˜) ๋ชจ๋“  ํ”Œ๋žซํผ์—์„œ ๋™์ผํ•œ UI ํ”ฝ์…€ ๋‹จ์œ„๋กœ ์™„๋ฒฝํžˆ ๋™์ผ โœ… ์žฅ์ : ์ผ๊ด€๋œ ๋””์ž์ธ โŒ ๋‹จ์ : ๋„ค์ดํ‹ฐ๋ธŒ ๋А๋‚Œ ๋ถ€์กฑ ๐ŸŽจ ์ปค์Šคํ…€ ์Šคํƒ€์ผ๋ง ์ž์œ ๋„ ๋†’์Œ QSS(Qt Style Sheets)๋กœ CSS์ฒ˜๋Ÿผ! wxWidgets ๋ฐฉ์‹ OS ๋„ค์ดํ‹ฐ๋ธŒ ์œ„์ ฏ ์ง์ ‘ ์‚ฌ์šฉ (Win32 / Cocoa / GTK+) ๊ฐ OS์—์„œ ๋„ค์ดํ‹ฐ๋ธŒ UI ํ‘œ์‹œ OS ์—…๋ฐ์ดํŠธ ์ž๋™ ๋ฐ˜์˜ โœ… ์žฅ์ : ์™„๋ฒฝํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋А๋‚Œ โŒ ๋‹จ์ : ํ”Œ๋žซํผ๋ณ„ UI ์ฐจ์ด ์กด์žฌ ๐Ÿ”ง OS ์ ‘๊ทผ์„ฑ ๊ธฐ๋Šฅ ์ž๋™ ์ง€์› ์Šคํฌ๋ฆฐ๋ฆฌ๋”, ๊ณ ๋Œ€๋น„ ๋ชจ๋“œ ๋“ฑ

โš”๏ธ Qt vs wxWidgets: ์ง„์งœ ๋น„๊ต

์ž, ์ด์ œ ๋‘ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๋Œ€๋กœ ๋น„๊ตํ•ด๋ณผ ์‹œ๊ฐ„์ด์•ผ.
์–ด๋А ๊ฒŒ ๋” ์ข‹๋‹ค๊ณ  ๋‹จ์ • ์ง“๊ธฐ๋ณด๋‹ค๋Š”, ์–ด๋–ค ์ƒํ™ฉ์—์„œ ์–ด๋–ค ๊ฑธ ์จ์•ผ ํ•˜๋Š”์ง€๋ฅผ ์•Œ์•„๋ณด์ž.

๋ผ์ด์„ ์Šค ๋น„๊ต

๐Ÿ”ต Qt ๋ผ์ด์„ ์Šค

LGPL v3 GPL v3 ์ƒ์—…์šฉ ๋ผ์ด์„ ์Šค

์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ: LGPL/GPL ๋ฌด๋ฃŒ
์ƒ์—…์šฉ ์•ฑ: Qt Company ์ƒ์—… ๋ผ์ด์„ ์Šค ํ•„์š”
(์—ฐ๊ฐ„ ์ˆ˜๋ฐฑ๋งŒ ์› ์ˆ˜์ค€)

โš ๏ธ ์ƒ์—…์šฉ์œผ๋กœ ์“ธ ๋•Œ ๋ผ์ด์„ ์Šค ๋น„์šฉ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์–ด!
๐ŸŸข wxWidgets ๋ผ์ด์„ ์Šค

wxWindows ๋ผ์ด์„ ์Šค

LGPL ๊ธฐ๋ฐ˜์ด์ง€๋งŒ ๋” ๊ด€๋Œ€ํ•ด.
์ƒ์—…์šฉ ์•ฑ์—๋„ ๋ฌด๋ฃŒ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅ!
์†Œ์Šค ์ฝ”๋“œ ๊ณต๊ฐœ ์˜๋ฌด ์—†์Œ.

โœ… ์™„์ „ ๋ฌด๋ฃŒ๋กœ ์ƒ์—…์šฉ ์•ฑ ๊ฐœ๋ฐœ ๊ฐ€๋Šฅ!
โš ๏ธ ์ค‘์š”! Qt์˜ LGPL ๋ผ์ด์„ ์Šค๋Š” ๋™์  ๋งํ‚น(Dynamic Linking)์„ ์‚ฌ์šฉํ•˜๋ฉด ์ƒ์—…์šฉ ์•ฑ์—์„œ๋„ ๋ฌด๋ฃŒ๋กœ ์“ธ ์ˆ˜ ์žˆ์–ด.
ํ•˜์ง€๋งŒ Qt์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ(ํŠนํžˆ Qt Quick/QML ์ผ๋ถ€)์„ ์“ฐ๋ ค๋ฉด ์ƒ์—… ๋ผ์ด์„ ์Šค๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ์œผ๋‹ˆ ๊ผญ ํ™•์ธํ•ด๋ด!

์„ฑ๋Šฅ ๋น„๊ต

์„ฑ๋Šฅ ๋ฉด์—์„œ๋Š” ์–ด๋–จ๊นŒ? ์†”์งํ•˜๊ฒŒ ์–˜๊ธฐํ•ด์ค„๊ฒŒ:

๐Ÿš€ ์‹œ์ž‘ ์‹œ๊ฐ„(Startup Time):
wxWidgets๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ๋น ๋ฅธ ํŽธ์ด์•ผ. Qt๋Š” ์ž์ฒด ๋Ÿฐํƒ€์ž„์„ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ์‹œ๊ฐ„์ด ํ•„์š”ํ•˜๊ฑฐ๋“ .
์ž‘์€ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์•ฑ์ด๋ผ๋ฉด wxWidgets๊ฐ€ ๋” ๊ฐ€๋ณ๊ฒŒ ๋А๊ปด์ ธ.

๐Ÿ’พ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰:
wxWidgets๊ฐ€ ๋” ์ ์€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด. Qt๋Š” ๋ชจ๋“ˆ์ด ๋งŽ์•„์„œ ๊ธฐ๋ณธ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ๋†’์•„.

๐ŸŽจ ๋ Œ๋”๋ง ์„ฑ๋Šฅ:
๋ณต์žกํ•œ ์ปค์Šคํ…€ ๊ทธ๋ž˜ํ”ฝ์ด๋‚˜ ์• ๋‹ˆ๋ฉ”์ด์…˜์—์„œ๋Š” Qt๊ฐ€ ์••๋„์ ์ด์•ผ.
Qt์˜ ํ•˜๋“œ์›จ์–ด ๊ฐ€์† ๋ Œ๋”๋ง ํŒŒ์ดํ”„๋ผ์ธ์€ ์ •๋ง ๊ฐ•๋ ฅํ•ด.

๐Ÿ“ฆ ๋ฐฐํฌ ํŒŒ์ผ ํฌ๊ธฐ:
wxWidgets ์•ฑ์ด ์ผ๋ฐ˜์ ์œผ๋กœ ๋” ์ž‘์•„. Qt๋Š” ํ•„์š”ํ•œ DLL/๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋งŽ์•„์„œ ๋ฐฐํฌ ํŒจํ‚ค์ง€๊ฐ€ ์ปค์งˆ ์ˆ˜ ์žˆ์–ด.

ํ•™์Šต ๊ณก์„  ๋น„๊ต

๐Ÿ”ต Qt ํ•™์Šต ๊ณก์„ 

์ดˆ๋ฐ˜์— Signal/Slot, MOC, Q_OBJECT ๊ฐ™์€
Qt ๊ณ ์œ  ๊ฐœ๋…์„ ์ตํ˜€์•ผ ํ•ด.
ํ•˜์ง€๋งŒ ๊ณต์‹ ๋ฌธ์„œ๊ฐ€ ์ •๋ง ์ž˜ ๋˜์–ด ์žˆ๊ณ ,
Qt Creator๊ฐ€ ๋งŽ์€ ๊ฑธ ์ž๋™ํ™”ํ•ด์ค˜.

๐Ÿ“š ํ•™์Šต ์ž๋ฃŒ: ๋งค์šฐ ํ’๋ถ€
๐ŸŒ ์ปค๋ฎค๋‹ˆํ‹ฐ: ๋งค์šฐ ํ™œ๋ฐœ
๐ŸŸข wxWidgets ํ•™์Šต ๊ณก์„ 

์ „ํ†ต์ ์ธ C++ ์Šคํƒ€์ผ์— ๊ฐ€๊นŒ์›Œ์„œ
MFC ๊ฒฝํ—˜์ž๋ผ๋ฉด ๋น ๋ฅด๊ฒŒ ์ ์‘ ๊ฐ€๋Šฅ.
ํ•˜์ง€๋งŒ ๊ณต์‹ ๋ฌธ์„œ๊ฐ€ Qt๋ณด๋‹ค ๋œ ์นœ์ ˆํ•˜๊ณ ,
์˜ˆ์ œ ์ฝ”๋“œ๋„ ์ƒ๋Œ€์ ์œผ๋กœ ์ ์–ด.

๐Ÿ“š ํ•™์Šต ์ž๋ฃŒ: ๋ณดํ†ต
๐ŸŒ ์ปค๋ฎค๋‹ˆํ‹ฐ: ํ™œ๋ฐœํ•˜์ง€๋งŒ Qt๋ณด๋‹ค ์ž‘์Œ

์‹ค์ œ ์‚ฌ์šฉ ์‚ฌ๋ก€

์–ด๋–ค ์œ ๋ช…ํ•œ ์•ฑ๋“ค์ด ์ด ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์“ฐ๋Š”์ง€ ์•Œ๋ฉด ์‹ ๋ขฐ๊ฐ€ ์ƒ๊ธฐ์ง€? ๐Ÿ˜„

ํ”„๋ ˆ์ž„์›Œํฌ์œ ๋ช… ์‚ฌ์šฉ ์‚ฌ๋ก€
QtVLC ๋ฏธ๋””์–ด ํ”Œ๋ ˆ์ด์–ด, Autodesk Maya, KDE ๋ฐ์Šคํฌํƒ‘, Telegram Desktop, Qt Creator ์ž์ฒด, Wireshark(์ผ๋ถ€), ๋‹ค์ˆ˜์˜ ์ž๋™์ฐจ ์ธํฌํ…Œ์ธ๋จผํŠธ ์‹œ์Šคํ…œ
wxWidgetsAudacity(์˜ค๋””์˜ค ํŽธ์ง‘๊ธฐ), FileZilla(FTP ํด๋ผ์ด์–ธํŠธ), Code::Blocks(IDE), BitTorrent ํด๋ผ์ด์–ธํŠธ๋“ค, ๊ตฌ๋ฒ„์ „ Tortoise SVN

Audacity ์จ๋ดค์–ด? ๊ทธ ์œ ๋ช…ํ•œ ๋ฌด๋ฃŒ ์˜ค๋””์˜ค ํŽธ์ง‘๊ธฐ๊ฐ€ wxWidgets๋กœ ๋งŒ๋“ค์–ด์ง„ ๊ฑฐ์•ผ! ๐ŸŽต
FileZilla๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๊ณ . ์ด ์ •๋„๋ฉด wxWidgets์˜ ์‹ค๋ ฅ์ด ์ฆ๋ช…๋œ ๊ฑฐ์ง€.


๐Ÿ› ๏ธ ์‹ค์ „ ํ”„๋กœ์ ํŠธ: ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์—๋””ํ„ฐ ๋งŒ๋“ค๊ธฐ

์ด๋ก ๋งŒ ๋ฐฐ์šฐ๋ฉด ์žฌ๋ฏธ์—†์ž–์•„! ์‹ค์ œ๋กœ ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์—๋””ํ„ฐ๋ฅผ ๋‘ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ๋งŒ๋“ค์–ด๋ณด๋ฉด์„œ ์ฐจ์ด๋ฅผ ๋А๊ปด๋ณด์ž. ๐Ÿ“

Qt๋กœ ๋งŒ๋“œ๋Š” ํ…์ŠคํŠธ ์—๋””ํ„ฐ

// mainwindow.h
#pragma once
#include <QMainWindow>
#include <QTextEdit>
#include <QMenuBar>
#include <QFileDialog>
#include <QMessageBox>
#include <QFile>
#include <QTextStream>

class MainWindow : public QMainWindow {
    Q_OBJECT
    
public:
    MainWindow(QWidget *parent = nullptr);
    
private slots:
    void newFile();
    void openFile();
    void saveFile();
    void about();
    
private:
    QTextEdit *textEdit;
    QString currentFile;
    
    void createMenus();
    void setCurrentFile(const QString &fileName);
};

// mainwindow.cpp
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    // ์ค‘์•™ ์œ„์ ฏ์œผ๋กœ ํ…์ŠคํŠธ ์—๋””ํ„ฐ ์„ค์ •
    textEdit = new QTextEdit(this);
    setCentralWidget(textEdit);
    
    // ํฐํŠธ ์„ค์ •
    QFont font("Consolas", 11);
    textEdit->setFont(font);
    
    createMenus();
    setWindowTitle("Qt ํ…์ŠคํŠธ ์—๋””ํ„ฐ โœ๏ธ");
    resize(800, 600);
}

void MainWindow::createMenus() {
    // ํŒŒ์ผ ๋ฉ”๋‰ด
    QMenu *fileMenu = menuBar()->addMenu("ํŒŒ์ผ(&F)");
    
    fileMenu->addAction("์ƒˆ ํŒŒ์ผ(&N)", this, &MainWindow::newFile,
                        QKeySequence::New);
    fileMenu->addAction("์—ด๊ธฐ(&O)...", this, &MainWindow::openFile,
                        QKeySequence::Open);
    fileMenu->addAction("์ €์žฅ(&S)", this, &MainWindow::saveFile,
                        QKeySequence::Save);
    fileMenu->addSeparator();
    fileMenu->addAction("์ข…๋ฃŒ(&Q)", this, &QWidget::close,
                        QKeySequence::Quit);
    
    // ๋„์›€๋ง ๋ฉ”๋‰ด
    QMenu *helpMenu = menuBar()->addMenu("๋„์›€๋ง(&H)");
    helpMenu->addAction("์ •๋ณด(&A)", this, &MainWindow::about);
}

void MainWindow::newFile() {
    if (textEdit->document()->isModified()) {
        auto reply = QMessageBox::question(this, "์ €์žฅ",
            "๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์‹œ๊ฒ ์–ด์š”?",
            QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
        if (reply == QMessageBox::Cancel) return;
        if (reply == QMessageBox::Yes) saveFile();
    }
    textEdit->clear();
    setCurrentFile("");
}

void MainWindow::openFile() {
    QString fileName = QFileDialog::getOpenFileName(this,
        "ํŒŒ์ผ ์—ด๊ธฐ", "", "ํ…์ŠคํŠธ ํŒŒ์ผ (*.txt);;๋ชจ๋“  ํŒŒ์ผ (*)");
    
    if (fileName.isEmpty()) return;
    
    QFile file(fileName);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QMessageBox::warning(this, "์˜ค๋ฅ˜", "ํŒŒ์ผ์„ ์—ด ์ˆ˜ ์—†์–ด์š”!");
        return;
    }
    
    QTextStream in(&file);
    in.setEncoding(QStringConverter::Utf8);
    textEdit->setPlainText(in.readAll());
    setCurrentFile(fileName);
}

void MainWindow::saveFile() {
    if (currentFile.isEmpty()) {
        currentFile = QFileDialog::getSaveFileName(this,
            "ํŒŒ์ผ ์ €์žฅ", "", "ํ…์ŠคํŠธ ํŒŒ์ผ (*.txt)");
        if (currentFile.isEmpty()) return;
    }
    
    QFile file(currentFile);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QMessageBox::warning(this, "์˜ค๋ฅ˜", "ํŒŒ์ผ์„ ์ €์žฅํ•  ์ˆ˜ ์—†์–ด์š”!");
        return;
    }
    
    QTextStream out(&file);
    out.setEncoding(QStringConverter::Utf8);
    out << textEdit->toPlainText();
    setCurrentFile(currentFile);
}

void MainWindow::setCurrentFile(const QString &fileName) {
    currentFile = fileName;
    textEdit->document()->setModified(false);
    
    QString title = fileName.isEmpty() ? "์ƒˆ ํŒŒ์ผ" : 
                    QFileInfo(fileName).fileName();
    setWindowTitle(title + " - Qt ํ…์ŠคํŠธ ์—๋””ํ„ฐ");
}

void MainWindow::about() {
    QMessageBox::about(this, "์ •๋ณด",
        "Qt๋กœ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์—๋””ํ„ฐ\n"
        "ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๊ฐœ๋ฐœ ์˜ˆ์ œ ๐Ÿ˜Š");
}

wxWidgets๋กœ ๋งŒ๋“œ๋Š” ํ…์ŠคํŠธ ์—๋””ํ„ฐ

// wxTextEditor.h
#pragma once
#include <wx/wx.h>
#include <wx/textctrl.h>
#include <wx/filedlg.h>

enum {
    ID_NEW = wxID_HIGHEST + 1,
    ID_OPEN,
    ID_SAVE,
    ID_ABOUT
};

class TextEditorFrame : public wxFrame {
public:
    TextEditorFrame();
    
private:
    wxTextCtrl *textCtrl;
    wxString currentFile;
    
    void OnNew(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnClose(wxCloseEvent& event);
    
    wxDECLARE_EVENT_TABLE();
};

// wxTextEditor.cpp
#include "wxTextEditor.h"

wxBEGIN_EVENT_TABLE(TextEditorFrame, wxFrame)
    EVT_MENU(ID_NEW, TextEditorFrame::OnNew)
    EVT_MENU(ID_OPEN, TextEditorFrame::OnOpen)
    EVT_MENU(ID_SAVE, TextEditorFrame::OnSave)
    EVT_MENU(ID_ABOUT, TextEditorFrame::OnAbout)
    EVT_MENU(wxID_EXIT, TextEditorFrame::OnExit)
    EVT_CLOSE(TextEditorFrame::OnClose)
wxEND_EVENT_TABLE()

TextEditorFrame::TextEditorFrame()
    : wxFrame(nullptr, wxID_ANY, "wxWidgets ํ…์ŠคํŠธ ์—๋””ํ„ฐ",
              wxDefaultPosition, wxSize(800, 600))
{
    // ํ…์ŠคํŠธ ์ปจํŠธ๋กค ์ƒ์„ฑ (๋ฉ€ํ‹ฐ๋ผ์ธ, ์Šคํฌ๋กค๋ฐ” ํฌํ•จ)
    textCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString,
                               wxDefaultPosition, wxDefaultSize,
                               wxTE_MULTILINE | wxTE_RICH2);
    
    // ํฐํŠธ ์„ค์ •
    wxFont font(11, wxFONTFAMILY_TELETYPE, wxFONTSTYLE_NORMAL,
                wxFONTWEIGHT_NORMAL);
    textCtrl->SetFont(font);
    
    // ๋ฉ”๋‰ด๋ฐ” ์ƒ์„ฑ
    wxMenuBar *menuBar = new wxMenuBar();
    
    wxMenu *fileMenu = new wxMenu();
    fileMenu->Append(ID_NEW, "์ƒˆ ํŒŒ์ผ(&N)\tCtrl+N");
    fileMenu->Append(ID_OPEN, "์—ด๊ธฐ(&O)...\tCtrl+O");
    fileMenu->Append(ID_SAVE, "์ €์žฅ(&S)\tCtrl+S");
    fileMenu->AppendSeparator();
    fileMenu->Append(wxID_EXIT, "์ข…๋ฃŒ(&Q)\tCtrl+Q");
    
    wxMenu *helpMenu = new wxMenu();
    helpMenu->Append(ID_ABOUT, "์ •๋ณด(&A)");
    
    menuBar->Append(fileMenu, "ํŒŒ์ผ(&F)");
    menuBar->Append(helpMenu, "๋„์›€๋ง(&H)");
    SetMenuBar(menuBar);
    
    // ์ƒํƒœ๋ฐ”
    CreateStatusBar();
    SetStatusText("์ค€๋น„๋จ");
}

void TextEditorFrame::OnNew(wxCommandEvent& event) {
    if (textCtrl->IsModified()) {
        int result = wxMessageBox("๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์‹œ๊ฒ ์–ด์š”?",
                                   "์ €์žฅ",
                                   wxYES_NO | wxCANCEL | wxICON_QUESTION);
        if (result == wxCANCEL) return;
        if (result == wxYES) OnSave(event);
    }
    textCtrl->Clear();
    currentFile.clear();
    SetTitle("์ƒˆ ํŒŒ์ผ - wxWidgets ํ…์ŠคํŠธ ์—๋””ํ„ฐ");
}

void TextEditorFrame::OnOpen(wxCommandEvent& event) {
    wxFileDialog openDialog(this, "ํŒŒ์ผ ์—ด๊ธฐ", "", "",
                             "ํ…์ŠคํŠธ ํŒŒ์ผ (*.txt)|*.txt|๋ชจ๋“  ํŒŒ์ผ (*.*)|*.*",
                             wxFD_OPEN | wxFD_FILE_MUST_EXIST);
    
    if (openDialog.ShowModal() == wxID_CANCEL) return;
    
    currentFile = openDialog.GetPath();
    textCtrl->LoadFile(currentFile);
    SetTitle(openDialog.GetFilename() + " - wxWidgets ํ…์ŠคํŠธ ์—๋””ํ„ฐ");
    SetStatusText("ํŒŒ์ผ ์—ด๋ฆผ: " + currentFile);
}

void TextEditorFrame::OnSave(wxCommandEvent& event) {
    if (currentFile.empty()) {
        wxFileDialog saveDialog(this, "ํŒŒ์ผ ์ €์žฅ", "", "",
                                 "ํ…์ŠคํŠธ ํŒŒ์ผ (*.txt)|*.txt",
                                 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
        if (saveDialog.ShowModal() == wxID_CANCEL) return;
        currentFile = saveDialog.GetPath();
    }
    
    textCtrl->SaveFile(currentFile);
    SetStatusText("์ €์žฅ๋จ: " + currentFile);
}

void TextEditorFrame::OnAbout(wxCommandEvent& event) {
    wxMessageBox("wxWidgets๋กœ ๋งŒ๋“  ๊ฐ„๋‹จํ•œ ํ…์ŠคํŠธ ์—๋””ํ„ฐ\n"
                 "ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๊ฐœ๋ฐœ ์˜ˆ์ œ ๐Ÿ˜Š",
                 "์ •๋ณด", wxOK | wxICON_INFORMATION);
}

void TextEditorFrame::OnExit(wxCommandEvent& event) {
    Close(true);
}

void TextEditorFrame::OnClose(wxCloseEvent& event) {
    if (textCtrl->IsModified()) {
        int result = wxMessageBox("๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์ €์žฅํ•˜์‹œ๊ฒ ์–ด์š”?",
                                   "์ข…๋ฃŒ",
                                   wxYES_NO | wxCANCEL | wxICON_QUESTION);
        if (result == wxCANCEL) { event.Veto(); return; }
        if (result == wxYES) {
            wxCommandEvent dummy;
            OnSave(dummy);
        }
    }
    event.Skip();
}

๋‘ ์ฝ”๋“œ๋ฅผ ๋น„๊ตํ•ด๋ณด๋ฉด ์–ด๋•Œ? ๐Ÿค”
Qt๋Š” ๋žŒ๋‹ค์™€ ํ˜„๋Œ€์ ์ธ C++ ์Šคํƒ€์ผ์„ ๋” ๋งŽ์ด ํ™œ์šฉํ•˜๊ณ ,
wxWidgets๋Š” ์ด๋ฒคํŠธ ํ…Œ์ด๋ธ”๊ณผ ์ „ํ†ต์ ์ธ C++ ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•ด.
๊ธฐ๋Šฅ์ ์œผ๋กœ๋Š” ๊ฑฐ์˜ ๋™์ผํ•˜์ง€๋งŒ ์ฝ”๋”ฉ ์Šคํƒ€์ผ์ด ๊ฝค ๋‹ค๋ฅด์ง€?


๐ŸŽจ ์Šคํƒ€์ผ๋ง๊ณผ ํ…Œ๋งˆ ์ ์šฉ

Qt Style Sheets (QSS)

Qt์˜ ๊ฐ€์žฅ ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๋ฐ”๋กœ Qt Style Sheets(QSS)์•ผ.
CSS์™€ ๊ฑฐ์˜ ๋™์ผํ•œ ๋ฌธ๋ฒ•์œผ๋กœ Qt ์œ„์ ฏ์˜ ์™ธ๊ด€์„ ์™„์ „ํžˆ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์–ด!

// QSS ์ ์šฉ ์˜ˆ์‹œ
QApplication app(argc, argv);

// ์ „์ฒด ์•ฑ์— ์Šคํƒ€์ผ ์ ์šฉ
app.setStyleSheet(R"(
    QMainWindow {
        background-color: #2b2b2b;
    }
    
    QPushButton {
        background-color: #5b8fa8;
        color: white;
        border: none;
        border-radius: 6px;
        padding: 8px 16px;
        font-size: 14px;
        font-weight: bold;
    }
    
    QPushButton:hover {
        background-color: #3d7a96;
    }
    
    QPushButton:pressed {
        background-color: #2c5f7a;
    }
    
    QTextEdit {
        background-color: #1e1e1e;
        color: #d4d4d4;
        border: 1px solid #3d3d3d;
        border-radius: 4px;
        font-family: 'Consolas', monospace;
        font-size: 12px;
    }
    
    QMenuBar {
        background-color: #2b2b2b;
        color: #cccccc;
    }
    
    QMenuBar::item:selected {
        background-color: #5b8fa8;
    }
)");

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋‹คํฌ ํ…Œ๋งˆ ์•ฑ์„ ๋š๋”ฑ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด! ๐ŸŒ™
QSS๋Š” CSS์™€ ๊ฑฐ์˜ ๊ฐ™์•„์„œ ์›น ๊ฐœ๋ฐœ ๊ฒฝํ—˜์ด ์žˆ์œผ๋ฉด ๊ธˆ๋ฐฉ ์ตํž ์ˆ˜ ์žˆ์–ด.

wxWidgets ํ…Œ๋งˆ

wxWidgets๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ์œ„์ ฏ์„ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์— OS ํ…Œ๋งˆ๋ฅผ ์ž๋™์œผ๋กœ ๋”ฐ๋ผ๊ฐ€.
Windows 11์—์„œ ์‹คํ–‰ํ•˜๋ฉด Windows 11 ์Šคํƒ€์ผ, macOS์—์„œ ์‹คํ–‰ํ•˜๋ฉด macOS ์Šคํƒ€์ผ์ด ์ž๋™ ์ ์šฉ๋ผ.
์ปค์Šคํ…€ ์Šคํƒ€์ผ๋ง์€ Qt๋ณด๋‹ค ์ œํ•œ์ ์ด์ง€๋งŒ, ๋Œ€์‹  OS ์ ‘๊ทผ์„ฑ ๊ธฐ๋Šฅ(๊ณ ๋Œ€๋น„ ๋ชจ๋“œ, ์Šคํฌ๋ฆฐ๋ฆฌ๋” ๋“ฑ)์ด ์ž๋™์œผ๋กœ ์ง€์›๋ผ.

โœ… ํŒ: wxWidgets์—์„œ ์ปค์Šคํ…€ ๊ทธ๋ฆฌ๊ธฐ๊ฐ€ ํ•„์š”ํ•˜๋ฉด wxDC(Device Context)๋ฅผ ์‚ฌ์šฉํ•ด.
OnPaint ์ด๋ฒคํŠธ์—์„œ ์ง์ ‘ ๊ทธ๋ž˜ํ”ฝ์„ ๊ทธ๋ฆด ์ˆ˜ ์žˆ์–ด. Qt์˜ QPainter์™€ ๋น„์Šทํ•œ ๊ฐœ๋…์ด์•ผ.

๐Ÿ“ฆ ๋ฐฐํฌ์™€ ํŒจํ‚ค์ง•

์•ฑ์„ ๋งŒ๋“ค์—ˆ์œผ๋ฉด ๋ฐฐํฌํ•ด์•ผ์ง€! ํฌ๋กœ์Šคํ”Œ๋žซํผ ์•ฑ ๋ฐฐํฌ๋Š” ์ƒ๊ฐ๋ณด๋‹ค ์‹ ๊ฒฝ ์“ธ ๊ฒŒ ๋งŽ์•„. ๐Ÿ˜…

Qt ์•ฑ ๋ฐฐํฌ

Qt๋Š” windeployqt, macdeployqt, linuxdeployqt ๊ฐ™์€ ๋ฐฐํฌ ๋„๊ตฌ๋ฅผ ์ œ๊ณตํ•ด:

# Windows ๋ฐฐํฌ (ํ•„์š”ํ•œ Qt DLL ์ž๋™ ๋ณต์‚ฌ)
windeployqt.exe MyApp.exe

# macOS ๋ฐฐํฌ (์•ฑ ๋ฒˆ๋“ค ์ƒ์„ฑ)
macdeployqt MyApp.app -dmg

# Linux (AppImage ์ƒ์„ฑ - linuxdeployqt ์‚ฌ์šฉ)
linuxdeployqt MyApp -appimage
๐Ÿ“ฆ Qt ๋ฐฐํฌ ์‹œ ํฌํ•จ๋˜๋Š” ํŒŒ์ผ๋“ค:
Qt6Core.dll, Qt6Gui.dll, Qt6Widgets.dll (๊ธฐ๋ณธ ๋ชจ๋“ˆ)
platforms/ ํด๋” (ํ”Œ๋žซํผ ํ”Œ๋Ÿฌ๊ทธ์ธ)
styles/ ํด๋” (์Šคํƒ€์ผ ํ”Œ๋Ÿฌ๊ทธ์ธ)
imageformats/ ํด๋” (์ด๋ฏธ์ง€ ํฌ๋งท ํ”Œ๋Ÿฌ๊ทธ์ธ)

์ „์ฒด ๋ฐฐํฌ ํŒจํ‚ค์ง€๊ฐ€ 20~50MB ์ •๋„ ๋  ์ˆ˜ ์žˆ์–ด.

wxWidgets ์•ฑ ๋ฐฐํฌ

wxWidgets๋Š” ์ •์  ๋งํ‚น(Static Linking)์„ ์‚ฌ์šฉํ•˜๋ฉด ๋‹จ์ผ ์‹คํ–‰ ํŒŒ์ผ๋กœ ๋ฐฐํฌํ•  ์ˆ˜ ์žˆ์–ด!
์ด๊ฒŒ wxWidgets์˜ ํฐ ์žฅ์  ์ค‘ ํ•˜๋‚˜์•ผ:

# CMake์—์„œ wxWidgets ์ •์  ๋งํ‚น ์„ค์ •
set(wxBUILD_SHARED OFF)  # ์ •์  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์‚ฌ์šฉ

find_package(wxWidgets REQUIRED COMPONENTS core base)

# ๊ฒฐ๊ณผ: ๋‹จ์ผ ์‹คํ–‰ ํŒŒ์ผ (Windows์—์„œ ์•ฝ 5~15MB)
โœ… ํŒ: wxWidgets ์ •์  ๋งํ‚น ์•ฑ์€ ์ถ”๊ฐ€ DLL ์—†์ด ๋‹จ์ผ .exe ํŒŒ์ผ๋งŒ์œผ๋กœ ๋ฐฐํฌ ๊ฐ€๋Šฅํ•ด!
USB์— ๋‹ด์•„์„œ ๋ฐ”๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ํฌํ„ฐ๋ธ” ์•ฑ ๋งŒ๋“ค๊ธฐ์— ์ตœ์ ์ด์•ผ.

ํฌ๋กœ์Šค ์ปดํŒŒ์ผ

Linux์—์„œ Windows ์•ฑ์„ ๋นŒ๋“œํ•˜๊ฑฐ๋‚˜, ๋ฐ˜๋Œ€๋กœ ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ์„ ์‚ฌ์šฉํ•ด.
Qt๋Š” ํฌ๋กœ์Šค ์ปดํŒŒ์ผ ์ง€์›์ด ์ž˜ ๋˜์–ด ์žˆ์–ด์„œ ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ ๊ฐœ๋ฐœ์— ๋งŽ์ด ์“ฐ์—ฌ.

# Linux์—์„œ Windows์šฉ Qt ์•ฑ ํฌ๋กœ์Šค ์ปดํŒŒ์ผ (MXE ์‚ฌ์šฉ)
# MXE(M cross environment) ์„ค์น˜ ํ›„:
i686-w64-mingw32.static-cmake ..
make

# ๊ฒฐ๊ณผ: Windows์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ .exe ํŒŒ์ผ ์ƒ์„ฑ!

๐Ÿ”ง ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ๋“ค

Qt์˜ ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ

GUI ์•ฑ์—์„œ ๋ฌด๊ฑฐ์šด ์ž‘์—…์„ ํ•  ๋•Œ UI๊ฐ€ ๋ฉˆ์ถ”๋ฉด ์•ˆ ๋˜์ž–์•„?
Qt๋Š” ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ์„ ์šฐ์•„ํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์–ด:

// Qt ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ์˜ˆ์ œ (QThread + Signal/Slot)
#include <QThread>
#include <QProgressBar>

class WorkerThread : public QThread {
    Q_OBJECT
    
signals:
    void progressUpdated(int value);
    void workFinished(const QString &result);
    
protected:
    void run() override {
        // ๋ฌด๊ฑฐ์šด ์ž‘์—… (UI ์Šค๋ ˆ๋“œ์™€ ๋ณ„๊ฐœ๋กœ ์‹คํ–‰)
        for (int i = 0; i <= 100; i++) {
            QThread::msleep(50);  // ์ž‘์—… ์‹œ๋ฎฌ๋ ˆ์ด์…˜
            emit progressUpdated(i);  // UI ์Šค๋ ˆ๋“œ์— ์ง„ํ–‰๋ฅ  ์ „๋‹ฌ
        }
        emit workFinished("์ž‘์—… ์™„๋ฃŒ! ๐ŸŽ‰");
    }
};

// ๋ฉ”์ธ ์œˆ๋„์šฐ์—์„œ ์‚ฌ์šฉ
WorkerThread *worker = new WorkerThread();
connect(worker, &WorkerThread::progressUpdated,
        progressBar, &QProgressBar::setValue);
connect(worker, &WorkerThread::workFinished,
        [](const QString &msg) {
            QMessageBox::information(nullptr, "์™„๋ฃŒ", msg);
        });
worker->start();  // ๋ฐฑ๊ทธ๋ผ์šด๋“œ ์Šค๋ ˆ๋“œ ์‹œ์ž‘

Qt์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™

// Qt SQL ์˜ˆ์ œ (SQLite ์‚ฌ์šฉ)
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>

// ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๊ฒฐ
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("myapp.db");

if (!db.open()) {
    qDebug() << "DB ์—ฐ๊ฒฐ ์‹คํŒจ:" << db.lastError().text();
    return;
}

// ํ…Œ์ด๋ธ” ์ƒ์„ฑ
QSqlQuery query;
query.exec("CREATE TABLE IF NOT EXISTS users ("
           "id INTEGER PRIMARY KEY AUTOINCREMENT,"
           "name TEXT NOT NULL,"
           "email TEXT UNIQUE)");

// ๋ฐ์ดํ„ฐ ์‚ฝ์ž…
query.prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
query.bindValue(":name", "ํ™๊ธธ๋™");
query.bindValue(":email", "hong@example.com");
query.exec();

// ๋ฐ์ดํ„ฐ ์กฐํšŒ
query.exec("SELECT * FROM users");
while (query.next()) {
    qDebug() << query.value("id").toInt()
             << query.value("name").toString()
             << query.value("email").toString();
}

Qt์˜ ๋„คํŠธ์›Œํฌ ํ†ต์‹ 

// Qt Network ์˜ˆ์ œ (HTTP GET ์š”์ฒญ)
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QJsonDocument>

QNetworkAccessManager *manager = new QNetworkAccessManager(this);

QNetworkRequest request(QUrl("https://api.example.com/data"));
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");

QNetworkReply *reply = manager->get(request);

connect(reply, &QNetworkReply::finished, [reply]() {
    if (reply->error() == QNetworkReply::NoError) {
        QByteArray data = reply->readAll();
        QJsonDocument doc = QJsonDocument::fromJson(data);
        
        // JSON ํŒŒ์‹ฑ
        QJsonObject obj = doc.object();
        qDebug() << "์‘๋‹ต:" << obj["message"].toString();
    } else {
        qDebug() << "์˜ค๋ฅ˜:" << reply->errorString();
    }
    reply->deleteLater();
});

๐Ÿ’ก ์–ด๋–ค ๊ฑธ ์„ ํƒํ•ด์•ผ ํ• ๊นŒ?

์ž, ์ด์ œ ์ง„์งœ ํ•ต์‹ฌ ์งˆ๋ฌธ์ด์•ผ. Qt๋ฅผ ์จ์•ผ ํ• ๊นŒ, wxWidgets๋ฅผ ์จ์•ผ ํ• ๊นŒ? ๐Ÿค”
์ƒํ™ฉ๋ณ„๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ์ •๋ฆฌํ•ด์ค„๊ฒŒ:

๐Ÿ”ต Qt๋ฅผ ์„ ํƒํ•ด์•ผ ํ•  ๋•Œ

โœ… ๋ณต์žกํ•˜๊ณ  ๊ธฐ๋Šฅ์ด ๋งŽ์€ ์•ฑ์„ ๋งŒ๋“ค ๋•Œ (Qt์˜ ํ’๋ถ€ํ•œ ๋ชจ๋“ˆ ํ™œ์šฉ)
โœ… ๋ชจ๋ฐ”์ผ(Android/iOS)๊นŒ์ง€ ์ง€์›ํ•ด์•ผ ํ•  ๋•Œ
โœ… ์ž„๋ฒ ๋””๋“œ ์‹œ์Šคํ…œ UI ๊ฐœ๋ฐœ (์ž๋™์ฐจ, ์‚ฐ์—…์šฉ ๊ธฐ๊ธฐ)
โœ… 3D ๊ทธ๋ž˜ํ”ฝ, ์• ๋‹ˆ๋ฉ”์ด์…˜์ด ๋งŽ์€ ์•ฑ
โœ… QML๋กœ ๋ชจ๋˜ํ•˜๊ณ  ํ™”๋ คํ•œ UI๋ฅผ ๋งŒ๋“ค๊ณ  ์‹ถ์„ ๋•Œ
โœ… ํŒ€ ๊ทœ๋ชจ๊ฐ€ ํฌ๊ณ  ์žฅ๊ธฐ ํ”„๋กœ์ ํŠธ์ผ ๋•Œ
โœ… ๊ฐ•๋ ฅํ•œ IDE(Qt Creator)์™€ ๋””๋ฒ„๊น… ๋„๊ตฌ๊ฐ€ ํ•„์š”ํ•  ๋•Œ
๐ŸŸข wxWidgets๋ฅผ ์„ ํƒํ•ด์•ผ ํ•  ๋•Œ

โœ… ์™„๋ฒฝํ•œ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฃฉ์•คํ•„์ด ์ค‘์š”ํ•  ๋•Œ
โœ… ์ƒ์—…์šฉ ์•ฑ์ธ๋ฐ ๋ผ์ด์„ ์Šค ๋น„์šฉ์„ ํ”ผํ•˜๊ณ  ์‹ถ์„ ๋•Œ
โœ… ๊ฐ€๋ณ๊ณ  ๋น ๋ฅธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ์•ฑ์„ ๋งŒ๋“ค ๋•Œ
โœ… ๋‹จ์ผ ์‹คํ–‰ ํŒŒ์ผ๋กœ ๋ฐฐํฌํ•ด์•ผ ํ•  ๋•Œ (์ •์  ๋งํ‚น)
โœ… MFC ๊ฒฝํ—˜์ด ์žˆ์–ด์„œ ๋น„์Šทํ•œ ์Šคํƒ€์ผ์„ ์›ํ•  ๋•Œ
โœ… OS ์ ‘๊ทผ์„ฑ ๊ธฐ๋Šฅ์ด ์ค‘์š”ํ•œ ์•ฑ (์Šคํฌ๋ฆฐ๋ฆฌ๋” ๋“ฑ)
โœ… ๊ธฐ์กด wxWidgets ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ์œ ์ง€๋ณด์ˆ˜ํ•  ๋•Œ
๐ŸŽฏ ๊ฒฐ๋ก : 2024๋…„ ๊ธฐ์ค€์œผ๋กœ ์ƒˆ ํ”„๋กœ์ ํŠธ๋ผ๋ฉด Qt๋ฅผ ์ถ”์ฒœํ•ด.
์ƒํƒœ๊ณ„, ๋ฌธ์„œ, ๋„๊ตฌ, ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ชจ๋“  ๋ฉด์—์„œ Qt๊ฐ€ ์•ž์„œ ์žˆ์–ด.
๋‹จ, ๋ผ์ด์„ ์Šค ๋น„์šฉ์ด ๋ถ€๋‹ด๋˜๊ฑฐ๋‚˜ ๋„ค์ดํ‹ฐ๋ธŒ ๋ฃฉ์•คํ•„์ด ์ ˆ๋Œ€์ ์œผ๋กœ ์ค‘์š”ํ•˜๋‹ค๋ฉด wxWidgets๋ฅผ ๊ณ ๋ คํ•ด๋ด.

๊ทธ๋ฆฌ๊ณ  ํ˜น์‹œ C++ GUI ๊ฐœ๋ฐœ ํ”„๋ฆฌ๋žœ์„œ๋กœ ํ™œ๋™ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด,
์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ Qt ๊ฐœ๋ฐœ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ.
Qt ๊ธฐ๋ฐ˜ ์‚ฐ์—…์šฉ ์†Œํ”„ํŠธ์›จ์–ด๋‚˜ ์ปค์Šคํ…€ GUI ๊ฐœ๋ฐœ ์˜๋ขฐ๊ฐ€ ๊พธ์ค€ํžˆ ์žˆ๊ฑฐ๋“ . ๐Ÿ’ผ


๐Ÿš€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ… ๊ฐ€์ด๋“œ

Qt ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ…

Step 1: Qt ๊ณต์‹ ์‚ฌ์ดํŠธ(qt.io)์—์„œ Qt Online Installer ๋‹ค์šด๋กœ๋“œ
Step 2: Qt Creator + Qt 6.x (์›ํ•˜๋Š” ๋ฒ„์ „) ์„ ํƒ ์„ค์น˜
Step 3: ์ปดํŒŒ์ผ๋Ÿฌ ์„ ํƒ (Windows: MSVC ๋˜๋Š” MinGW, Linux/Mac: GCC/Clang)
Step 4: Qt Creator ์‹คํ–‰ โ†’ ์ƒˆ ํ”„๋กœ์ ํŠธ โ†’ Qt Widgets Application ์„ ํƒ
Step 5: ๋นŒ๋“œ & ์‹คํ–‰! ๐ŸŽ‰

wxWidgets ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์„ธํŒ…

Windows (vcpkg ์‚ฌ์šฉ - ์ถ”์ฒœ!)
git clone https://github.com/microsoft/vcpkg
./vcpkg/bootstrap-vcpkg.bat
./vcpkg/vcpkg install wxwidgets:x64-windows
./vcpkg/vcpkg integrate install

Linux (Ubuntu/Debian)
sudo apt-get install libwxgtk3.2-dev

macOS (Homebrew)
brew install wxwidgets
โœ… ์ถ”์ฒœ IDE: Visual Studio Code + CMake Tools ํ™•์žฅ ๋˜๋Š” CLion
wxWidgets๋Š” Qt Creator๋ณด๋‹ค VS Code๋‚˜ CLion์—์„œ ๋” ํŽธํ•˜๊ฒŒ ๊ฐœ๋ฐœํ•  ์ˆ˜ ์žˆ์–ด.

Qt vs wxWidgets ์ข…ํ•ฉ ๋น„๊ตํ‘œ ํ•ญ๋ชฉ Qt wxWidgets ๋ผ์ด์„ ์Šค LGPL/GPL/์ƒ์—…์šฉ wxWindows ๋ผ์ด์„ ์Šค (๋ฌด๋ฃŒ) ๋ Œ๋”๋ง ๋ฐฉ์‹ ์ž์ฒด ๋ Œ๋”๋ง ์—”์ง„ ๋„ค์ดํ‹ฐ๋ธŒ OS ์œ„์ ฏ ํ•™์Šต ๋‚œ์ด๋„ ์ค‘๊ฐ„ (Qt ๊ณ ์œ  ๊ฐœ๋… ํ•„์š”) ์ค‘๊ฐ„ (์ „ํ†ต์  C++ ์Šคํƒ€์ผ) ๋ฐฐํฌ ํฌ๊ธฐ ํผ (20~50MB+) ์ž‘์Œ (์ •์ ๋งํ‚น 5~15MB) ๋ชจ๋ฐ”์ผ ์ง€์› โœ… Android / iOS โŒ ๋ฐ์Šคํฌํƒ‘ ์ „์šฉ ์ปค๋ฎค๋‹ˆํ‹ฐ/๋ฌธ์„œ ๋งค์šฐ ํ’๋ถ€ โญโญโญโญโญ ๋ณดํ†ต โญโญโญ ์ปค์Šคํ…€ ์Šคํƒ€์ผ๋ง ๋งค์šฐ ์ž์œ ๋กœ์›€ (QSS) ์ œํ•œ์  (๋„ค์ดํ‹ฐ๋ธŒ ๋”ฐ๋ฆ„)

๐Ÿ“š ํ•™์Šต ๋กœ๋“œ๋งต

์ž, ์ด์ œ ์–ด๋–ป๊ฒŒ ๊ณต๋ถ€ํ•ด์•ผ ํ• ์ง€ ๋กœ๋“œ๋งต์„ ๊ทธ๋ ค์ค„๊ฒŒ! ๐Ÿ—บ๏ธ

Qt ํ•™์Šต ๋กœ๋“œ๋งต

๐Ÿฅš ์ž…๋ฌธ ๋‹จ๊ณ„ (1~2๊ฐœ์›”)
C++ ๊ธฐ์ดˆ (ํด๋ž˜์Šค, ์ƒ์†, ํฌ์ธํ„ฐ, ์Šค๋งˆํŠธ ํฌ์ธํ„ฐ)
Qt ์„ค์น˜ ๋ฐ Qt Creator ์‚ฌ์šฉ๋ฒ•
๊ธฐ๋ณธ ์œ„์ ฏ (QPushButton, QLabel, QLineEdit, QTextEdit)
Signal & Slot ๊ฐœ๋… ์ดํ•ด
๋ ˆ์ด์•„์›ƒ ๊ด€๋ฆฌ (QVBoxLayout, QHBoxLayout, QGridLayout)

๐Ÿฃ ์ดˆ๊ธ‰ ๋‹จ๊ณ„ (2~3๊ฐœ์›”)
QMainWindow, QDialog, QMessageBox
ํŒŒ์ผ I/O (QFile, QTextStream)
Qt ์ปจํ…Œ์ด๋„ˆ (QList, QMap, QVector)
QString ํ™œ์šฉ๋ฒ•
Qt Designer๋กœ UI ๋งŒ๋“ค๊ธฐ

๐Ÿฅ ์ค‘๊ธ‰ ๋‹จ๊ณ„ (3~6๊ฐœ์›”)
Qt Network (HTTP ํ†ต์‹ , WebSocket)
Qt SQL (๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™)
QThread ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ
Model/View ์•„ํ‚คํ…์ฒ˜ (QAbstractItemModel)
QPainter ์ปค์Šคํ…€ ๊ทธ๋ฆฌ๊ธฐ
QSS ์Šคํƒ€์ผ๋ง

๐Ÿฆ… ๊ณ ๊ธ‰ ๋‹จ๊ณ„ (6๊ฐœ์›”+)
QML / Qt Quick
Qt 3D
Qt for Android/iOS
ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ
์„ฑ๋Šฅ ์ตœ์ ํ™” ๋ฐ ํ”„๋กœํŒŒ์ผ๋ง

์ถ”์ฒœ ํ•™์Šต ์ž๋ฃŒ

๐Ÿ“– ๊ณต์‹ ๋ฌธ์„œ: doc.qt.io (์ •๋ง ์ž˜ ๋˜์–ด ์žˆ์–ด, ๊ผญ ๋ด!)
๐Ÿ“บ ์œ ํŠœ๋ธŒ: "Qt Tutorial" ๊ฒ€์ƒ‰ํ•˜๋ฉด ๋ฌด๋ฃŒ ๊ฐ•์˜ ๋งŽ์•„
๐Ÿ“š ์ฑ…: "Qt 6 Core Beginners with C++" (Packt ์ถœํŒ์‚ฌ)
๐Ÿ’ป ์‹ค์Šต: Qt ๊ณต์‹ ์˜ˆ์ œ ์ฝ”๋“œ (Qt Creator์— ๋‚ด์žฅ๋˜์–ด ์žˆ์–ด)
๐ŸŒ ์ปค๋ฎค๋‹ˆํ‹ฐ: Qt Forum (forum.qt.io), Stack Overflow
โœ… ์ตœ๊ณ ์˜ ํ•™์Šต๋ฒ•: ์ง์ ‘ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ์•ฑ์„ ์ •ํ•˜๊ณ , ๊ทธ๊ฑธ ๋งŒ๋“ค๋ฉด์„œ ๋ฐฐ์šฐ๋Š” ๊ฑฐ์•ผ!
"๊ฐ„๋‹จํ•œ ๊ณ„์‚ฐ๊ธฐ โ†’ ๋ฉ”๋ชจ์žฅ โ†’ ์Œ์•… ํ”Œ๋ ˆ์ด์–ด" ์ˆœ์„œ๋กœ ์ ์  ๋ณต์žกํ•œ ์•ฑ์„ ๋งŒ๋“ค์–ด๋ด.

๐ŸŒŸ ๋งˆ๋ฌด๋ฆฌ: ํฌ๋กœ์Šคํ”Œ๋žซํผ์˜ ๋ฏธ๋ž˜

Qt์™€ wxWidgets๋Š” 30๋…„์ด ๋„˜๋Š” ์—ญ์‚ฌ๋ฅผ ๊ฐ€์ง„ ๊ฒ€์ฆ๋œ ๋„๊ตฌ๋“ค์ด์•ผ.
Electron(JavaScript ๊ธฐ๋ฐ˜), Flutter(Dart ๊ธฐ๋ฐ˜), Tauri(Rust ๊ธฐ๋ฐ˜) ๊ฐ™์€ ์ƒˆ๋กœ์šด ํฌ๋กœ์Šคํ”Œ๋žซํผ ํ”„๋ ˆ์ž„์›Œํฌ๋“ค์ด ๋“ฑ์žฅํ–ˆ์ง€๋งŒ,
C++ ๊ธฐ๋ฐ˜ ๋„ค์ดํ‹ฐ๋ธŒ ์„ฑ๋Šฅ์ด ํ•„์š”ํ•œ ๋ถ„์•ผ์—์„œ๋Š” Qt์™€ wxWidgets์˜ ์ž๋ฆฌ๋Š” ๊ตณ๊ฑดํ•ด.

ํŠนํžˆ Qt๋Š” ์ž๋™์ฐจ ์ธํฌํ…Œ์ธ๋จผํŠธ, ์˜๋ฃŒ ๊ธฐ๊ธฐ, ์‚ฐ์—…์šฉ ์ œ์–ด ์‹œ์Šคํ…œ, ํ•ญ๊ณต์šฐ์ฃผ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐ™์€
๊ณ ์„ฑ๋Šฅ, ๊ณ ์‹ ๋ขฐ์„ฑ์ด ์š”๊ตฌ๋˜๋Š” ๋ถ„์•ผ์—์„œ ๊ณ„์† ๊ฐ•์„ธ๋ฅผ ๋ณด์ด๊ณ  ์žˆ์–ด.

wxWidgets๋„ Audacity, FileZilla ๊ฐ™์€ ์œ ๋ช… ์˜คํ”ˆ์†Œ์Šค ํ”„๋กœ์ ํŠธ๋“ค์ด ๊ณ„์† ์‚ฌ์šฉํ•˜๋ฉด์„œ
๊พธ์ค€ํžˆ ์—…๋ฐ์ดํŠธ๋˜๊ณ  ์žˆ๊ณ , ํŠนํžˆ ๊ฐ€๋ณ๊ณ  ๋„ค์ดํ‹ฐ๋ธŒํ•œ ๋ฐ์Šคํฌํƒ‘ ์•ฑ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” ์—ฌ์ „ํžˆ ์ตœ๊ณ ์˜ ์„ ํƒ์ด์•ผ.

๐Ÿš€ ํ•ต์‹ฌ ๋ฉ”์‹œ์ง€: C++ ํฌ๋กœ์Šคํ”Œ๋žซํผ ๊ฐœ๋ฐœ์€ ์–ด๋ ต์ง€ ์•Š์•„!
Qt๋‚˜ wxWidgets ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•ด์„œ ๊พธ์ค€ํžˆ ๊ณต๋ถ€ํ•˜๋ฉด,
Windows, macOS, Linux ์–ด๋””์„œ๋“  ๋Œ์•„๊ฐ€๋Š” ๊ฐ•๋ ฅํ•œ ์•ฑ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์–ด.
์ง€๊ธˆ ๋‹น์žฅ Qt Creator๋ฅผ ์„ค์น˜ํ•˜๊ณ  "Hello World" ์•ฑ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ด! ๐Ÿ’ช

๋งˆ์ง€๋ง‰์œผ๋กœ, C++ GUI ๊ฐœ๋ฐœ ์‹ค๋ ฅ์„ ์Œ“์•˜๋‹ค๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ ํ”„๋ฆฌ๋žœ์„œ๋กœ ํ™œ๋™ํ•˜๋Š” ๊ฒƒ๋„ ๊ณ ๋ คํ•ด๋ด.
Qt ๊ธฐ๋ฐ˜ ์ปค์Šคํ…€ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ, wxWidgets ์•ฑ ์œ ์ง€๋ณด์ˆ˜ ๊ฐ™์€ ์˜๋ขฐ๋“ค์ด ๊พธ์ค€ํžˆ ์˜ฌ๋ผ์˜ค๊ฑฐ๋“ .
๊ธฐ์ˆ ์„ ๋ฐฐ์šฐ๊ณ  โ†’ ์‹ค๋ ฅ์„ ์Œ“๊ณ  โ†’ ์ˆ˜์ต๊นŒ์ง€ ์ฐฝ์ถœํ•˜๋Š” ์„ ์ˆœํ™˜์„ ๋งŒ๋“ค์–ด๋ด! ๐ŸŽฏ

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.