QT - GUI 뿐만 아니라 프레임워크로서 존재
유저 인터페이스만을 위한 게 아닌, 시스템에 대한 인터페이스, 통신, 시스템 내부에 대한 api가 잘 만들어져있는 도구. 엄청 많이는 아니어도, 제법 유용하게 사용되고 있는 도구임.
한화비전에서도 큐티 기반으로 어플리케이션을 만들고 배포하기 때문에, 큐티에 대한 요구사항들이 있을 것. 큐티를 잘 해두면 좋은 스킬이 될 것임.
강사님 강의자료로 진행.
GUI를 쉽게 만들기 위해 생겨난 GUI 프로그래밍 프레임워크.
크로스 플랫폼을 목적으로, 다양한 운영체제에서 동작 가능하다.
C++ 기반으로 구성.
객체 지향 라이브러리 형태.
→ 시그널이 발생했을 때 슬롯 내용이 이벤트를 처리하는 기본 메커니즘으로 되어있다.
이 방식을 어떻게 연결하는가가 Qt 프로그래밍의 핵심.
엄청 많은 위젯이 존재. 스타일이 다양하게 존재
네트워크, 데이터베이스, 멀티미디어 등 다양한 분야의 api, 직관적 구조의 라이브러리 제공.
→ “Write once, compile anywhere” : Qt의 목표
다양한 모듈이 있으나, 무료 모듈이 있고, 유료가 있음.
GPL : 공개 되어진 소프트웨어에서 사용하는 라이센스. 이 라이센스를 사용했다면 이 소프트웨어를 사용한 내 코드도 공개되어야함.
LGPL : 소스코드 공개는 안해도되나, 라이브러리 형태로는 공개해야함.
상용 목적으로 qt를 쓰려면 돈주고 써야함.
수업때 배울 간단한 코드는 상관없으나 회사가서는 라이센스에 주의하세요
QML language : qt 전용 라이브러리로, 빠르게 개발이 가능하다. 돈주고 써야함ㅋ
강의자료 이미지(4페이지) 는 옜날자료라, 링크타고 들어가보면 최신화된 데이터를 볼수있음.
5페이지
중요한 모듈들
QT Core : C++ 컨테이너, 스레드관리 등 C++에서 기존 사용하던 함수들을 더 편리하게 래핑(wrapping)하여 더 편하게 쓸 수 있도록 만들어둔 라이브러리.
QT GUI, QT Widget : 다양한 그래픽 컴포넌트 툴킷 제공.
QT network : TCP/IP 등 소켓 프로그래밍을 큐티에서 쉽게 할 수있게 구성..
다양한 모듈들이 있지만, 교육기간에는 Core, GUI, Widget을 위주로 사용할것임.
12페이지
QT designer, QT design studio, QT Assistant, QT Linguist 등 제공하는 툴을 활용해볼것임..
13페이지
빌드(ctrl b), 실행(ctrl r), 디버그(f5) 키 기억하기.
다양한 도큐먼트 사이트들이 제공되고 있기에, 예제코드나 이해하기 쉬운 부분들을 제공하고 있음.
위젯은 베이직 위젯 위주로 사용할것임.
처음 프로젝트 생성 시, 다 기본적인 파일들을 생성해준다.
Q_OBJECT : QT전용 오브젝트. 이게 없으면 큐티 시그널, 슬롯 사용이 안댐
기본적으로 클래스 생성 시 이 매크로가 자동 정의된다. 아래 자세히 설명함.
Q_WIDGET 상속받아서 WIDGET 클래스가 생성된다.
QApplication 객체.
이 객체가 프로그램 실행 시, 이벤트 핸들러 역할을 한다.
a.exec() 멤버함수 호출을 통해 GUI 시작함.
가장 핵심은 어플리케이션 객체를 만들고, 내부에 다양한 객체들과 이벤트들을 연결하고, exec함수로 어플리케이션을 실행해서 이벤트 처리를 진행한다는 것임. 무한루프를 돌면서 계속해서 신호를 대기하고 시그널 발생 → 슬롯함수 실행 매커니즘이 반복됨.
기본 상태에서 빌드 진행 (Ctrl B)
Ctrl R 하면 첫 프로젝트 실행 결과가 윈도우창이 뜨면서 결과가 나타난다.

