PyQt QtDesigner 메인윈도우

1. QtDesigner 메인윈도우

이번 아티클에서는 QtDesigner를 이용하여 메인윈도우 폼을 만들어 보자. QtDesigner를 실행한 후, Main Window 폼을 선택하여 메인윈도우를 생성하고, 아래 화면과 같이 메뉴, 툴바, 위젯들을 배치한다.

메뉴

메뉴(QMenu)는 "Type Here"를 더블 클릭하고 메뉴 텍스트를 입력하고 Enter를 치면 된다. 상위 메뉴가 입력되면 서브메뉴를 넣을 수 있는 "Type Here"가 표시되며, 필요한 경우 "Add Separator"를 클릭하여 메뉴 분리선을 추가할 수 있다. 이 예제에서는 화면에 보이진 않지만 [파일] 메뉴 밑에 [열기]와 [저장] 서브메뉴를 생성하였다.

툴바

툴바는 메뉴 바로 밑에 위치하는데, 보통 메뉴들 중 중요한 기능들을 툴바에 이미지 버튼으로 표시한다. 툴바를 생성하기 위해서는 폼에서 Rightclick한 후, Add Tool Bar를 선택한다. 툴바가 생성된 후에는 오른쪽 하단의 Action Editor 탭을 선택하고 메뉴에서 이미 생성한 [열기]와 [저장] 아이템을 드래그-앤-드랍으로 툴바에 끌어 놓으면 된다. 이어 툴바 버튼에 이미지를 넣기 위해서 먼저 Qt 리소스를 생성하여 이미지를 리소스에 넣어야 한다.

리소스 생성

QtDesigner에서 이미지 등을 관리하기 위해 리소스 파일을 사용한다. 리소스 파일은 .qrc 확장자를 갖는 파일인데, 리소트 파일 안에는 리소스에 대한 XML 데이타를 가지고 있다. 먼저 리소스 파일을 생성하기 위해, 오른쪽 하단의 Resource Browser 탭을 선택한 후, 아래 그림과 같이 연필 모양의 [Edit Resources] 툴바를 선택한다.

이어 [Edit Resources] 다이얼로그의 좌측 하단에 있는 [New Resource File] 아이콘을 선택하고, 적절한 리소스 파일명(예: myres.qrc)을 적는다. 이어 화면 중앙 하단의 [Add Prefix] 아이콘을 눌러 적당한 Prefix명 (예: icon)을 적고, 다음 [Add Files] 버튼을 눌러 아이콘이나 이미지 파일을 import 하면 된다. 이렇게 이미지 리소스들을 추가한 후 OK를 눌러 [Select Resource] 다이얼로그로 돌아간다. 위의 [Select Resource] 화면은 이러한 방식으로 3개의 아이콘들(open.png ~ save.png)을 추가한 후의 화면이다.

이렇게 리소스 파일로 import 된 이미지들은 이미지를 표시할 수 있는 여러 위젯들에 사용될 수 있다. 툴바에서 이미지를 넣기 위해서는 [Action Editor]에서 해당 Action을 선택한 후, [Property Editor]에서 Icon 속성을 클릭하고 아래 그림과 같이 [Choose Resource...]을 선택하고 리소스 이미지를 지정하면 된다.

기타 위젯들

위 첫번째 그림에 있는 "마이 윈도우" 화면을 완성하기 위해 몇가지 위젯들을 추가해야 한다. 즉, "키워드"라는 텍스트를 가진 QLabel, 입력 텍스트 박스인 QLineEdit (objectName: txtKeyword), "검색" 버튼인 QPushButton (btnSearch), 그리고 중앙에 결과를 표시하는 QTableWidget (resultTable) 등을 위 그림과 같이 배치한다. QTableWidget에서 컬럼을 추가하기 위해서는 QTableWidget을 선택한 후 Rightclick하여 [Edit Items] 메뉴를 선택하고 No와 Title 이라는 컬럼 두 개를 정의하면 된다.

2. 리소스 파이썬 파일 생성

QtDesigner에서 UI가 대충 완성되었으면, 이를 MyWindow.ui라는 파일로 저장하고, 앞 아티클에서 설명한 대로 pyuic4 명령을 사용하여 .py 파이썬 파일을 생성한다. 그런데, 이번 UI는 리소스 파일(.qrc 파일)도 사용하고 있으므로, 이 리소스 파일도 pyrcc4 명령을 사용하여 .py 파이썬 파일으로 생성해 주어야 한다. 파이썬 파일 생성을 위한 pyrcc4 명령은 아래와 같은데, 여기서는 Python 3 를 사용하므로 -py3 옵션을 반드시 지정해 주어야 한다.

