Signal 은 우리말로 신호를 의미하고 Slot은 무언가를 넣을 수 있는 자리나 틈 같은 것을 의미한다. 즉 신호가 발생하면 slot에 있는 무언가를 시작한다. 디자인 패턴을 이해한다면 "생산자 소비자 패턴"을 수행한다고 생각할수도 있겠다.

보통 하나의 클래스에서 시그널과 슬롯을 구현하면서 설명을 하겠지만 신호가 발생되는 곳과 그것에 대한 처리가 발생하는 곳이 항상 같지는 않으므로 별개의 두개의 클래스를 가지고 설명해보겠다.

Signal이 발생하는 곳을 SignalGenerator라고 하고, Slot을 처리하는 곳을 SlotProcessor라고 하자. 주의할 점은 Signal and Slot 메커니즘이 작동하기 위해서는 반드시 QObject를 상속받아야 한다. 그 외에 매크로도 추가해야 하지만 Qt Creator는 간편한 위저드 기능을 제공한다.

아마 특별한 설정을 하지 않았다면 파일명이 소문자로 표시될 것이다. Qt Creator의 기본값이 소문자여서 그렇다. 아래와 같이 옵션으로 변경할 수 있다.

 

 

프로젝트명에서 마우스 우클릭을 하여 Add New 를 실행하면 위와 같은 위저드 화면이 나온다. 여기서 Base class를  QObject를 선택하면 자동으로 필요한 내용이 추가로 체크된다. 

 

생성된 파일을 헤더를 보면 필요한 상속과 매크로까지 미리 작성되어 있음을 확인할 수 있다. 이제 Sinal을 발생시키는 부분을 작성해 보자.

 

위 소스를 보면 emit란 용어는 처음 볼겠지만 대략 GeneratorTextSignal 함수가 호출되면 내부적으로 textSignal 을 호출함을 알 수 있을 것이다. 사실 위에서 보이는 signals 와 emit은 표준 c++에는 있지 않은 용어다. 즉 qt가 정의한 키워드이며 qt는 c++ 소스 코드에서 해당 키워드를 이용하여 표준 c++에 맞도록 코드를 추가하고 컴파일을 진행한다.

 

SlotProcessor의 함수를 보면 두 클래스의 의도가 SignalGenerator에서 GeneratorTextSignal을 호출하면 Signal and slot 메커니즘에 따라 SlotProcessor의 onSlotMessage가 호출되기 위한 코드이다. 두 클래스의 인스탄스를 main에서 정의해보자.

자 위 코드를 추가한 후 성급하게 빌드하고 실행해본 사람이 없길 바란다. 변수 sg 에서 GenerateTextSignal을 통해 Signal을 발생시켰지만 sp는 그 발생 사실을 알 수 없어 slot함수를 실행할 수 없게 된다. Qt는 signal / slot 키워드를 통해 추가적인 코드를 만든는 것이지 알아서 두 클래스를 연결해 주는 것은 아니다. 마법은 없다.

 

Connect 함수를 통해 두 인스탄스를 Signal / Slot을 연결해 주고 나서 실행하면 아래와 같은 텍스트가 출력됨을 Application Out 창을 통해 확인할 수 있다. connect 함수에 F1 을 클릭해서 (더이상 F1을 이야기 하지 않겠다) 설명을 보면 여러가지 버전으로 재정의 되어 있다. 처음에 주석 처리한 방식도 정상적으로 작동된다. 나는 그중에 멤버 함수의 포인터를 이용하여 연결하는 방식을 사용하였다.

자 이제 좀더 자세히 이게 뭐하는 것인지 살펴보자.  이처럼 기능이 작동되는 것을 보면 C++ 개발자라면 함수 포인터를 이용한 Callback 함수랑 뭐가 다른거지 라는 생각이 들겠지만 마지막 파라미터인 ConnectionType을 보면 보다 진보된 형태의 함수 포인터를 관리해준다고 느낄 수 있다.

즉 콜백함수와 같이 즉시 실행되는 것만이 아니라 상황에 따라 유연하게 queue에 넣어 slot 함수의 작동을 제어할 수 있다. 또한 connect함수에 대응되는 disconnect함수도 제공하여 연결을 끊을 수도 있다. 

