본문 바로가기
GUI 튜토리얼/PySide6 # Qt의 원조가 돌아왔다!

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

by 일코 2021. 3. 24.

QMainWindow

이전 포스팅에서 여섯 줄의 코드로 QWidget 창을 화면에 띄워봤고, QWidget 대신 QPushButton을 사용해서, 한 개의 위젯이 한 개의 창이 될 수 있다는 부분을 말씀드렸습니다. 나만 사용하는 스크립트에 GUI를 붙이는 수준의 작업이라면, 거창하게 GUI를 설계할 것이 아니라, 파일경로나 폴더를 선택하는 정도의 버튼이면 충분한 경우가 많잖아요?

나아가 여러 가지 기능을 포함하고 있거나, 어느 정도 탄탄한 수준의 앞단을 만들기 위해서는 QWidget으로는 까다로운 부분이 많기 때문에, 미리 설계된 뼈대가 숨겨져 있는 QMainWindow를 사용하면 간편하게 구조화된 GUI 윈도우를 만들 수 있다고 말씀드렸습니다. 파이썬의 유명한 웹프레임워크 "장고"처럼요.

(적절한 표현인지는 사실 잘 모르겠습니다; 사실 QMainWindow는 QWidget을 상속한 클래스거든요..)

 

빈 메인화면을 그리는 기본 코드와 실행결과는 아래와 같습니다.

메인 윈도우를 생성하는 최소의 코드입니다. 우측하단에 생성된 창이예요.

이제부터는 이 안에다가 다른 콘텐츠들(QtWidget 하위의 위젯들)을 추가해보려고 합니다. 다양한 위젯뿐만 아니라 메인윈도우의 타이틀도 바꾸고, 파비콘(favicon)도 넣을 거고, 사이즈도 바꾸고, 각종 액션도 추가해 보고 싶지 않으신가요?

나중에는 "클래스"라는 걸 사용해서 여기서 저기서 "상속"하면서 더 재미있는 기능들을 더욱 쉽게 추가할 수 있는 걸 보여드리겠지만, 지금은 (여러분이 PySide와 파이썬의 입문자라는 가정하에) 당분간은 클래스를 생성하지 않고, 순차적이고 단순한 코드로만 진행을 해보겠습니다.

 

위의 코드에 두 줄의 코드를 추가해보겠습니다. 4번라인이 창의 제목을 python에서 다른 문자열로 바꾸는 코드, 다른 하나는 푸쉬버튼을 생성하는 코드입니다.

하위의 위젯이, 어느 상위위젯 안으로 들어가고 싶은지 결정하는 방식입니다.

여기서 QMainWindow 관련 팁을 한 가지 드리자면, QPushButton을 생성할 때 괄호 안에 parent=window라는 파라미터 설정을 통해서 pushbutton이 window 창 안에 들어가고 싶다는 표현을 하게 했는데, 반대로 window가 pushbutton을 부르는 형태로 코드를 수정할 수 있습니다. QPushButton 인스턴스 생성시 parent 인자를 지우고 대신 setCentralWidget 메서드를 활용하는 방법입니다.

상위위젯이 하위에 집어넣을 위젯을 고르는 방식입니다. 결과는 비슷합니다.

이렇게 두 가지 방식으로 메인윈도우 안에 푸쉬버튼을 넣어보는 과정을 보여드렸습니다. 크게 중요하지는 않지만 이런 방법도 있다는 걸 보여드렸습니다. 여기까지 해보시면서 어느 정도 코드가 익숙해지는 것 같다 생각이 되실 때까지 어느 정도 반복하시는 것은 추천드립니다. 단순한 걸 짜면서 기본적인 패턴이 머릿속에 들어오면 나중에도 참 쉽습니다. 간단하든 복잡하든 뭔가 일맥상통하는 패턴 같은 게 있기는 하거든요.

 

이번엔 위의 코드를 클래스 형식으로 짠 코드를 한 번 보여드리겠습니다.

(사실 조금 익숙해질 법한 시점부터 클래스를 정의하는 방식으로 진행할 예정이기는 합니다.)

메인윈도우 클래스를 직접 생성한 후 만든 GUI창입니다.

윈도우7 PC에서 이어서 포스팅하는 거라 테마는 조금 바뀌어 있지만 큰 틀은 같아요^^ 당장은 "번거로워 보이기만 하고 아무 차이 없는데?"라고 생각하실 수 있어요. 절반은 맞는 이야기입니다. 기존에 만들어져 있는 기능만 사용하시는 경우에는 클래스를 생성하지 않고, 기존에 만들어진 클래스를 그대로 사용해도 괜찮거든요. 입문용 포스팅을 몇 개만 더 진행하고 나서 응용프로그램이나 조금 더 복잡한 GUI를 짜면서 클래스에 메서드를 추가하는 등의 작업을 보여드리게 될 텐데, 그 때부터 클래스를 활용하셔도 됩니다. 지금은 "이런 게 있구나" 정도로만 봐 두셔도 좋을 것 같아요^^

 

마지막으로, 파이참으로 "사이즈를 변경"하는 메서드를 찾아서 추가하는 과정을 보여드리고 마치겠습니다. 교재나 매뉴얼을 보고 작성하셔도 좋지만, 어느 정도 코드를 직접 찾아서 완성하는 습관을 들이시다 보면, "감"이라는 게 생긴다는 걸 느끼실 겁니다.

우선 힌트를 먼저 드립니다. 뭔가 변경할 때 자주 쓰이는 키워드는 "set"입니다. 그리고, 사이즈를 변경하는 메서드니까 메서드명에 99%의 확률로 "size"가 들어가겠죠?

