PyQt개발강좌, 그리기 도구와 사용자 상호작용 구현

PyQt는 Python에서 Qt 애플리케이션을 개발하기 위한 강력한 라이브러리로, GUI 응용 프로그램 및 그래픽 기능을 구현하는 데 유용합니다. 본 강좌에서는 PyQt를 활용하여 그래픽 도구를 만드는 방법과 사용자와 상호작용하는 방법을 다룰 것입니다. 우리가 구현할 예제는 간단한 드로잉 도구와 여러 사용자 상호작용 기능을 포함할 것입니다.

1. PyQt 소개

PyQt는 C++로 작성된 Qt 프레임워크를 Python에서 사용할 수 있게 해주는 바인딩입니다. GUI 애플리케이션을 쉽게 개발할 수 있도록 여러 위젯과 도구를 제공합니다. PyQt는 Qt의 기능을 모두 사용할 수 있고, 크로스 플랫폼 지원 덕분에 Windows, macOS, Linux 등 다양한 운영 체제에서 실행할 수 있습니다.

2. PyQt 설치

PyQt를 설치하려면 pip 명령어를 사용할 수 있습니다. 터미널 또는 명령 프롬프트를 열고 다음 명령어를 입력해주세요:

pip install PyQt5

3. 기본 GUI 구성요소

PyQt에서 GUI를 만들기 위해서는 QApplication과 QMainWindow와 같은 기본 구성 요소가 필요합니다. QApplication은 GUI 애플리케이션을 위한 클래스로, 이벤트 처리를 관리합니다. QMainWindow는 주 창을 생성하는 데 사용됩니다.

3.1 간단한 PyQt 윈도우 만들기

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("간단한 PyQt 윈도우")
        self.setGeometry(100, 100, 800, 600)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    sys.exit(app.exec_())

4. 그리기 도구 구현하기

이제 실제로 그리기 도구를 구현해 보겠습니다. QMainWindow를 상속받은 클래스를 만들고, 마우스 이벤트를 처리하는 함수를 정의하여 사용자와의 상호작용을 구현합니다.

4.1 QGraphicsScene 사용하기

QGraphicsScene은 그래픽 항목을 관리하는 데 사용됩니다. 그리기 도구를 만들기 위해 이를 활용할 것입니다. 사용자가 마우스 클릭 및 드래그를 통해 선을 그릴 수 있도록 구현해 보겠습니다.

from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView

class DrawingApp(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("그리기 도구")
        self.setGeometry(100, 100, 800, 600)

        # QGraphicsScene 생성
        self.scene = QGraphicsScene(self)
        self.view = QGraphicsView(self.scene, self)
        self.setCentralWidget(self.view)

        # 마우스 이벤트 연결
        self.last_point = None
        self.view.setMouseTracking(True)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.last_point = event.pos()
        
    def mouseMoveEvent(self, event):
        if self.last_point is not None:
            line = QLineF(self.last_point, event.pos())
            self.scene.addLine(line)
            self.last_point = event.pos()
    
    def mouseReleaseEvent(self, event):
        self.last_point = None

4.2 도형 색상 변경 및 지우기 기능 추가하기

그리기 도구에 색상을 변경하고, 그린 도형을 지울 수 있는 기능을 추가합니다. 버튼을 추가하여 사용자가 도형의 색상을 선택하거나 화면을 지울 수 있도록 설정합니다.

from PyQt5.QtWidgets import QPushButton, QColorDialog
from PyQt5.QtCore import Qt

class DrawingApp(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("그리기 도구")
        self.setGeometry(100, 100, 800, 600)

        self.scene = QGraphicsScene(self)
        self.view = QGraphicsView(self.scene, self)
        self.setCentralWidget(self.view)

        # 색상 변경 버튼
        self.color_button = QPushButton("색상 선택", self)
        self.color_button.clicked.connect(self.chooseColor)
        self.color_button.move(10, 10)

        # 지우기 버튼
        self.clear_button = QPushButton("지우기", self)
        self.clear_button.clicked.connect(self.clearScene)
        self.clear_button.move(10, 50)

        self.last_point = None
        self.brush_color = Qt.black

    def chooseColor(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.brush_color = color

    def clearScene(self):
        self.scene.clear()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.last_point = event.pos()
        
    def mouseMoveEvent(self, event):
        if self.last_point is not None:
            line = QLineF(self.last_point, event.pos())
            self.scene.addLine(line, QPen(self.brush_color, 2))
            self.last_point = event.pos()
    
    def mouseReleaseEvent(self, event):
        self.last_point = None

5. 사용자 상호작용 및 최적화

이제 그리기 도구의 기본 기능이 구현되었습니다. 이를 최적화하고 사용자 경험을 개선하기 위한 몇 가지 방법을 살펴보겠습니다.

5.1 그리기 도구에 단축키 추가하기

특정 기능을 빠르게 사용할 수 있도록 단축키를 추가합니다. 예를 들어, ‘C’ 키를 누르면 색상 선택 창이 열리도록 구현할 수 있습니다.

from PyQt5.QtGui import QKeySequence

class DrawingApp(QMainWindow):
    def __init__(self):
        super().__init__()
        # 기존 코드 유지…

        # 단축키 설정
        self.color_button.setShortcut(QKeySequence("Ctrl+C"))
    
    def keyPressEvent(self, event):
        if event.key() == Qt.Key_C:
            self.chooseColor()

5.2 undo/redo 기능 추가하기

사용자가 그림을 그리면서 실수할 경우 쉽게 복구할 수 있도록 undo 및 redo 기능을 추가합니다. 이를 위해 스택을 사용할 수 있습니다.

class DrawingApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.undo_stack = []
        self.redo_stack = []
        
    def addLineToUndoStack(self, line):
        self.undo_stack.append(line)
    
    def undo(self):
        if self.undo_stack:
            line = self.undo_stack.pop()
            self.scene.removeItem(line)
            self.redo_stack.append(line)
    
    def redo(self):
        if self.redo_stack:
            line = self.redo_stack.pop()
            self.scene.addItem(line)

6. 최종 프로젝트

지금까지의 내용을 바탕으로 최종적으로 완성된 그리기 도구를 구현해 보겠습니다. 각 기능을 통합하여 최종 프로젝트를 구성합니다.

class DrawingApp(QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.setWindowTitle("최종 그리기 도구")
        self.setGeometry(100, 100, 800, 600)

        # Scene과 View 설정
        self.scene = QGraphicsScene(self)
        self.view = QGraphicsView(self.scene, self)
        self.setCentralWidget(self.view)

        # 버튼 설정
        self.color_button = QPushButton("색상 선택", self)
        self.color_button.clicked.connect(self.chooseColor)
        self.color_button.move(10, 10)

        self.clear_button = QPushButton("지우기", self)
        self.clear_button.clicked.connect(self.clearScene)
        self.clear_button.move(10, 50)

        self.undo_button = QPushButton("Undo", self)
        self.undo_button.clicked.connect(self.undo)
        self.undo_button.move(10, 90)

        self.redo_button = QPushButton("Redo", self)
        self.redo_button.clicked.connect(self.redo)
        self.redo_button.move(10, 130)

        self.last_point = None
        self.brush_color = Qt.black
        self.undo_stack = []
        self.redo_stack = []

    def chooseColor(self):
        color = QColorDialog.getColor()
        if color.isValid():
            self.brush_color = color

    def clearScene(self):
        self.scene.clear()

    def addLineToUndoStack(self, line):
        self.undo_stack.append(line)

    def undo(self):
        if self.undo_stack:
            line = self.undo_stack.pop()
            self.scene.removeItem(line)
            self.redo_stack.append(line)

    def redo(self):
        if self.redo_stack:
            line = self.redo_stack.pop()
            self.scene.addItem(line)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.last_point = event.pos()

    def mouseMoveEvent(self, event):
        if self.last_point is not None:
            line = QLineF(self.last_point, event.pos())
            self.scene.addLine(line, QPen(self.brush_color, 2))
            self.addLineToUndoStack(line)
            self.last_point = event.pos()

    def mouseReleaseEvent(self, event):
        self.last_point = None

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = DrawingApp()
    window.show()
    sys.exit(app.exec_())

7. 결론

이번 강좌를 통해 PyQt를 활용하여 간단한 그리기 도구를 만들고, 사용자 상호작용을 구현하는 방법을 배웠습니다. 각 기능을 프로그램에 통합하여 최종 프로젝트를 완성했습니다. 이제 여러분은 이러한 경험을 바탕으로 더 복잡한 GUI 애플리케이션을 개발할 준비가 되었습니다. PyQt는 강력한 라이브러리이므로 다양한 기능을 자유롭게 조합하고 실험해 보시기를 권장합니다. 많은 실습과 경험을 통해 나만의 독창적인 애플리케이션을 만들어 보세요!