Signal / Slot 은 개념이해는 큰 어려움이 없을 것이다. 오히려 문법이 생소해 잘 외워지지 않는데 Signal에서 선언한 함수의 형태와 Slot 에서 구현된 함수의 형태가 같아야만 하는 것을 기억하면 된다. 

 

  • 프로젝트 생성

QtCreator를 이용하여 새로운 콘솔 프로젝트를 아래와 같이 생성해 보자. 나는 관행적으로 D드라이브에 _dev라는 폴더를 두고 그 아래에 개발 관련 프로젝트를 모아 놓는다. 편한곳에 생성하면 된다.

 

다음으로 이동하면 처음부터 당황스런 화면이 나온다. 기본값은 qmake 이니 그대로 선택하여 다음으로 가자. qt6부터는 cmake가 기본이라고도 하던데 뭐가 다른지는 그때 고민해 보자.

 

다음을 눌러보자. 뭔가 더 복잡한게 나왔다. 이것은 Qt가 다국어를 처리하기위 지원하는 파일이다. 실무적으로 개발하기 전까지는 항상  none으로 설정하겠다. 다음.

 

뭔가 더욱더 복잡한게 나왔다. 키트를 선택하란다. 키트란 뭔가? 그동안 대충 다음으로 넘어갔지만 이번 정리를 위해 좀더 찾아 보았다. 키트란 결국 배포하려는 플랫폼을 의미한다. 나는 여러 버전의 Qt를 설치했으므로 많이 나오지만 여러분은 좀 다르게 나올것이다. 적절히 Qt5 버전대를 선택하라. 

None으로 그대로 두고 다음으로 넘어간다. 마찬가지로 실무적으로 이용할 경우 version control은 당연히 하겠지만 이 정리에선 하지 않겠다. 

 

  • 프로젝트 구성

자 드디어 익숙한 소스 코드가 보인다. 개발자라면 무수히 보았을 main.cpp 소스 파일 하나과 뭔지 모를 HelloWorld.pro 파일 하나가 덩그러니 있다.

 

 이 pro 파일이 Visual Stuio에서의 프로젝트 파일 역할을 한다.  하지만 훨씬 직곽적이고 수정하기가 용이하다. 아래를 보면 콘솔 프로젝트 임으로 gui 가 프로젝트에서 배제되어 있음을 알 수 있다. 또한 C_++11 기반으로  개발하고 있으며 main.cpp가 project에 등록되어 있음을 알 수 있다. Qt는 이렇게 +=, -=통해 속성들을 추가, 삭제할 수 있다.

 

 

  • 코드 보기

자 이제 본격적으로 소스 코드를 살펴보자.

 

메인 함수 안에는 아무것도 없고 처음 보는 QCoreApplication 하나가 선언되어 있다. 한번 실행 해보자. 실행은 좌측 하단의 녹색 버튼을 클릭하면 된다.

 

자 기대했던것이 나왔는가? 기대했던 Hello World 글자는? 아싸 소스 코드를 보면 알겠지만 Hello World를 출력하는 코드가 없다. QCoreApplication은 Qt 기반의 프로그램을 시작하도록 해주는 객체이고 현재 프로그램은  a.exec() 함수 안에 머물러 있다. 자 강제로 종료하고 코드를 입력해보자.

 

C++방식으로 Hello World를 출력하도록 하고 실행하면 Hello World를 볼 수 있다.  이제 다른 방식은 어떨까. Qt의 기능을 이용할 수 있으면 좋겠는데.  있다. qDebug 를 이용하는 것이다. 

 

Qt 에서 제공하는 qDebug 기능을 이용하면 Qt가 내부적으로 Console에 출력을 시켜준다. 해당 키워드에 대해 좀더 알고 싶으면 qDebug 에 마우스를 대고 F1키를 누르면 친절할 설명이 나온다.  qDebug외에서 qInfo, qWarn, qFatal, qError 등이 있다. 나는 잘 쓰지 않지만 이렇게 레벨을 걸고 출력을 하도록 한뒤 일정 레벨만 실제 콘솔에 출력하도록 세분화 할 수는 장점이 있다. 

 