일단 아무것도 안넣어서 빈 창이 발생한다.
만약 코드에서 궁금한 부분이 있다면, 대상을 블록지정하고 F1누르면 매뉴얼을 띄워준다.
도움말을 즉각 받아볼 수 있으니 잘 활용하자.
프로젝트 종류가 어플리케이션, 콘솔, 위젯 등 다양했다.
지금당장은 위젯 프로그램을 만들어 볼 것임.
위젯은 사용자가 gui를 통해 입력을 주고, 시그널이 발생하면, 그것을 처리(슬롯함수)하는 역할을 한다.
유저 인터페이스에 사용되는 클래스가 위젯클래스.
앞서 상속의 상속이 이루어져서 수많은 클래스가 만들어졋다고 하심.
QObject ← 중요
모든 큐티객체는 QObject로부터 시작함.
이를 상속받아 위젯, 타이머, 상속의 상속을 통해 다양한 객체가 만들어짐.
우리는 위젯쪽을 집중적으로 볼것.
QAbstractButton ← 버튼을 관리하기 위한 추상클래스
이를 통해 푸쉬버튼, 툴버튼, 등 자식클래스를 정의하게 된다.
https://doc.qt.io/qt-6.8/hierarchy.html
상속에 관한 내용들을 텍스트로 정리한 문서

QPushButton 은 QWidget(조부모) ← QAbstractButton(부모) ← QPushButton(자식) 에 위치

QTextEdit의 추상관계도도 검색을 통해 쉽게 찾을 수 있다.

들어가보면 해당 클래스에 대한 자세한 사항들을 볼 수 있음.
Qt에서는 프로그램 실행 중 생성되는 창B들은 마지막에 연 창이 가장 위에 표시되는 방식으로 관리되며, 스택처럼 동작한다.
메인 윈도우에서 여러 개의 하위 창을 열 수 있으며, 이들은 순차적으로 관리되거나 번호를 붙여 추적할 수 있다.
각 창 내부는 위젯 계층 구조를 이루며, 부모 위젯은 자식 위젯들을 소유하고 관리한다.
자식 위젯들의 위치와 크기는 레이아웃 매니저에 의해 자동으로 조정되며, 이를 통해 다양한 해상도에서도 UI가 적절히 배치되도록 한다.
QLabel을 써보자.
qt 매뉴얼에서 QLabel을 검색.

생성자 확인.
QString을 넣느냐 안넣느냐 차이임.
show 함수 안보임 → 부모에 있겠다. → 근데없네? → 조부모에 있겠다 → 응 그래그래 그게 맞아.
QWidget에서 show를 상속받아 사용함.
show 함수는 말그대로 출력. 만들어진 객체를 윈도우에 그려주는 함수라고 보면 됨.
#include "widget.h"
#include <QApplication>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLabel hello("<i> Hello Qt!</i>");
hello.show();
return a.exec();
}

라벨 출력 완료 !
html 태그를 문자열로 전달하면 큐티에서 태그를 해석하여 띄워준다. i태그는 이탤릭체를 의미.
hello.resize(100, 100);
를 통해 라벨객체 사이즈가 조정됨.
푸쉬버튼을 사용해보자.
다음과 같은 생성자를 가진다.
QPushButton에 대한 헤더를 인클루드하고 생성한다.
또한 show함수로 해당 위젯이 보여지게 해주자.
#include "widget.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton quit("Quit");
quit.resize(75,25);
quit.show();
return a.exec();
}

귀엽고 앙증맞은 quit이 생겨났다!
객체 간 통신을 시그널-슬롯으로 진행
근데 quit 버튼을 누르더라도 아무런 일도 일어나지 않았다.
quit을 눌러서 종료하게하는 액션이 구현되었으면 좋겟다
앞서 설명해왔듯, Qt는 시그널 - 슬롯함수의 연결로 동작한다.
따라서 우리는 “Quit를 눌러서 발생하는 시그널 + 해당 시그널에 대한 동작 정의” 를 통해 원하는 동작을 수행하도록 하면 된다.
시그널과 슬롯을 연결할 때 쓰는 함수가 connect() 이다.
connect의 인자에 대해 알아보자.
sender: 시그널을 보내는 객체 주소
signal: 함수명을 의미
receiver: 시그널을 받을 객체 주소(생략시 현재 수행하고 있는 객체정보(this)가 넘어감)
method: 받았을 때 어떤 처리를 할지에 대한 정보(함수명)
type:커넥션 타입(근데 직접지정할일은없다고함, 그냥디폴트타입사용)
connect()는 시그널과 시그널이 발생햇을때 어떤함수를호출할지에 대한 함수다.
더이상 해당 커넥션을 쓰지않는다면, disconnect()를 통해 해제하면됨.