C> pyrcc4 "리소스명.qrc" -o "리소스명_rc.py" -py3

여기서 한가지 중요한 사항은 리소스 파일 myres.qrc 에 대해 파이썬 출력 파일명을 myres_rc.py 와 같이 리소스명(myres) 뒤에 "_rc" 를 붙여야 한다는 것이다. 만약 다른 이름을 사용하면 프로그램 실행시 에러가 발생한다.

3. 메인윈도우를 위한 파이썬 코드

이제 UI와 리소스를 각각 파이썬 파일로 변경하였으므로, 파이썬 코드에서 UI 윈도우를 화면에 표시하고 핸들링하는 것을 살펴보자. 앞 아티클의 다이얼로그와 마찬가지로, MyWindow UI 모듈을 import하여 MyWindow.Ui_MainWindow 클래스를 베이스로한 사용자 정의 메인윈도우 클래스 XWindow를 아래와 같이 정의하였다. 그리고 XWindow의 생성자에서 setupUi() 메서드를 호출하여 UI 초기화를 실행한다. setupUi()으로 UI 초기화를 마친 후, self.show() 호출하면 메인윈도우 화면을 볼 수 있다.

from PyQt4.QtGui import *
import MyWindow
import sys
import pickle

class XWindow(QMainWindow, MyWindow.Ui_MainWindow):
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)

        # 초기 샘플데이타
        self.initData()

        # 검색 버튼 이벤트 핸들링
        self.btnSearch.clicked.connect(self.search)

        # 메뉴, 툴바 클릭 이벤트 핸들링
        self.actionSave.triggered.connect(self.saveData)
        self.actionOpen.triggered.connect(self.openData)
		
		# 메인윈도우 보이기
        self.show()

    def search(self):
        keyword = self.txtKeyword.text()
        resultData = self.sampleData[keyword]
        self.resultTable.setRowCount(len(resultData))
        row = 0
        for item in resultData:
            self.resultTable.setItem(row, 0, QTableWidgetItem(keyword))
            self.resultTable.setItem(row, 1, QTableWidgetItem(item))
            row += 1

    def initData(self):
        self.sampleData = {
            'Python': ['Fluent Python', 'Python Programming', 'Learning Python'],
            'go' : 'The Go Programming Language',
            'C#' : ['Inside C#', 'C# In Depth'],
            'C' : 'The C Programming Language'
        }

    def saveData(self):
        with open("test.data","wb") as f:
            pickle.dump(self.sampleData, f)
        QMessageBox.information(self, "저장", "데이타 저장됨")
    
    def openData(self):
        with open("test.data","rb") as f:
            self.sampleData = pickle.load(f)
        QMessageBox.information(self, "오픈", "데이타 로딩됨")

app = QApplication(sys.argv)
xwin = XWindow()
app.exec_()

여기서 검색 기능을 추가해 보기 위해, initData() 메서드에 임의의 간단한 Map 데이타를 만들었다 (실제로는 DB나 외부 저장소에서 데이타를 가져올 것임) . 그리고 [검색] 버튼 (btnSearch)의 클릭 이벤트를 search() 메서드에 연결 시켰으며, 이 메서드 안에서 입력 검색어 (txtKeyword.text())에 따라 Map 을 검색해서 결과를 QTableWidget (resultData)에 표시해 주고 있다.

추가적으로 메뉴 및 툴바에 연결된 QAction들 (actionSave, actionOpen)에 대한 이벤트 핸들러 예를 보이기 위하여, 이들의 triggered 이벤트에 각각 saveData(), openData() 핸들러를 연결하였다. QAction의 triggered 이벤트는 메뉴가 클릭되었거나 툴바가 클릭되었을 때, 혹은 해당 단축키 눌려 졌을 때 발생하는 이벤트이다. 여기서는 전체 맥락에 잘 맞진 않지만 테스트 예제로서 Map 데이타를 저장하고 불러오는 코드를 saveData(), openData() 메서드에 넣었다. 특히 이들 메서드에서 파이썬의 pickle 모듈을 사용하였는데, pickle.dump()는 파이썬 객체를 바이트들로 변환하여 파일 스트림과 같은 스트림에 저장하는 것이고 (Serialization이라고 함), pickle.load()은 반대로 스트림에서 바이트 데이타를 읽어 파이썬 객체로 복원(Deserialization이라고 함)하는 것이다.

아래는 프로그램이 실행되었을 때의 화면이다.

Python 프로그래밍 실습

본 웹사이트는 광고를 포함하고 있습니다. 광고 클릭에서 발생하는 수익금은 모두 웹사이트 서버의 유지 및 관리, 그리고 기술 콘텐츠 향상을 위해 쓰여집니다.