본문 바로가기
파이썬-PySide6(PyQt6)

1. PySide6 메모장 만들기 - 위젯 추가하기

by Martinii의 회사원코딩 2021. 4. 1.

우린 지금 어디쯤?

지금 우리는 윈도우10의 기본프로그램 중 하나인 메모장을 PySide6로 클론코딩하는 작업을 진행하고 있습니다. 지난 포스팅에서는 메모장의 틀을 만들고, 메뉴바를 완성했습니다. (아직 메뉴바에 기능을 구현하지는 않은 상태이고요.) 이번 두 번째 포스팅에서는 QtDesigner로 텍스트에디트 위젯을 추가하고 기본적인 기능을 구현하는 과정을 같이 진행해보려고 합니다. 포스팅 관련 궁금한 점은 댓글로 남겨주시면 답변 달아드리겠습니다.

QtDesigner 여는 건 익숙해지셨나요?

이번 시간엔 파이참으로 디자이너를 열어봅시다. Alt-F12를 눌러 터미널을 연 후에, "pyside6-designer"라고 입력하고 엔터를 쳐보세요.

파이참 터미널을 열고 pyside6-designer 실행

지난 번에 완성했던 ui파일을 아래 첨부해 둡니다. 다만, 디자이너에 익숙해지는 과정이라 생각하시고 1번 포스팅도 안 보셨다면 꼭 참고하셔서 디자이너작업을 해 보시기를 추천드립니다.

 


notepad_mainwindow.ui
0.01MB


 

디자이너로 이 파일을 열어봅시다.

Ctrl-R을 누르면 [미리 보기]창이 열립니다.

지난 시간에 완성한 메뉴바는 그럴싸해 보이긴 하는데, 아직 가장 중요한 기능 하나가 빠져 있습니다. 바로 텍스트 입력칸이 없습니다. 그 위젯을 후딱 추가해보겠습니다.

좌측 위젯상자에서 Plain Text Edit 선택

왼쪽 위젯상자 중간쯤, Input Widgets 안에 Plain Text Edit 위젯이 있습니다. 

Plain Text Edit

얘를 드래그해다가 우리 메인윈도우에 놓아봅시다.

드래그앤드롭으로 플레인텍스트 위젯을 삽입했습니다.

우리 메인윈도우가 아래처럼 변경되었습니다.

가운데 작은 부분이 텍스트위젯

Qt나 GUI를 처음 다루시는 분이라면 보통 이런 생각을 하실 것 같습니다.

마우스로 파란 점을 드래그해서 창 넓이만큼 벌리자.

정밀하게 넓혔지만..

근데 아마 이게 여러분이 원하는 모습을 아닐 것 같습니다. 왜냐면,

위젯의 크기 != 윈도우의 크기

이제 위젯의 사이즈조절이 왜 의미가 없는지 아셨겠죠?

그럼 메인윈도우 크기를 조절할 때 텍스트위젯의 크기가 같이 따라가게 하려면 어떻게 해야 하는지 보여드리겠습니다.

답은 바로, "레이아웃"을 적용하는 겁니다.

 

우선 메인윈도우 안의 텍스트위젯은 그대로 두시고,

디자이너화면 우측 상단의 객체 탐색기를 봐주세요. 아마 저와 비슷한 모양일 겁니다.

우측의 centralwidget에 빨간 금지표시가 보이시나요?

객체탐색기에 centralwidget을 보시면 빨간 통행금지표시 같은 동그라미가 표시돼 있습니다.

이 표시는 "레이아웃이 풀려 있는 상태"라는 뜻입니다. 그래서 어떤 위젯을 놓아도 QWidget객체인 centralwidget와 따로 놀게 되는 것이죠. 그래서 우리가 할 일은 centralwidget에 특정 레이아웃을 적용하는 겁니다. 이건 vertical이든 horizontal이든, 혹은 grid나 Form Layout이든 어떤 레이아웃을 적용해도 상관없습니다. 어차피 텍스트위젯 하나로만 꽉 채울 거니까 차이가 없거든요. 레이아웃을 잡는 방법은 아주 간단한데 여러가지 방법이 있습니다. 아래 세 가지 중 익숙하신 방법을 사용하시면 되겠습니다. 우선 레이아웃은 그리드레이아웃을 적용합시다. (다시 말하지만 다른 레이아웃도 괜찮습니다.)

 