그래서 저는 "setsize"를 타이핑하고 Ctrl-Space를 눌러보겠습니다.

자동완성기능(Ctrl-Space)으로 메서드를 고릅니다. 어느 메서드가 사이즈를 조정하는 놈으로 보이시나요?

일곱 개의 메서드 후보가 나왔는데, 어느 메서드가 가장 적절한 녀석일까요?

문맥상 "setFixedSize" 또는 "setBaseSize" 정도로 후보를 좁혀볼 수 있을 것 같아요. (여러분도 그렇게 생각하셨나요?)

우선 self.setFixedSize()로 먼저 진행해보겠습니다. 클래스 정의 맨 아래쪽에다 해당 코드를 추가해봅니다.

괄호 안에서 Ctrl-p로 파라미터 정보를 열어보면?

괄호 안에서 Ctrl-p를 눌러서 파라미터 정보를 조회해 보니까 재미있게도 두 줄이 나왔습니다. (이전 포스팅에서도 세 개, 네 개의 파라미터정보가 나온 적이 있었죠?) "오버로딩"이라는 개념으로, 파라미터를 어떻게 입력하냐에 따라 메서드의 작동방법이 바뀐다는 개념입니다.

참고로 파이썬에는 아주아주 제한적인 오버로딩을 사용할 수 있는데, 바로 "+", "-" 등의 연산자에 오버로딩을 적용할 수 있습니다. 같은 "+" 연산자지만, 리스트끼리 더하게, 혹은 정수나 문자열끼리 더할 수 있도록 합니다.

클래스에 관련한 내용은 나중에 다루기로 하고, 우선 setFixedSize는 다음의 두 가지 방식으로 작동할 수 있습니다.

 

1. self.setFixedSize(QSize(x:int, y:int)) 형태의 QSize 객체 한 개를 arg__1 인자의 파라미터로 넣거나,

 

2. self.setFixedSize(x:int, y:int) 형태로 정수 두 개를 직접 넣거나,

 

둘은 동일하게 작동합니다. (파이썬에서는 일반적으로 마지막에 정의된 메서드로만 동작하죠.)

둘 중에 조금 더 복잡해 보이는 QSize를 넣는 방법으로 작성해보겠습니다. 너비(w)를 300픽셀, 높이(h)를 200픽셀로 고정해보려고 합니다.

파이참의 문맥완성(Alt-Enter) 기능으로 QSize를 자동으로 임포트하였습니다.

파이참이 똑똑한 덕분에 QSize 빨간줄에 캐럿을 놓고 Alt-Enter를 입력했더니, 경로를 찾아서 직접 임포트까지 완료하였습니다. 이대로 한 번 실행해보겠습니다.

실행한 결과 w300px x h200px의 창이 생성되었습니다.

그리고 메서드 이름대로(setFixedSize) 창의 크기를 마우스로 변경할 수 없는 상태입니다.

이런 식으로 실행과정을 반복하면서 원하는 창의 형태를 점차 만들어나갈 수 있습니다.

처음엔 다소 시간이 걸리지만, 몇 번만 매뉴얼 없이 이런 연습을 해 보면 시간이 금방 단축될 겁니다.

setCentralWidget 라인을 지워보면?

참고로 바로 윗 줄의 setCentralWidget을 설명없이 집어넣었는데, "윈도우 센터에 위치할 위젯을 직접 고른다"의 의미를 갖고 있습니다. 이 라인을 지우고 실행한 결과와 비교해볼까요?^^;

실행했더니 버튼이 사라졌습니다. (버튼 인스턴스는 만들었지만 윈도우에 넣는 코드가 없거든요.)

 아차! 버튼을 정의할 때 parent가 누군지 알려줘야 한다고 이전 포스팅에서 말씀드렸죠?

button을 정의하는 인자에 parent를 추가해서 다시 실행해보겠습니다.

parent 파라미터를 self로 정의했더니 올바르게 버튼이 나타났습니다.

버튼이 기본사이즈인데다 창과 따로 노는 느낌이어서 전혀 예쁘지가 않네요..

parent=self ?

여기서 파라미터가 window가 아니고 self인 이유는(많은 분들이 이미 알고 계시겠지만) 클래스를 정의하는 시점에서는 window라는 변수명이 아직 정의되지 않은 시점이기 때문입니다. 곧 생성될 객체의 이름은 우리가 정하지 않았지만, 파이썬에서는 생성될 변수명 대신에 __init__() 메서드에 넣은 파라미터 이름(self)으로 접근을 할 수 있습니다. 자바스크립트의 this와 유사한 개념이라고 생각하셔도 좋습니다. 참고로 self 대신에 this를 넣고, 생성될 인스턴스를 self 대신 this로 사용하셔도 무방합니다. (다만, 관례상 파이썬에서 클래스를 정의할 때 인스턴스의 이름은 self로 통일하는 편입니다.)

self 대신 다른 단어를 써도 잘 작동합니다. self를 일괄 this로 리팩토링(Shift-F6)해보았습니다.

굳이 self를 사용하지 않아도 정상적으로 작동하는 것을 확인하였습니다.

 

그럼 이번 포스팅은 여기서 마치겠습니다. 메인윈도우에 대해서는 추후에 더 자세히 다루기로 하고, (setBaseSize에 대해서도 꼭 다시 알려드리겠습니다.)

다음 포스팅은 Qt의 시그니쳐라고 부를만한(가장 재미있는) 시그널&슬롯에 대해서 알려드리겠습니다.

 

 


donaricano-btn

댓글