객체 간 시그널-슬롯 연결을 통해 시그널발생 시 설정된 함수가 호출되도록 한다.
객체간 통신, 이벤트처리를 connect함수로 사용자가 정의하여 사용 가능.
기본제공되는 미리 qt에서 만들어둔 시그널-슬롯을 사용해도 된다고 함.
하나의 시그널에 여러 슬롯함수를 연결하는 것도 가능.
단, 등록된 순서대로 슬롯함수를 호출함. 모든 슬롯이 순차적으로 호출된다.
시그널이 호출되었을 때 연결된 슬롯함수에서 또 다른 시그널이 발생하고, 다른 슬롯함수가 동작하게 할 수도 있다. (시그널 체이닝)
시그널이 자신과 연결되는 슬롯보다 더많은 수의 매개변수를 갖는 경우 유효성이 예외적으로인정
→ 슬롯은 시그널보다 적은 수의 인자를 받을 수 있다.
반대로 슬롯이 시그널보다 더 많은 인자를 요구하면 안됨. (슬롯이 더 많은 인자를 요구하면 컴파일 에러 발생)
시그널은 상태변화를 공지하는 수단
시그널은 미리 정의된 클래스에서만 동작.
정의되지않은 클래스에선 시그널사용불가.
슬롯함수는 일반함수처럼 호출이 가능하지만, 시그널과 connect() 함수로 연결해서 쓰는게 일반적.
슬롯함수는 접근지정자와 함께(public slot 등) 정의해야한다.
// old style
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
// new style
QObject::connect(sender, &Class명::signal, receiver, &Class명::slot);
new 패턴을 더 많이 쓰도록 하자. 펑터 클래스 사용해서 쓰도록 되어있다.
자 이제 푸쉬버튼을 눌렀을 때 종료되도록 해보자.

QAbstractButton에 다음과 같은 시그널들이 존재한다.