첫 번째 방법. 메인윈도우 빈 격자부분에 마우스 우클릭 후 배치-격자형으로 배치(G)

(또는 클릭 후 Ctrl-5)

사실 격자형이 아니어도 됩니다. 수평이든 수직이든 폼이든 여기서는 상관없긴 합니다.

두 번째 방법. 우측 객체탐색기에서 centralwidget 선택 후 Ctrl-5

객체탐색기를 통한 메인윈도우 수정

세 번째 방법. centralwidget 선택 후 화면 상단의 툴바 중 레이아웃 아이콘들을 선택하는 방법

클릭하는 즉시 메인윈도우가 변경됩니다.

가급적 기호에 맞게 사용하시라고 여러 가지 방법을 보여드렸는데, 제일 친숙한 방법 하나만 익히시면 됩니다.

하여튼 이렇게 조치를 하셨으면 아래와 같이 창의 크기를 변경해도 위젯 크기가 자동으로 따라갑니다.

(어찌 보면 너무 당연한 기능인데, 직접 GUI를 만들어보려니깐 이런 것도 생각하게 되는군요...)

메인윈도우의 크기가 변함에 따라 내부의 위젯도 같이 변합니다. 레이아웃 덕분이죠.

여기까지 기본적인 메뉴화면과 텍스트창 그리고 하단의 상태표시줄이 만들어졌습니다.

이번 포스팅을 마치기 전에 기능 하나만 같이 추가해봅시다. 바로 "새로 만들기"입니다.

"새 창(W)" 기능 추가

윈도우10 메모장에서 "새 창(W)" 메뉴를 선택할 때마다 동일한 GUI가 하나씩 더 생성됩니다.

여러 개의 메모장을 생성할 수 있는 기능입니다.

본격적으로 다채로운 기능을 가진 멋진 메모장을 만들기 앞서, 시그널-슬롯 개념을 다시 한 번 짚어보면서,

Qt디자이너를 통해 메뉴기능을 추가하는 방법을 같이 알아보겠습니다. 사실 굉장히 간단합니다.

우선 현재까지 작업한 디자이너파일을 저장합니다. 저는 notepad_mainwindow.ui로 저장했습니다.

 

지난 QtDesigner 첫 포스팅에서   pyside6-uic 소스.ui -o 결과물.py   명령어를 이용해 파이썬파일로 컴파일을 하는 걸 보여드렸는데,

 

1. PySide6의 QtDesigner를 사용해봅시다.

QtDesigner 실행해보기 pip를 통해 PySide6를 설치했다면, 파이썬폴더\Library\bin이나 파이썬폴더\Lib\site-packages\PySide6 폴더 안에 designer.exe(또는 pyside6-designer.exe)가 같이 설치되어 있습니다. 귀..

www.martinii.fun

 

이번 시간에는 더욱 간편하게 디자이너에서 직접 py파일 내용을 복사해와서 파이참에 붙여넣는 방식으로 진행해봅시다.

디자이너 메뉴 중 폼 - Python코드 보기(P)를 선택한 후, 코드 팝업에서 모두 복사를 선택합니다.

코드를 클립보드로 복사했습니다.

이렇게 복사한 파이썬 코드를 기존의 notepad_mainwindow.py에 붙여넣기합니다.

기존의 notepad_mainwindow.py에 붙여넣기했습니다.

main.py 는 아래와 같습니다.

from PySide6.QtWidgets import QApplication, QMainWindow
from notepad_mainwindow import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)


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

이제 main.py 파일을 실행해봅니다. (파이참 단축키는 Ctrl-Shift-F10)

Ctrl-Shift-F10으로 main.py를 실행한 화면입니다.

메모장 윈도우가 하나 실행되었습니다.

모양도 어느 정도 갖춰져 있네요.

여기서 메모장을 생성하는 코드는 12, 13번 라인, 겨우 두 줄입니다.

window = MainWindow()
window.show()

그럼 시험삼아 코드를 아래와 같이 수정해보겠습니다.

from PySide6.QtWidgets import QApplication, QMainWindow
from notepad_mainwindow import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)


app = QApplication()
window = MainWindow()
window.show()
window1 = MainWindow()
window1.show()
app.exec_()

14, 15번 라인이 추가되었습니다. 실행해보면,

 