이제[ 코드를 좀더 자세히 보자. 전통적인 c++ 프로그램의 main 함수가 호출되면 콘솔창이 생성되고 키입력과 같은 코드를 넣지 않으면 그대로 프로그램이 종료된다. 프로그램을 실행하면 텍스트가 출력되고 Console 창이 그대로 떠 있다. 어떻게 된 걸까? 비밀은 QCoreApplication이 선언되어 있고 exec 함수를 호출함에 의해 가능해진다. QCoreApplication에 마우스를 클릭하고  F1을 눌러 설명을 보자. 

 

이런 설명을 볼수 있다. 즉 UI가 없이 Qt 애플리케이션의 이벤트 루프를 제공한다라고 되어 있다. 좀더 자세히 보기 위해 More를 클릭해 보자.

QCoreApplication은 이벤트 루프를 유지하고 그 이벤트 루프는 exec 함수를 호출하면서 시작된다. 이벤트 루프를 종료하기 위해선 quit 와 같은 함수를 호출했을때 가능하다라고 되어있지만. console 환경에서는 창을 강제 종료해야만 종료할 수 있다.  설명을 보면 signal / slot 이란 용어가 나온다. Qt 메커니즘의 가장 중요한 개념인 Sinal / Slot에 대해 알아보자.

Qt Creator 를 실행 후 New Project 를 실행하면 아래 창을 볼수 있다.

먼저 템프릿을 첫번째인 Application(Qt)를 클릭하면 두개의 템플릿을 볼 수 있다. 나는 Widget를 다루지 않을 것이므로 간단히 콘솔기반인 두번째를 선택하여 Qt 의 핵심적이 부분에 대해서 설명할 것이다.

두번째를 선택하면 Quick 버전에 따라 창의 구성이 조금씩 달라지긴 하지만 대동 소이하다. 전부 QML을 이용한 것이고 Empty 프로젝트에 추가적인 기능을 보완한것이다. 이 정리에서 기본적인 부분을 위해 Console과 Empty 프로젝트만으로 설명하고 실무적인 부분을 설명할때 다시 추가적인 Template에 대해 설명하겠다.

  • 무엇을 정리할 것이가?

먼저 이 게시물을 클릭했다면 Qt 가 뭔지 정도는 알고 있을 것이므로 특별히 QT의 역사나 용도에 대해서는 설명하지 않겠다. 이 정리(혹은 강좌)를 통해 먼저 QML 이전에 Qt 에 대해 전반적으로 정리한 후 QML을 짚어간뒤 실무적인 부분에 생겼던 문제들에 대해서 풀어갈 것이다.

 

Qt를 이용하여 GUI를 구성하는 또다른 방법인 Widget은 다루지 않는다. 이 부분에서 한가지 이야기 하고 싶은것은 몇몇 Qt 관련 글에서 QML은  GUI가 터치 스크린을 사용하고 그래픽 효과를 많이 사용하는 안드로이드나 iOS와 같은 경우 적합하고 데스크탑에서는 C++의 Widget 방식이 더 효율적이라고 평하는 것을 보았다. 사실 전혀 동의하기 어려운게 적어도 데스크탑 개발을 하는 환경에서는 QML이 생산성면에서 그리고 GUI의 유연함에서 Widget과 비교할 바가 안된다. C#의 WPF를 보듯이 보다 진보한 GUI Toolkit은 모든 QML 과 같은 선언적 언어를 이용하고 있음 보면 알 수 있을 것이다. 

QT로 개발을 시작할 때 Widget 과 QML을 고민한다면 그냥 QML을 해라. 그것이 미래다. 아니 현재다. 학습곡선이 좀더 높다고 할 수 있지만 그래봐야 GUI Toolkit 하나 익히는 정도의 학습곡선일  뿐이다. 나중에 피눈물 흘리지 말고 그냥 QML 로 가라.

피씨의 성능이 나쁘면 Widget이 더 좋다던데요? 그 피씨의 성능 나쁘다는 기준이 한 15년전 아톰(?) 피씨 기준일 것이다. 생각해보면 황당하지 않은가 QML은 안드로이드에 적합하다더니, 아무리 후진 피씨도 안도로이드 기반보다는 몇배 이상의 성능 우위를 가질텐데 뭔가 앞뒤가 맞지 않는다. 한번 물어 봐라 QML로 문제가 될만한 피씨 사양은 어느정도인가요? 아마 어버버 할 것이다. 그리고 솔직한 사람이라면 전 위젯만 해봐서 잘 모릅니다 하겠지.

프로그램 시작할 때 좀 더 느리게 뜬다는 데요? 그거 빠르게 할 방법도 있고. 그거 약간 빠르게 하자고  Widget을 써봐야 다시 이야기 하지만 생산성면에서 비교가 안된다. 강조한다. QT를 이용하여 개발을 시작한다면 고민하지 말고 QML로 GUI를 구현하라

좀 강하게 이야기 하는 이유는 C#으로 GUI 을 구현하는 방식은 Winform 과 WPF 가 있는데 이 둘중 어떤것으로 개발해야 할까요 할때 지겹게 나오는 이유가 간단한 것을 개발하거나 성능이 떨어지는 피씨일때는 Winform이 낫습니다 라고 말하는 많이 본다는 것이다.  일단 두 프레임웍에 모두 익숙하다는 전제하에 간단한 것을 개발할때는 둘다 크게 차이가 없다. 반면 복잡한 것을 구현할때는  Winform은 불가능에 가까운 경우가 대부분이다. Winform 은 Window base control에 기반하고 있기 때문이다. 간단한 체크 박스  크기 하나 크게 만들려고 해서 별 괴랄한 방식을 써야한다. 성능 이슈도 QML과 마찬가지로 한 10년은 훌쩍 넘은 피씨가 아니라면 문제가 되지 않는다. 매번 성능나쁜  피씨 타령해서 물어보면 자기도 그렇게 들었다는게 다였다. 그리고 대개 그렇게 이야기 말했던 분들은 Winform을 오래 써와서 매우 익숙한 상태에서 WPF는 배우고 있거나 WPF의 선언적 프로그래밍 방식에 거부감이 있는 경우였다. 좀 이야기가 옆으로 셋지만 QT로 개발하려면 QML을 C#으로 개발하려면 WPF를 해라. 끝!

 

  • QT Version 과 개발환경.

2021년 5월 현재 QT는 중대한 메이저 버전이 변경되었다. 8년간의 QT5의 시대가 끝나고 QT6가 출시 되었다. 아직은 QT5로 개발해야할 일이 많은 것이므로 QT5으로 정리하고  QT5와 QT6의 차이와 마이그레이션에 대해서는 추가로 정리해보겠다.(나도 아직 모름. 공부하고 정리하겠다는 의미^^)

Qt 사이트에서 오픈 소스버전으로 5.13 이후 버전으로 받으면 이 정리를 읽으면서 따라 해보는데 어려움이 없을 것이다. 사이트 찾고 다운 받는 것은 무수히 많은 사이트에서 알려주고 있으니 다시 반복하진 않겠다. 나는 현재 5.13.0 버전과 6.1 버전 두가지를 다운 받았으며 5.13을 실무에서 활용중이고 6.1은 개인적 학습을 위한 것이다.(아까 나중에 마이그레이션 알려준다고 했으니 공부 따로 해야겠지)

 

나는 개발할때 Visual Studio를 이용하지만 정리는 Qt Creator를 이용할 것이다. Qt Creator와 Visual Studio 를 혼횽해서  사용하는 방식에 대해서도 별도 게시물로 정리하겠다. 

 

  • 독자 수준

나두 실무에서 필요한 부분만 쓰다가 한번 전반적으로 정리를 하고자 함이니 혹시나 이문서를 읽는 분들은 다음과 같다고 가정한다.

- C++, Modern C++에 대해 기본적으로 알고 있어 C++문법, 자료구조등을 알고 있어야 한다.

- 영어로 된 기술 개발 문서를 읽고 해독할 수 있어야 한다.

 

각종 사이트의 게시판에서 흥하는 곳중 1, 2위를 다투는 것이 아마도 자유 게시판이나 Q/A 게시판일 것이다. 나도 질문을 하기도 하고 질문에 답을 주기도 하지만 인상이 써지는 답변을 볼 경우가 많다. 물론 질문도 문제가 있는 경우도 있지만 그건 여기서는 논외로 하고 대표적으로 불쾌한 스타일로 아래 두가지를 꼽을 수 있겠다.

 

1. 질문을 극단화 하는 경우.

Q: 카메라 렌즈를 사려고 하는데 두개의 렌즈중에 고민중이어서 두 렌즈중 어떤것이 해상력이 좋은가요?

A: 세상에나! 렌즈에서 해상력이 중요 요소는 아니에요. 아직 초보라서 잘 모르셔서 해상력에만 목숨을 거는데 사실 중요한 것은 블라 블라 블라~~~. 

 

* 누가 해상력에 목숨건다고 물었나. 그냥 둘중 어떤것이 해상력이 좋은지 물어본거지. 그나마 답변이나 해주고 조언하면 좋겠지만 질문은 어디가고 갑자기 근원(?)적인 문제로 들어가면서 지들 끼리 치고 박고 싸운다.

 

2. 질문을 개인적인 공격으로 받아들이는 경우.

Q: A사 폰을 만족스럽게 쓰고 좋은데요 차기 버전 출시는 언제쯤일까요?

A: B사 폰 쓰는데 그건 문제라는 것 같아 기분 나쁘네요... A사 알바 아닌가요? 블라블라블라.

 

* 니껀 니꺼대로 좋겠지. 니꺼 쓰는걸 누가 뭐라고 했냐? 있지도 않던 B사 까가 되고 싶네 그랴

 

결론

답변을 할 생각이라면 물어본것에 대한 것만 답변을 주자. 아니면 그냥 패스하시길.

 

 

 

 

Do C++17을 지원하도록 각 프로젝트의 속성에서 아래와 같이 옵션을 추가하라.

/await /std:c++latest

'Language & Toolkit > C++' 카테고리의 다른 글

STL container - other containers  (0) 2019.03.10
STL container - std::list  (0) 2019.03.10
STL container - std::queue & stack  (0) 2019.03.10
STL container - std::map & set  (0) 2019.03.10
STL container - std::vector  (0) 2019.03.09

multi-set

중복 키를 허용하지만 요소를 수정할 수 없다.


multi-map

중복 키를 허용한다.


deque

Double Ended queue로 양쪽 끝에서 삽입 삭제를 허용한다.


priority-queue

자동으로 정렬되는 큐이다.

'Language & Toolkit > C++' 카테고리의 다른 글

visual studio 에서 c++17 지원  (0) 2019.05.03
STL container - std::list  (0) 2019.03.10
STL container - std::queue & stack  (0) 2019.03.10
STL container - std::map & set  (0) 2019.03.10
STL container - std::vector  (0) 2019.03.09

1. std::list 기초

양방향 연결리스트(Double Linked List)로 양쪽 끝에서 삽입 삭제가 가능하다. 따라서 reserver 같은 함수가 있을 수 없다.

operator[] 를 정의할 수 없다.

삽입과 제거에 어디든 가능하고 걸리는 시간이 상수다.


iterator insert(iterator position, const value_type& value)

position 이 가리키는 위치에 삽입.


void push_front(const value_type& value)

처음에 요소 삽입


void push_back(const value_type& value)

마지막에 요소 삽입


void pop_front()

첫번째 요소 삭제


void pop_back()

마지막 요소 삭제


iterator erase(iterator position)

position이 가리키는 요소 삭제


void remove(const value_type& value)

요소와 같은 값을 전부 삭제





'Language & Toolkit > C++' 카테고리의 다른 글

visual studio 에서 c++17 지원  (0) 2019.05.03
STL container - other containers  (0) 2019.03.10
STL container - std::queue & stack  (0) 2019.03.10
STL container - std::map & set  (0) 2019.03.10
STL container - std::vector  (0) 2019.03.09

+ Recent posts