728x90
반응형

 

PyQt5 의 기본 사용방법은 앞 포스팅에서 살펴보았습니다. 이번에는 응용하여 프로그램을 하나 만들어 보겠습니다. 

만들 프로그램은 사진의 GPS 정보를 이용하여 사진과 사진 사이의 거리를 측정하는 프로그램 입니다.


필요한 라이브러리

  1. PyQt5: GUI 애플리케이션 개발.
  2. Pillow (PIL): 사진 파일에서 EXIF 데이터 추출.
  3. geopy: GPS 좌표를 사용한 거리 계산.

설치 명령어

아래 명령어를 사용해 필요한 라이브러리를 설치하세요:

pip install pyqt5 pillow geopy

실행코드

import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QFileDialog, QListWidget, QVBoxLayout, QPushButton, QLabel, QWidget
)
from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from geopy.distance import geodesic


class GPSDistanceApp(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()
        self.photos = []  # 선택한 사진 경로 리스트
        self.gps_data = []  # 사진의 GPS 정보 리스트

    def initUI(self):
        # 위젯 설정
        self.setWindowTitle("GPS Distance Calculator")
        self.setGeometry(300, 300, 600, 400)

        self.centralWidget = QWidget()
        self.setCentralWidget(self.centralWidget)

        layout = QVBoxLayout()

        self.photoList = QListWidget()
        self.resultLabel = QLabel("Distances will appear here.")

        self.selectButton = QPushButton("Select Photos")
        self.selectButton.clicked.connect(self.openFileDialog)

        self.calculateButton = QPushButton("Calculate Distances")
        self.calculateButton.clicked.connect(self.calculateDistances)

        layout.addWidget(self.photoList)
        layout.addWidget(self.selectButton)
        layout.addWidget(self.calculateButton)
        layout.addWidget(self.resultLabel)

        self.centralWidget.setLayout(layout)

    def openFileDialog(self):
        # 여러 사진 선택
        filePaths, _ = QFileDialog.getOpenFileNames(self, "Select Photos", "", "Images (*.jpg *.jpeg *.png)")
        if filePaths:
            self.photos = filePaths
            self.photoList.clear()
            self.photoList.addItems(filePaths)

    def extractGPS(self, photoPath):
        try:
            img = Image.open(photoPath)
            exif_data = img._getexif()
            if not exif_data:
                return None
            gps_info = {}
            for tag, value in exif_data.items():
                tag_name = TAGS.get(tag, tag)
                if tag_name == "GPSInfo":
                    for gps_tag in value.keys():
                        gps_name = GPSTAGS.get(gps_tag, gps_tag)
                        gps_info[gps_name] = value[gps_tag]
            if gps_info:
                return self.convertGPS(gps_info)
            return None
        except Exception as e:
            print(f"Error reading GPS data: {e}")
            return None

    def convertGPS(self, gps_info):
        """Convert GPS EXIF data to latitude and longitude in decimal format."""
        def to_decimal(coord, ref):
            degrees, minutes, seconds = coord
            decimal = degrees + (minutes / 60.0) + (seconds / 3600.0)
            if ref in ['S', 'W']:
                return -decimal
            return decimal

        try:
            lat = to_decimal(gps_info["GPSLatitude"], gps_info["GPSLatitudeRef"])
            lon = to_decimal(gps_info["GPSLongitude"], gps_info["GPSLongitudeRef"])
            return lat, lon
        except KeyError:
            return None

    def calculateDistances(self):
        # GPS 정보 추출
        self.gps_data = [self.extractGPS(photo) for photo in self.photos]

        # 유효하지 않은 GPS 정보 확인
        if None in self.gps_data:
            self.resultLabel.setText("Some photos do not have valid GPS data.")
            return

        # 거리 계산
        distances = []
        for i in range(len(self.gps_data) - 1):
            dist = geodesic(self.gps_data[i], self.gps_data[i + 1]).meters
            distances.append(dist)

        # 결과 출력
        result_text = "Distances between photos:\n"
        for i, dist in enumerate(distances):
            result_text += f"{os.path.basename(self.photos[i])} -> {os.path.basename(self.photos[i + 1])}: {dist:.2f} m\n"
        self.resultLabel.setText(result_text)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = GPSDistanceApp()
    ex.show()
    sys.exit(app.exec_())

 


코드 설명

  1. GUI 구성
    • QListWidget: 선택한 사진 경로를 리스트 형식으로 표시.
    • QPushButton: 파일 선택 및 거리 계산 기능을 트리거.
    • QLabel: 거리 계산 결과를 표시.
  2. 사진 선택
    • QFileDialog.getOpenFileNames: 여러 장의 사진 선택.
    • 선택된 파일 경로를 self.photos 리스트에 저장하고 화면에 표시.
  3. GPS 정보 추출
    • PIL.Image의 _getexif 메서드를 사용해 EXIF 데이터 추출.
    • GPSInfo를 읽어 GPS 좌표를 추출하고, 이를 소수점 형식의 경위도(latitude, longitude)로 변환.
  4. 거리 계산
    • geopy.distance.geodesic: 두 GPS 좌표 간의 직선 거리를 계산.
    • 결과는 미터 단위로 표시.
  5. 결과 출력
    • 사진 간의 거리와 파일 이름을 화면에 표시.

728x90

실행결과

 

 


참고 포스팅

https://tylee82.tistory.com/418

 

PyQt5: QGridLayout으로 깔끔한 레이아웃 만들기

QGridLayout은 PyQt5에서 제공하는 레이아웃 관리 도구 중 하나로, 위젯들을 행(row)과 열(column)로 구성된 그리드 형태로 배치할 수 있습니다.이번 포스팅에서는 QGridLayout의 사용법과 예제 코드를 자세

tylee82.tistory.com

https://tylee82.tistory.com/420

 

QFileDialog를 활용한 파일 열기와 저장하기

QFileDialog는 PyQt5에서 파일 또는 디렉터리를 선택하는 대화 상자를 제공하는 클래스입니다. 파일 열기와 저장을 간단히 구현할 수 있어 응용 프로그램 개발에 자주 사용됩니다. 이번 포스팅에서

tylee82.tistory.com

https://tylee82.tistory.com/413

 

파이썬으로 이미지의 GPS 정보 읽기

사진 속에는 우리가 눈으로 볼 수 없는 다양한 메타데이터가 포함되어 있습니다. 특히 스마트폰이나 GPS 기능이 있는 카메라로 촬영한 사진에는 GPS 정보가 포함될 수 있습니다. 이번 포스팅에서

tylee82.tistory.com

 

728x90
반응형
728x90
반응형

QFileDialog는 PyQt5에서 파일 또는 디렉터리를 선택하는 대화 상자를 제공하는 클래스입니다. 파일 열기와 저장을 간단히 구현할 수 있어 응용 프로그램 개발에 자주 사용됩니다. 이번 포스팅에서는 QFileDialog의 기본 사용법과 주요 메서드를 설명하고, 간단한 예제 코드를 통해 이를 활용하는 방법을 소개합니다.


예제 코드: 파일 열기와 저장 구현하기

아래 코드는 QFileDialog를 사용해 파일을 열고 저장하는 기능을 구현한 예제입니다.

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTextEdit, QAction, QFileDialog


class MyApp(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 중앙에 텍스트 편집기 추가
        self.textEdit = QTextEdit(self)
        self.setCentralWidget(self.textEdit)

        # 파일 열기 액션
        openFile = QAction('Open', self)
        openFile.setShortcut('Ctrl+O')  # 단축키 설정
        openFile.setStatusTip('Open a file')  # 상태 표시줄 설명
        openFile.triggered.connect(self.showOpenDialog)  # 클릭 시 연결될 메서드 설정

        # 파일 저장 액션
        saveFile = QAction('Save', self)
        saveFile.setShortcut('Ctrl+S')
        saveFile.setStatusTip('Save a file')
        saveFile.triggered.connect(self.showSaveDialog)

        # 메뉴바 생성 및 추가
        menubar = self.menuBar()
        fileMenu = menubar.addMenu('&File')  # 메뉴 이름 지정
        fileMenu.addAction(openFile)  # 메뉴에 'Open' 추가
        fileMenu.addAction(saveFile)  # 메뉴에 'Save' 추가

        # 윈도우 설정
        self.setWindowTitle('QFileDialog Example')  # 창 제목 설정
        self.setGeometry(300, 300, 400, 300)  # 창 위치와 크기 설정
        self.show()

    def showOpenDialog(self):
        """파일 열기 대화 상자"""
        # 파일 열기 대화 상자 호출
        filePath, _ = QFileDialog.getOpenFileName(
            self, 'Open File', '', 'Text Files (*.txt);;All Files (*)'
        )
        if filePath:  # 사용자가 파일을 선택한 경우
            with open(filePath, 'r', encoding='utf-8') as file:
                self.textEdit.setText(file.read())  # 파일 내용을 텍스트 편집기에 로드

    def showSaveDialog(self):
        """파일 저장 대화 상자"""
        # 파일 저장 대화 상자 호출
        filePath, _ = QFileDialog.getSaveFileName(
            self, 'Save File', '', 'Text Files (*.txt);;All Files (*)'
        )
        if filePath:  # 사용자가 저장 위치를 지정한 경우
            with open(filePath, 'w', encoding='utf-8') as file:
                file.write(self.textEdit.toPlainText())  # 텍스트 편집기의 내용을 저장


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

코드 설명

1. 메인 윈도우 및 텍스트 편집기 구성

  • QMainWindow: PyQt5에서 기본적으로 제공하는 윈도우 위젯으로, 메뉴 바와 상태 표시줄 등을 포함할 수 있습니다.
  • QTextEdit: 다중 줄 텍스트 입력 및 출력 위젯. 중앙에 배치하여 사용자가 텍스트를 입력하거나 파일 내용을 표시합니다.

2. 파일 열기와 저장 액션

  • QAction: 메뉴나 툴바에서 선택할 수 있는 작업(액션)을 정의합니다.
    • setShortcut: 단축키를 지정합니다. 예: Ctrl+O는 파일 열기.
    • setStatusTip: 상태 표시줄에 표시할 텍스트를 설정합니다.
    • triggered.connect: 액션이 트리거되었을 때 호출할 메서드를 연결합니다.

3. 파일 열기 대화 상자

  • QFileDialog.getOpenFileName:
    • 사용자가 파일을 선택하면 선택된 파일의 경로를 반환합니다.
    • filter 인수를 사용하여 특정 파일 형식만 표시할 수 있습니다. 예: Text Files (*.txt);;All Files (*).

4. 파일 저장 대화 상자

  • QFileDialog.getSaveFileName:
    • 사용자가 저장 위치와 파일 이름을 선택하면 그 경로를 반환합니다.
    • 파일 확장자는 filter를 통해 설정할 수 있습니다.

5. 파일 입출력 처리

  • with open(filePath, mode, encoding='utf-8'):
    • 파일을 읽거나 쓸 때 사용합니다.
    • mode='r': 읽기 모드.
    • mode='w': 쓰기 모드.
    • encoding='utf-8': UTF-8 인코딩 사용.
728x90

주요 메서드 정리

  1. QFileDialog.getOpenFileName
    • 파일 열기 대화 상자를 호출합니다.
    • 반환값: (선택된 파일 경로, 선택된 필터).
  2. QFileDialog.getSaveFileName
    • 파일 저장 대화 상자를 호출합니다.
    • 반환값: (선택된 파일 경로, 선택된 필터).
  3. QAction.setShortcut
    • 단축키를 지정합니다.
    • 예: Ctrl+O는 파일 열기에 할당.
  4. QTextEdit
    • setText: 텍스트를 설정합니다.
    • toPlainText: 입력된 텍스트를 가져옵니다.

실행 결과

  1. 파일 열기:
    • 메뉴에서 File > Open을 선택하거나 Ctrl+O를 누르면 파일 열기 대화 상자가 표시됩니다.
    • 선택한 파일의 내용을 텍스트 편집기에 로드합니다.
  2. 파일 저장:
    • 메뉴에서 File > Save를 선택하거나 Ctrl+S를 누르면 파일 저장 대화 상자가 표시됩니다.
    • 텍스트 편집기에 입력한 내용을 저장합니다.


결론

이 예제에서는 QFileDialog를 사용해 파일을 열고 저장하는 기본적인 기능을 구현했습니다. QFileDialog는 다양한 옵션을 제공해 더 복잡한 파일 선택 기능도 구현할 수 있습니다. 이 예제를 응용해 텍스트 파일 외에도 다양한 형식의 파일을 처리해 보세요!

728x90
반응형
728x90
반응형

QPixmap은 PyQt5에서 이미지를 다룰 때 사용되는 대표적인 클래스입니다. 주로 이미지의 표시, 조작, 저장 등에 사용됩니다. 이번 포스팅에서는 QPixmap을 활용해 간단히 이미지를 표시하는 예제를 소개합니다.


샘플 코드: QPixmap으로 이미지 표시

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout
from PyQt5.QtGui import QPixmap


class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 1. QLabel 생성
        label = QLabel(self)

        # 2. QPixmap 생성 및 이미지 로드
        pixmap = QPixmap('../img/20231014_164906.jpg')  # 이미지 파일 경로
        pixmap = pixmap.scaled(500, 300)
        label.setPixmap(pixmap)

        # 3. 레이아웃 설정
        vbox = QVBoxLayout()
        vbox.addWidget(label)
        self.setLayout(vbox)

        # 4. 윈도우 설정
        self.setWindowTitle('QPixmap Example')
        self.setGeometry(300, 300, pixmap.width(), pixmap.height())
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

 


코드 설명

1. QLabel 생성

label = QLabel(self)

 

  • 이미지를 표시할 QLabel 위젯을 생성합니다.
  • QPixmap은 QLabel에 이미지를 연결하여 화면에 표시합니다.

2. QPixmap 생성 및 이미지 로드

pixmap = QPixmap('../img/20231014_164906.jpg')  # 이미지 파일 경로
label.setPixmap(pixmap)

 

 

  • QPixmap('파일 경로'): 지정된 경로의 이미지를 불러옵니다.
  • label.setPixmap(pixmap): QLabel에 QPixmap을 연결하여 이미지를 표시합니다.
  • 이미지 파일은 현재 코드와 동일한 디렉토리에 있어야 합니다.
    • 경로가 다를 경우 전체 경로나 상대 경로를 정확히 지정해 주세요.

3. 레이아웃 설정

vbox = QVBoxLayout()
vbox.addWidget(label)
self.setLayout(vbox)

 

 

  • QVBoxLayout을 이용해 QLabel을 레이아웃에 추가합니다.
  • 이미지를 추가한 레이아웃을 현재 창에 설정합니다.

4. 윈도우 설정

self.setGeometry(300, 300, pixmap.width(), pixmap.height())

 

 

  • 이미지의 크기에 맞춰 윈도우 크기를 동적으로 설정합니다.
  • pixmap.width()와 pixmap.height()를 사용해 이미지의 크기를 가져옵니다.

 

실행 결과

코드를 실행하면 지정한 이미지 파일이 새로운 창에 표시됩니다.

 

728x90

주요 메서드 및 속성

메서드/속성설명

QPixmap('파일 경로') 지정된 경로의 이미지를 불러옵니다.
label.setPixmap(pixmap) QLabel에 QPixmap 객체를 설정합니다.
pixmap.width() 이미지의 너비를 반환합니다.
pixmap.height() 이미지의 높이를 반환합니다.
pixmap.scaled(width, height) 이미지를 지정한 크기로 조정한 새로운 QPixmap 객체를 반환합니다. (비율 유지 옵션을 함께 설정 가능)
pixmap.save('저장 경로') 현재 QPixmap 객체를 파일로 저장합니다.

 


활용 팁

pixmap = pixmap.scaled(200, 200)
  1. 이미지 크기 조정
    • scaled() 메서드를 사용해 이미지를 특정 크기로 조정할 수 있습니다.
    • 원본 비율을 유지하려면 Qt.KeepAspectRatio 옵션을 사용할 수 있습니다.
  2. 이미지 파일 경로
    • 이미지를 프로젝트와 동일한 디렉토리에 두거나, 전체 경로를 명시적으로 작성하세요.
  3. QPixmap과 QImage의 차이
    • QPixmap: 렌더링에 최적화된 클래스. 주로 화면 표시용.
    • QImage: 이미지 데이터의 읽기/쓰기, 픽셀 조작에 적합.

결론

QPixmap은 PyQt5에서 이미지를 표시하는 데 필수적인 클래스입니다. 이번 예제를 참고하여 프로젝트에 이미지를 손쉽게 추가해 보세요!

다음 포스팅에서는 QPixmap을 활용한 이미지 크기 조정과 저장 방법에 대해 다뤄보겠습니다. 😊

728x90
반응형
728x90
반응형

QGridLayout은 PyQt5에서 제공하는 레이아웃 관리 도구 중 하나로, 위젯들을 행(row)과 열(column)로 구성된 그리드 형태로 배치할 수 있습니다.
이번 포스팅에서는 QGridLayout의 사용법과 예제 코드를 자세히 설명하겠습니다.


예제 코드: 간단한 QGridLayout 구현

아래는 QGridLayout을 이용해 간단한 사용자 입력 폼을 구현한 코드입니다.

import sys
from PyQt5.QtWidgets import (QApplication, QWidget, QGridLayout, QLabel, QLineEdit, QTextEdit)


class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 1. GridLayout 생성
        grid = QGridLayout()
        self.setLayout(grid)

        # 2. 위젯 추가
        grid.addWidget(QLabel('Title:'), 0, 0)    # (0, 0) 위치에 Label 추가
        grid.addWidget(QLabel('Author:'), 1, 0)  # (1, 0) 위치에 Label 추가
        grid.addWidget(QLabel('Review:'), 2, 0)  # (2, 0) 위치에 Label 추가

        grid.addWidget(QLineEdit(), 0, 1)        # (0, 1) 위치에 QLineEdit 추가
        grid.addWidget(QLineEdit(), 1, 1)        # (1, 1) 위치에 QLineEdit 추가
        grid.addWidget(QTextEdit(), 2, 1)        # (2, 1) 위치에 QTextEdit 추가

        # 3. 윈도우 설정
        self.setWindowTitle('QGridLayout')
        self.setGeometry(300, 300, 300, 200)
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

코드 설명

1. QGridLayout 생성

grid = QGridLayout()
self.setLayout(grid)

 

  • QGridLayout 객체를 생성하고, self.setLayout()을 통해 현재 QWidget에 레이아웃으로 설정합니다.
  • 이제 생성한 그리드 레이아웃에 위젯을 자유롭게 추가할 수 있습니다.

2. 위젯 추가

 

grid.addWidget(QLabel('Title:'), 0, 0)
grid.addWidget(QLabel('Author:'), 1, 0)
grid.addWidget(QLabel('Review:'), 2, 0)
  • addWidget(widget, row, column) 메서드를 사용해 특정 위치에 위젯을 추가합니다.
  • 여기서 (row, column)은 그리드 내 위젯이 배치될 위치를 의미합니다.
    • 예: 0, 0은 첫 번째 행, 첫 번째 열을 뜻합니다.
  • 예제에서는 제목, 저자, 리뷰라는 라벨을 (0, 0), (1, 0), (2, 0) 위치에 추가했습니다.

3. 입력 위젯 배치

grid.addWidget(QLineEdit(), 0, 1)
grid.addWidget(QLineEdit(), 1, 1)
grid.addWidget(QTextEdit(), 2, 1)

 

 

  • 텍스트를 입력받는 위젯을 라벨의 오른쪽에 배치했습니다.
    • (0, 1): 제목 입력란
    • (1, 1): 저자 입력란
    • (2, 1): 리뷰 입력란
  • QLineEdit: 한 줄 텍스트 입력을 위한 위젯입니다.
  • QTextEdit: 여러 줄 텍스트 입력을 위한 위젯입니다.

4. 윈도우 설정

self.setWindowTitle('QGridLayout')
self.setGeometry(300, 300, 300, 200)
self.show()

 

 

  • setWindowTitle: 윈도우 제목을 설정합니다.
  • setGeometry: 윈도우의 위치와 크기를 지정합니다.
    • (x, y, width, height) 순서로 설정됩니다.

실행 결과

코드를 실행하면 아래와 같은 윈도우가 생성됩니다.

 

 

  • TitleAuthor는 한 줄 입력란(QLineEdit),
  • Review는 여러 줄 입력란(QTextEdit)으로 구성되어 있습니다.
  •  

 

QGridLayout의 특징

  • 그리드 레이아웃은 행(row)과 열(column)을 기준으로 위젯을 배치합니다.
  • 여러 개의 위젯을 체계적으로 정렬할 때 유용합니다.
  • 하나의 셀에 여러 행 또는 열을 차지하도록 설정할 수도 있습니다.

QGridLayout 추가 메서드

메서드설명

addWidget(widget, row, column) 지정된 위치에 위젯을 추가합니다.
addWidget(widget, row, column, rowspan, colspan) 위젯을 여러 행/열에 걸쳐 배치합니다.
setSpacing(spacing) 셀 간의 간격을 설정합니다.
setColumnStretch(column, value) 특정 열의 비율을 설정합니다. (값이 클수록 공간을 더 많이 차지함)
setRowStretch(row, value) 특정 행의 비율을 설정합니다.

 

활용 팁

  1. 다양한 위젯 배치
    QGridLayout은 버튼, 슬라이더, 콤보박스 등 다양한 위젯을 배치할 수 있습니다.
  2. 동적 레이아웃 구성
    위젯을 추가/삭제하거나 크기를 조정하여 반응형 UI를 구성할 수 있습니다.
  3. 공간 비율 조정
    setColumnStretch()와 setRowStretch()를 사용하면 특정 행이나 열이 더 많은 공간을 차지하도록 설정할 수 있습니다.

결론

QGridLayout은 PyQt5에서 유연하고 강력한 레이아웃 관리 도구로, 복잡한 UI를 간단히 구현할 수 있습니다.
이번 포스팅에서 소개한 예제를 바탕으로 QGridLayout을 활용한 다양한 프로젝트를 시도해 보세요! 😊

 

728x90
반응형
728x90
반응형

PyQt5에서 QPushButton은 가장 기본적인 UI 위젯 중 하나로, 사용자가 특정 작업을 실행하도록 트리거 역할을 합니다. 이번 포스팅에서는 QPushButton의 주요 메서드와 시그널(이벤트)에 대해 살펴보고, 이를 활용한 간단한 예제 코드를 작성해 보겠습니다.


QPushButton의 주요 기능

QPushButton의 생성

QPushButton은 텍스트, 아이콘, 스타일 등을 지정할 수 있는 버튼 위젯입니다.
다음은 QPushButton의 생성 방법과 주요 속성입니다.

btn = QPushButton('Button Text', parent)

 

  • 첫 번째 인자: 버튼의 텍스트를 설정합니다.
  • 두 번째 인자: 버튼의 부모 위젯을 지정합니다.

주요 메서드와 속성

메서드/속성설명

setText(text) 버튼의 텍스트를 설정합니다.
text() 버튼의 텍스트를 반환합니다.
setEnabled(state) 버튼의 활성화 여부를 설정합니다. (True: 활성화, False: 비활성화)
isEnabled() 버튼이 활성화 상태인지 확인합니다.
setCheckable(state) 버튼을 토글 가능한 상태로 설정합니다. (True: 체크 가능, False: 체크 불가)
isChecked() 버튼이 체크된 상태인지 확인합니다. (setCheckable(True) 설정 후 사용 가능)
setIcon(icon) 버튼에 아이콘을 추가합니다.

QPushButton의 주요 시그널(이벤트)

시그널설명

clicked() 버튼이 클릭되었을 때 발생합니다.
pressed() 버튼이 눌렸을 때 발생합니다.
released() 버튼을 눌렀다 떼었을 때 발생합니다.
toggled(state) 버튼이 체크 상태가 변경될 때 발생합니다. (setCheckable(True) 설정 후 사용 가능)

 

728x90

예제 코드: QPushButton의 다양한 기능 활용

다음은 QPushButton의 주요 기능을 활용한 간단한 예제입니다.

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # 체크 가능한 버튼
        btn1 = QPushButton('&Button1', self)
        btn1.setCheckable(True)  # 토글 가능한 버튼 설정
        btn1.toggle()  # 초기 상태를 체크 상태로 설정

        # 일반 버튼
        btn2 = QPushButton(self)
        btn2.setText('Button&2')

        # 비활성화된 버튼
        btn3 = QPushButton('Button3', self)
        btn3.setEnabled(False)  # 버튼 비활성화

        # 레이아웃 설정
        vbox = QVBoxLayout()
        vbox.addWidget(btn1)
        vbox.addWidget(btn2)
        vbox.addWidget(btn3)

        self.setLayout(vbox)
        self.setWindowTitle('QPushButton Example')
        self.setGeometry(300, 300, 300, 200)
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

코드 설명

  1. 버튼 1 (btn1)
    • setCheckable(True)를 사용해 토글 버튼으로 설정했습니다.
    • toggle()로 초기 상태를 체크 상태로 설정했습니다.
  2. 버튼 2 (btn2)
    • setText()를 통해 버튼의 텍스트를 설정했습니다.
    • 텍스트에는 &를 사용하여 **단축키(Alt+B)**를 추가했습니다.
  3. 버튼 3 (btn3)
    • setEnabled(False)를 통해 비활성화 상태로 설정했습니다.
    • 사용자가 클릭할 수 없는 상태로 만들어졌습니다.

실행 결과

 


QPushButton의 시그널 활용 예시

다음은 버튼의 주요 시그널을 활용한 예제입니다.

import sys
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout


class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.btn = QPushButton('Click Me', self)
        self.btn.clicked.connect(self.on_click)
        self.btn.pressed.connect(self.on_press)
        self.btn.released.connect(self.on_release)

        vbox = QVBoxLayout()
        vbox.addWidget(self.btn)

        self.setLayout(vbox)
        self.setWindowTitle('QPushButton Signals')
        self.setGeometry(300, 300, 300, 200)
        self.show()

    def on_click(self):
        print('Button clicked!')

    def on_press(self):
        print('Button pressed!')

    def on_release(self):
        print('Button released!')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

 


실행 결과

  1. 버튼을 누르면 "Button pressed!" 메시지가 출력됩니다.
  2. 버튼을 뗄 때 "Button released!" 메시지가 출력됩니다.
  3. 클릭 동작이 완료되면 "Button clicked!" 메시지가 출력됩니다.


결론

PyQt5의 QPushButton은 버튼 하나만으로도 다양한 상호작용과 UI 구성을 지원합니다.

  • 기본적으로 클릭 이벤트를 처리하거나, 토글 가능한 상태를 설정할 수 있습니다.
  • 시그널(이벤트)을 활용하면 버튼과 사용자 간의 상호작용을 보다 유연하게 처리할 수 있습니다.

이번 포스팅을 통해 QPushButton의 기본적인 사용법을 익히고, 자신만의 PyQt5 프로젝트에 활용해 보세요! 😊

728x90
반응형
728x90
반응형

PyQt5는 GUI 애플리케이션을 제작하기 위한 강력한 라이브러리로, 메뉴와 같은 다양한 인터페이스 구성 요소를 쉽게 구현할 수 있습니다. 이번 글에서는 PyQt5를 사용하여 간단한 메뉴를 만드는 방법을 소개합니다.


전체코드

아래 코드는 PyQt5를 사용하여 메뉴를 생성하는 간단한 예제입니다. File 메뉴와 Exit 액션을 추가하여, 사용자가 메뉴를 통해 프로그램을 종료할 수 있도록 구성되어 있습니다.

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QAction, qApp


class MyApp(QMainWindow):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        # Exit 액션 정의
        exitAction = QAction('Exit', self)
        exitAction.setShortcut('Ctrl+Q')  # 단축키 설정
        exitAction.setStatusTip('Exit application')  # 상태 표시줄 메시지
        exitAction.triggered.connect(qApp.quit)  # 종료 이벤트 연결

        # 상태 표시줄 생성
        self.statusBar()

        # 메뉴바 생성
        menubar = self.menuBar()
        menubar.setNativeMenuBar(False)  # macOS의 기본 메뉴바 동작을 비활성화
        filemenu = menubar.addMenu('&File')  # File 메뉴 추가
        filemenu.addAction(exitAction)  # Exit 액션 추가

        # 창 속성 설정
        self.setWindowTitle('Menubar')
        self.setGeometry(300, 300, 300, 200)
        self.show()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

728x90

코드 설명

1. QMainWindow 기반 클래스 사용

QMainWindow는 PyQt5에서 창을 생성하기 위한 표준 클래스입니다. 메뉴바, 툴바, 상태 표시줄 등 다양한 GUI 구성 요소를 기본적으로 지원합니다.

2. Exit 액션 추가

exitAction = QAction('Exit', self)
exitAction.setShortcut('Ctrl+Q')  # 단축키 설정
exitAction.setStatusTip('Exit application')  # 상태 표시줄에 표시될 메시지
exitAction.triggered.connect(qApp.quit)  # 메뉴 선택 시 애플리케이션 종료
  • QAction: 메뉴에서 사용할 액션을 정의합니다.
  • setShortcut: 단축키를 설정합니다.
  • setStatusTip: 상태 표시줄에 표시할 힌트를 제공합니다.
  • triggered.connect: 액션이 트리거될 때 실행할 작업을 연결합니다.

3. 메뉴바 생성

menubar = self.menuBar()
menubar.setNativeMenuBar(False)  # macOS 기본 메뉴바 비활성화
filemenu = menubar.addMenu('&File')  # File 메뉴 추가
filemenu.addAction(exitAction)  # Exit 액션 추가
  • menuBar: 메뉴바를 생성합니다.
  • addMenu: 메뉴바에 새 메뉴를 추가합니다.
  • addAction: 특정 메뉴에 액션을 연결합니다.
  • setNativeMenuBar(False): macOS에서는 기본적으로 메뉴바가 상단에 고정됩니다. 이를 창 내부로 표시하려면 해당 설정을 비활성화합니다.

4. 상태 표시줄 생성

self.statusBar()
  • 메뉴나 액션과 관련된 힌트를 사용자에게 제공하기 위해 상태 표시줄을 생성합니다.

5. 창 속성 설정

self.setWindowTitle('Menubar')
self.setGeometry(300, 300, 300, 200)
self.show()
  • setWindowTitle: 창의 제목을 설정합니다.
  • setGeometry: 창의 위치와 크기를 설정합니다.

실행 결과

위 코드를 실행하면 다음과 같은 GUI 창이 나타납니다:

  • File 메뉴 클릭 시 Exit 옵션이 나타납니다.
  • Ctrl+Q 단축키를 누르거나 Exit을 클릭하면 프로그램이 종료됩니다.

주요 학습 포인트

  1. PyQt5에서 QMainWindow를 활용한 GUI 애플리케이션 개발 방법을 익힐 수 있습니다.
  2. 메뉴와 액션을 생성하고 연결하는 과정을 이해할 수 있습니다.
  3. 상태 표시줄을 사용하여 사용자 경험(UX)을 향상시키는 방법을 배울 수 있습니다.

PyQt5를 활용하면 이 외에도 다양한 기능을 쉽게 구현할 수 있습니다. 메뉴에 서브 메뉴를 추가하거나, 도구 모음을 생성하는 방법도 이어서 학습해 보세요! 😊

728x90
반응형
728x90
반응형

 

PyQt5는 Python에서 GUI(Graphical User Interface)를 구현하기 위해 널리 사용되는 라이브러리입니다. 이번 포스팅에서는 PyQt5를 사용해 간단한 창을 여는 방법을 소개합니다.


1. PyQt5 설치하기

PyQt5를 사용하기 위해서는 먼저 라이브러리를 설치해야 합니다. 다음 명령어를 터미널이나 커맨드라인에서 실행하세요:

> pip install pyqt5

설치가 성공적으로 완료되면 PyQt5와 관련된 패키지가 다운로드됩니다. 출력 예시는 다음과 같습니다:

Collecting pyqt5
  Downloading PyQt5-5.15.11-cp38-abi3-win_amd64.whl (6.9 MB)
   ...
Successfully installed PyQt5-Qt5-5.15.2 PyQt5-sip-12.16.1 pyqt5-5.15.11

 


2. PyQt5 기본 코드 설명

다음은 PyQt5를 사용해 간단한 창을 만드는 코드입니다:

전체 코드

import sys
from PyQt5.QtWidgets import QApplication, QWidget


class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('My First Application')
        self.move(300, 300)
        self.resize(400, 200)
        self.show()


if __name__ == '__main__':
   app = QApplication(sys.argv)
   ex = MyApp()
   sys.exit(app.exec_())

728x90

코드 분석

1. PyQt5 모듈 가져오기

import sys
from PyQt5.QtWidgets import QApplication, QWidget
  • sys: 시스템 관련 작업을 처리하기 위한 모듈입니다. 프로그램 종료 시 필요한 인자를 전달합니다.
  • QApplication: PyQt5 프로그램에서 반드시 생성해야 하는 객체로, GUI 애플리케이션의 기본적인 환경을 제공합니다.
  • QWidget: PyQt5에서 기본 창 역할을 하는 클래스입니다.

2. MyApp 클래스 정의

class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
  • MyAppQWidget을 상속받아 정의한 클래스입니다.
  • __init__ 메서드에서 부모 클래스(QWidget)의 생성자를 호출한 뒤, 사용자 정의 초기화 메서드 initUI()를 실행합니다.

3. UI 초기화

    def initUI(self):
        self.setWindowTitle('My First Application')
        self.move(300, 300)
        self.resize(400, 200)
        self.show()
  • setWindowTitle: 창의 제목을 설정합니다.
  • move: 창의 시작 위치를 설정합니다. (x=300, y=300)
  • resize: 창의 크기를 설정합니다. (너비 400, 높이 200)
  • show: 창을 화면에 표시합니다.

4. 프로그램 실행

if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())
  • QApplication 객체 생성: sys.argv를 인자로 전달하여 애플리케이션 객체를 생성합니다.
  • MyApp 객체 생성: MyApp 클래스의 인스턴스를 생성합니다.
  • app.exec_(): 이벤트 루프를 실행합니다. 프로그램이 종료될 때까지 계속 실행되며, 종료 시 반환 값을 시스템에 전달합니다.

3. 실행 결과

위 코드를 실행하면 다음과 같은 창이 열립니다:

  • 제목: My First Application
  • 크기: 400 x 200
  • 위치: 화면에서 x=300, y=300 지점에 표시

 


4. 추가적인 내용

PyQt5 학습 포인트

  1. 위젯 추가하기: 창에 버튼, 레이블, 텍스트 입력창 등을 추가하는 방법을 학습하세요.
  2. 레이아웃 관리: 위젯들을 창 내부에서 효율적으로 배치하는 방법을 익히세요.
  3. 이벤트 처리: 버튼 클릭 등 사용자 동작에 반응하는 이벤트를 처리하는 방법을 알아보세요.

참고 자료


이번 포스팅에서는 PyQt5를 이용한 간단한 창 구현 방법을 살펴보았습니다. PyQt5는 강력한 기능을 제공하며, 이를 활용해 다양한 GUI 애플리케이션을 제작할 수 있습니다. 앞으로 PyQt5로 더욱 흥미로운 애플리케이션을 만들어 보세요!

728x90
반응형
728x90
반응형

사진 속에는 우리가 눈으로 볼 수 없는 다양한 메타데이터가 포함되어 있습니다. 특히 스마트폰이나 GPS 기능이 있는 카메라로 촬영한 사진에는 GPS 정보가 포함될 수 있습니다. 이번 포스팅에서는 파이썬을 사용해 이미지에서 GPS 정보를 추출하는 방법을 소개합니다.


준비물

이 작업을 위해 두 가지 라이브러리가 필요합니다: PillowExifRead. 아래 명령어를 사용하여 설치할 수 있습니다.


Pillow

Pillow는 Python의 강력한 이미지 처리 라이브러리로, 이미지 파일을 열고, 읽고, 저장하며 다양한 변환 작업(예: 크기 조정, 포맷 변환 등)을 수행할 수 있습니다.

이 포스팅에서는 이미지를 열고 EXIF 메타데이터를 추출하기 위해 사용됩니다. 직관적이고 간단한 API 덕분에 이미지 처리에 널리 활용됩니다.


ExifRead

ExifRead는 이미지의 EXIF 메타데이터를 분석하는 데 특화된 라이브러리입니다. GPS 정보와 같은 세부 데이터를 효율적으로 읽고, 해석하는 기능을 제공합니다.

Pillow만으로도 EXIF 데이터를 읽을 수 있지만, ExifRead는 특히 GPS 데이터를 더 세밀하고 직관적으로 다룰 수 있도록 설계되어 있습니다.

 

pip install Pillow ExifRead

코드 구현

다음은 파이썬으로 이미지의 GPS 정보를 추출하는 코드입니다.

1. 이미지의 EXIF 데이터 읽기

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_exif_data(image_path):
    """이미지에서 Exif 데이터를 추출합니다."""
    try:
        image = Image.open(image_path)
        exif_data = image._getexif()
        
        if not exif_data:
            return None
        
        exif = {}
        for tag, value in exif_data.items():
            tag_name = TAGS.get(tag, tag)  # 태그를 사람이 읽을 수 있는 이름으로 변환
            exif[tag_name] = value
        
        return exif
    except Exception as e:
        print(f"Error reading EXIF data: {e}")
        return None
  • Image.open(image_path): Pillow를 사용해 이미지를 엽니다.
  • image._getexif(): 이미지의 EXIF 데이터를 추출합니다.
  • TAGS.get(tag, tag): EXIF 태그 번호를 사람이 읽을 수 있는 이름으로 변환합니다.
728x90

2. GPS 정보 추출

def get_geotagging(exif_data):
    """Exif 데이터에서 GPS 정보를 추출합니다."""
    if not exif_data or "GPSInfo" not in exif_data:
        return None
    
    gps_info = exif_data["GPSInfo"]
    geotags = {}
    
    for key, val in gps_info.items():
        tag_name = GPSTAGS.get(key, key)  # GPS 태그 이름 변환
        geotags[tag_name] = val
    
    return geotags
  • exif_data["GPSInfo"]: EXIF 데이터에서 GPS 정보를 포함하는 부분만 추출합니다.
  • GPSTAGS.get(key, key): GPS 태그 번호를 사람이 읽을 수 있는 이름으로 변환합니다.

3. GPS 데이터를 도(degree)로 변환

def convert_to_degrees(value):
    """GPS 좌표 값을 도(degree)로 변환합니다."""
    d, m, s = value  # degree, minute, second 형식
    return d + (m / 60.0) + (s / 3600.0)

EXIF 데이터에서 GPS 좌표는 (degree, minute, second) 형식으로 저장됩니다. 이를 십진수 형식으로 변환하는 함수입니다.


4. 위도와 경도 계산

def get_coordinates(geotags):
    """GPS 정보에서 위도와 경도를 추출합니다."""
    if not geotags:
        return None
    
    lat = geotags.get("GPSLatitude")
    lat_ref = geotags.get("GPSLatitudeRef")
    lon = geotags.get("GPSLongitude")
    lon_ref = geotags.get("GPSLongitudeRef")
    
    if not lat or not lon or not lat_ref or not lon_ref:
        return None
    
    lat = convert_to_degrees(lat)
    if lat_ref != "N":
        lat = -lat
    
    lon = convert_to_degrees(lon)
    if lon_ref != "E":
        lon = -lon
    
    return lat, lon

 

  • GPSLatitude****, ********GPSLongitude: 위도와 경도 정보를 가져옵니다.
  • GPSLatitudeRef****, ********GPSLongitudeRef: 위도/경도의 북(N)/남(S), 동(E)/서(W) 방향을 확인합니다. 방향이 남(S) 또는 서(W)일 경우 음수로 변환합니다.

전체 코드

위의 함수들을 조합하면, 이미지에서 GPS 정보를 추출하는 전체 코드는 다음과 같습니다:

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS

def get_exif_data(image_path):
    try:
        image = Image.open(image_path)
        exif_data = image._getexif()
        if not exif_data:
            return None
        exif = {TAGS.get(tag, tag): value for tag, value in exif_data.items()}
        return exif
    except Exception as e:
        print(f"Error reading EXIF data: {e}")
        return None

def get_geotagging(exif_data):
    if not exif_data or "GPSInfo" not in exif_data:
        return None
    gps_info = exif_data["GPSInfo"]
    geotags = {GPSTAGS.get(key, key): val for key, val in gps_info.items()}
    return geotags

def convert_to_degrees(value):
    d, m, s = value
    return d + (m / 60.0) + (s / 3600.0)

def get_coordinates(geotags):
    if not geotags:
        return None
    lat = geotags.get("GPSLatitude")
    lat_ref = geotags.get("GPSLatitudeRef")
    lon = geotags.get("GPSLongitude")
    lon_ref = geotags.get("GPSLongitudeRef")
    if not lat or not lon or not lat_ref or not lon_ref:
        return None
    lat = convert_to_degrees(lat)
    if lat_ref != "N":
        lat = -lat
    lon = convert_to_degrees(lon)
    if lon_ref != "E":
        lon = -lon
    return lat, lon

# 사용 예제
image_path = "example.jpg"  # 이미지 경로
exif_data = get_exif_data(image_path)
geotags = get_geotagging(exif_data)

if geotags:
    coordinates = get_coordinates(geotags)
    if coordinates:
        print(f"GPS Coordinates: {coordinates}")
    else:
        print("GPS 정보가 없습니다.")
else:
    print("Exif에 GPS 정보가 없습니다.")

결과

사진에 GPS 정보가 포함되어 있다면, 위 코드를 실행하면 다음과 같은 출력 결과를 얻을 수 있습니다:

GPS Coordinates: (37.7749, -122.4194)

 

이 결과는 위도(latitude)와 경도(longitude)를 나타냅니다. 예를 들어, 37.7749, -122.4194는 샌프란시스코의 좌표입니다.


주의사항

  1. GPS 정보 유무: 모든 이미지에 GPS 정보가 포함되어 있지는 않습니다. 스마트폰이나 GPS 기능이 있는 카메라로 촬영된 사진만 GPS 정보를 포함할 가능성이 높습니다.
  2. EXIF 제거 여부: 일부 소셜 미디어나 편집 프로그램은 이미지를 저장할 때 EXIF 데이터를 제거할 수 있습니다.
  3. 라이브러리 버전: 최신 버전의 Pillow를 사용하는 것을 권장합니다.
728x90
반응형
728x90
반응형

파이썬을 이용하여 마우스를 특정한 위치에 자동으로 클릭하는 프로그램을 만들어 보겠습니다. 특정 위치에 대한 정보를 얻고 그 위치에 마우스 포인터를 이동 시키고 몇초 간격으로 클릭을 실행하는 프로그램입니다. 프로그램은 GUI를 이용하여 만들어 볼 건데, 저도 처음 사용하는 라이브러리인 tkinter 를 사용해 보겠습니다. 간단한 설명 문서는 아래 사이트를 참조 하면 됩니다.

https://docs.python.org/ko/3/library/tkinter.html
 

tkinter — Tcl/Tk 파이썬 인터페이스 — Python 3.10.2 문서

tkinter — Tcl/Tk 파이썬 인터페이스 소스 코드: Lib/tkinter/__init__.py The tkinter package (《Tk interface》) is the standard Python interface to the Tcl/Tk GUI toolkit. Both Tk and tkinter are available on most Unix platforms, including mac

docs.python.org

 

마우스를 제어하기 위하여 키보드나 마우스를 제어할 수 있는 pyput 과 pyautogui 을 이용합니다. 관련 사이트는 아래를 참조하면 됩니다.

https://pypi.org/project/pynput/
 

pynput

Monitor and control user input devices

pypi.org

https://pyautogui.readthedocs.io/en/latest/
 

Welcome to PyAutoGUI’s documentation! — PyAutoGUI documentation

Welcome to PyAutoGUI’s documentation! PyAutoGUI lets your Python scripts control the mouse and keyboard to automate interactions with other applications. The API is designed to be simple. PyAutoGUI works on Windows, macOS, and Linux, and runs on Python 2

pyautogui.readthedocs.io

 

위 이미지와 같이 tkinter를 사용하여 다이얼로그를 만들도록 하겠습니다. 우선 tkinter를 사용하기 위해서 import를 해줍니다. 그리고 아래와 같이 소스를 코딩하면 위와 같이 나타납니다.

from tkinter import *

root = Tk() # Tk클래스 객체 생성
root.title("마우스 자동 클릭") # 타이틀 이름 설정
root.geometry("550x180") # grid 형식으로 너비x높이 설정(픽셀단위)

root.mainloop() # Tk 클래스 객체의 mainloop 실행하여 다이얼로그 표시함함

빈 다이얼로그 창에 코드를 추가하여 버튼과 입력창을 만들어 보겠습니다. 

from tkinter import *

root = Tk() # Tk클래스 객체 생성
root.title("마우스 자동 클릭") # 타이틀 이름 설정
root.geometry("550x180") # grid 형식으로 너비x높이 설정(픽셀단위)

################
label1 = Label(root, text="X좌표")
label1.grid(row=1, column=1)

entry1 = Entry(root, width=10)
entry1.grid(row=1, column=2)

label2 = Label(root, text="Y좌표")
label2.grid(row=1, column=3)

entry2 = Entry(root, width=10)
entry2.grid(row=1, column=4)

button1 = Button(root, text="마우스위치")
button1.grid(row=1, column=5)

#################
label3 = Label(root, text="반복횟수")
label3.grid(row=2, column=1)

entry3 = Entry(root, width=10)
entry3.grid(row=2, column=2)
entry3.insert("end","120")

label4 = Label(root, text="인터벌(초)")
label4.grid(row=2, column=3)

entry4 = Entry(root, width=10)
entry4.grid(row=2, column=4)
entry4.insert("end","30")

##################
label5 = Label(root, text="* 120 회 * 30초 = 3600초(60분) 동안 동작")
label5.grid(row=3, column=2, columnspan=4)

##################
button2 = Button(root, text="클릭 시작")
button2.grid(row=4, column=3)
##################

root.mainloop() # Tk 클래스 객체의 mainloop 실행하여 다이얼로그 표시함함

위 소스로 실행되면 다이얼로그 창에 원하는 위치에 버튼과 입력창을 만들 수 있습니다.

이제 버튼이 클릭했을 때 동작하는 함수를 만들어 보겠습니다. 각 버튼에 아래와 같이 클릭시 실행하는 함수를 선언 할 수 있습니다.

button1 = Button(root, text="마우스위치", command=lambda: mousePointerPos())
# (중략)
button2 = Button(root, text="클릭 시작", command = lambda:startMacro())

위에서 실행될 함수를 작성하여 줍니다.

def mousePointerPos():
    with mouse.Listener(
        on_click=posClick
    ) as listener: listener.join()
    entry1.insert("end", x1)
    entry2.insert("end", y1)

def posClick(x, y, button, pressed):
    if pressed:
        global x1
        global y1
        x1 = x
        y1 = y

    if not pressed:
        return False

def startMacro():
    click_num = int(entry3.get())
    intervalSec = int(entry4.get())

    ##반복시작
    for a in range(0, click_num):
        time.sleep(intervalSec)
        pyautogui.click(x1, y1)

아래는 전체 코드입니다.

 

from tkinter import *
from pynput import mouse
import pyautogui
import time

root = Tk() # Tk클래스 객체 생성
root.title("마우스 자동 클릭") # 타이틀 이름 설정
root.geometry("550x180") # grid 형식으로 너비x높이 설정(픽셀단위)

################
label1 = Label(root, text="X좌표")
label1.grid(row=1, column=1)

entry1 = Entry(root, width=10)
entry1.grid(row=1, column=2)

label2 = Label(root, text="Y좌표")
label2.grid(row=1, column=3)

entry2 = Entry(root, width=10)
entry2.grid(row=1, column=4)

button1 = Button(root, text="마우스위치", command=lambda: mousePointerPos())
button1.grid(row=1, column=5)

#################
label3 = Label(root, text="반복횟수")
label3.grid(row=2, column=1)

entry3 = Entry(root, width=10)
entry3.grid(row=2, column=2)
entry3.insert("end","120")

label4 = Label(root, text="인터벌(초)")
label4.grid(row=2, column=3)

entry4 = Entry(root, width=10)
entry4.grid(row=2, column=4)
entry4.insert("end","30")

# checkbutton1 = Checkbutton(root, text="무한")
# checkbutton1.grid(row=2, column=5)
##################
label5 = Label(root, text="* 120 회 * 30초 = 3600초(60분) 동안 동작")
label5.grid(row=3, column=2, columnspan=4)

##################
button2 = Button(root, text="클릭 시작", command = lambda:startMacro())
button2.grid(row=4, column=3)
##################


def mousePointerPos():
    with mouse.Listener(
        on_click=posClick
    ) as listener: listener.join()
    entry1.insert("end", x1)
    entry2.insert("end", y1)

def posClick(x, y, button, pressed):
    if pressed:
        global x1
        global y1
        x1 = x
        y1 = y

    if not pressed:
        return False

def startMacro():
    click_num = int(entry3.get())
    intervalSec = int(entry4.get())

    ##반복시작
    for a in range(0, click_num):
        time.sleep(intervalSec)
        pyautogui.click(x1, y1)

root.mainloop() # Tk 클래스 객체의 mainloop 실행하여 다이얼로그 표시함함

 

지금 까지 간단하게 다이얼로그에 버튼, 입력창을 만들고 이것을 마우스 위치를 알아내여 마우스 클릭을 자동으록 실행하는 프로그램을 만들어 보았습니다. 

728x90
반응형
728x90
반응형

프로그램을 만들다 보면 많은 오류를 만나게 됩니다. 이러한 오류에 대해 예외적으로 오류를 처리할 수 있는 방법을 알아보도록 하겠습니다.

 

예외처리

오류 예외 처리 기법

아래의 형식으로 예외처리를 어떻게 할 수 있는지 알아보겠습니다.

# 1. try, except만 쓰는 방법
try:
    ...
except:
    ...
# =>  오류 종류에 상관없이 오류가 발생하면 except 블록을 수행


# 2. 발생 오류만 포함한 except문
try:
    ...
except 발생 오류:
    ...
# => 이 경우는 오류가 발생했을 때 except문에 미리 정해 놓은 오류 이름과 일치할 때만 except 블록을 수행

# 3. 발생 오류와 오류 메시지 변수까지 포함한 except문
try:
    ...
except 발생 오류 as 오류 메시지 변수:
    ...
# => 이 경우는 두 번째 경우에서 오류 메시지의 내용까지 알고 싶을 때 사용하는 방법

try ... finally

finally 절은 try 수행 도중 예외 발생 여부와 상관없이 무조건 수행이 됩니다. 이는 파일을 열고 닫는 부분에서 많이 사용을 합니다.

f = open('c:\\dev\\new.txt', 'w')
try:
    # 수행
finally:
    f.close()

여러개의 오류처리하기

try 문 안에서 여러개의 오류를 처리하기 위해서는 다음과 같은 형식을 사용합니다.

try:
    ...
except 발생 오류1:
   ... 
except 발생 오류2:
   ...

만약 발생 오류1, 발생 오류2 를 동일하게 처리하기 위해서는 괄호로 묶어 except (발생 오류1, 발생 오류2) as e 와 같은 형식으로 사용을 합니다.

 

오류 발생시키기

파이썬에서는 raise 명령어를 사용해 오류를 강제로 발생시킬 수 있습니다. 아래와 같은 형식으로 사용합니다.

raise 발생오류

 

예외 만들기

예외는 직접 만들어서 사용할 수 있습니다. 바로 상속을 이용을 하는 것입니다. 이때 상속을 받을 부모는 Exception 클래스입니다.

class MyError(Exception):
    pass

직접 만든 예외를 이용한 프로그램 코드 입니다.

class MyError(Exception):
    pass


def say_nick(nick):
    if nick == '바보':
        raise MyError()
    print(nick)


try:
    say_nick("천사")
    say_nick("바보")
except MyError:
    print("허용되지 않는 별명입니다.")
    
    
### 결과
천사
허용되지 않는 별명입니다.
728x90
반응형

+ Recent posts