DEEP.I - Lab

오프라인 공간의 지능화를 꿈꾸는 딥아이 연구실입니다.

Python/PyQt

[Python] PyQt를 이용하여 마우스로 직선 그리기

Jongwon Kim 2020. 10. 20. 19:26
반응형

PyQt5를 이용한 마우스로 직선 그리기

 

pythonPyQt을 이용하여 일반적인 그림판과 같이 다양한 도형체를 그릴수 있습니다. 이러한 작업이 프로그램에 녹아들어 유저 인터페이스와 연결되기 위해서는 그림 1과 같이 그리고 있는 시각적인 효과가 중요합니다. 오늘은 PyQt 내부 QPainter 클래스로 간단한 그림판을 구현해보도록 하겠습니다.

 

 

그림1. 그림판의 시각적 효과

 

1.  Screen.py (기본 UI 만들기)

 

from PyQt5 import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import*

class Screen(QMainWindow):
    def setupUi(self):
        self.resize(800, 600)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        
        self.screen = QLabel(self.centralwidget)
        self.screen.setPixmap(QPixmap("screen.png"))
        self.screen.setScaledContents(True)
        self.screen.setObjectName("screen")
        
        self.gridLayout.addWidget(self.screen, 0, 0, 1, 1)
        self.setCentralWidget(self.centralwidget)
    
    def __init__(self):
        super().__init__() 
        self.setupUi()
        self.show()
        
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    ui = Screen()
    sys.exit(app.exec_())

 

QT Designer 또는 파이썬 코드를 이용하여 기본 UI를 구성해줍니다. QLabel은 screen.png 이미지로 Pixmap을 설정했습니다. 첨부된 UI를 이용하여 코드를 실행하면 그림 2와 같이 단순한 프레임의 위젯이 실행됩니다.

 

 

그림2. screen.py 실행화면

 

 

2. QPainter (직선 그리기)

 

def draw_Line(self):
        self.img = QPixmap("screen.png")
        
        # QPainter 선언
        painter = QtGui.QPainter(self.img) 
        # QPainter Pen 설정 (색상 / 두께 / 선 타입)
        painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
        # QPainter Line 그리기 (x1,y1,x2,y2)
        painter.drawLine(400,300,600,300)
        painter.end
        self.screen.setPixmap(QtGui.QPixmap(self.img))

 

페인터의 그리기 함수는 단순합니다. QPainter를 도화지가 되는 img를 바탕으로 선언해주고, 원하는 pen이나 brush 타입을 지정한 뒤, drawLine 함수로 그려주면 됩니다. 모든 그리기가 완료된 다음에는 꼭 end로 종료해야 그리기가 완료됩니다. 시작 시 QPinater 선언 -> 완료 시 QPainter.end 입니다. 기본적인 그리기 함수는 다음과 같습니다.

 

함수 타입
drawLine(x1, y1, x2, y2)         직선 그리기
drawEllipse(cx, cy, width, height)  타원 또는 원 그리기
drawText(cx, cy, text)   텍스트 입력

 

3. mouseEvent (마우스 버튼 이벤트 연동)

 

    # 마우스 드레그 이벤트
    def mouseMoveEvent(self,event):
    	# event.x(),y() : 마우스의 절대좌표 값
        self.draw_Line(event.x(),event.y())
        
    # 마우스 릴리즈 이벤트
    def mouseReleaseEvent(self,event):
    	# event.x(),y() : 마우스의 절대좌표 값
        self.draw_Line(event.x(),event.y())

    def draw_Line(self,x,y):
        self.img = QPixmap("screen.png")
        painter = QtGui.QPainter(self.img)
        painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
        painter.drawLine(400,300,x,y)
        painter.end
        self.screen.setPixmap(QtGui.QPixmap(self.img))

 

직선 그리기를 위해 마우스 이동을 감지하는 mouseMoveEvent 와 버튼을 클릭 후 놓는 순간을 감지하는 mouseReleaseEvent를 선언합니다. 마우스 이벤트 함수는 화면상에서 마우스의 절대좌표값이 반환됩니다. 직선을 마우스로 그리기 위해 draw_Line 함수의 입력 값을 수정한 뒤, 실행하게 되면 (400,300) 좌표값으로부터 직선이 마우스의 위치에 따라 동적으로 변화며 그리게 됩니다. 좌표값이 저장되지 않고 사라지기때문에 보다 유동적으로 여러 도형을 그리기 위해서는 좌표값을 메모리에 추가하거나 삭제하는 알고리즘적인 부분이 추가되어야 합니다.

 