QApplication에는 위와 같은 슬롯함숙 존재함.
아무래도, clicked 시그널이 호출되면, QApplication의 closeAllWindows() 슬롯함수가 동작하게끔 연결해주면 될듯하다!
자 그러면 connect()함수를 통해 연결해보도록 하자!
#include "widget.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton quit("Quit");
quit.resize(75,25);
quit.connect(&quit, &QPushButton::clicked, &a, &QApplication::closeAllWindows);
// QObject::connect(&quit, &QPushButton::clicked, &a, &QApplication::closeAllWindows);
quit.show();
return a.exec();
}
QObject::connect(&quit, SIGNAL(clicked()), &a, SLOT(closeAllWindows()));
를 통해, quit에서 clicked 시그널이 발생하면 a가 closeAllWindows라는 슬롯함수를 발생하게함
connect는 QObject의 스태틱 멤버함수이기때문에, quit 클래스에서 해당함수를 호출하든, QObject 클래스에서 호출하든 동일한 함수를 부르게된다.
펑터 쓰는 위치에, 함수이름 적기 대신, 람다식을 적어서 슬롯함수를 등록하는것 또한 가능함.
하나의 화면에서 여러 위젯을표현하게 한다면?
QLabel + QPushButton 해보자.
move, setgeometry함수는 위젯의 위치를 설정할 수 있음.
#include "widget.h"
#include <QApplication>
#include <QLabel>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QLabel hello("<b> Hi Qt!</b>", &w);
QPushButton quit("Quit", &w);
hello.resize(75, 30);
quit.move(60, 10);
quit.connect(&quit, &QPushButton::clicked, &a, &QApplication::closeAllWindows);
w.show();
return a.exec();
}
만약 quit 버튼을 눌렀을 때, Label문자열이 quit 으로 수정되게 하고싶다면…
QLabel 의 함수를 이용해서 문자열이 수정되게 해보자.
→ 펑터 대신 람다함수를 입력해줄 수 있었던 걸 활용
#include "widget.h"
#include <QApplication>
#include <QLabel>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QLabel hello("<b> Hi Qt!</b>", &w);
QPushButton quit("Quit", &w);
hello.resize(75, 30);
quit.move(60, 10);
quit.connect(&quit, &QPushButton::clicked, &hello, [&](){
hello.setText("Quit!!");
});
w.show();
return a.exec();
}
람다함수 대신, &QLabel::setText 하게 되면, 안된다. 해당하는 슬롯함수가 인자를 받아야하는데,
setText에 대한 인자가 전달되지 못하기 때문.(clicked가 인자를 전달해주지 않는 시그널임)
변경하는 작업을 수행하도록, 람다식을 통해 작업을 진행하게 한다.
qt에서 람다식 쓸 땐, &로 참조하여 쓰기.
이미 만들어진 위젯을 사용했으나, 직접 위젯을 만들어야할 경우가 있다.
위젯을 만드는 가장 일반적인 방법은, QWidget을 상속받아서 생성자함수에서 필요로하는 위젯들을 구성하면 된다.
#include "widget.h"
#include <QLabel>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
hello = new QLabel("<b> Hi Qt!</b>", this);
quit = new QPushButton("Quit", this);
hello->resize(75, 30);
quit->move(60, 10);
connect(quit, &QPushButton::clicked, hello, [&](){
hello->setText("Quit!!");
});
}
Widget::~Widget() {}
생성한 QLabel, QPushButton을 위젯의 멤버로 선언하고 동적할당하여 계속 존재하도록 하자.
디버그문구를 출력하고자한다면,
Widget::~Widget()
{
delete hello;
delete quit;
qDebug() << "소멸자\n";
}
→ qt creator의 application output에 문구가 출력됨.
근데 qt 내부 라이브러리는 스마트포인터로 구현되어있음.
내가 new로 할당했더라도 자동적으로 할당이 해제됨.
(근데 이건 강사님이 제대로 알아와주신다함)
Qt에서 Q_OBJECT 매크로는 Qt의 메타-오브젝트 시스템(Meta-Object System) 을 활성화하기 위해 클래스에 꼭 필요한 매크로입니다. 이 매크로는 Qt의 핵심 기능 중 하나인 시그널과 슬롯(Signals & Slots), 런타임 타입 정보(RTTI), 동적 속성(Property) 시스템 등을 사용할 수 있게 해줍니다.
시그널(Signal)과 슬롯(Slot) 기능 활성화
→ QObject 기반 클래스에서 signals, slots 키워드를 사용하려면 Q_OBJECT 매크로가 필요합니다.
런타임 타입 정보(RTTI)
→ QObject::metaObject()나 object->metaObject()->className()처럼 클래스 이름이나 속성을 런타임에 조회할 수 있습니다.
Qt의 리플렉션(Reflection) 시스템
→ 클래스의 속성(property)을 문자열로 조회하거나 수정할 수 있습니다. QML 연동이나 디버깅 툴에서도 활용됩니다.
Qt의 메타-오브젝트 컴파일러(moc) 사용을 위한 마커
→ Q_OBJECT가 있으면 moc가 그 파일을 처리해서 시그널/슬롯 연결용 코드를 자동 생성합니다.
#include <QObject>
class MyObject : public QObject {
Q_OBJECT
public:
MyObject(QObject *parent = nullptr);
signals:
void mySignal();
public slots:
void mySlot();
};
이 클래스에 Q_OBJECT가 없으면 signals, slots 키워드가 작동하지 않으며, 컴파일러가 에러를 발생시킬 수도 있습니다.
Q_OBJECT가 있는 클래스는 .cpp 파일이 반드시 존재해야 하며, moc가 이를 처리할 수 있도록 qmake나 CMake가 설정되어 있어야 합니다.Q_OBJECT 매크로가 없으면 시그널/슬롯은 선언할 수는 있지만, 연결(connect) 자체가 작동하지 않습니다.위젯에 커스텀 슬롯함수 등록하기
헤더에
// widget.h
class Widget : public QWidget
{
Q_OBJECT
class QLabel* hello;
class QPushButton* quit;
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void clickedQuit();
};
public slots:
로 슬롯함수 접근지정자를 선언.
이후 clickedQuit에 대한 동작을 정의
// widget.cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
hello = new QLabel("<b> Hi Qt!</b>", this);
quit = new QPushButton("Quit", this);
hello->resize(75, 30);
quit->move(60, 10);
connect(quit, &QPushButton::clicked, this, &Widget::clickedQuit);
}
void Widget::clickedQuit()
{
qDebug() << "ClickedQuit called\n";
qApp->closeAllWindows();
}
슬롯함수를 정의하듯, 시그널도 정의 가능하다.
Q_OBJECT 매크로 선언된 클래스에서.
본교재 129페이지. 시그널 앤 슬롯
emit ← 뒤에 오는 시그널을 강제로 발생시킨다는 의미..