MainWindow 객체를 두 개 생성했더니, 메모장이 두 개 실행되었습니다.

감이 빠른 분들은 눈치채셨을 겁니다.

"새 창" 메뉴의 시그널을 찾아서 저 두 줄을 실행하게 하면 원하는 기능이 구현될 것 같지 않나요?

그럼 구체적으로 "새 창" 기능을 구현해 봅시다.

먼저 Qt디자이너를 다시 열어서 "새 창(W)" 메뉴 액션이름을 찾아보겠습니다.

파이참에서 Alt-F12키를 눌러 터미널을 연 후, pyside6-designer를 입력하고 엔터를 칩니다.

터미널을 열고 pyside6-designer를 실행합니다.

"열기"를 선택하고, 우리가 작업한 notepad_mainwindow.ui 파일을 선택합니다.

notepad_mainwindow.ui 파일을 열었습니다.

메인윈도우에서 파일(F)-새 창(W)를 선택한 후 objectName을 확인합니다.

제 경우 "action_W로 설정되어 있네요.

메뉴텍스트 지정할 때 괄호 안에 들어있던 W키를 넣어 자동생성된 이름입니다. 굳이 바꿀 필요가 없지만, 튜토리얼이니만큼 new_window라고 수정해보겠습니다.

objectName을 new_window로 수정하였습니다.

ui를 저장하고, 다시 한 번 파이썬 코드를 클립보드로 저장하고,

파이참을 열어서 notepad_mainwindow.py 에다 붙여넣은 후에, 디자이너를 닫습니다.

main.py 파일을 열어서 코드를 아래처럼 수정합니다. MainWindow 클래스 정의 부분만 추가되었습니다.

from PySide6.QtWidgets import QApplication, QMainWindow
from notepad_mainwindow import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setupUi(self)
        self.new_window.triggered.connect(self.add_window)
        self.windows = []

    def add_window(self):
        add_window = MainWindow()
        self.windows.append(add_window)
        add_window.show()


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

참고로 9~15번 라인만 수정하였습니다.

new_window 메뉴의 시그널(triggered)과, 그에 해당하는 슬롯인 add_window메서드를 정의하였으며,

인스턴스 내부에 windows라는 리스트를 추가하여 새 창이 생성될 때마다

self.windows에다가 해당 인스턴스를 추가하게 하였습니다.

(이런 식으로 인스턴스를 저장해 두지 않으면, 창이 생성되자마자 바로 종료되어버립니다.)

코드를 다 작성하셨으면 Ctrl-Shift-F10을 눌러 실행해보겠습니다.

"새 창" 메뉴가 잘 작동합니다.

설명은 길게 남겼지만, 기능구현 자체는 간단하게 느껴지지 않으셨나요?^^;

이어서 다음 포스팅에서도 핵심기능 위주로 메뉴바 기능을 완성하는 내용을 진행하겠습니다.

 

수고하셨습니다.

 


참고자료

 

Pyside GUI Application Development

COUPANG

www.coupang.com

 

PyQT: how to open new window

First of all, similar questions have been answered before, yet I need some help with this one. I have a window which contains one button (Class First) and I want on pressed, a second blank window ...

stackoverflow.com

 

 

Correct way to address Pyside Qt widgets from a .ui file via Python

I have created a GUI with Qt Designer and accessed it via def loadUiWidget(uifilename, parent=None): loader = QtUiTools.QUiLoader() uifile = QtCore.QFile(uifilename) uifile.open(QtCore...

stackoverflow.com

 

 

Using a custom PySide2 widget in Qt Designer

I'm searching for a way to use custom widgets in Qt Designer written with Qt for Python (PySide2) effectively. I found out, that it is possible to design the GUI with the base widget, then just sw...

stackoverflow.com

 

 

 

 

 


donaricano-btn

댓글2

  • pyguy 2021.09.09 09:43

    안녕하세요 강좌 감사합니다. 메인 메모장내에 하나의 화면이 아니라 여러 화면이동이 필요한 경우는 어떻게 구현 할까요?
    답글

    • pyguy님 안녕하세요ㅎ 문의주신 내용을 제가 잘 이해하지 못했습니다ㅜ 조금만 구체적으로 설명해 주시면 도움드릴 수 있을 것 같습니다. 한 번에 여러 창을 띄우고 각각 move메서드를 사용하는 걸 말씀하시는 건지요?