본문 바로가기
업무자동화/파이썬-아래아한글 자동화 기초

[PySide6 GUI] 체크버튼으로 한/글 열고 닫기

by Martinii의 회사원코딩 2021. 7. 6.

시작하며

요즘 아래아한글 자동화로 쏠쏠하게 정부 및 각종 기관의 자문을 수행하고 있습니다.

근데 이게, 저 혼자 실행할 때는 고민하지 않았던 GUI 부분이

아무래도 정부기관 자문을 하게 되니 불가피하게 필요하게 되더군요.

"소스코드를 보내줄테니 파이썬과 파이참 깔고 모듈 설치 후 실행해보라"고 할 수도 없는 노릇이고

결국엔 GUI까지 짜서 보내주게 되는데,

그 과정에서 얻은 나름의 노하우도 블로그에 공유하고 싶습니다.

 

한/글 엑셀 자동화보다 PySIde6 카테고리 조회수가 높다?

제 블로그 카테고리 중 PySide6 관련한 포스팅이 사실 좀 뜸하긴 하지만

나름 조회수를 톡톡히 올려주고 있기는 합니다.

아마 많이들 PyQt5나 PySide2를 써오시다가 최근 PySide6로 갈아타는 분들이 있어서 그런가 싶습니다.

 

이번 시간에 진행해볼 튜토리얼은 GUI!

체크속성을 가진, 즉 한 번 누르면 눌린 상태가 되고, 한 번 더 누르면 해제되는 버튼을 하나만 만들고

버튼을 누르면 한/글 창이 열리고 버튼을 한 번 더 누르면 한/글 창이 닫히는 기능을 구현해 보고자 합니다.

이어지는 포스팅에서는 메뉴바와 여러 가지 요소를 하나씩 추가해보고 한/글 관련 기능도 붙여서

쓸모있고 보기 좋은 GUI를 만들어볼 예정입니다.

시연화면은

너무 간단한 "한/글 열고 닫기" 동작이지만, 가장 기본이 된다고 생각합니다.

이번 포스팅에서는 딱 여기까지만 진행해보겠습니다.

전체 코드는

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton
import win32com.client as win32


class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.button = QPushButton(parent=self)
        self.setCentralWidget(self.button)
        self.button.setCheckable(True)
        self.button.setText("클릭")
        self.button.clicked.connect(self.button_checked)

    def button_checked(self, checked):
        if checked:
            self.button.setText("한/글 열림")
            self.hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
            self.hwp.XHwpWindows.Item(0).Visible = True

        else:
            self.button.setText("한/글 닫힘")
            self.hwp.Quit()


app = QApplication()
window = MainWindow()
window.show()
app.exec()

코드설명

from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton
import win32com.client as win32

윗줄은 PySide6 관련 임포트, 아랫줄은 한/글을 열기 위한 win32com모듈 임포트입니다.

Qt로 GUI를 작성할 때 꼭 필요한 QApplication과 QMainWindow(혹은 QWidget), 그리고 버튼구현을 위한 QPushButton클래스를 from/import 구문으로 임포트했습니다.

 

class MainWindow(QMainWindow):

QMainWindow클래스를 상속받아 MainWindow라는 클래스를 생성합니다.

Q메인윈도우 클래스는 PySide6 튜토리얼 카테고리에서 설명한 포스팅을 남겨놓습니다. 참고하시기 바랍니다.

 

1. PySide6의 QMainWindow에 대해 알아봅시다.

QMainWindow 이전 포스팅에서 여섯 줄의 코드로 QWidget 창을 화면에 띄워봤고, QWidget 대신 QPushButton을 사용해서, 한 개의 위젯이 한 개의 창이 될 수 있다는 부분을 말씀드렸습니다. 나만 사용하는 스

www.martinii.fun

 

def __init__(self):

클래스의 생성자(Generator) 문법입니다.

객체지향 기반의 프로그래밍을 할 때 자주 접하는 "생성자"라는 용어 자체가 조금 어색한데,

