Qt를 처음 배우시는 분들을 위한, 간단한 GUI 프로그램 만들기 - HandyToonView
글쓴이: HDNua / 작성시간: 월, 2012/10/29 - 7:35오후
솔직히 Mac OS X에서 Qt가 잘 설치되었다면
이것보다는 깔끔하게 만들 수 있었을 것 같습니다.
Ubuntu에 Qt를 설치하고 여러 가지 라이브러리 함수를 테스트하고자
만들었던 간단한 만화 보기 프로그램이었습니다.
구현이 안 된 부분도 많고 여러 모로 강좌란에 올리기 부끄러운 작품이지만
제가 Qt를 처음 배우면서 한 삽질을, 이 글이 필요한 입문자 분들은
그나마 좀 덜 할 수 있으면 좋겠다는 생각이 들어 올려봅니다.
프로그램으로 사용하진 마시고, 이런 기능을 구현하려할 때
이런 함수를 쓴다는 정도만 알아가시면 딱 적당하리라 생각합니다.
-----
main.cpp
#include <QtGui/QApplication> #include "mainwindow.h" /*************************************************************************** // 프로그램 동작 방식 1. 사용자가 만화 파일이 들어있는 경로를 설정합니다. 2. 이미지 파일의 갯수를 세어 정렬된 순서대로 동적 할당한 배열에 넣습니다. 3. 프로그램 종료 시에 배열을 할당 해제합니다. --- 프로그램은 실제로 다음과 같이 동작합니다. 1. 사용자가 이미지 파일을 클릭합니다. 2. QStringList 멤버 변수에 해당 폴더에 있는 모든 파일의 이름을 넣습니다. 3. ., ..과 같은 이름을 QStringList에서 삭제한 다음 sort() 메서드를 이용해 정렬합니다. (근데 sort()메서드는 인자 없이 어떻게 정렬을 했을까요.. 자동으로 오름차순 정렬인가.) 4. 선택한 이미지 파일을 창에 뿌립니다. // 프로그램의 문제점 1. 동적 할당한 변수를 제대로 해제하지 않고 있습니다. // 특징 - 좌우 방향키를 이용해 페이지를 이동할 수 있다. - 상하 방향키를 이용해 프로그램을 최소화/최대화할 수 있다. - 페이지 기억 기능을 지원한다. 텍스트 파일에 경로명만 집어넣으면 끝. --- 3번째는 구현하지 않았습니다. *****************************************************************************/ int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
mainwindow.h
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtGui/QMainWindow> #include <QtGui> class QDir; class QLabel; class QImage; class QMenuBar; class QMenu; class QFileDialog; class QString; class QStringList; class MainWindow : public QMainWindow { Q_OBJECT private: // 화면 관리 // 메뉴 관리 QMenuBar *_menuBar; // 파일 관리 QDir _dir; QString _fileName; QFileDialog *_fd; QStringList _filters; // 이미지 목록 관리 int _first; int _last; int _index; QImage **_list; QStringList _entryList; // 이미지 출력 QLabel *_node; QImage *_image; private: // 초기화 함수 void BasicValueSetting(); void MenuSetting(); void ImageListInit(); void ImagePrintInit(); public: MainWindow(QWidget *parent = 0); ~MainWindow(); // 추가 메서드 void glance(); void printImage(); void changeImageToLeft(); void changeImageToRight(); // 이벤트 처리 void keyPressEvent(QKeyEvent *event); // void resizeEvent(QResizeEvent *event); public: // 슬롯에 대한 함수 void process_open(); void print_developer(); public slots: // 슬롯 함수 void open(); // 파일 오픈 슬롯 void developer(); }; #endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h" #include <Qt> #include <QtCore> #include <QtGui> #include <iostream> #define BIG(X, Y) ( (X)>(Y)?(X):(Y) ) // 한 번의 초기화 이후에 다시 그 값을 설정하지 않음 #define ADD_ACTION_TO_MENU(MENU, ACTION_NAME, SIG, SLT) \ action = new QAction(tr(ACTION_NAME), this); \ connect(action, SIGNAL(SIG), this, SLOT(SLT)); \ MENU->addAction(action) #define ADD_ACTION_TO_MENU_WITH_SHORTCUT(MENU, ACTION_NAME, SIG, SLT, SC) \ ADD_ACTION_TO_MENU(MENU, ACTION_NAME, SIG, SLT); action->setShortcut(SC) MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { // 기본 값 설정 this->BasicValueSetting(); // 메뉴 this->MenuSetting(); // 이미지 목록 관리 this->ImageListInit(); // 이미지 출력 this->ImagePrintInit(); } MainWindow::~MainWindow() { } // 내부 메서드 void MainWindow::BasicValueSetting() { _dir = "/home"; _fd = new QFileDialog(this); _fd->setDirectory(_dir); // 확장자 설정 _filters << "Image files (*.png *.xpm *.jpg)"; _fd->setNameFilters(_filters); } void MainWindow::MenuSetting() { QMenu *menu; QAction *action; // 메뉴 초기화 _menuBar = menuBar(); menu = new QMenu(tr("&File")); _menuBar->addMenu(menu); ADD_ACTION_TO_MENU_WITH_SHORTCUT(menu, "&Open", triggered(), open(), QKeySequence::Open); ADD_ACTION_TO_MENU_WITH_SHORTCUT(menu, "E&xit", triggered(), close(), QKeySequence::Quit); menu->addSeparator(); menu = new QMenu(tr("&Setting")); _menuBar->addMenu(menu); ADD_ACTION_TO_MENU(menu, "De&veloper", triggered(), developer()); } void MainWindow::ImageListInit() { _first = -1; _last = -1; _index = -1; _list = 0; } void MainWindow::ImagePrintInit() { _node = new QLabel(this); _image = new QImage(); } // 추가 메서드 void MainWindow::glance() { // 본래 목적은 이미지를 읽어오기 전에 한 번 훑어봄으로써 // 이미지를 로드하는 속도를 높이려는 것이었는데, // 그 목적 대신 폴더에서 이미지를 가져와서 // _entryList라는 리스트에 넣는 함수가 되어버렸다. int i; _entryList = _dir.entryList(); std::cout<<"First"<<std::endl; for (i=0; i<_entryList.count(); ++i) std::cout<<_entryList[i].toStdString()<<std::endl; // ., ..과 같은 것도 경로로 치는 모양이다. _entryList.removeOne("."); _entryList.removeOne(".."); _entryList.sort(); std::cout<<"Second"<<std::endl; for (i=0; i<_entryList.count(); ++i) std::cout<<_entryList[i].toStdString()<<std::endl; _last = _entryList.count() - 1; _index = _entryList.indexOf(_fileName); _first = 0; std::cout<<"First: "<<_first<<std::endl; std::cout<<"Index: "<<_index<<std::endl; std::cout<<"Last : "<<_last<<std::endl; } void MainWindow::printImage() { QString fileName = _entryList.value(_index); fileName = _dir.absoluteFilePath(fileName); if( _image->load(fileName) ) { double d_width = _image->width(); double d_height = _image->height(); double ratio = d_width/d_height; d_height = this->geometry().height(); // geometry() 메서드는 현재 창의 크기를 가져온다. d_width = ratio * d_height; int width = d_width; int height = d_height; // 이건.. 도움말 보고 짜맞춘 겁니다. 3, 4번째 인자는 레퍼런스를 참조하세요. QImage image = _image->scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); // 이미지를 창에 뿌리기 전에 현재 창의 크기를 이미지에 맞게 조절합니다. this->setGeometry(0, 0, this->geometry().width(), this->geometry().height()); // 이미지를 가져와서 이미지의 크기를 조절합니다. _node->setPixmap(QPixmap::fromImage(image)); _node->setGeometry(this->geometry().width()/2 - width/2, this->geometry().height()/2 - height/2, width, height); // 창에 이미지를 뿌립니다. _node->show(); } } void MainWindow::changeImageToLeft() { if( --_index<_first ) _index = _last; std::cout<<"First: "<<_first<<std::endl; std::cout<<"Index: "<<_index<<std::endl; std::cout<<"Last : "<<_last<<std::endl; this->printImage(); } void MainWindow::changeImageToRight() { if( ++_index>_last) _index = _first; std::cout<<"First: "<<_first<<std::endl; std::cout<<"Index: "<<_index<<std::endl; std::cout<<"Last : "<<_last<<std::endl; this->printImage(); } // 이벤트 처리 void MainWindow::keyPressEvent(QKeyEvent *event) { int key = event->key(); switch (key) { // 방향키에 대한 이벤트 설정 case Qt::Key_Up: // std::cout<<"Up"<<std::endl; if( this->isMaximized() ) this->showNormal(); else this->showMaximized(); break; case Qt::Key_Right: // std::cout<<"Right"<<std::endl; this->changeImageToRight(); break; case Qt::Key_Down: // std::cout<<"Down"<<std::endl; this->showMinimized(); break; case Qt::Key_Left: // std::cout<<"Left"<<std::endl; this->changeImageToLeft(); break; // 기타 키에 대한 이벤트 case Qt::Key_Return: case Qt::Key_Enter: // std::cout<<"Enter"<<std::endl; this->process_open(); break; } } /* : 메인 윈도우의 창 크기가 변경될 때 호출되는 이벤트입니다. void MainWindow::resizeEvent(QResizeEvent *event) { QSize size = event->size(); std::cout<<size.width()<<std::endl; std::cout<<size.height()<<std::endl; // (1215, 747) / (1215, 776) }*/ // 슬롯에 대한 함수 void MainWindow::process_open() { QString filePath = _fd->getOpenFileName(this); if( !filePath.isNull() ) { QDir dir = QFileInfo(filePath).absoluteDir(); _dir = dir; _fileName = _dir.relativeFilePath(filePath); this->glance(); this->printImage(); } } void MainWindow::print_developer() { // 개발하다 말았습니다. } // 슬롯 메서드 void MainWindow::open() { this->process_open(); } void MainWindow::developer() { this->print_developer(); }
-----
봐주셔서 감사합니다.
Forums:
감사합니다.
이제막 Qt를 새로시작하게 됐습니다.
좋은 정보 감사합니다.
댓글 달기