위 코드의 emit은 valueChanged라는 시그널을 발생시키고, 인자로 val을 슬롯함수에 넘기게 되어있다.
일반적인 시그널들은 외부입출력신호와 같은 시그널로 발생하나, 객체와 객체 간 시그널을 보내는 것은 emit을 통해 사용자 임의대로 할 수 있다.
emit 으로 시그널을 보내면, connect함수에 연결된 slot함수로 전달되게 되어있고, emit과 함께 보낼 값을 인자로 주면 슬롯에서 처리할 수 있음.
클래스 내 특정 영역에서 emit하고 시그널을 강제 발생하면, 함수 호출 시 시그널 발생을 만들어낼 수 있다.
// widget.cpp
#include "widget.h"
#include <QLabel>
#include <QPushButton>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
hello = new QLabel("<b> Hi Qt!</b>", this);
quit = new QPushButton("Quit", this);
hello->resize(75, 30);
quit->move(60, 10);
connect(quit, &QPushButton::clicked, this, &Widget::clickedQuit);
connect(this, &Widget::valueChanged, this, &Widget::valueChangedSlot);
}
void Widget::clickedQuit()
{
qDebug() << "clickedQuit() called\n";
emit valueChanged("click");
//qApp->quit();
}
void Widget::valueChangedSlot(QString num)
{
hello->setText(num);
}
Widget::~Widget()
{
// delete hello;
// delete quit;
qDebug() << "소멸자\n";
}
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QApplication>
class Widget : public QWidget
{
Q_OBJECT
class QLabel* hello;
class QPushButton* quit;
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void clickedQuit();
void valueChangedSlot(QString);
signals:
void valueChanged(QString);
};
#endif // WIDGET_H
시그널 선언은 클래스 내 헤더파일에.
시그널에 인자를 적어주면, 해당 시그널 발생 시 connect된 슬롯함수로 인자를 넘긴다.
교재 7장
qt에서 제공하는 데이터타입이 굉장히 많다.
QString ← CString을 거의 그대로 구현
숫자를 인자로 주면 스트링으로 변환할때 사용하면 좋음.
| Qt 타입 | 설명 |
|---|---|
QString | 문자열 클래스. UTF-16 기반. std::string보다 유니코드 및 Qt 위젯과 호환성 좋음 |
QByteArray | 바이너리 데이터나 ASCII 문자열 처리용. std::vector<char> 또는 std::string 대체 |
QVariant | 여러 타입을 저장할 수 있는 컨테이너. int, QString, double 등 유동적으로 저장 가능 |
QDate, QTime, QDateTime | 날짜 및 시간 다루는 클래스. 포맷 지정, 연산, 비교 등 풍부한 기능 제공 |
QChar | 유니코드 문자 하나를 표현. wchar_t 비슷하지만 Qt 위젯과 더 잘 통합됨 |
QLatin1String, QStringView | 성능 개선용 문자열 뷰. 복사 없이 읽기 전용 문자열 처리할 때 사용 |
| Qt 타입 | 설명 |
|---|---|
QList<T> | 리스트. std::vector와 유사하지만 insert/remove 성능이 조금 다름 |
QVector<T> | 실제 배열 기반 컨테이너. std::vector에 가장 가까움 |
QMap<Key, Value> | 정렬된 맵. std::map 대체 |
QHash<Key, Value> | 해시 기반 맵. std::unordered_map 대체 |
QSet<T> | 집합 자료형. 중복 허용 안함 |
QStringList | QString의 리스트. 자주 쓰이는 문자열 리스트용 컨테이너 |
🧠 STL을 사용할 수도 있지만, Qt 신호/슬롯 및 QML 연동, 직렬화 등을 고려할 땐 Qt 컨테이너가 더 유리해요.
| Qt 타입 | 설명 |
|---|---|
QColor | 색상 표현. RGB, HSV, 이름 등 다양한 방식 지원 |
QSize, QPoint, QRect | GUI 요소의 크기, 위치, 영역 등 표현 |
QFont, QPixmap, QImage | 폰트, 이미지, 비트맵 등을 처리하는 데 사용 |
QBrush, QPen, QPainter | 그리기 API에서 쓰이는 브러시, 펜, 페인터 객체 |
QModelIndex, QAbstractItemModel | 모델/뷰 구조에서 쓰이는 인덱스 및 모델 타입 |
| Qt 타입 | 설명 |
|---|---|
QTimer | 타이머 기능. 일정 시간마다 시그널 발생 |
QFile, QTextStream | 파일 읽기/쓰기 및 스트림 처리 |
QDebug | 디버깅 출력. qDebug() << "Hello"; 형태 |
QJsonObject, QJsonArray, QJsonDocument | JSON 데이터 처리용 |
QProcess | 외부 프로세스 실행 및 통신 |
QThread, QMutex, QSemaphore | 멀티스레딩 관련 클래스 |
QAbstractTableModel)이나 UI 속성 저장할 때 매우 유용합니다.QMetaType 시스템과 연결되어 있어, 동적 타입 처리, Qt Designer, QML과도 잘 맞아요.// widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QVector>
class Widget : public QWidget
{
Q_OBJECT
QVector<char> v;
class QPushButton* plus;
class QPushButton* minus;
class QPushButton* equal;
class QPushButton* num[3];
class QLabel* result;
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void doPlus();
void doMinus();
void doEqual();
void pushOne();
void pushTwo();
void pushThree();
};
#endif // WIDGET_H
// widget.cpp
#include "widget.h"
#include <QPushButton>
#include <QLabel>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
plus = new QPushButton("+", this);
plus->resize(20, 20);
plus->move(10, 10);
minus = new QPushButton("-", this);
minus->resize(20, 20);
minus->move(40, 10);
equal = new QPushButton("=", this);
equal->resize(20, 20);
equal->move(70, 10);
for (int i = 0; i < 3; i++)
{
num[i] = new QPushButton(QString(QChar(i + '1')), this);
num[i]->resize(20, 20);
num[i]->move(10 + 30 * i, 40);
}
connect(num[0], &QPushButton::clicked, this, &Widget::pushOne);
connect(num[1], &QPushButton::clicked, this, &Widget::pushTwo);
connect(num[2], &QPushButton::clicked, this, &Widget::pushThree);
result = new QLabel("Press the button", this);
result->move(25, 80);
connect(plus, &QPushButton::clicked, this, &Widget::doPlus);
connect(minus, &QPushButton::clicked, this, &Widget::doMinus);
connect(equal, &QPushButton::clicked, this, &Widget::doEqual);
}
void Widget::doPlus()
{
qDebug() << "DoPlus\n";
if (v.empty() || v.back() < '0' || v.back() > '9')
return ;
v.push_back('+');
}
void Widget::doMinus()
{
qDebug() << "DoMinus\n";
if (v.empty() || v.back() < '0' || v.back() > '9')
return ;
v.push_back('-');
}
void Widget::doEqual()
{
qDebug() << "DoEqual\n";
if (v.empty())
return;
int res = v[0] - '0';
for (int i = 1; i < v.size(); i+=2)
{
qDebug() << i << " | " << res << '\n';
if (v[i] < '0' || v[i] > '9') // operator
{
char op = v[i];
if (op == '+')
res += v[i+1] - '0';
else if (op == '-')
res -= v[i+1] - '0';
}
}
result->setText(QString::number(res));
v.clear();
}
void Widget::pushOne()
{
qDebug() << "pushOne\n";
if (!v.empty() && v.back() >= '0' && v.back() <= '9')
return;
v.push_back('1');
qDebug() << v.back() << '\n';
}
void Widget::pushTwo()
{
qDebug() << "pushTwo\n";
if (!v.empty() && v.back() >= '0' && v.back() <= '9')
return;
v.push_back('2');
qDebug() << v.back() << '\n';
}
void Widget::pushThree()
{
qDebug() << "pushThree\n";
if (!v.empty() && v.back() >= '0' && v.back() <= '9')
return;
v.push_back('3');
qDebug() << v.back() << '\n';
}
Widget::~Widget() {}