파이썬에서는 클래스의 인스턴스를 생성할 때마다 실행해주는, 일종의 초기화 코드입니다.

    super(MainWindow, self).__init__()

상위클래스(QMainWindow)의 생성자를 실행하는 문법입니다. 간단히 super().__init__()라고 입력해도 괜찮습니다.

상위클래스인 QMainWindow의 생성자는 어떤 모습일까요?

파이참으로 한 번 탐색해봅시다. QMainWindow에다 캐럿을 놓고 Ctrl-B를 눌러봅니다.

아쉽게도 pass 한 줄입니다. 

PySide6 자체가 파이썬으로 쓰인 모듈이 아니다 보니(C++ 기반 Qt 파이썬 바인딩)

QMainWindow의 __init__()의 코드를 구체적으로 파악할 수는 없지만,

이런 경우라면 그냥 컨벤션이겠거니 하고 작성해 주시기 바랍니다.

실제로 super메서드의 __init__을 실행하지 않으면 런타임에러가 발생합니다.

super().__init__() 코드를 주석처리하고 실행한 결과

super().__init__() 코드를 주석처리하고 실행해봤더니

"MainWindow 오브젝트의 베이스클래스의 __init__ 메서드가 호출되지 않았다"는 메시지가 뜨네요..

 

    self.button = QPushButton(parent=self)
    self.setCentralWidget(self.button)
    self.button.setCheckable(True)
    self.button.setText("클릭")
    self.button.clicked.connect(self.button_checked)

메인윈도우 위젯 안에 집어넣을 "버튼"을 설정하는 코드 다섯 줄입니다.

각 의미는 첫 번째 라인부터 차례로

1. 버튼 생성(인스턴스 생성만 하고 아직 적용하지는 않은 상태)

2. 메인윈도우 위젯(self)의 중앙에 버튼을 세팅함

3. 버튼을 일반적인 푸쉬버튼이 아니라 체크버튼으로 바꿈(한 번 클릭하면 클릭된 상태, 다시 한 번 클릭하면 해제됨)

4. 버튼의 텍스트 설정

5. (중요) 버튼을 클릭하는 시그널을 self.button_checked라는 슬롯(메서드)와 연결하기

 

다섯 번째 라인의 "button_checked"는 제가 이해하기 쉽게 임의로 작성한 메서드 이름입니다.

바로 아래에 button_checked 메서드를 작성할 예정입니다.

 

def button_checked(self, checked):
    if checked:
        self.button.setText("한/글 열림")
        self.hwp = win32.gencache.EnsureDispatch("HWPFrame.HwpObject")
        self.hwp.XHwpWindows.Item(0).Visible = True
    else:
        self.button.setText("한/글 닫힘")
        self.hwp.Quit()

button_checked를 정의합니다.

시그널과 슬롯에 대해 조금 백그라운드가 있어야 이해하기 쉽기 때문에

시그널/슬롯에 대한 별도의 포스팅을 참고로 남겨놓습니다.

 

1. PySide6의 Signal과 Slot에 관하여

시그널과 슬롯 짐작컨대 이 몇 개 안 되는 튜토리얼 시리즈를 따라오시면서, 여러분이 가장 많이 하셨던 생각 중 하나는, "그래서 이 버튼이 뭔가 액션을 하게 하려면 어떻게 해야 하나?" 일 거라

www.martinii.fun

메서드 정의시 두 번째 파라미터로 들어가 있는 "checked"도 제가 알아보기 쉽게 임의로 작성한 이름입니다.

(임의로 수정하셔도 괜찮습니다.)

버튼이 체크, 해제될 때마다 바로 위에 입력한 button.clicked.connect를 통해

button_checked에게 특정한 신호를 보냅니다. 체크하면 True를, 체크해제하면 False를 각각 쏴주는 거죠.

button_checked 메서드는 True를 받고 if checked: 구문 아래의 코드, 한/글 열기를 실행하고, 

