GUI(QT) Programming
QT란 무엇인가?
- 리눅스나 유닉스에서 X-Window용 프로그램을 개발하려면 많은 지식이 필요하다.
- 다음과 같은 특징이 있다.
- C++ 기반 - 고급 언어들에 비해 어느정도 속도도 나오고, C에 비하면 좀더 모듈화가 되어 있어 확장이 용이
- 객체지향 - 라이브러리들이 모듈화가 잘 되어 있음
- 멀티플랫폼 - 다양한 플랫폼을 지원하고, 플랫폼이 바뀐다고 해서 전체를 싹 갈아엎지 않아도 된다.
- 시그널 & 슬롯 - 이벤트 처리 모델이 정형화되어 있다. 즉, 시그널 & 슬롯만 알면 콜백함수 등 실수할 여지가 줄어든다.
- Internationalization - 16비트 유니코드 완벽지원.
- API - 200개가 넘는 클래스를 지원한다. 웬만한 프로그램은 QT 안에 있는 라이브러리들로 해결 가능.
- 안정성 - 기업 베이스다. 개발은 아무나 할 수 있지만 커밋은 기업 내에서 이루어진다. 일반적으로 산으로 가는 프로젝트를 만들지 않는다.
QT 프로그램 구경하기
- Youtube : https://www.youtube.com/watch?v=VsT1yKRKkXE&list=PLumkkj1MBmYs-WArrEkw2R6wO9Agj3FoX
- QT 프로그램은 Ubuntu의 경우 소프트웨어센터에서 설치할 수 있다.
- 새 프로젝트(New Project)를 선택하면 다음과 같은 화면이 나온다.
- 위젯 어플리케이션을 선택하면 다음과 같은 화면이 나온다.
- 프로젝트 이름을 정하고 컴파일 키트를 선택한다.
- 프로젝트 이름은 임의로 작성하고, 컴파일 키트는 기본 옵션으로 설정하면 된다.
- 클래스 설정 화면은 다음과 같다.
- Base Class를 다음과 같이 QDialog로 변경한다.
- Github 등을 사용한다면 본인 계정 등을 설정하도록 한다. 이 내용은 QT/Github 항목을 참조.
- 여기서는 그냥 버전컨트롤 없이 진행해도 상관없다.
- Form에 *.ui 를 더블클릭하여 선택하면 다음과 같이 디자이너 모드로 변경된다.
- 어디서 많이 보던것 같지 않은가? Visual Studio의 편집 화면과 비슷하다. Microsoft Visual Studio를 사용해본 경험이 있다면 거의 비슷하게 사용할 수 있다.
- 자, 이제 버튼과 텍스트박스를 집어넣어봅시다.
- 왼쪽에 있는 컴포넌트에서 드래그해서 넣을 수 있다.
- PushButton의 이름을 바꾸는건 간단하다. PushButton 항목을 선택하고, 오른쪽 속성창의 값을 변경해주면 끝.
- 화면 구성을 했으니 버튼에 이벤트를 넣어봅시다.
- 인사하기에서 우클릭을 하고 Go to Slot을 선택합니다.
- Go to Slot을 선택하면 다음과 같은 내용이 나옵니다.
- Clicked를 선택하면 코드 입력 부분이 나오는데, 다음과 같이 입력합니다.
<source lang="c"> ui->lineEdit->setText("Hello World"); </source>
- 지우기 부분 코드
<source lang="c"> ui->lineEdit->setText(""); </source>
- 종료하기 부분 코드
<source lang="c"> this.close(); </source>
기본 문법
변수와 상수 사용하기
- Youtube : https://www.youtube.com/watch?v=tHzPBCUi0G8&list=PLumkkj1MBmYs-WArrEkw2R6wO9Agj3FoX
- 변수는 프로그램 내에서 수시로 값이 (변)할수 있는 (수)를 말합니다. 반면에 상수는 항(상) 같은 값을 유지하는 (수)를 말하는거죠.
- 프로젝트를 하나 만들고 시작해 보겠습니다.
- C++의 경우 변수를 사용하기 위해서는 선언을 해야 합니다. 일반적으로 헤더파일에 선언을 하죠. 여기서는 data라는 변수를 추가해 보겠습니다.
- 또한, 값을 확인하기 위한 디버그 모듈을 사용할 것입니다.
- 헤더에 QDebug를 사용한다고 선언하고, 정수형 data를 미리 선언합니다.
- 그리고, 다이얼로그가 열릴 때 처리될 수 있도록 다음과 같이 코드를 넣어주면 됩니다.
- qDebug() 함수를 사용할 때, 앞에 q는 소문자임에 유의해 주세요. qDebug() 함수는 c++의 cout과 같은 기능을 한다고 보시면 됩니다.
- 실행하면 아래 디버그 창에 값이 출력되는걸 확인할 수 있습니다.
- 여기서 사용된 data는 사용자가 임의로 만들 수 있는 변수입니다. 변수는 프로그램 내에서 숫자나 문자 등을 보관하는 역할을 합니다.
- 변수는 필요에 따라 얼마든지 만들어 사용할 수 있습니다.
- = 기호는 수학의 등호가 아닙니다. 오른쪽의 값을 왼쪽의 변수에 기억시키는 (또는 할당하는) 연산자입니다.
- 위의 프로그램에서 data 변수는 처음에 100을 기억했다가 다시 200을 기억합니다.
- 이와 같이 변수는 다른 값을 가질 수 있습니다. 그래서 변수입니다.
- 그에 반해 100이나 200같은 숫자는 상수라고 합니다. 이 숫자들은 프로그램이 아무리 실행되어도 항상 100과 200을 유지합니다. 그래서 상수입니다.
- 이제 여러가지 형식의 변수를 선언하고 이용해보도록 하겠습니다.
파일:Qt 1 pro 3.png 파일:Qt 1 pro 4.png
- 정수형 변수 dataint는 정수를 기억합니다. 컴퓨터가 가장 빠른 연산을 할 수 있는 데이터형입니다.
- 실수형 변수 datadou는 소수점 이하의 수를 기억합니다. 내부적으로는 지수 형태로 기억하지만, 일반적으로 소숫점이 있는 수를 저장할 때 많이 사용합니다.
- 논리형 변수 databoo는 true와 false 논리 상수를 기억합니다. 일반적으로 flag같은 값을 많이들 저장합니다.
- 문자열형 변수 datastr은 할당할 문자열을 반드시 겹따옴표 사이에 기술해야 합니다. 문자열은 문자의 집합을 의미합니다.
- 변수의 종류를 말할 때 위와 같이 데이터형에 따라 정수형 변수, 실수형 변수, 문자열형 변수, ...와 같이 구분합니다. 근데 또 다른 관점에서 구분하는 경우도 있습니다.
- 변수가 영향을 미치는 유효 범위에 따라 다음과 같이 구분하기도 합니다.
- 프로시져 변수 - 프로시져(중괄호{}) 내부에 선언된 변수. 프로시져 안에서만 쓸 수 있다. 보통 지역변수라고들 많이 이야기한다.
- 모듈 변수 - 모듈(파일) 내부에 선언된 변수. 그 파일 안에서만 쓸 수 있다.
- 전역 변수 - 헤더파일에 Public으로 선언한 변수. 다른 모듈에서도 갖다 쓸 수 있다.
- 정적 변수 - 프로시져 내부에 Static으로 선언하는 변수. 프로시져가 종료되어도 값을 유지한다.
- 이에 대해 알아보기 위해 간단하게 프로그램을 하나 작성해보도록 하겠습니다.
파일:Qt 1 pro 5.png 파일:Qt 1 pro 6.png
- 위와 같이 해놓으면 에러가 발생할 것입니다.
- 이를 어떻게 해결하냐면, 이걸 헤더 내에 모듈 변수로 선언을 하면 됩니다.
- 실행해보면 제대로 출력되는걸 볼 수 있을겁니다.
파일:Qt 1 pro 7.png 파일:Qt 1 pro 8.png
- const라는 게 있습니다.
- 상수를 변수처럼 사용할 수 있게 만들어 주는거죠.
- 예를 들어, 파이값같은걸 쓴다치면, 계속 3.1415926이라는 값을 입력하면 귀찮으니, pi라는 변수처럼 생긴 놈 안에다가 그 값을 넣어두는 겁니다.
- const 선언을 하게 되면, 그 값을 바꿀 수 없습니다. Ansi-C에서는 #define이라는 전처리기(Preprocessor)를 사용했었는데, C++ 계열에서는 거의 대부분 const로 해결합니다. 이해도 쉽고, const를 쓰는게 좋습니다.
파일:Qt 1 pro 9 .png 파일:Qt 1 pro 10 .png
연산자
- 다음과 같이 연산자를 사용할 수 있다.
<source lang="c"> int data1; int data2;
data1 = 10; data2 = 3;
// 산술 연산 qDebug() << "data1 + data2 = " << data1 + data2; qDebug() << "data1 - data2 = " << data1 - data2; qDebug() << "data1 * data2 = " << data1 * data2; qDebug() << "data1 / data2 = " << data1 / data2; qDebug() << "data1 % data2 = " << data1 % data2;
// 논리 연산 qDebug() << QString("(data1 < 11) && (data2 > 2) = %1").arg((data1 < 11) && (data2 > 2)); qDebug() << QString("(data1 < 11) || (data2 < 2) = %1").arg((data1 < 11) || (data2 < 2)); qDebug() << QString("!(data1 < 11) = %1").arg(!(data1 < 11)); </source>
조건문
- Youtube : https://www.youtube.com/watch?v=b-mylI0gTY8
- if는 다음과 같이 사용할 수 있습니다.
<source lang="c"> if(조건식) { 명령문; } </source>
- 1개의 조건문 예시
<source lang="c"> int jumsu;
jumsu = 50;
if(jumsu < 60) {
qDebug() << "낙제입니다"; qDebug() << "재수강 신청하세요"; qDebug() << "마감일은 12월 20일입니다";
} else {
qDebug() << "낙제가 아닙니다"; qDebug() << "재수강 신청하지 마세요"; qDebug() << "마감일 신경쓰지 마세요";
} qDebug() << "점수는 " << jumsu << "점 입니다."; </source>
- elseif 예시
<source lang="c"> int jumsu;
jumsu = 50;
if(jumsu >= 90) {
qDebug() << "A 학점입니다.";
} else if(jumsu >= 80) {
qDebug() << "B 학점입니다.";
} else if(jumsu >= 70) {
qDebug() << "C 학점입니다.";
} else if(jumsu >= 60) {
qDebug() << "D 학점입니다.";
} else // elseif가 아님 {
qDebug() << "F 학점입니다.";
} </source>
- switch 문은 일반적으로 enum과 함께 쓰입니다.
<source lang="c"> enum weekday {
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
};
int today, yesterday;
today = Saturday;
yesterday = today -1;
switch(yesterday) {
case Friday:
case Saturday: qDebug() << "Burning"; break;
case Monday: qDebug() << "What the Hell"; break;
default:
qDebug("Groomy Working Day");
} </source>
- enum은 위와 같이 사용합니다. 자세한 사용법은 구글님께.
반복문
- for는 다음과 같이 사용합니다.
<source lang="c"> for(변수 = 초기값; 최종값에 대한 식; 변수를 어떻게 증감할건지) {
명령문들;
} </source>
- 예제를 하나 보도록 하죠.
<source lang="c"> for(int i = 0; i < 10; i++) {
res += i; qDebug() << i << "까지의 합은 " << res << "입니다.";
} </source>
- do~while문은 다음과 같이 사용합니다.
<source lang="c"> do {
명령문들;
} while (최종값에 대한 식); </source>
- 이것도 역시 예제를 위의 for와 같은걸 해보도록 하죠.
<source lang="c"> int i = 0; // 이처럼 변수 선언을 하면서 초기값을 설정할 수 있습니다. do {
i++; res += i; qDebug() << i << "까지의 합은 " << res << "입니다.";
} while (i < 3); </source>
- 자, for문과 do~while문의 차이점은 뭘까요?
- for는 괄호 안에 모든 내용을 다 집어넣었지요? 사람들은 반복문을 사용할 때 for를 더 많이 사용하는 이유가 있지요.
- for는 루프 내에서만 사용되는 변수를 지정할 수 있습니다. while은 미리 변수를 선언해야 하고요.
- while은 또 한가지 유의할 점이 있습니다. *무조건* 한번은 프로시져가 실행된다는 점이죠.
배열
- 프로그램에서 데이터를 임시로 저장하기 위해서 변수를 사용한다는건 아실겁니다.
- 그런데 변수중에 '배열'이라는걸 들어보셨을거에요.그걸 왜 쓰는지 궁금하실겁니다.
- 일단 '배열'이라는건 같은 데이터 타입을 가지는 변수의 '집단'이라고 할 수 있습니다.
- 예를 들어 10개의 과목에 대한 점수를 기억하려면 다음과 같이 10개의 정수형 변수가 필요할 것입니다.
<source lang="c"> int score1; int score2; int score3; int score4; int score5; int score6; int score7; int score8; int score9; int score10; </source>
- 보세요. 보기만 해도 선언도 귀찮고 기억하기도 힘들겠죠?
- 근데, 이걸 100명분을 작성한다고 칩시다.
- 이럴땐 다음과 같이 배열로 하면 좀더 쉽게 작성할 수 있습니다.
<source lang="c"> 타입 변수명[갯수]; </source>
- 예제를 하나 보죠.
<source lang="c"> int score[100]; </source>
- 이런식으로 사용합니다. 다음은 1부터 10까지 돌면서 해당 값에 2를 곱해서 저장하는 프로그램입니다.
<source lang="c"> int score[10]; for(int i = 0; i < 10; i++) {
score[i] = i * 2; qDebug() << "i = " << score[i];
} </source>
- 실행 결과는 다음과 같을 것입니다.
- 이걸 보고 이상하다는 생각이 들지 않나요?
- 컴퓨터한테는 첫번째 숫자가 1이 아니라 0입니다.
- 이걸 1부터 시작해서 10으로 끝나게 만들려면 어떻게 해야 할까요? 한번 고민해보고 만들어보시기 바랍니다. :)
동적 배열
- 그런데 배열의ㅈㅈ습니다. (이거 뭐라고 하는지 모르겠으니 수정해주시면 감사하겠습니다.)
<source lang="c"> int* 변수이름 = new 타입[갯수]; </source>
- 타입 뒤에 *가 들어갑니다. 중요합니다.
- 또한, 할당하고 나서 다음과 같이 꼭 해제를 해줘야 합니다.
<source lang="c"> delete[] 변수이름; </source>
- 요즘 인기있는 언어들이 Garbage Collector를 포함하며, 인터프리터를 지향하고 있는 이유는 해제할 타이밍이 애매한 경우가 많아서입니다.
- 하지만, 조금 크게 메모리를 할당하거나 하는 방법으로 메모리 해제 타이밍을 잡을 수 있습니다.
- 또한 QT에서는 QT 데이터타입을 사용하면 내부적으로 Garbage Collector를 적용한다고 합니다.
- 아무튼 예제를 하나 보도록 하겠습니다. 마찬가지로 위와 같은 프로그램입니다.
<source lang="c"> int* score = new int[10]; for(int i = 0; i < 10; i++) {
score[i] = i * 2; qDebug() << "i = " << score[i];
} </source>
다차원배열
- 지금까지 본건 1차원 배열입니다.
- QT를 컴파일하는 gcc의 경우 10차원이 넘는 배열을 선언할 수 있습니다.
- 간단한 프로그램을 작성해 봅시다.
<source lang="c"> int data[3][5]; for(int i = 0; i < 3; i++) {
for(int j = 0; j < 5; j++)
{
data[i][j] = i * j;
qDebug() << i << "*" << "j" << "=" << data[i][j];
}
} </source>
- 대충 무슨 프로그램인지 보이시지요?
- 자 이걸 구구단으로 바꿔보세요.
구조체
- 구조체는 다음과 같이 사용합니다.
<source lang="c"> struct { }; </source>
함수
GUI 기초 및 응용
컨트롤
파일:Layouts.png파일:Spacers.png파일:Buttons.png파일:Item Views.png파일:Item Widget.png파일:Containers.png파일:Input Widget.png파일:Display Widget.png
프로그램을 작성하는 순서
- 일반적으로 프로그램은 다음과 같은 순서로 작성합니다.
- GUI 구상 - 어떤 GUI를 만들 것인지 구상합니다.
- 객체 배치 - 컨트롤을 사용하여 객체들을 폼 위에 배치합니다.
- 속성 조절 - 속성창에서 조절할 필요가 있는 속성들을 지정합니다.
- 슬롯 선택 - 객체별로 필요한 슬롯을 선택하고 코딩을 합니다. 이때 프로그램에서 제어할 필요가 있는 속성은 객체->속성으로 지정하고, 객체->메소드나 함수, 명령문을 사용하여 객체의 이벤트를 완성합니다.
- 디버깅 - 실행을 하고 에러가 있으면 수정을 해서 다시 실행합니다.
- 물론 이것이 정석적인 방법이라고 볼 수는 없겠습니다만, 일반적인 취향이라고 볼 수 있겠습니다.
컨트롤을 쉽게 배치하는 방법
- 폼 위에 객체를 그리다 보면 동일한 객체를 여러개 그려야 하는 경우가 많습니다. 이들의 크기나 위치등을 하나씩 배치할수도 있겠으나, 우리는 도구를 쓰도록 합시다.
파일:Qt 2 gui 0.png 파일:Qt 2 gui 1.png 파일:Qt 2 gui 2.png p;;;;;
QPushButton 컨트롤 사용하기
- 버튼입니다. 프로그램 만들면 많이들 사용하는 컨트롤이죠.
- 이 버튼은 대개 누르면 작업이 실행되게 하는 용도로 사용되죠.
- Enabled라는 속성에 대해 좀 중점적으로 보시면 좋을듯 합니다.
- 다음과 같은 프로그램을 만들어봅시다.
- QPushButton 3개와 QLabel 1개를 배치해 봅시다.
- 그리고 QPushButton에 Clicked 슬롯을 만들고 다음과 같이 작성해 줍니다.
<source lang="c"> void Dialog::on_pushButton_clicked() {
ui->label->setText("하드웨어 지원 최강");
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(true);
}
void Dialog::on_pushButton_2_clicked() {
ui->label->setText("유저가 최강");
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
ui->pushButton_3->setEnabled(true);
}
void Dialog::on_pushButton_3_clicked() {
ui->label->setText("스타벅스 가냐?");
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(false);
} </source>
- 유의할 점은 void Dialog::on_pushButton_clicked() <- 이 부분은 직접 코딩하는게 아닙니다!!
- 슬롯을 전부 만드시고 위와 같이 코드를 작성하셨다면 누른 버튼이 비활성화되는게 보이실겁니다.
QLineEdit 컨트롤 사용하기
- 주로 주관식 데이터를 입력하기 위해 많이 사용하는 LineEdit 컨트롤을 지정해 봅시다.
- 성적을 계산하는 프로그램인데, 텍스트상자를 이용해서 이름과 점수를 입력합니다.
- 다음과 같은 프로그램을 만들 것입니다.
- Grid Layout을 이용하면 의외로 간단하게 화면 구성이 가능합니다.
- 다음과 같이 그리드 레이아웃을 만들고 왼쪽에는 Label을, 오른쪽에는 LineEdit를 드래그해서 집어넣습니다.
파일:Qt 2 drag drop 0.png 파일:Qt 2 drag drop 1.png 파일:Qt 2 drag drop 2.png
- 그리고 버튼도 Horizontal Layout을 이용하면 쉽게 배열이 가능합니다.
- 레이블과 버튼, 라인에디트를 배열하고 각각 속성에서 제목을 적어줍니다.
- 헤더파일에 QDebug를 include하고, 다음과 같이 변수를 선언해 줍니다.
<source lang="c"> QString name; int kor; int eng; int math;
int total; int avg; </source>
- 각 버튼의 코드는 다음과 같습니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
name = ui->lineEdit->text(); kor = ui->lineEdit_2->text().toInt(); eng = ui->lineEdit_3->text().toInt(); math = ui->lineEdit_4->text().toInt(); total = kor + eng + math; avg = total /3; qDebug() << "이름 국어 영어 수학 총점 평균"; qDebug() << name << " " << kor << " " << eng << " " << math << " " << total << " " << avg;
}
void Widget::on_pushButton_2_clicked() {
this->close();
} </source>
- 실제 입력에 따라 다음과 같이 결과가 출력되는걸 볼 수 있습니다.
결과 나오는 화면 파일:Qt App 2 Result.png
QCheckBox 컨트롤 사용하기
- 체크박스는 체크 표시된 항목을 선택하는 기능을 제공합니다.
- 아마도 웹사이트에서 많이 보셨을겁니다.
- 이것의 특징은, 라디오버튼과 달리 여러개의 항목을 동시에 선택할 수 있다는 겁니다.
- 남자가 결혼하기 전에 사야 할 물품을 정리해 보았습니다.
- 폼에 판매 품목과 가격을 체크상자로 표시하고, 소비자가 상자를 선택하고 총액계산 버튼을 누르면 텍스트 상자에 총액이 표시되도록 하는것이 목표입니다.
실행 화면
- 헤더에 변수를 하나 선언합니다.
<source lang="c"> int sum; </source>
- 위 폼은 쉽게 만들 수 있을것이라 생각하고, 각 버튼의 코드는 다음과 같습니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
sum = 0;
if(ui->checkBox->isChecked())
sum += 650000;
if(ui->checkBox_2->isChecked())
sum += 550000;
if(ui->checkBox_3->isChecked())
sum += 150000;
if(ui->checkBox_4->isChecked())
sum += 250000;
ui->lineEdit->setText(QString::number(sum));
}
void Widget::on_pushButton_2_clicked() {
ui->checkBox->setChecked(false);
ui->checkBox_2->setChecked(false);
ui->checkBox_3->setChecked(false);
ui->checkBox_4->setChecked(false);
ui->lineEdit->setText("");
} </source>
- 체크버튼을 누르면 바로 적용되도록 만들 수 있을 것입니다.
- 이건 직접 해보시는게 어떨까요?
QRadioButton 컨트롤 사용하기
- 라디오버튼은 옵션 버튼이라고도 합니다.
- 체크 상자와 비슷하게 항목을 선택할 때 사용되지만, 옵션 버튼은 여러개 중에서 한개만 선택할 수 있는데에 많이 사용됩니다.
- 체크버튼가지고도 코드 부분을 좀 수정하면 라디오버튼과 같은 동작을 하게 만들수 있습니다.
- 특정 버튼을 선택했다가 다른 버튼을 선택하면 이전에 선택했던 버튼의 체크표시는 지워집니다.
- 아래 프로그램을 한번 만들어 보도록 하겠습니다. 라디오버튼과 체크버튼을 같이 쓰니까 비교하기가 쉬울겁니다.
- 자신의 연령대를 선택하고 연애인을 선택한 후 결과보기 버튼을 누르면 텍스트 상자에 결과가 표시됩니다.
- 다시보기 버튼을 누르면 내용이 싹 지워져서 새로 선택하기 편하도록 편의성을 높였습니다.
- 헤더에 추가할 코드는 다음과 같습니다.
<source lang="c"> QString age; QString singer; </source>
- 소스코드에 추가할 내용입니다. PushButton에 슬롯으로 작성하는건 이제 다들 익숙해지셨으리라 생각합니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
singer = "";
if(ui->radioButton->isChecked())
age = "10대";
if(ui->radioButton_2->isChecked())
age = "20대";
if(ui->radioButton_3->isChecked())
age = "30대";
if(ui->radioButton_4->isChecked())
age = "40대";
if(ui->radioButton_5->isChecked())
age = "외계인";
if(ui->checkBox->isChecked())
singer += "소녀시대 ";
if(ui->checkBox_2->isChecked())
singer += "2ne1 ";
if(ui->checkBox_3->isChecked())
singer += "이선희 ";
if(ui->checkBox_4->isChecked())
singer += "걸스데이 ";
if(ui->checkBox_5->isChecked())
singer += "EXO ";
ui->lineEdit->setText(age + "인 당신은 " + singer +"를 좋아하네요.");
}
void Widget::on_pushButton_2_clicked() {
ui->radioButton->setChecked(false);
ui->radioButton_2->setChecked(false);
ui->radioButton_3->setChecked(false);
ui->radioButton_4->setChecked(false);
ui->radioButton_5->setChecked(false);
ui->checkBox->setChecked(false);
ui->checkBox_2->setChecked(false);
ui->checkBox_3->setChecked(false);
ui->checkBox_4->setChecked(false);
ui->checkBox_5->setChecked(false);
ui->lineEdit->setText("");
} </source>
QGroupBox
- 그룹박스는 다른 객체들을 묶는 역할을 합니다.
- 다른 여러 프로그램상에서 많이들 보셨을겁니다.
- 이건 말보다 프로그램을 직접 보시는게 나을듯.
실행화면
- 보시면 2개의 그룹박스를 사용하고 있습니다.
- PC 보유현황과 주변장치현황이 프레임입니다.
- 나머지 내용은 위의 QRadiobutton강좌와 같다고 보시면 됩니다.
- 헤더에는 변수를 선언해 줍니다.
<source lang="c"> QString com; QString phr; </source>
- 다음은 버튼에 관한 코드입니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
phr = "";
if(ui->radioButton->isChecked())
com = ui->radioButton->text();
if(ui->radioButton_2->isChecked())
com = ui->radioButton_2->text();
if(ui->radioButton_3->isChecked())
com = ui->radioButton_3->text();
if(ui->radioButton_4->isChecked())
com = ui->radioButton_4->text();
if(ui->checkBox->isChecked())
phr += ui->checkBox->text();
if(ui->checkBox_2->isChecked())
phr += ui->checkBox_2->text();
if(ui->checkBox_3->isChecked())
phr += ui->checkBox_3->text();
if(ui->checkBox_4->isChecked())
phr += ui->checkBox_4->text();
ui->lineEdit->setText("당신은 " + com + "컴퓨터와 " + phr + "주변장치를 보유중입니다.");
} </source>
QListWidget
- ListWidget 컨트롤은 상자 안에 항목들을 나열하는 기능을 제공합니다.
- 이거랑 ComboBoxWidget이 목록을 제공하는 대표적인 컨트롤입니다.
- ListWidget은 여러개의 항목 선택을 할 수 있도록 되어 있으며, Shift나 Ctrl등을 이용해서 선택할 수 있도록 되어 있습니다.
- 코드는 매우 간단합니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
ui->listWidget->addItem(ui->lineEdit->text());
ui->lineEdit->setText("");
} </source>
QComboBox
- 콤보박스 컨트롤은 펼침 목록 기능을 제공합니다.
- 웹사이트를 방문해보면 주소 입력하는데 대부분 이거 씁니다.
- 프로그래밍에서도 종종 씁니다.
- ListWidget과 사용법은 비슷합니다.
결과화면
- 이번에는 버튼을 만들지 않고, 콤보박스의 내용이 변경되는 즉시 반영되도록 해봅시다.
- 슬롯 선택시 다음과 같이 선택하세요.
- 코드는 다음과 같습니다.
<source lang="c"> void Widget::on_comboBox_currentIndexChanged(int index) {
if(index == 0)
{
ui->comboBox_2->clear();
ui->comboBox_2->addItem("연남동");
ui->comboBox_2->addItem("서교동");
ui->comboBox_2->addItem("동교동");
}
if(index == 1)
{
ui->comboBox_2->clear();
ui->comboBox_2->addItem("삼청동");
ui->comboBox_2->addItem("사직동");
ui->comboBox_2->addItem("계동");
}
if(index == 2)
{
ui->comboBox_2->clear();
ui->comboBox_2->addItem("신사동");
ui->comboBox_2->addItem("논현동");
ui->comboBox_2->addItem("도곡동");
}
}
void Widget::on_comboBox_2_currentIndexChanged(int index) {
ui->lineEdit->setText("선택된 주소는 " + ui->comboBox->currentText() + " " + ui->comboBox_2->currentText() + "입니다.");
} </source> Introductions! Invite to SourcingIC.com as well as we are searching for your RFQ or Bom Listing for us to quote.
STM32F412RET6 1000PCS ST 2018+ 2.45 USD LQFP64.
We are Hong Kong distributor of the complying with IC brands for 15 years:.
TOSHIBA. ALTERA. ANALOG DEVICES. TEXAS TOOLS. ST. FAIRCHILD. ATMEL. XILINX. SILICON CHIP. SAMSUNG. ADAGE. NEC. NXP. ON SEMI. PHILIPS. FREESCALE. INFINEON. INTERSIL. DIRECT TECHNOLOGY. MOTOROLA.
I know you might need to discover ICs.
The significant goal for us is sourcing ICs. As you recognize more than 99% ICs available in this planet might be located in China, however it is time-costly to find or send out questions to thousands of distributors or firms one by one to discover that obtained stocks and also get great quote!
Step 1: Skype or email our teammate: sales@sourcingic.com.
Step 2: Inform us component number and the amount or other requirements.
Step 3: I will resource from distributors and our teammate will select the trusted supplier to estimate.
Step 4: Our experienced IC technicans will certainly test the ICs to verify they are genius as well as functioning well.
Tip 5: Well loaded and shipped Welcome for Full Bom Listing query! Payment Technique: Paypal/ Western Uniuon/ TT See you! Best Regards, Sourcing IC To provide every rare ICs
Firm History:
Souring IC Ltd is a Hong Kong based firm with China workplaces in different districts. We provide a large range of electronic elements, focused on IC consisting of Sound IC, Power Administration IC, Consumer Electronic IC, and so on. Our objective is to provide any kind of components which are hard to be sourced in the electronic market, especially the one discountinued by manufacturing facilities. With the aid of latest A.I system as well as the elite teammates we had, we have the ability to resource every ICs that is not commonly utilized by the co-operation with thousands manufacturing facilities as well as companies in China. We have the ability to give the most competitive rate without MOQ.
QTimer
- 타이머는 시간과 관련된 컨트롤입니다.
- 다음과 같이 시계를 만들어 보도록 하겠습니다.
실행화면
- 시계는 코드에 직접 작성해 주어야 합니다.
- 헤더파일에 QTimer와 QDateTime을 include해줍니다.
- QTimer는 타이머고, QDateTime은 현재시각을 받아오기 위해 사용합니다.
- private:에 timer를 하나 선언하고, private slots:에 tupdate() 함수를 등록해 줍니다.
<source lang="c"> private:
QTimer* timer;
private slots:
int tupdate();
</source>
- 프로그램이 실행되면서 타이머가 동작하도록 아래의 코드를 메인 위젯 안에 넣어줍니다.
<source lang="c"> timer = new QTimer(this); // 타이머 생성 connect(timer, SIGNAL(timeout()), this, SLOT(tupdate())); // 타이머가 타임아웃이 되면 tupdate()를 호출 timer->start(1000); // 1000은 밀리세컨드 단위. 타임아웃을 몇 ms로 할것인지 정함. 여기서는 1초마다 한번씩. </source>
- 그리고, tupdate() 함수를 다음과 같이 작성합니다.
<source lang="c"> int Widget::tupdate() {
QDateTime local(QDateTime::currentDateTime()); ui->label_3->setText(local.toString()); return 0;
} </source>
QFileDialog
- 파일 컨트롤은 파일을 선택하거나, 파일을 저장할 때에 많이 사용되는 컨트롤입니다.
- 이건 기본 컨트롤엔 없으나, 사용 빈도가 굉장히 높습니다.
실행화면
- 파일 다이얼로그를 사용하기 위해서는 QFileDialog를 include해야 합니다.
<source lang="c">
- include <QFileDialog>
</source>
- 그리고 버튼에 대한 코드는 다음과 같습니다.
<source lang="c"> void Widget::on_pushButton_clicked() {
QString file = QFileDialog::getOpenFileName(); ui->lineEdit->setText(file);
}
void Widget::on_pushButton_2_clicked() {
this->close();
} </source>
- 파일 컨트롤도 참 쉽죠?
- 속성도 지정할 수 있습니다. png 파일만 연다든지.. 이 부분은 직접 해보세요 :)
QGraphicsView
- GraphicsView는 각종 도형, 텍스트 등을 좀 더 유연하게 사용할 수 있도록 만들어진 Canvas같은 개념의 컨트롤입니다.
- 단독으로는 아무것도 할 수 없고, GraphicsScene과 함께 동작합니다.
- 그림파일을 하나 불러와 보여주는 프로그램을 작성해 보겠습니다.
- 헤더파일의 수정은 다음과 같습니다.
<source lang="c"> // 헤더를 include해줍니다.
- include <QGraphicsScene>
- include <QPixmap>
// private 선언부에 scene 변수를 선언해 둡니다. QGraphicsScene scene; </source>
- 소스코드입니다.
<source lang="c"> // Widget 안 setupUi 이후에 다음과 같은 코드를 삽입합니다.
QPixmap pix("hello.png");
scene.addPixmap(pix);
ui->graphicsView->setScene(&scene);
ui->graphicsView->show();
</source>
- 실행파일과 같은 디렉토리에 hello.png (png 파일 아무거나 넣어보세요)가 있다면 그 그림파일이 출력될 것입니다.
- 과제 : 전에 배운 FileOpenDialog를 이용해서, 파일을 선택해 보여줄 수 있도록 만들어 봅시다.
QTabWidget
- 탭 컨트롤에 대해 알아보겠습니다.
- 보통, 설정같이 내용은 많고, 각각의 성격에 따라 분류하고 싶을 경우 많이들 사용합니다.
- 코드로 작성하기보다는 일반적으로 디자인에서 다 하는 경우가 많습니다.
QProgressBar
- 프로그레스바에 대해 알아보도록 하겠습니다.
- 가짜로 만든 로딩바 입니다.
- 헤더는 다음과 같습니다
<source lang="c"> // QTimer를 include해줍니다
- include <QTimer>
// 함수 정의에 다음과 같이 해줍니다. private:
Ui::Widget *ui; QTimer* timer; int tick;
private slots:
int tupdate();
</source>
- 소스코드는 다음과 같습니다.
<source lang="c"> // setupUi 다음에 넣어줍니다.
timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT(tupdate())); tick = 0; timer->start(10);
// tupdate 함수는 다음과 같습니다. int Widget::tupdate() {
if(tick == 100) ui->label->setText("Loading Complete");
if(tick < 100) tick++;
ui->progressBar->setValue(tick);
} </source>
계산기
- Youtube : https://www.youtube.com/watch?v=3FT3c7mFQFI
- 흔히 집에 하나씩 있는 천원짜리 계산기를 한번 만들어 보도록 하겠습니다.
- 새로운 개념이 추가된 것은 없습니다. 기존에 배운 개념을 활용하여 만들 수 있습니다.
- 소스코드는 아래와 같습니다.
<syntaxhighlight lang="c"> void Widget::on_pushButton_1_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "1");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "1");
}
}
void Widget::on_pushButton_2_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "2");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "2");
}
}
void Widget::on_pushButton_3_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "3");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "3");
}
}
void Widget::on_pushButton_4_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "4");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "4");
}
}
void Widget::on_pushButton_5_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "5");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "5");
}
}
void Widget::on_pushButton_6_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "6");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "6");
}
}
void Widget::on_pushButton_7_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "7");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "7");
}
}
void Widget::on_pushButton_8_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "8");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "8");
}
}
void Widget::on_pushButton_9_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "9");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "9");
}
}
void Widget::on_pushButton_11_clicked() {
if (QString::compare (ui->lineEdit_2->text(), "") == 0)
{
ui->lineEdit->setText(ui->lineEdit->text() + "0");
}
else
{
ui->lineEdit_3->setText(ui->lineEdit_3->text() + "0");
}
}
void Widget::on_pushButton_10_clicked() {
ui->lineEdit->setText("");
ui->lineEdit_2->setText("");
ui->lineEdit_3->setText("");
ui->lineEdit_4->setText("");
}
void Widget::on_pushButton_13_clicked() {
ui->lineEdit_2->setText("+");
}
void Widget::on_pushButton_14_clicked() {
ui->lineEdit_2->setText("-");
}
void Widget::on_pushButton_15_clicked() {
ui->lineEdit_2->setText("*");
}
void Widget::on_pushButton_16_clicked() {
ui->lineEdit_2->setText("/");
}
void Widget::on_pushButton_12_clicked() {
if (ui->lineEdit_2->text() == "+")
ui->lineEdit_4->setText(QString::number(ui->lineEdit->text().toInt(NULL, 10) + ui->lineEdit_3->text().toInt(NULL, 10)));
else if (ui->lineEdit_2->text() == "-")
ui->lineEdit_4->setText(QString::number(ui->lineEdit->text().toInt(NULL, 10) - ui->lineEdit_3->text().toInt(NULL, 10)));
else if (ui->lineEdit_2->text() == "*")
ui->lineEdit_4->setText(QString::number(ui->lineEdit->text().toInt(NULL, 10) * ui->lineEdit_3->text().toInt(NULL, 10)));
else if (ui->lineEdit_2->text() == "/")
ui->lineEdit_4->setText(QString::number(ui->lineEdit->text().toInt(NULL, 10) / ui->lineEdit_3->text().toInt(NULL, 10)));
} </syntaxhighlight>
파일 다루기
메모장 프로그램
- Youtube : https://www.youtube.com/watch?v=5wbMaH50GdM
- 메모장 프로그램을 한번 만들어 봅시다.
- 간단하게 만들어 본 프로그램입니다.
- TextEdit 컨트롤과 ListWidget 컨트롤, PushButton 컨트롤을 사용하였습니다.
- 헤더파일에 추가할 내용은 다음과 같습니다.
<source lang="c"> // 헤더 include
- include <QFileDialog>
- include <QMessageBox>
// Private 변수
QDir dir; QFileInfoList list;
</source>
- 소스코드는 다음과 같습니다.
<source lang="c"> void Widget::on_pushButton_4_clicked() {
dir = QFileDialog::getExistingDirectory();
dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
ui->listWidget->clear();
list = dir.entryInfoList();
for (int i = 0; i < list.size(); ++i) {
QFileInfo fileInfo = list.at(i);
ui->listWidget->addItem(QString("%1").arg(fileInfo.fileName()));
}
}
void Widget::on_pushButton_clicked() {
QString path, filename;
filename = QString("%1").arg(list.at(ui->listWidget->currentIndex().row()).absoluteFilePath());
QFile file(filename);
file.open(QIODevice::ReadOnly);
ui->textEdit->clear();
ui->textEdit->append(file.readAll());
file.close();
QMessageBox msgbox;
msgbox.setText("File Opened");
msgbox.exec();
}
void Widget::on_pushButton_2_clicked() {
QString path, filename;
filename = QString("%1").arg(list.at(ui->listWidget->currentIndex().row()).absoluteFilePath());
QFile file(filename + ".text");
QByteArray bytearray = ui->textEdit->toPlainText().toUtf8().left(ui->textEdit->toPlainText().length());
file.open(QIODevice::WriteOnly);
file.write(bytearray);
file.close();
QMessageBox msgbox;
msgbox.setText("File Saved");
msgbox.exec();
}
void Widget::on_pushButton_3_clicked() {
this->close();
}
void Widget::on_listWidget_doubleClicked(const QModelIndex &index) {
QString path, filename;
filename = QString("%1").arg(list.at(index.row()).absoluteFilePath());
QFile file(filename);
file.open(QIODevice::ReadOnly);
ui->textEdit->clear();
ui->textEdit->append(file.readAll());
file.close();
} </source>
- 좀 길어보이긴 하지만 다 했던 내용입니다.
- 연습문제 : 상단 메뉴바가 있는 MainWindow 프로그램으로 변환해 보세요.
데이터베이스 다루기
- sqlite를 이용하여 간단한 일기장을 만들어 보도록 하겠습니다.
- QT에서는 기본적으로 sqlite3를 지원해 줍니다.
- ubuntu에서는 기본으로 sqlite2지만, sqlite3를 설치하면 됩니다.
- SQL 관련 내용을 사용하기 위해서는 pro 파일도 수정해야 합니다.
<source lang="c"> QT += core gui sql </source>
- 위와 같이 sql을 추가해 줍니다.
- 추가하지 않으면 헤더를 추가해도 라이브러리가 참조되지 않아, 컴파일 에러가 납니다. 꼭 추가해 주어야 합니다.
- 이제, 헤더에 다음과 같은 내용을 추가합니다.
<source lang="c"> // 헤더 include
- include <QtSql/QtSql>
// private 변수
QSqlDatabase db;
</source>
- sql 파일의 위치는 이따 소스코드에 직접 지정해 주세요.
- sql 파일은 sqlite3에서 다음과 같은 명령어로 생성하였습니다.
<source lang="bash"> sqlite> create table note ( id INTEGER PRIMARY KEY AUTOINCREMENT, date text, title text, content text); </source>
- 소스코드는 다음과 같습니다.
<source lang="c"> void Widget::on_calendarWidget_clicked(const QDate &date) {
qWarning() << date.toString();
}
void Widget::on_pbOpen_clicked() {
QSqlQuery query; QString exeq;
int exist = 0;
query.clear();
exeq = "select * from note where date ='" + ui->calendarWidget->selectedDate().toString() + "';";
query.exec(exeq);
while(query.next())
{
QString date = query.value(0).toString();
ui->leTitle->setText(query.value("title").toString());
ui->teContent->clear();
ui->teContent->appendPlainText(query.value("content").toString());
exist = 1;
}
if(!exist)
qWarning() << "None";
}
void Widget::on_pbExit_clicked() {
db.close(); this->close();
}
void Widget::on_pbSave_clicked() {
QSqlQuery query; QString exeq;
query.clear();
exeq = "insert into note (date, title, content) values ('" + ui->calendarWidget->selectedDate().toString()+"', '"+ui->leTitle->text()+"', '"+ui->teContent->toPlainText()+"');";
} </source>
- 연습문제 : 노트패드의 경우와 같이, 메뉴가 되어 있는 프로그램으로 변경해 봅시다. 데이터베이스 생성도 같이.
네트워크 프로그래밍
채팅
- 네트워크 어플리케이션의 시작은 채팅 프로그램입니다.
- 아래 파일은 서버 / 클라이언트가 함께 동작하는 예제 프로그램입니다.