3. mouseEvent flag 추가 (좌표값 저장)

 

    def __init__(self):
        super().__init__() 
        self.setupUi()
        self.show()
        # 마우스 이벤트 시작값
        self.past_x = None
        self.past_y = None
        # 마우스 이벤트 종료값
        self.present_x = None
        self.present_y = None
        
    # 마우스 MOVE
    def mouseMoveEvent(self,event):
        self.draw_Line(event.x(),event.y())
        
    # 마우스 RELEASE
    def mouseReleaseEvent(self,event):  
        self.draw_Line(event.x(),event.y())
        # 마우스 이벤트 시작값 초기화
        self.past_x = None
        self.past_y = None

    def draw_Line(self,x,y):
        # 마우스 이벤트 시작값 선언
        if self.past_x is None:
            self.past_x = x
            self.past_y = y
        else:
            self.present_x = x
            self.present_y = y

            self.img = QPixmap("screen.png")
            painter = QtGui.QPainter(self.img)
            painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
            painter.drawLine(self.past_x,self.past_y,self.present_x,self.present_y)
            painter.end
            self.screen.setPixmap(QtGui.QPixmap(self.img))

 

직선의 두 좌표값을 past_x,y와 parent_x,y로 초기화해줍니다. mouseMoveEvent 로 시작값이 입력되면 draw_line에서 이벤트 시작값을 선언해주고, mouseReleaseEvent 가 호출되면 이전 시작값을 초기화하여 새로운 직선을 그릴 때 이전 값의 영향을 받지 않도록 해줍니다. 이러한 알고리즘을 사용하면 간단한 그림판 프로그램은 파이썬만으로 쉽게 제작할 수 있을것같습니다. 

 

4. Screen.py (최종)

 

# -*- coding: utf-8 -*-
"""
Created on Tue Oct 20 14:08:50 2020
@author: Deep.I inc.
"""

from PyQt5 import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import*

class Screen(QMainWindow):
    def setupUi(self):
        self.resize(800, 600)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.gridLayout = QGridLayout(self.centralwidget)
        self.gridLayout.setObjectName("gridLayout")
        
        self.screen = QLabel(self.centralwidget)
        self.screen.setPixmap(QPixmap("screen.png"))
        self.screen.setScaledContents(True)
        self.screen.setObjectName("screen")
        
        self.gridLayout.addWidget(self.screen, 0, 0, 1, 1)
        self.setCentralWidget(self.centralwidget)
    
    def __init__(self):
        super().__init__() 
        self.setupUi()
        self.show()
        
        self.past_x = None
        self.past_y = None
        
        self.present_x = None
        self.present_y = None
        
    # 마우스 MOVE
    def mouseMoveEvent(self,event):
        self.draw_Line(event.x(),event.y())
        
    # 마우스 RELEASE
    def mouseReleaseEvent(self,event):  
        self.draw_Line(event.x(),event.y())
        self.past_x = None
        self.past_y = None

    def draw_Line(self,x,y):
        
        if self.past_x is None:
            self.past_x = x
            self.past_y = y
        else:
            self.present_x = x
            self.present_y = y

            self.img = QPixmap("screen.png")
            painter = QtGui.QPainter(self.img)
            painter.setPen(QPen(Qt.black, 10, Qt.SolidLine))
            painter.drawLine(self.past_x,self.past_y,self.present_x,self.present_y)
            painter.end
            self.screen.setPixmap(QtGui.QPixmap(self.img))
        
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Screen()
    sys.exit(app.exec_())

 

그림3. 지능형 방문자 경로 추적 시스템 응용

 

진행중인 방문자 경로 추적 프로그램 작업에서 사용자 입력이 되어야하는 부분에 본 알고리즘을 응용하여 활용하였습니다. 다음 포스팅에서는 직교좌표를 그리거나 평행한 직선 등의 알고리즘을 실시간으로 구현해보도록 하겠습니다.

 

QPainter_1.zip
0.01MB

 

 

 

# 머신러닝 프로젝트 제작, 상담 및 컨설팅  / 머신러닝 접목 졸업작품 컨설팅

# 데이터 가공, 수집, 라벨링 작업 / C, 파이썬 프로그램 제작

# email : deepi.contact.us@gmail.com

# site : www.deep-i.net

반응형