QT Programming Simple Editor
실습 예제 : 간단한 텍스트 편집기 작성
텍스트 파일을 읽어들여 QTextEdit에 쓰고 텍스트를 파일로 저장하는 기능을 구현합니다.
![]() [JPG image (49.35 KB)] QDialog에 QTextEdit 컨트롤과 Spacer를 이용하여 디자인합니다. Spacer와 QTextEdit을 위에서부터 순서대로 추가한 후 Form을 선택한 상태에서 메뉴의 Layout->Lay out vertically를 선택하여 정렬합니다. spacer는 일종의 버팀목 같은 것으로 일정공간을 확보하기 위해 추가하는 컨트롤입니다. 여기에서는 동적으로 생성할 QMenuBar의 공간을 확보하기 위해 사용합니다.
Form생성시에 메뉴바를 생성하고 Spacer의 크기를 재조정하도록 합니다.
void Form_Main::Initialize() { //--------------------------------------------------------------------------------------------------- //local variables : //--------------------------------------------------------------------------------------------------- QMenuBar* pMenuBar = NULL; QPopupMenu *pPopupMenu = NULL; QRect rect; //--------------------------------------------------------------------------------------------------- // // 메인 메뉴를 추가한다. // pMenuBar = new QMenuBar(this , NULL); //메뉴 바 객체를 생성한다. rect = pMenuBar->geometry(); //메뉴 바의 크기를 구한다. spacer_menu->changeSize( rect.width() , rect.height() ); //spacer의 크기를 메뉴 바의 크기로 한다. this->repaint(true); //윈도우를 다시 그린다. /* *메뉴 바의 메뉴 구성은 팝업 메뉴들의 집합으로 나타나다. QPopupMenu객체를 생성한 후 QPopupMenu 객체에 *메뉴 아이템(항목)을 추가한 후 QMenuBar에 QPopupMenu객체를 추가하면 된다. */ //"File" 메뉴 생성 pPopupMenu = new QPopupMenu; pPopupMenu->insertItem("&New" , this , SLOT( menuhandler_file_new() ) , CTRL+Key_N ); pPopupMenu->insertItem("&Open" , this , SLOT( menuhandler_file_open() ) , CTRL+Key_O ); pPopupMenu->insertItem("&Save" , this , SLOT( menuhandler_file_save() ) , CTRL+Key_S ); pMenuBar->insertItem("File" , pPopupMenu ); //생성한 팝업 메뉴를 메뉴바에 추가 return; } 메뉴바에 메뉴항목을 추가하는 부분을 확인하세요.
파일의 읽기와 쓰기 부분은 스레드 클래스와 진행사항을 보여주는 다이얼로그박스를 이용하여 구현하였습니다.
void Form_Main::menuhandler_file_open() { //--------------------------------------------------------------------------------------------------- //local variables : //--------------------------------------------------------------------------------------------------- QOpenFileDialog openFileDialog; QString qstr , qstr2; QTextCodec* pQTC = NULL; FileLoadThread workerThread; Form_Progress form_progress(this ); //처리 상태를 표현하기 위한 메세지 박스 int flags = 0; //--------------------------------------------------------------------------------------------------- pQTC = QTextCodec::codecForName("utf8"); if( pQTC == NULL ) { return; } flags = openFileDialog.exec(); //열 파일을 선택하기 위한 다이얼로그를 생성한다. if( flags == QOpenFileDialog::Accepted ) //open 버튼을 눌렀을 경우 { qstr = openFileDialog.selectedFile(); //파일 다이얼로그박스에 저장된 파일 이름(경로포함)을 얻는다. qstr2 = "파일을 여는 중입니다."; qstr2 = pQTC->toUnicode( qstr2 ); form_progress.Initialize(qstr , qstr2 ,&workerThread); //파일을 읽어들이는 스레드 객체를 생성하고 스레드를 실행시킨 workerThread.set_FilePath(qstr); workerThread.start(); form_progress.exec(); if( workerThread.get_WorkFinished() > 0 ) { this->textEdit_main->setText( workerThread.get_LoadedTextString() ); } } else //cancel버튼을 눌렀을 경우 { return; } } QFileDialog를 상속한 OpenFileDialog를 이용하여 파일의 경로를 얻습니다. 진행경과를 나타내는 Form_Progress 윈도우에서는 실제로 작업을 처리하는 스레드 객체 workerThread에 대한 포인터 참조를 이용하여 작업이 어느 정도까지 진행되는지 확인하며 폼 안의 QProgressBar를 갱신합니다. 작업이 완료되면 workerThread->WorkFinished 값을 확인하고 종료됩니다. exec()로 생성된 다이얼로그창은 done()을 이용하여 종료하는 것을 확인하세요.
#include < qmessagebox.h > #include < qpushbutton.h > #include "asyncworkerthread.h" void Form_Progress::Initialize(QString& qstr_FileName , QString& qstr_description ,AsyncWorkerThread* pAsyncWorkerThread) { QString qstr; qstr = "Loading "; qstr += qstr_FileName; this->setCaption( qstr ); this->textLabel_fileName->setText(qstr_FileName); this->m_pAsyncWorkerThread = pAsyncWorkerThread; this->textLabel_description->setText( qstr_description ); startTimer( 100 ); //setTimer의 단위는 millisecond(1000분의 1초) } void Form_Progress::timerEvent( QTimerEvent* pEvent) { if( this->m_pAsyncWorkerThread->get_Percentage() >= 100 && this->m_pAsyncWorkerThread->get_WorkFinished() != 0 ) { this->progressBar_fileStoring->setProgress( m_pAsyncWorkerThread->get_Percentage() , 100); this->repaint(); usleep(100000); //진행사항을 보여주기 위해 살짝 쉰다. this->done(0); //100이 되면 종료 } else if( this->m_pAsyncWorkerThread->get_WorkFinished() < 0 ) { QMessageBox::critical( this , this->caption() , "작업 중 오류가 발생하였습니다" ); return; } else { this->progressBar_fileStoring->setProgress( m_pAsyncWorkerThread->get_Percentage() , 100); return; } } FileSaveThread와 FileOpenThread는 AsyncWorkerThread를 상속받아 구현된 파일을 읽고 쓰는 작업을 하는 클래스입니다. AsyncWorkerThread는 Qt의 스레드 구현인 QThread를 상속받아 작업의 진행 정도와 성공여부를 표현할 속성을 추가한 클래스입니다.
Qt에서 스레드를 사용하기 위해서는 QThread를 상속받는 클래스를 정의한 후 QThread::run() 함수를 재정 의하고 그 안에 스레드 루틴을 작성해서 삽입하면 됩니다.
#ifndef _asyncworkderthread_h_ #define _asyncworkderthread_h_ #include < qthread.h > #define DEFINE_PROPERTY(type,property) type property;type get_##property(){return property;} void set_##property(type value){this->property=value;} class AsyncWorkerThread : public QThread { public: // //member variables : // //properties : DEFINE_PROPERTY(int,Percentage) DEFINE_PROPERTY(int,WorkFinished) // //member functions : // AsyncWorkerThread(); // 생성자 virtual void run(); //상속받아서 실제로 처리할 일을 삽입할 함수 }; #endif 스레드는 QThread::start()함수를 호출함으로서 시작됩니다. Qt 내부에서 문자는 utf8 포맷으로 인코딩되어 사용됩니다. 이번 구현에서는 utf8 코덱으로 텍스트 파일을 읽어들이고 저장합니다. 파일을 읽어들이는 부분입니다.
void FileLoadThread::run() { QFile qfile; QByteArray qByteArray; QTextCodec* pQTC = NULL; if( FilePath=="") { set_WorkFinished(-1); return; } pQTC = QTextCodec::codecForName("utf8"); if( pQTC == NULL ) { return; } qfile.setName( FilePath ); if( qfile.open(IO_ReadOnly) ) //파일을 읽기 전용으로 연다. { /* *이곳에서 파일을 읽고 쓰는 일을 처리한다. 파일의 크기에 따라 *일정량을 읽어들인 후 set_Percentage()함수를 이용해서 데이터를 읽어들인 양을 *표시할 수 있을 것이다. */ qByteArray = qfile.readAll(); //이 구현에서는 한번에 다 읽어들인다. set_Percentage(50); //절반이 된것으로 표현한다. if( qByteArray.count() > 0 ) { set_LoadedTextString(pQTC->toUnicode( qByteArray , qByteArray.count() ) ); set_WorkFinished(1); } else { set_WorkFinished(-1); } set_Percentage(100); //읽기 작업이 모두 끝났다. } return; } 파일을 저장하는 부분입니다.
void FileSaveThread::run() { QFile qfile; QTextCodec* pQTC; pQTC = QTextCodec::codecForName("utf8"); if( pQTC == NULL ) { return; } qfile.setName( get_FilePath() ); if( qfile.open( IO_WriteOnly ) ) { set_Percentage(0); QTextStream t(&qfile); t.setEncoding( QTextStream::UnicodeUTF8); t << DataString; qfile.close(); set_WorkFinished(1); set_Percentage(100); } } 동적인 메뉴 사용 및 텍스트의 읽기/쓰기를 구현할 때 위 코드를 참조하시기 바랍니다.
![]() [JPG image (13.25 KB)] ![]() [JPG image (55.72 KB)] 파일이 읽힌 모습
![]() [JPG image (46.51 KB)] |
Even the boldest zebra fears the hungry lion. |