반대로 False를 받을 때는 else: 구문 아래 있는 코드, 한/글 닫기를 실행하게 됩니다.

 

app = QApplication()
window = MainWindow()
window.show()
app.exec()

app은 PySide6로 만든 최상위 어플리케이션 인스턴스입니다. 이 코드는 항상 실행되어야 합니다.

window는 위에서 생성한 MainWindow 클래스를 통해 생성된 인스턴스(실체)입니다.

실질적으로 모니터에 보이는 GUI창입니다.

window.show()는 window인스턴스를 모니터에 나타나게 합니다.

기본적으로는 숨겨진 상태입니다.

app.exec()는 GUI가 동작할 수 있게 "시동을 거는" 코드입니다.

 

혹 어떤 분들은 이런 궁금증을 가지실 겁니다.

그럼 app은 뭐고, window는 뭐냐? 이 간단한 GUI를 만들면서 인스턴스를 두 개나 생성하는 이유는?

이건 Qt의 작동 방식을 알면 간단히 풀리는 궁금증입니다.

짧게 설명드리면 app은 내부적으로 시그널-슬롯이 동작할 수 있도록 계속해서 이벤트루프를 돌려주는 인스턴스입니다.

app.exec()를 통해 이벤트루프를 시작합니다. window는 눈에 보이는 GUI창의 인스턴스고요.

이 부분도 전에 작성해 둔 포스팅이 있어 남겨놓습니다. 참고하시기 바랍니다.

 

[3/?] PySide6에서 가장 기초가 되는 QApplication과 QWidget

PySide6에서 가장 기초가 되는 두 가지 클래스, QApplication과 QWidget 안녕하세요? 회사원코딩입니다. 이번 포스팅에서 설명드릴 코드는 가장 단순한 창만들기입니다. 임포트문을 제외하면 네 줄밖에

www.martinii.fun

 

포스팅을 마치며

이 코드에는 크게 아쉬운 부분이 두 가지 있습니다.

1. 직접 한/글 창을 닫은 후 버튼을 클릭하면 이런 오류가 발생합니다. (닫을 한/글 창이 없어 발생하는 오류입니다.)

try/except문으로 간단히 예외처리를 해 주면 오류가 나지 않을텐데 말이죠.

꼭 예외처리를 해 줘야 하는 부분입니다.

 

2. 한/글 창에 글을 입력하거나 하면, 체크버튼으로 한/글 종료시 저장하겠냐고 물어보는 팝업이 뜹니다.

버튼을 한 번 클릭하는 것으로, 임의의 파일명으로 자동저장하고 종료까지 알아서 해 주면 좋을 것 같습니다.

 

이 포스팅을 끝까지 읽어주신 분들 중

코드를 어떻게 수정하면 좋을지 댓글로 남겨주신 분께는 (소정의 상품을 드리기는 좀 그렇고;)

한/글 관련해서 본인이 자동화하고 싶은 업무와 관련해서

무료로 자문을 드리도록 하겠습니다.

기간한정은 따로 두지 않으니 많은 참여 바랍니다.

 

긴 글 읽어주셔서 감사합니다.

행복한 하루 되세요!

 


부록 : 건강상식

의사들이 가장 기피하는 음식

Worst1

Worst2

Worst3

출처

 

 

 


donaricano-btn

댓글1

  • eom 2021.09.16 01:13

    덕분에 많은 것을 배우고 있습니다. 고맙습니다~
    그런데 질문 있습니다.
    qt에서 제공?하는 designer.exe로 (예를들어)윈도우.ui파일을 만들어서
    그 안에 hwpctrl을 QAxWidget에 심고 싶은데.. 제 능력 밖이더군요
    64비트 파이썬으론 불가능하고 32비트 에서 어찌어찌 열리긴 하는데
    만든 윈도우.ui안에는 안담기고 독립된 창으로 열리더군요.

    요지는 QPushButton과 한글창이 같은 창안에 구현될까요 입니다.
    알고계시면 한 수 부탁 드립니다.
    고맙습니다.


    답글