시작하며
요즘 아래아한글 자동화로 쏠쏠하게 정부 및 각종 기관의 자문을 수행하고 있습니다.
근데 이게, 저 혼자 실행할 때는 고민하지 않았던 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 튜토리얼 카테고리에서 설명한 포스팅을 남겨놓습니다. 참고하시기 바랍니다.
def __init__(self):
클래스의 생성자(Generator) 문법입니다.
객체지향 기반의 프로그래밍을 할 때 자주 접하는 "생성자"라는 용어 자체가 조금 어색한데,
파이썬에서는 클래스의 인스턴스를 생성할 때마다 실행해주는, 일종의 초기화 코드입니다.
super(MainWindow, self).__init__()
상위클래스(QMainWindow)의 생성자를 실행하는 문법입니다. 간단히 super().__init__()라고 입력해도 괜찮습니다.
상위클래스인 QMainWindow의 생성자는 어떤 모습일까요?
파이참으로 한 번 탐색해봅시다. QMainWindow에다 캐럿을 놓고 Ctrl-B를 눌러봅니다.
PySide6 자체가 파이썬으로 쓰인 모듈이 아니다 보니(C++ 기반 Qt 파이썬 바인딩)
QMainWindow의 __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를 정의합니다.
시그널과 슬롯에 대해 조금 백그라운드가 있어야 이해하기 쉽기 때문에
시그널/슬롯에 대한 별도의 포스팅을 참고로 남겨놓습니다.
메서드 정의시 두 번째 파라미터로 들어가 있는 "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창의 인스턴스고요.
이 부분도 전에 작성해 둔 포스팅이 있어 남겨놓습니다. 참고하시기 바랍니다.
포스팅을 마치며
이 코드에는 크게 아쉬운 부분이 두 가지 있습니다.
1. 직접 한/글 창을 닫은 후 버튼을 클릭하면 이런 오류가 발생합니다. (닫을 한/글 창이 없어 발생하는 오류입니다.)
try/except문으로 간단히 예외처리를 해 주면 오류가 나지 않을텐데 말이죠.
2. 한/글 창에 글을 입력하거나 하면, 체크버튼으로 한/글 종료시 저장하겠냐고 물어보는 팝업이 뜹니다.
버튼을 한 번 클릭하는 것으로, 임의의 파일명으로 자동저장하고 종료까지 알아서 해 주면 좋을 것 같습니다.
이 포스팅을 끝까지 읽어주신 분들 중
코드를 어떻게 수정하면 좋을지 댓글로 남겨주신 분께는 (소정의 상품을 드리기는 좀 그렇고;)
한/글 관련해서 본인이 자동화하고 싶은 업무와 관련해서
무료로 자문을 드리도록 하겠습니다.
기간한정은 따로 두지 않으니 많은 참여 바랍니다.
긴 글 읽어주셔서 감사합니다.
행복한 하루 되세요!
부록 : 건강상식
의사들이 가장 기피하는 음식
출처
'아래아한글 자동화 > python+hwp 중급' 카테고리의 다른 글
워드의 특수문자 단축키 지정, 한/글로는 어떻게 구현할까? (0) | 2021.07.08 |
---|---|
파이썬으로 한/글의 용지규격과 방향을 조회할 때 (0) | 2021.07.05 |
hwp.Run("AutoChangeRun") (0) | 2021.06.30 |
댓글