반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

 

GUI(Graphical User Interface) 애플리케이션을 개발할 때, Python의 기본 GUI 라이브러리인 Tkinter를 많이 사용합니다. 하지만 Tkinter의 기본 스타일은 오래되어 모던한 디자인을 적용하기 어렵습니다. 이를 보완하기 위해 등장한 것이 CustomTkinter입니다!

 

CustomTkinter는 Tkinter를 기반으로 하면서도 더 세련된 디자인과 다크 모드 지원, 커스텀 스타일 적용이 가능한 강력한 GUI 라이브러리입니다. 특히, 기본적으로 반응형 UI 요소를 제공하여 더욱 깔끔하고 현대적인 인터페이스를 구현할 수 있습니다.

 

이 글에서는 지난 글에서 다루었던 CustomTkinter 기초에 이어서 CustomTkinter의 다양한 위젯을 소개하고, 각 위젯을 어떻게 사용할 수 있는지 코드 예제와 함께 설명해 보겠습니다.

 

아래는 CustomTkinter에서 제공하는 주요 위젯들을 한 번에 보여주는 코드입니다. 이 후 각 위젯을 개별적으로 설명하겠습니다.

 

[코드]

import customtkinter as ctk

# CustomTkinter 설정
ctk.set_appearance_mode("Dark")
ctk.set_default_color_theme("blue")

# 메인 윈도우 생성
root = ctk.CTk()
root.geometry("600x800")
root.title("CustomTkinter 위젯 예제")

# Switch 위젯 (모드 토글)
def toggle_mode():
    if ctk.get_appearance_mode() == "Dark":
        ctk.set_appearance_mode("Light")

    else:
        ctk.set_appearance_mode("Dark")

mode_toggle = ctk.CTkSwitch(root, text="모드 변경", command=toggle_mode)
mode_toggle.pack(pady=10, anchor="se", padx=10)

# Entry 위젯
entry = ctk.CTkEntry(root, placeholder_text="이름을 입력하세요")
entry.pack(pady=10)

# Slider 위젯 (라벨 위젯으로 슬라이더 값 표시)
label = ctk.CTkLabel(root, text="슬라이더 값: ")
label.pack(pady=10)

def slider_event(value):
    label.configure(text=f"슬라이더 값: {int(value)}")

slider = ctk.CTkSlider(root, from_=0, to=100, command=slider_event)
slider.pack(pady=10)

# CheckBox 위젯
checkbox = ctk.CTkCheckBox(root, text="동의합니다")
checkbox.pack(pady=10)

# RadioButton 위젯
radio_var = ctk.StringVar(value="옵션1")
radiobutton1 = ctk.CTkRadioButton(root, text="옵션 1", variable=radio_var, value="옵션1")
radiobutton2 = ctk.CTkRadioButton(root, text="옵션 2", variable=radio_var, value="옵션2")
radiobutton1.pack()
radiobutton2.pack()

# ComboBox 위젯
combobox = ctk.CTkComboBox(root, values=["선택 1", "선택 2", "선택 3"])
combobox.pack(pady=10)

# ProgressBar 위젯
progressbar = ctk.CTkProgressBar(root)
progressbar.pack(pady=10)
progressbar.set(0.5)  # 50% 진행 상태

# TabView 위젯
tabview = ctk.CTkTabview(root)
tabview.pack(pady=10)

# 탭 추가
tab1 = tabview.add("탭 1")
tab2 = tabview.add("탭 2")

# 각 탭에 내용 추가
ctk.CTkLabel(tab1, text="탭 1의 내용입니다").pack(pady=10)
ctk.CTkLabel(tab2, text="탭 2의 내용입니다").pack(pady=10) 

# ScrollableFrame 위젯
scrollable_frame = ctk.CTkScrollableFrame(root, width=300, height=150)
scrollable_frame.pack(pady=10)
for i in range(10):
    ctk.CTkLabel(scrollable_frame, text=f"항목 {i+1}").pack()

# 실행
root.mainloop()

 

[결과]


 

1. Switch 위젯

전환 가능한 스위치 버튼으로, ON/OFF 상태를 가집니다. CTkSwitch( ) 클래스를 이용해서 추가 가능하며, 이 스위치를 조작했을 때, 다크/라이트 모드가 변경되도록 함수를 정의하고 스위치 클래스와 연결해 보았습니다.

 

참고로 스위치는 pack( ) 메소드의 anchor 파라미터를 "e"로 설정해서 우측에 위치하도록 하였습니다.

 

  • "n": north (위) / "s": south (아래) / "e": east (오른쪽) / "w": west (왼쪽)  --> 조합도 가능 (ex. "ne")

[코드]

 

 

 

 

 

 

 

 

 

 

# Switch 위젯 (모드 토글)
def toggle_mode():
    if ctk.get_appearance_mode() == "Dark":
        ctk.set_appearance_mode("Light")

    else:
        ctk.set_appearance_mode("Dark")

mode_toggle = ctk.CTkSwitch(root, text="모드 변경", command=toggle_mode)
mode_toggle.pack(pady=10, anchor="ne", padx=10)

 

[결과]

 

2. Entry 위젯

Entry 위젯은 사용자가 텍스트를 입력할 수 있는 입력 필드입니다. Entry라는 용어가 익숙하지 않으신 분들은 Input 위젯이라고 생각하시면 되겠습니다. 이번 시간에는 입력 받은 값을 어떻게 사용하는지는 다루지 않고 이런 위젯이 있다는 것만 언급하고 넘어가도록 하겠습니다.

 

[코드]

entry = ctk.CTkEntry(root, placeholder_text="이름을 입력하세요")
entry.pack(pady=10)

 

[결과]

 

3. Slider 위젯

사용자가 드래그하여 값을 조정할 수 있는 슬라이더입니다. 슬라이더가 조정될 때 변하는 값을 관찰하기 위해서 지난 시간에 배웠던 Label 위젯을 먼저 추가해주었습니다. slider_event 함수는 CTkSlider의 값을 받아서 그 값을 포함한 Label을 출력해주도록 정의하였습니다.

 

CTkSlider는 "from_" 과 "to" 파라미터로 시작과 끝 값을 지정해주며, command 파라미터의 인자로 위에서 정의한 slider_event 함수를 입력해주었습니다.

 

여기서 slider_event의 파라미터인 value는 어떻게 입력되는지 잘 이해가 되지 않아서 찾아보니, 슬라이더의 현재 값이 자동으로 command 파라미터로 지정된 함수(slider_event)로 입력된다고 합니다.

 

[코드]

# Slider 위젯 (라벨 위젯으로 슬라이더 값 표시)
label = ctk.CTkLabel(root, text="슬라이더 값: ")
label.pack(pady=10)

def slider_event(value):
    label.configure(text=f"슬라이더 값: {int(value)}")

slider = ctk.CTkSlider(root, from_=0, to=100, command=slider_event)
slider.pack(pady=10)

 

[결과]

 

4. CheckBox 위젯

사용자가 체크할 수 있는 체크박스입니다. 체크 박스 옆의 메시지를 "text" 파라미터로 설정할 수 있습니다.

 

[코드]

checkbox = ctk.CTkCheckBox(root, text="동의합니다")
checkbox.pack(pady=10)

 

[결과]

 

 

 

5. RadioButton 위젯

여러 개의 옵션 중 하나를 선택할 수 있는 버튼입니다. radio_var이란 변수를 설정해주고, 그 값을 CTkRadioButton( )의 variable 파라미터의 인자로 넣어주는 이유는 옵션을 선택했을 때 그 옵션의 "value"를 저장하기 위함입니다. 이 값을 다른 코드에서 입력으로 받아서 사용할 수 있도록 말입니다. 참고로 value는 문자열이 아니라 숫자도 가능합니다.

 

[코드]

radio_var = ctk.StringVar(value="옵션1")
radiobutton1 = ctk.CTkRadioButton(root, text="옵션 1", variable=radio_var, value="옵션1")
radiobutton2 = ctk.CTkRadioButton(root, text="옵션 2", variable=radio_var, value="옵션2")
radiobutton1.pack()
radiobutton2.pack()

 

[결과]

 

6. ComboBox 위젯

드롭다운 목록을 통해 값을 선택할 수 있는 콤보박스입니다. values 파라미터에 선택지를 리스트 타입으로 입력합니다.

 

[코드]

combobox = ctk.CTkComboBox(root, values=["선택 1", "선택 2", "선택 3"])
combobox.pack(pady=10)

 

[결과]

 

7. ProgressBar 위젯

진행 상태를 표시하는 프로그레스 바입니다. 프로그레스 바는 무언가 진행되는 정도를 보여주기 위한 위젯이기 때문에 해당 위젯 이외에 프로그레스 바의 수치를 10초간 10%씩 증가시키는 update_progress( ) 함수와 해당 함수를 실행하기 위한 버튼을 추가해주었습니다.

 

여기서 조금 어려운 포인트는 lambda 함수를 사용해 준 부분입니다. 여기서 lambda 함수를 써준 이유는 버튼 한 번의 클릭으로 두 가지 기능을 수행하기 위함입니다. progressbar.set(0)로 프로그레스 바의 값을 0으로 초기화 해준 다음 update_progress( ) 함수를 수행하게 됩니다.

 

[코드]

# ProgressBar 위젯
progressbar = ctk.CTkProgressBar(root)
progressbar.pack(pady=10)
progressbar.set(0)  # 초기값 0%

def update_progress():
    current_value = progressbar.get()
    if current_value < 1.0:
        progressbar.set(current_value + 0.1)  # 10% 증가
        root.after(1000, update_progress)  # 1초 후 다시 실행

# 실행 버튼
start_button = ctk.CTkButton(root, text="실행", command=lambda: [progressbar.set(0), update_progress()])
start_button.pack(pady=10)

 

[결과]

 

8. TabView 위젯

여러 개의 탭을 포함하여 다양한 화면을 제공하는 위젯입니다. 먼저 CTkTabview( ) 클래스로 TabView 위젯을 하나 생성합니다. 메인 윈도우창인 root만 인자로 입력 받네요. 바로 이어서 방금 생성한 tabview 객체에 add( ) 메소드를 활용하여 "탭 1"과 "탭 2"를 생성해줍니다.

 

여기까지가 TabView 위젯을 생성하는 것이고, 다음 코드는 생성한 탭 안에 라벨 위젯을 넣는 코드입니다. 익숙한 코드인데 조금 다른 점은 pack( ) 메소드를 곧바로 붙여서 작성했다는 것과, 첫번째 인자를 root가 아니라 tab1과 tab2로 입력해주었다는 것입니다.

 

[코드]

# TabView 위젯
tabview = ctk.CTkTabview(root)
tabview.pack(pady=10)

# 탭 추가
tab1 = tabview.add("탭 1")
tab2 = tabview.add("탭 2")

# 각 탭에 내용 추가
ctk.CTkLabel(tab1, text="탭 1의 내용입니다").pack(pady=10)
ctk.CTkLabel(tab2, text="탭 2의 내용입니다").pack(pady=10)

 

[결과]

 

9. ScrollableFrame 위젯

스크롤 가능한 프레임으로, 많은 항목을 표시할 때 유용합니다. CTkScrollableFrame( ) 클래스는 width와 height 파라미터에 정수형 자료를 입력해서 크기를 조절할 수 있습니다. 그리고 그 안에 내용을 넣을 때는 위에서 탭에 내용을 추가 했을 때 처럼 Label 위젯의 첫번째 인자를 root가 아닌 방금 생성한 scrollable_frame 객체로 해주면 됩니다.

 

[코드]

scrollable_frame = ctk.CTkScrollableFrame(root, width=300, height=150)
scrollable_frame.pack(pady=10)
for i in range(10):
    ctk.CTkLabel(scrollable_frame, text=f"항목 {i+1}").pack()

 

[결과]


이번 글에서는 CustomTkinter의 다양한 위젯들을 살펴보며 각각의 기능과 사용법을 익혔습니다. 이제 기본적인 위젯 사용법을 이해했으니, 다음 글에서는 간단한 프로젝트를 통해 실제로 GUI 프로그램을 어떻게 활용할 수 있는지 알아보겠습니다. CustomTkinter를 사용하여 실용적인 애플리케이션을 만들고, 이를 통해 GUI 개발의 흐름과 응용 방법을 배워보도록 하겠습니다.

 

 

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

 

이번 시간에는 우리가 .py 파일에 작성한 코드를 GUI(Graphical User Interface)를 기반으로 사용자 입력을 받아서 실행시킬 수 있는 방법에 대해서 알아보겠습니다.

 

예전 글에서는 PyQT에 대해서 주로 다루었습니다. 하지만 PyQT의 경우 기능이 많고 예쁜 GUI를 만들 수 있다는 장점이 있는 반면 라이브러리가 무거워서 불필요하게 프로그램 사이즈가 커지는 경우가 자주 발생했습니다. 비유를 들자면 아주 간단한 과자를 주문했는데 그걸 포장한 박스가 아주 비싸고 화려하고 무거운 느낌이랄까요?

 

그래서 이번 시간에는 파이썬에서 기본적으로 제공하지만 너무 못 생겨서 잘 사용하지 않는 Tkinter를 쓸만 할 정도로 예쁘게 만든 CustomTkinter에 대해서 알아보겠습니다.


1. CustomTkinter란?

CustomTkinter는 Tkinter의 확장 버전으로, 보다 현대적인 UI 디자인을 쉽게 적용할 수 있도록 만들어진 GUI 라이브러리입니다. 기존 Tkinter의 제한적인 디자인을 보완하며, 다크 모드 및 다양한 색상 테마를 지원합니다.

이 글에서는 CustomTkinter의 주요 기능, 장점과 단점, 그리고 간단한 사용법을 소개합니다.


2. CustomTkinter의 장점과 단점

[장점]

1) 모던한 UI 디자인: 기존 Tkinter보다 세련된 스타일을 제공하며, 기본적으로 다크 모드를 지원합니다.

2) Tkinter와의 높은 호환성: 기존 Tkinter 코드와 호환되며, 추가적인 스타일링 기능을 제공합니다.

3) 간단한 코드 작성: 보다 직관적인 API를 제공하여 코드 작성을 단순화합니다.

4) 다크 모드 및 테마 지원: 애플리케이션의 전체적인 색상 테마를 쉽게 조정할 수 있습니다.

5) 크로스 플랫폼 지원: Windows, Mac, Linux에서 원활하게 작동합니다.

[단점]

1) Tkinter의 한계를 가짐: Tkinter 기반이므로 PyQt나 PySide 같은 고급 GUI 프레임워크보다는 기능이 제한적입니다.

2) 커뮤니티 자료가 적음: 비교적 새로운 라이브러리라 CustomTkinter에 대한 예제나 문서가 많지 않습니다.


3. CustomTkinter 설치

터미널(또는 명령 프롬프트)에서 아래 명령어를 실행하세요.

pip install customtkinter

 


4. CustomTkinter 간단한 사용법

CustomTkinter는 Tkinter와 유사하지만 보다 현대적인 UI 디자인을 쉽게 적용할 수 있습니다. 이번 시간에는 아주 간단히 CustomTkinter 창을 띄우고 라벨과 버튼 하나씩을 창에 추가하는 코드로 CustomTkinter와 친해져보는 시간을 가져보겠습니다.

 

[코드]

import customtkinter as ctk

# 1) 기본 설정
ctk.set_appearance_mode("Light")  # 창 모드 설정 (System, Light, Dark)
ctk.set_default_color_theme("blue")  # UI 테마 설정 (blue, dark-blue, green)

# 2) 메인 윈도우 생성
root = ctk.CTk()
root.geometry("400x300")
root.title("CustomTkinter 예제")

# 3) 라벨 추가
label = ctk.CTkLabel(root, text="Hello, CustomTkinter!", font=("Arial", 20))
label.pack(pady=20)

# 4) 버튼 추가
def on_click():
    label.configure(text="버튼이 클릭됨!")

button = ctk.CTkButton(root, text="클릭하세요", command=on_click)
button.pack(pady=10)

# 5) 실행
root.mainloop()

 

1) 기본 설정

[코드]

# 기본 설정
ctk.set_appearance_mode("Dark")  # 다크 모드 설정 (System, Light, Dark)
ctk.set_default_color_theme("green")  # 테마 설정 (blue, dark-blue, green)

 

CustomTkinter는 3가지 창 모드와 3가지 UI 색상 테마를 설정할 수 있습니다.

 

창 모드는 set_appearance_mode( ) 클래스로 설정 가능하며, "System", "Light", "Dark" 모드를 괄호 안에 넣어서 설정 가능합니다. 여기서 "System" 모드는 사용자의 운영체제(OS) 설정에 따라서 자동으로 다크 또는 라이트 모드가 적용되는 모드입니다.

 

컬러 테마는 버튼 혹은 슬라이드, 체크 박스 등의 색상을 결정하는 옵션입니다. "blue", "dark-blue", "green" 모드를 괄호 안에 넣어서 설정 가능합니다. 개인적인 취향이지만 저는 "green"은 별로라서 안쓸 것 같네요.

 

[결과]

 

2) 메인 윈도우 생성

[코드]

# 메인 윈도우 생성
root = ctk.CTk()
root.geometry("400x300")
root.title("CustomTkinter 예제")

 

메인 윈도우 생성은 CTk( ) 클래스를 이용합니다. 보통 GUI 프로그래밍을 할 때, 관례적으로 메인창을 나타내는 변수명은 'root'로 지어줍니다.

 

창 크기는 geometry( ) 메소드의 괄호 안에 "가로x세로"를 입력함으로써 설정 가능하며, 창의 타이틀은 title( ) 메소드의 괄호 안에 "원하는 타이틀"을 문자열로 입력함으로써 설정 가능합니다.

 

3) 라벨 추가

[코드]

# 라벨 추가
label = ctk.CTkLabel(root, text="Hello, CustomTkinter!", font=("Arial", 20))
label.pack(pady=20) # pady: 위아래 여백

 

간단히 텍스트를 추가하는 코드입니다.  GUI 프로그래밍에서는 창 존재하는 텍스트를 "Label"이라고 부르는 편입니다. CTkLabel( ) 클래스를 이용하며 괄호 안에 들어가는 이번 시간에는 3가지만 알아보겠습니다.

 

버튼, 라벨 등의 위젯(Widget) 관련 클래스는 모두 가장 처음 root를 입력 받습니다. 가장 기본이 되는 규칙이니 기억해주세요. 다음은 라벨의 내용을 text 파라미터에 문자열로 입력해주었으며, 폰트의 글꼴과 사이즈를 튜플 형태로 입력해주었습니다.

 

pack( ) 메소드의 pady 파라미터를 통해서 텍스트의 위아래 여백도 넣어주었습니다. pack 메소드는 위젯을 창에 배치하는 역할로 넣어주지 않으면 안되는 코드입니다. 항상 어떤 위젯이든지 넣어준다고 생각하면 되겠습니다.

 

이 외에도 폰트 색상, 텍스트 배경 색상, 텍스트 상자의 크기, 그에 따른 자동 줄바꿈 설정까지 존재하지만, 아마도 이 CustomTkinter를 사용하는 이유가 심플하게 GUI를 구현하는 것이라서 큰 의미는 없을 것이라 생각되네요.

 

4) 버튼 추가

[코드]

# 버튼 추가
def on_click():
    label.configure(text="버튼이 클릭됨!")

button = ctk.CTkButton(root, text="클릭하세요", command=on_click)
button.pack(pady=10)

 

버튼을 추가하기 전에, 버튼을 눌렀을 때 실행되기 원하는 함수를 정의해주어야 합니다. on_click( )이라는 함수를 정의해주었고 그 기능은 위에서 만들어 주었던 label의 텍스트를 "버튼이 클릭됨!"으로 수정해주는 것입니다.

 

함수를 정의해주었으니 이제 버튼을 추가해보겠습니다. 버튼 추가 역시 라벨을 추가했을 때와 거의 동일합니다. CTkButton( ) 클래스로 추가해주며, 필수 요소인 root를 첫번째 인자로 넣어주고 그 다음 버튼을 나타낼 텍스트, 버튼을 눌렀을 때 실행될 함수명을 입력해줍니다. 마지막으로는 라벨 때와 마찬가지로 pack( )을 메소드로 버튼을 창에 배치해줍니다.

 

버튼을 클릭하니까 위에 있던 라벨이 "버튼이 클릭됨!"으로 변경된 것이 보이시나요?

 

[결과]

 

5) 버튼 추가

[코드]

# 실행
root.mainloop()

 

매우 간단하지만 코드지만 이 코드 한줄이 없으면 GUI 창이 열렸다가 바로 꺼질 정도로 필수적인 코드입니다. 참고로 mainloop()는 GUI 프로그램이 실행되는 동안 계속 동작하면서 사용자의 입력(클릭, 키보드 입력 등)을 감지하고 처리하는 역할을 합니다.


5. CustomTkinter 위젯 종류들

CustomTkinter에는 위에서 소개드린 위젯 (라벨, 버튼) 외에 여러가지 위젯들이 존재합니다. 이러한 위젯들을 활용하면 프로그램 실행에 필요한 변수들을 사용자가 쉽게 조정 가능하죠. 추가적인 위젯들에 대한 내용은 다음 글에서 소개드리도록 하겠습니다.

CustomTkinter 위젯들

 


오늘 준비한 내용은 여기까지입니다. 다음에도 코딩유치원을 찾아주세요~

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

코딩유치원에서는 파이썬 기초부터 사무자동화, 웹크롤링, 데이터 분석, 머신러닝 등의 다양한 패키지까지 초보자도 알기 쉽도록 내용을 정리해 놓았습니다.

업무는 물론 투자에도 도움이 될만한 전자공시시스템(DART)나 텔레그램(Telegram) 관련 패키지도 배울 수 있으니 많은 관심 부탁드립니다.

 


저는 사용자 친화적인 프로그램을 만들기 위해서 지금까지 파이썬 GUI(Graphical User Interface) 라이브러리 중 가장 유명한 pyqt5를 사용해왔습니다.

 

<PyQT 관련 글>

 

2021.05.07 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_1강.PyQt의 개념과 창 만들기 (창 이름, 사이즈, 변경 및 아이콘 삽입)

2021.05.08 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_2강.위젯의 종류, 시그널과 슬롯, 이벤트 루프

2021.05.10 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_3강.Qt Designer로 내마음대로 GUI 구성하기

2021.05.22 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] 잡플래닛 리뷰 정보 크롤링 GUI 프로그램

2021.12.06 - [파이썬 패키지/GUI 프로그램] - [Python/Pyqt5] QWidget, QMainWindow, Qdialog 차이 총정리 (ft. Modal과 Modeless)

 

하지만, 아주 유용하면서도 직관적인 PyQt이지만 중대한 단점이 존재합니다. (단점이 개인적인 의견일 수 있음)

 

1. PyQt의 단점

 

GPL 라이브러리, 즉 오픈소스 프로그램을 위한 라이선스라는 것입니다. 이 말이 무슨말이냐면 상업용으로 프로그램을 제작했을 때 그 코드를 공개하고 누구나 마음껏 사용할 수 있다는 말입니다. 만약 그러고 싶지 않다면 별도의 라이선스를 구매해야하죠.

 

아마 상업용 프로그램을 개발해서 판매/배포하는 분들에게 중요한 문제가 아닐까 싶습니다.

 

이런 문제를 해결해줄 수 있는 라이브러리가 바로 PySide입니다.

 

2. PySide6란?

 

PySide란 Qt의 공식적인 파이썬 바인딩, 즉 C++ 기반의 GUI 프로그램 프레임워크인 Qt를 Python에서 사용할 수 있도록 잘 포장(?)한 것입니다.

 

"어라? PyQT가 이름만 봐도 Qt의 공식 파이썬 바인딩인 아니었어?"라고 생각하셨을 것 같은데요.

 

사실 Qt를 제작한 회사(The Qt Company)가 아닌, 영국의 Riverbank Computing가 오픈 소스인 Qt를 이용해서 PyQt를 만들었던 것이라고 하네요.

 

GPL 기반의 PyQt를 Qt와 같은 LGPL로 변경할 것을 제안했으나 RC에서 거절함에 따라, 2016년 5월부로 원조인 Qt사에서 PySide를 공식 지원하겠다고 발표하였습니다. 여기서 Side란 핀란드어로 '바인딩'을 의미한다고 하네요.

 

PySide2까지만 해도 그 기능이 PyQt5에 비해서 뒤쳐졌지만 2020년 12월에 PySide6를 출시하면서, PyQt6와 거의 비슷한 수준까지 올라왔다고 합니다.

 

제가 아직 공부를 깊게 하진 못했지만 PyQt6와 거의 동일하며, 당연히 Qt Designer도 사용할 수 있습니다.

 

PySide2를 잘 정리해놓은 무료전자책이 있어 소개드립니다. 6는 아니지만 Pyside 개념을 잡는데에 많은 도움이 될 것 같아요.

 

https://wikidocs.net/book/2957

 

공학자를 위한 PySide2

이 책은 [공학자를 위한 Python](https://wikidocs.net/book/1704)의 자매책이다. #### History * 2019.5.13 : 1차 ...

wikidocs.net

 

3. GPL vs LGPL

 

위에서 언급했던 공개 소프트웨어 라이선스의 두 가지 종류에 대해서 조금 더 자세히 알아보겠습니다.

 

1) GPL

기본적으로 어떤 프로그램을 개발할 때, GPL 코드를 일부라도 사용하게 되면 그 프로그램은 GPL이 됩니다. GPL을 가진 프로그램을 유료로 판매하는 것은 가능하지만, 반드시 전체 소스코드는 무료로 공개해야 합니다.

 

GPL 코드를 사용한 SW를 내부적인(개인, 기관, 단체 등) 목적으로만 사용할 때에는 소스코드를 공개할 필요가 없지만 어떤 형태로든(유료든 무료든) 외부에 공표/배포할 때에는 전체 소스코드를 공개해야 합니다.

 

2) LGPL

LGPL(Lesser General Public License)는 GPL보다 훨 씬 완화된 라이선스 방식입니다.

 

가장 큰 차이점은 LGPL 코드를 정적(static) 또는 동적(dynamic) 라이브러리로 사용한 프로그램을 개발하여 판매/배포할 경우에 프로그램의 소스코드를 공개하지 않아도 된다는 점입니다. LGPL 코드를 사용했음을 명시만 하면 된다고 하는데 어떻게 명시해야하는지는 아직 잘 모르겠네요.

 

여기서 주의할 점은, LGPL 코드를 단순히 이용하는 것이 아니라 이를 수정한 또는 이로부터 파생된 라이브러리를 개발하여 배포하는 경우에는 전체 코드를 공개해야 한다는 것입니다.

 

 

4. 동적 로드 라이브러리 vs 정적 라이브러리

 

세상에.. 공부하면 할 수록 모르는 것 투성이네요. 위에서 LGPL을 설명하면서 나왔던 정적, 동적 라이브러리에 대해서 잠시 다루어보겠습니다. 여기서 말하는 라이브러리는 함수, 구조체, 클래스 등을 포함하고 있는 컴파일된 파일을 의미합니다.

 

1) 정적 라이브러리(Static Library)

프로그램 빌드 시, 라이브러리를 실행 코드에 넣는 방식을 의미합니다. 이 방식의 장점은 별도 외부 파일이 필요없이 단일 어플리케이션으로 사용가능하다는 것이며, 단점은 로딩하는데에 무겁다는 것입니다.

 

확장자는 윈도우에서는 .lib이며, 리눅스에서는 .a입니다.

 

2) 동적 로드 라이브러리(Dynamic Load Library)

동적 로드 라이브러리는 쉽게 말해서 외부에 라이브러리 파일을 두고, 그때 그때 그 안의 내용물을 불러와서 사용하는 방식입니다. 그렇기 때문에 정적 라이브러리와 반대로 로딩이 빠른 대신에, 반드시 라이브러리 파일을 함께 배포해야 하는 불편함이 있습니다.

 

확장자는 윈도우에서는 .dll이며, 리눅스에서는 .so입니다.

 

 


<참고 자료>

 

1. [Python] PyQt와 PySide에 대한 잡설

https://dev-overload.tistory.com/44

 

2. [Python] QT 지원 | PYQT5 vs PySide2

https://blog.naver.com/PostView.nhn?blogId=piwpiw&logNo=221997619201&parentCategoryNo=&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView 

 

3. [Software] 공개 SW 라이센스(GPL, LGPL, BSD)

http://jinyongjeong.github.io/2016/06/01/software_license/

 

4. 정적 라이브러리와 동적 라이브러리(Static Library, Dynamic Library)

https://m.blog.naver.com/kr_dukie27/10175747579

 

 

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

코딩유치원에서는 파이썬 기초부터 사무자동화, 웹크롤링, 데이터 분석, 머신러닝 등의 다양한 패키지까지 초보자도 알기 쉽도록 내용을 정리해 놓았습니다.

업무는 물론 투자에도 도움이 될만한 전자공시시스템(DART)나 텔레그램(Telegram) 관련 패키지도 배울 수 있으니 많은 관심 부탁드립니다.

 


 

오늘은 Pyqt5를 다루면서 항상 의문이었던 부분을 정리해보려 합니다.

 

바로 파이썬 Pyqt5 패키지로 GUI 창을 만들 때 사용되는 QWidget, QDialog, QMainWindow 클래스 3형제들입니다.

 

class MyWindow(QWidget):

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

 

구글링하면 Pyqt5 관련 패키지의 코드들을 보면 QWidget이 들어간 자리에 이 3형제들이 골고루 들어가 있어서 혼란스러웠기에 저같은 분들이 있으실 듯 하여 정리해보는 시간을 갖기로 하였습니다.

 

참고로 제가 즐겨 사용하는 qt designer을 켜면 아래와 같이 3가지 클래스(Dialog, Main Window, Widget)를 선택하는 창이 가장 처음 출력됩니다.

 

 

1. QWidget

 

QWidget을 딱 한마디로 설명하면 버튼, input 위젯 같은 다양한 위젯들을 올려놓을 수 있는 사각형의 영역입니다.

 

즉, 그림을 그릴 수 있는 도화지 같은 것이죠.

 

특징으로는 Main Window와 다르게 상단의 메뉴창과 하단의 상태창을 추가할 수 없습니다.

 

qt designer에서의 창 형태

qt designer에서의 객체 및 클래스 분류

 

2. QMainWindow

 

위에서 잠시 보았던 QWidget과 비슷하지만 조금 다릅니다.

 

QMainWindow는 최상위 위젯으로 메뉴바, 도구 모음, 상태바등이 포함된 미리 정의된 레이아웃을 가지고 있습니다.

 

가장 기본적인 QMainWindow의 형태

 

qt designer의 객체 탐색기를 살펴보면 QMainWindow라는 상위 클래스에 QWidget이 속해 있는 것을 알 수 있죠.

 

즉, MainWindow를 도화지와 도화지를 담고 있는 프레임이라고 생각하시면 됩니다.

 

qt designer에서의 객체 및 클래스 분류

 

 

3. QDialog

 

항상 별도의 창에 표시되는 대화상자로, 주로 우리가 흔히 보는 팝업창이나 경고창 역할을 주로 합니다.

 

아래의 그림에서 보시면 기본 템플릿에서 버튼을 제공하는 것이 있는데, 주로 사용자가 간단히 확인, 취소 버튼을 누를 때 사용하기 때문입니다. 아직 테스트는 해보지 않았지만 버튼을 최대로 넣을 수 있는 제한 같은게 있다고 하네요.

 

 

겉보기에는 Qwidget과 별 다를 것이 없죠?

 

qt designer에서의 객체 및 클래스 분류

 

4. Modal, Modeless 개념 (참고)

 

위에서 배운 기본적인 GUI 창 3형제를 더 깊이 이해하려면 Modal 및 Modaless의 개념에 대해서 알아야 합니다.

 

두 개념은은 MainWindow를 제외한 Widget과 Dialog에서 사용하는 실행 형식입니다.

 

참고로 Dialog 창은 Modal 속성을 주로 사용한답니다.

 

 

1) Modal

 

- 새롭게 Modal 속성을 가진 창이 열렸을 경우 기존에 있던 창을 사용하지 못하는 '제어권 독점' 방식입니다.

  (이 특성을 이용해서 중요한 메세지를 표시하는 Dialog는 거의 Modal 창을 이용합니다.)

 

- exec()의 실행 형식으로 독립적입니다. (이 부분은 좀 더 공부 필요)

 

2) Modeless

 

- 어느 하나의 Dialog 창이 있어도 프로그램 제어권을 독점하지 않으므로 다른 작업이 가능합니다. (즉, 다른창을 선택 가능)

 

- show()의 실행 형식으로 독립적이지 않습니다. (이 부분은 좀 더 공부 필요)

 


<참고자료>

 

1. 개발자 라면_QWidget과 QDialog의 차이 - Modal/Modeless

https://flower0.tistory.com/457

 

 

2. 타스의 개발 블로그_[MFC] Modal&Modeless Dialog: 설명

https://tars-c.github.io/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D/mfc/dialog/Dialog-Modal-and-Modeless-%EC%84%A4%EB%AA%85/

 

 

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

 

 


오늘은 지난번 공유드렸던 아래의 프로젝트를 Pyqt5 패키지를 이용해 GUI로 사용할 수 있도록 만들어보았습니다.

 

개인적 필요에 의해 만들었던 프로그램인데, 회사의 인사팀에 속해 계신분들은 유용하시지 않을까 생각되네요.

리뷰 크롤링 결과를 저장한 엑셀 파일

2021.03.29 - [파이썬 프로젝트] - [파이썬 프로젝트] 잡플래닛 리뷰 정보 크롤링 코드 공유

 

우선 전체 코드는 아래와 같으며, 어떻게 사용하는지는 아래에서 설명드리겠습니다.

 

사실 Pyinstaller라는 패키지를 이용해 exe 실행 파일로 만들어서 공유드리려 했으나, 관련 패키지를 잔뜩 import 해서인지 프로그램의 크기가 190MB를 넘어가서 그냥 코드로 공유드립니다.

 

#관련 패키지 import
import time
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5 import uic

#UI파일 연결 코드
UI_class = uic.loadUiType("MyGui.ui")[0]

#화면을 띄우는데 사용되는 Class 선언
class WindowClass(QMainWindow, UI_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

        # GUI의 버튼을 눌렀을 때 아래 정의한 ReviewCrawlingFunction이 실행됨
        self.pushButton.clicked.connect(self.ReviewCrawlingFunction)

    #이하 지난 프로젝트 조금 개선해서 메소드 안에 넣어줌
    def ReviewCrawlingFunction(self) :

        # 크롬 드라이버 실행 및 잡플래닛 로그인 페이지 접속
        driver = webdriver.Chrome("크롬드라이버가 위치하는 경로 ex)/Users/codingkindergarten/Desktop/chromedriver")
        driver.get("https://www.jobplanet.co.kr/users/sign_in?_nav=gb")
        driver.implicitly_wait(10)

        #입력 받은 정보로 로그인
        login_id = driver.find_element_by_css_selector("input#user_email")
        login_id.send_keys(self.lineEdit_ID.text())

        login_pw = driver.find_element_by_css_selector("input#user_password")
        login_pw.send_keys(self.lineEdit_PW.text())

        login_id.send_keys(Keys.RETURN)
        driver.implicitly_wait(10)
		time.sleep(1) #implicityly_wait로 잘 작동하지 않아서 추가함
        
        #원하는 회사의 리뷰 페이지까지 이동
        company = driver.find_element_by_css_selector("input#search_bar_search_query")
        company.send_keys(self.lineEdit_CN.text())
        company.send_keys(Keys.RETURN)
        driver.implicitly_wait(15)

        driver.find_element_by_css_selector("a.tit").click()
        driver.implicitly_wait(15)

        driver.find_element_by_css_selector("button.btn_close_x_ty1 ").click()
        driver.implicitly_wait(15)

        review_cnt_raw = driver.find_elements_by_css_selector("span.num.notranslate")[1]
        review_cnt = int(review_cnt_raw.text)
        review_page = int(review_cnt/5) + 1
        

        #크롤링한 정보를 담을 리스트명 정의
        list_div = []
        list_cur = []
        list_date =[]
        list_stars = []
        list_summery = []
        list_merit = []
        list_disadvantages = []
        list_managers =[]


        #원하는 회사의 직무/근속여부/일시/요약/평점/장점/단점/경영진에게 바라는 점 크롤링 (for문으로 반복)
        for i in range(review_page): 

            #직무, 근속여부, 지역 ,일시
            user_info = driver.find_elements_by_css_selector("span.txt1")

            #한 페이지 안의 리뷰 갯수
            #한 페이지에 정보 5set씩 나옴. 마지막 페이지는 5개 미만일 수 있으므로 count 변수를 반복횟수로 넣어줌.
            count = int(len(user_info)/4)

            list_user_info = []

            for j in user_info:
                list_user_info.append(j.text)

            for j in range(count):            
                a = list_user_info[4*j]
                list_div.append(a)
                
                b = list_user_info[4*j+1]
                list_cur.append(b)

                c = list_user_info[4*j+3]
                list_date.append(c)

            #별점
            stars = driver.find_elements_by_css_selector("div.star_score")
            for j in stars:
                a = j.get_attribute('style')
                if a[7:9] == '20':
                    list_stars.append("1점")
                elif a[7:9] == '40':
                    list_stars.append("2점")
                elif a[7:9] == '60':
                    list_stars.append("3점")
                elif a[7:9] == '80':
                    list_stars.append("4점")
                else:
                    list_stars.append("5점")
                
            #요약 정보
            summery = driver.find_elements_by_css_selector("h2.us_label")

            for j in summery:
                list_summery.append(j.text)
            
            #장점, 단점, 경영진에게 바라는 점
            list_review = []

            review = driver.find_elements_by_css_selector("dd.df1")

            for j in review:
                list_review.append(j.text)

            for j in range(count):            #한 페이지에 정보 5set씩 나옴. 마지막 페이지는 5개 미만일 수 있으므로 count 변수를 반복횟수로 넣어줌.
                a = list_review[3*j]
                list_merit.append(a)
                
                b = list_review[3*j+1]
                list_disadvantages.append(b)

                c = list_review[3*j+2]
                list_managers.append(c)

            # 다음 페이지 클릭 후 for문 진행, 끝 페이지에서 다음 페이지 클릭 안되는 것 대비해서 예외처리 구문 추가
            try:
                driver.find_element_by_css_selector("a.btn_pgnext").click()
                driver.implicitly_wait(15)
                time.sleep(2) #implicityly_wait로 잘 작동하지 않아서 추가함
            except:
                pass


        # step8.pandas 라이브러리로 표 만들기
        total_data = pd.DataFrame()
        total_data['날짜'] = pd.Series(list_date)
        total_data['직무'] = pd.Series(list_div)
        total_data['재직여부'] = pd.Series(list_cur)
        total_data['별점'] = pd.Series(list_stars)
        total_data['요약'] = pd.Series(list_summery)
        total_data['장점'] = pd.Series(list_merit)
        total_data['단점'] = pd.Series(list_disadvantages)
        total_data['경영진에게 바라는 점'] = pd.Series(list_managers)

        # step9.엑셀 형태로 저장하기
        total_data.to_excel(self.lineEdit_CN.text() + "_잡플래닛 리뷰.xls" ,index=True)

        # step10.크롬 드라이버 종료
        driver.quit()

if __name__ == "__main__" :
    #QApplication : 프로그램을 실행시켜주는 클래스
    app = QApplication(sys.argv) 

    #WindowClass의 인스턴스 생성
    myWindow = WindowClass() 

    #프로그램 화면을 보여주는 코드
    myWindow.show()

    #프로그램을 이벤트루프로 진입시키는(프로그램을 작동시키는) 코드
    app.exec_()

 

<코드를 사용하기 위한 필요조건>

 

1. 파이썬과 관련 패키지가 설치되어 있을 것

2021.03.02 - [파이썬 기초/개발환경 구축] - [코딩유치원] 파이썬 개발환경 구축 1편 (파이썬 VS 아나콘다)

 

2. 잡플래닛 계정과 회사 리뷰를 최소 1개 작성할 것 (리뷰를 작성해야만 모든 리뷰가 조회 가능)

 

3. QtDesigner를 이용해서 아래와 같이 GUI 구성하고, Ui 파일을 파이썬 파일과 같은 폴더에 넣기

    (아래에 제가 만든 ui파일을 파일첨부로 올려두었으니, 다운 받아서 사용하세요)

 

GUI를 커스터마이징 할 시, designer의 objectname과 파이썬 코드의 objectname을 일치 시킬 것.

 

MyGui.ui
0.00MB

 

<크롤링 결과>

 

테스트로 네이버랩스의 리뷰를 크롤링 해보았습니다.

 

크롤링이 끝나면 파이썬 파일과 같은 경로에 엑셀 파일이 생성됩니다.

 

리뷰 17개가 모두 잘 받아진 것을 확인할 수 있습니다.

리뷰 크롤링 결과를 저장한 엑셀 파일

 

 

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

 

 

 

<파이썬 GUI 프로그래밍 관련 지난 글>

 

출처. WIKIPEDIA

 

2021.05.07 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_1강.PyQt의 개념과 창 만들기 (창 이름, 사이즈, 변경 및 아이콘 삽입)

2021.05.08 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_2강.위젯의 종류, 시그널과 슬롯, 이벤트 루프

 

 

이번 시간에는 GUI 화면을 그래픽 기반의 드래그 앤 드롭 방식으로 쉽게 구성할 수 있도록 도와주는 도구인 Qt Designer에 대해서 알아보겠습니다.

 


 

Qt Designer 설치 및 실행

 

우선 코딩 유치원에서 추천하는 Anaconda로 파이썬을 설치하셨다면, Qt Designer는 이미 설치되어 있습니다.

만약 파이썬 공식 홈페이지를 통해 Python을 설치하셨다면, cmd창에서 pip install pyqt를 입력하시면 설치가 될 것입니다.

 

Anaconda가 설치되어 있다는 가정하에 Qt Designer의 실행방법은 아래와 같습니다.

 

Window

Window 시작 메뉴에서 Anaconda Prompt를 검색하여 실행시커나, VScode를 사용하고 계신다면 터미널창에 designer라는 명령어를 입력하면 Qt Designer가 실행됩니다.

 

Mac

Finder를 실행한 후, 응용 프로그램(Application) 탭을 클릭하거나 launchpad에서 Anaconda Navigator를 찾아서 우클릭하고 Show Original을 누릅니다. Anaconda Navigator 내부로 들어갔다면, bin폴더에 있는 Designer라는 파일을 실행하면 Qt Designer가 실행됩니다.

 

매번 이렇게 실행시키기는 좀 귀찮겠죠? Qt Designer를 Application 폴더로 복사/붙여넣기 하시면 launchpad에서 Qt Designer를 실행시킬 수 있습니다.

 

 

Qt Designer의 화면구성

 

만약 Qt Designer가 제대로 실행되었다면, 가장 처음 보이는 화면은 아래와 같습니다. (Window OS 기준)

 

 

 

화면 중앙에 위치한 창에서 Dialog without Buttons를 누른 후 Create를 눌러주겠습니다.

 

 

Dialog Window

 

그러면 아래와 같이 'Dialog - untitled' 라는 이름의 창이 뜨는데 우리는 여기에 우리만의 GUI 프로그램을 디자인 해줄 수 있습니다.

그림에 비유하자면 마치 도화지와 같다고 생각하시면 되겠습니다.

 

 

Widget Box (위젯 상자)

 

도화지가 준비되었으니, 도화지를 예쁘게 꾸밀 물감이 필요하겠죠? Widget Box는 그런 물감을 모아놓은 팔레트라고 생각하시면 됩니다.

바로 화면의 좌측에 위치하는 위젯(프로그램에서 기능을 하는 버튼 등의 객체)이 그 역할을 합니다.

 

이곳에서 원하는 위젯을 Dialog Window로 드래그하여 GUI 프로그램이라는 그림을 그려줄 수 있습니다.

 

 

Property Editor (속성 편집기)

 

우리는 도화지와 물감만 있다고 원하는데로 그림을 그릴 수가 없습니다. 의도한 그림을 구현하기 위해서는 붓이 필요하겠죠?

Property Editor는 위젯의 이름(objectName), 위치와 크기(geometry) 등의 특성을 조정해줄 수 있는 창입니다.

 

 

 

Qt Designer로 내 맘대로 GUI 디자인 해보기

 

위에서 배운 도화지, 물감, 붓 들을 이용해 나만의 그림(GUI)을 그려 보겠습니다. 저는 이것저것 막 드래그해서 아래와 같이 구성해봤습니다.

똑같이 따라하실 필요는 전혀 없습니다! 단순히 버튼 하나만 넣으셔도 됩니다.

 

 

이렇게 만들고 저장해주면 생성되는 ui 파일을 코드에서 가져다 사용하면 됩니다. 정말 쉽죠?

 

어떻게 코드에서 사용하는지 알아보기 전에, 하나만 알고 넘어가시면 좋을 것 같아요.

바로 objectName입니다. 여기서 제가 추가한 QpushButton 위젯 객체의 이름은 pushButton입니다.

 

나중에 이 버튼 객체를 지난 시간에 배웠던 슬롯(함수)와 연결시켜 어떤 기능을 하기 위해서는 이름을 알고 있어야 합니다.

앞으로 GUI를 디자인 하실 때, 각 위젯의 objectName에 직관적인 이름을 지어주고 사용하시면 됩니다.

 

 

 

참고로 저장 전에 미리보기를 할 수 있습니다. 미리보기 단축키는 Ctrl(Command) + R입니다.

 

 

Qt Designer 파일(.UI) 저장

 

Qt Designer의 UI는 저장 버튼 혹은 단축키(Ctrl + S / Command + S)로 저장을 할 수 있습니다. 저장된 UI파일은 데이터 저장 규칙인 XML 형식을 가지며, Python 코드에서 이 XML 파일을 Import한 후 위젯들에 기능을 할당해주면 실제로 기능을 가지고 작동하는 GUI프로그램이 되는 것입니다.

 

UI 파일을 저장할 때 주의할 점은 Python코드에서 import하기 쉽도록 Python 코드와 같은 디렉토리에 위치시키는 것이 좋습니다. UI파일의 이름은 원하는 이름으로 아무렇게나 지정해도 됩니다.

 

 

 

UI 파일과 Python 코드의 연결

 

UI파일과 Python코드를 연결 방법은 2가지로 나뉩니다.

 

1) UI파일을 Python 코드에서 import하는 방법

2) UI 파일을 코드로 변환해서 Python 코드에 포함시키는 법

 

코딩유치원에서는 쉬운 방법인 UI파일을 Python 코드에서 import하는 방법에 대해서만 다루도록 하겠습니다.

혹시, 두 번째 방법이 궁금하신 분들은 아래의 링크를 참고해주세요.

 

ybworld.tistory.com/10?category=929856

 

 

UI파일을 Python 코드에서 import하는 방법

 

UI파일과 동일한 위치에 Python파일을 하나 만든 후, 아래의 코드를 그대로 복사/붙여넣기 합니다. 이때 중간에 있는 "UI파일이름.ui"는 자신이 가지고 있는 UI의 이름으로 수정해주셔야 합니다.

 

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic   # ui 파일을 사용하기 위한 모듈 import

#UI파일 연결 코드
UI_class = uic.loadUiType("UI파일이름.ui")[0]


class MyWindow(QMainWindow, UI_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

app = QApplication(sys.argv) 

Window = MyWindow() 

Window.show()

app.exec_()

 

위의 코드를 실행시켰다면 성공적으로 Qt Designer를 이용하여 제작한 GUI가 표시되는 것을 볼 수 있습니다.

다음 시간에는 지금까지 배워왔던 것을 갖고 간단한 기능을 하는 GUI 프로그램을 만들어보겠습니다.

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

코딩유치원에서는 파이썬 기초부터 사무자동화, 웹크롤링, 데이터 분석, 머신러닝 등의 다양한 패키지까지 초보자도 알기 쉽도록 내용을 정리해 놓았습니다.

업무는 물론 투자에도 도움이 될만한 전자공시시스템(DART)나 텔레그램(Telegram) 관련 패키지도 배울 수 있으니 많은 관심 부탁드립니다.

 

 

<GUI 프로그래밍 관련 이전 글>

 

출처. WIKIPEDIA

2021.05.07 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_1강.PyQt의 개념과 창 만들기 (창 이름, 사이즈, 변경 및 아이콘 삽입)

2021.05.08 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_2강.위젯의 종류, 시그널과 슬롯, 이벤트 루프

2021.05.10 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_3강.Qt Designer로 내마음대로 GUI 구성하기

 

지난 시간에는 PyQt가 무엇인지, 대충 어떻게 생겼고 기본적인 창을 만들고 조금조금 바꿔보는 것을 배워봤습니다.

 

그런데 창 안에는 아무것도 존재하지 않았죠? 오늘은 그 안을 어떤 위젯으로 채울 수 있는지 간단하게 알아보고, 위젯을 조작했을 때 어떤 방식으로 함수와 연결되는지에 대해서 알아보겠습니다.

 


 

위젯의 종류

 

위젯이란 지난 시간 배운 Window라는 Container에 담을 수 있는 내용물을 뜻합니다.

 

PyQt에는 아래와 같은 위젯들이 존재하며, 각각 다른 모양과 기능을 가지고 있습니다. (여기 있는 것 외에도 위젯들이 있을 수 있습니다)

 

위젯 종류 세부 위젯 종류
버튼 푸쉬버튼(QPushButton)

라디오버튼(QRadioButton)

체크박스(QCheckBox)
출력 한줄 문자열(QLabel)

여러줄 문자열(QTextBrowser)

사진(QPixmap)

작업진행도(QProgressBar)
입력 한줄 문자열 입력(QLineEdit)

여러줄 문자열 입력(QTextEdit, QPlainTextEdit)

여러 개 선택지 중 하나 선택(QComboBox)

상하 버튼으로 숫자 조절(QSpinBox, QDoubleSpinBox)

슬라이드와 다이얼(QSlider, Qdial)

날짜/시간 (QDateTimeEdit, QDateEdit, QTimeEdit), 

 

참고로, 우리는 위젯 구성을 다음시간에 배울 Qt Designer라는 프로그램으로 할 것입니다. 

아래 이미지는 Qt Desinger의 위젯 상자입니다. 여기서 원하는 위젯을 골라서 '드래그 앤 드롭' 하여 사용할 거예요.

 

 

 

시그널과 슬롯

 

아직 위젯을 만드는 법은 배우지 않았지만 위젯을 추가했다고 가정해봅시다. 현재의 위젯은 마치 그림의 떡과 같이 아무 쓸모가 없습니다.

그래서 우리는 이 위젯이 어떤 기능을 할 수 있도록 추가적인 코드를 작성해주어야 합니다.

 

위에서 살펴본 위젯들 중, 가장 기초적인 버튼 위젯을 예로 설명해보겠습니다.

 

사용자가 버튼을 클릭하는 행위를 입력(Input),

위젯에 어떤 입력이 들어왔을 때 발생하도록 정의된 이벤트를 시그널(Signal),

시그널이 발생했을 때 수행할 함수를 '이벤트 핸들러' 혹은 슬롯(Slot)이라고 합니다.

 

쉽게 비유하자면 제가 친구의 옆구리를 찌른 것이 '입력'이고, 친구가 받은 옆구리의 통증이 시그널, 친구의 반응이 '슬롯'이죠.

 

시그널은 위젯마다 다르며, 하나의 위젯에 여러개의 시그널이 존재할 수 있습니다.

이 부분을 하나하나 다루기에는 너무 양이 방대하여 링크로 대신하도록 하겠습니다.

 

[위키독스] 초보자를 위한 Python GUI 프로그래밍 - PyQt5  (위젯과 레이아웃 링크)

wikidocs.net/35483

 

 

슬롯은 우리가 직접 함수로 정의해주면 됩니다. 아래의 코드를 보시죠.

 

import sys
from PyQt5.QtWidgets import *

class MyWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):    
        btn = QPushButton("버튼", self)
        btn.clicked.connect(self.surprise)

    def surprise(self):
        print("으엌! 깜짝이야!!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    app.exec_()

 

이 코드에서 먼저 입력과 시그널, 슬롯은 무엇일까요?

 

입력은 '사용자의 물리적인 마우스 클릭과 마우스를 통해 변화된 전자적 입력'입니다.

 

시그널은 btn.clicked.connect( )에서 .cliked 입니다.

이 코드는 btn이란 이름의 QPushButton의 인스턴스가 클릭되었을 때, ( )안의 메소드(슬롯)와 연결해주는 역할을 하죠.

 

슬롯은 def surprise(self): 로 정의하였습니다. 이 슬롯은 위에서의 .connect( )로 시그널과 연결되는 것입니다.

 

 

이벤트 루프

 

혹시 지난 시간에 배웠던 코드 중에 닫기 버튼 누를 때 까지 계속 GUI 프로그램을 실행시키는 코드를 기억하시나요?

 

app.exec_( ) 를 프로그램의 마지막에 입력하시면 루프를 돌며, '닫기' 이벤트가 발생하기 전까지 GUI 창을 계속 띄워놓는 코드입니다.

그래서 이벤트 루프라고 부르며, 이벤트라는 것은 사용자가 마우스클 클릭하거나 키보드를 입력하는 것과 같은 동작을 의미합니다.

 

참고로, exec_( ) 앞에 붙는 app은 QApplication 클래스의 인스턴스이며, 이름은 app 말고도 원하는대로 지어주시면 됩니다.

 

exec_( ) 메서드를 호출하면 이벤트 루프가 생성되고 실행됩니다. 이를 보다 명확히 알아보기 위해 다음과 같이 print( ) 함수를 추가해서 커맨드 창을 관찰해보시면 좋을 것 같습니다.

 

import sys
from PyQt5.QtWidgets import *

class MyWindow(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()
        
    def initUI(self):    
        btn = QPushButton("버튼", self)
        btn.clicked.connect(self.surprise)

    def surprise(self):
        print("으엌! 깜짝이야!!")

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyWindow()
    window.show()
    app.exec_()
    
#해당 코드 실행 시 부터 이벤트 루프 발생 (즉, 이 코드 아래로는 이벤트 발생 전까지 안내려감)
app.exec_()

print("루프 밖")

 


 

이번 시간에는  위젯의 종류와 입력/시그널/슬롯 간의 관계에 대해서 알아보았습니다.

 

다음 시간에는 Qt Designer를 이용해 위젯을 실제로 구성해보고, 슬롯을 정의해서 연결시켜보면서 실제 프로그램을 만들기 위한 공부를 해보겠습니다.

반응형
반응형

안녕하세요, 왕초보 코린이를 위한 코딩유치원에 오신 것을 환영합니다.

코딩유치원에서는 파이썬 기초부터 사무자동화, 웹크롤링, 데이터 분석, 머신러닝 등의 다양한 패키지까지 초보자도 알기 쉽도록 내용을 정리해 놓았습니다.

업무는 물론 투자에도 도움이 될만한 전자공시시스템(DART)나 텔레그램(Telegram) 관련 패키지도 배울 수 있으니 많은 관심 부탁드립니다.

 

 

PyQt를 사용하기 위해서는 클래스(class)에 대한 이해가 선행되어야 합니다.

 

2021.05.02 - [파이썬 기초/중급 문법] - [파이썬 중급 문법] 클래스(class) 총정리 1편_객체,속성,메소드,인스턴스

2021.05.03 - [파이썬 기초/중급 문법] - [파이썬 중급 문법] 클래스(class) 총정리 2편_ 초기화, 상속, 메소드 오버라이딩, 클래스 변수, 인스턴스 변수

 

 

<파이썬 GUI 프로그래밍 관련 지난 글>

 

2021.05.07 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_1강.PyQt의 개념과 창 만들기 (창 이름, 사이즈, 변경 및 아이콘 삽입)

2021.05.08 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_2강.위젯의 종류, 시그널과 슬롯, 이벤트 루프

2021.05.10 - [파이썬 패키지/GUI 프로그램] - [파이썬 GUI 프로그래밍] PyQt5 기초_3강.Qt Designer로 내마음대로 GUI 구성하기

 


1. PyQt란?

출처. WIKIPEDIA

 

 

PyQt는 Python + Qt를 합쳐서 지은 이름으로, C++ 기반의 GUI Framework인 Qt를 Python에서 사용할 수 있게 만든 패키지입니다.

 

Python에는 기본적으로 내장되어있는 Tkinter라는 GUI 모듈이 있지만, 오로지 코딩으로 우리가 만들 GUI를 구현해야하는 불편하다는 단점과 무엇보다 시각적으로 예쁘지 않다는 치명적인 단점이 있습니다. 그냥 고민없이 PyQt를 사용하시면 되겠습니다.

 

추후 배울 Qt Designer라는 프로그램을 이용하면, 드래그 앤 드롭 방식으로 너무나도 쉽게 GUI를 구성할 수 있습니다.

우리가 할 일은 GUI의 위젯(버튼, 슬라이드 등)을 조작했을 때, 우리가 코딩해놓은 함수가 작동하도록 연결만 해주기만 하면 되는 것입니다.

 

궁극적으로는 내가 만든 파이썬 프로그램을 파이썬을 모르는 사람도 쉽게 조작할 수 있는 말그대로 어플리케이션을 만들 수 있습니다.

 

2. PyQt 기초

 

가장 처음 말씀드렸듯이 PyQt를 사용하려면 클래스(class)의 개념을 조금 알고 계셔야합니다.

추천드린 지난 글을 보고 오셨다면 더 이해가 쉽겠지만 안보셨더라도 이해하실 수 있도록 최대한 쉽게 설명드려 보겠습니다.

 

참고로 클래스는 도면이고, 객체는 도면으로 만든 어떤 실체, 메소드는 클래스 안에 정의된 함수(도면의 내용)라고 생각하시면 됩니다.

 

PyQt5를 사용하여 아주아주 간단한 GUI 프로그램을 만들어보았습니다.

 

참고로 Anaconda를 설치하셨다면 pyqt 패키지는 이미 설치되어 있으니, 따로 설치하지 않으셔도 PyQt5 패키지가 import 됩니다.

 

<전체 코드>

import sys
from PyQt5.QtWidgets import *

app = QApplication(sys.argv)

window = QWidget()
window.show()

app.exec_()

 

<코드 설명>

 

1) 관련 패키지 import

import sys

from PyQt5.QtWidgets import *

 

가장 먼저 파이썬 내장 라이브러리에 존재하는 sys모듈을 import합니다.

sys 모듈은 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈입니다. (점프 투 파이썬 sys 모듈 설명 참고)

 

PyQt5 패키지의 QtWidgets 모듈에서 전체를 가져오는 코드입니다. import *의 *는 모듈을 전부 가져온다는 의미입니다.

 

 

2) PyQt 필수 객체 생성 - QApplication(sys.argv)

app = QApplication(sys.argv)

 

QApplication( ) 클래스로 app이란 이름의 객체를 생성하는 코드입니다.

QApplication는 QtWidgets 모듈 안에 존재하는 여러 메소드(함수) 중의 하나이며, PyQt를 사용하면 무조건 써야하는 클래스입니다.

 

이때 현재 소스코드 파일에 대한 경로를 담고 있는 리스트(sys.argv)를 클래스의 생성자(초기화 메서드, __init__)로 전달해주어야 합니다.

궁금하신분은 print(sys.argv)로 안에 무엇이 들었는지 확인해보세요.

 

참고로, argv는 가변적인 개수의 문자열(arguments vector)을 의미한다고 합니다. 

 

 

3) 기능없는 창(window) 만들어보기

window = Qwidget( )

window.show( )

 

Qwidget( )은 실제로 화면에 보여지는 윈도우를 생성하는 클래스입니다.

이를 이용해 window라는 이름으로 객체를 생성한 후에 show 메소드로 창을 띄워줍니다.

 

여기서 Qwidget( )는 그냥 창의 껍데기만 만드는 것이라고만 이해하고 넘어가도록 합시다.

 

 

4) 닫기 버튼 누를 때 까지 계속 실행하는 코드

app.exec_()

 

위의 소제목과 같이 닫기 버튼을 누를 때 까지, 루프를 돌며 GUI 창을 계속 띄워놓는 코드입니다.이 부분은 다음 강의에서 자세히 설명드릴테니, 이정도로 이해하고 넘어가겠습니다.

 

 

3. 나만의 윈도우 만들기

 

아래와 같이 아이콘과 창 이름을 넣어주고, 원하는 위치에 원하는 크기로 창을 띄우는 실습을 통해서 PyQt에 대해서 알아보도록 하겠습니다.

 

 

1) 윈도우 생성

 

PyQt에서 모든 위젯의 가장 기초가 되는 위젯을 윈도우라고 부릅니다. GUI를 만드는 것을 그림 그리는 것이라 생각하면 윈도우를 생성하는 것은 도화지를 준비하는 것입니다. 

 

<도화지 코드>

import sys
from PyQt5.QtWidgets import *

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()


app = QApplication(sys.argv)

window = MyWindow()   
# 위의 기본 코드와 다른 점
# QMainWindow 클래스를 상속받은 MyWindow 클래스를 선언
# 그 후 부모클래스를 의미하는 super()메소드와 그 클래스의 속성을 불러오는 __init__ 초기화 메소드 사용
# QMainWindow의 속성이 무엇인지는 모르겠음

window.show()

app.exec_()

 

아까 처음 본 코드와의 차이점은 class MyWindow 부분과 window = MyWindow( ) 부분 입니다.

 

나만의 윈도우 클래스를 만들어서 사용하기 위해 PyQt가 제공하는 QMainWindow를 상속 받아서 MyWindow라는 클래스를 정의해주어야 합니다.

 

한마디로 MyWindow라는 클래스의 역할은 객체를 생성했을 때, 부모 클래스인 QMainWindow의 def __init__의 속성과 메소드를 불러오거나 실행시켜주는 역할이라고 생각하면 됩니다.

 

 

2) 윈도우 타이틀 변경

 

원하는 창의 이름을 넣어 주고 싶을 땐 아래와 같이 setWindowTitle( ) 메소드를 사용합니다.

def __init__(self) 메소드 안에 self.setWindowTitle("원하는 창 이름")을 넣으주면 됩니다.

 

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
		
        # 도화지 코드의 이 위치에 아래 코드 한 줄을 추가할 것
        self.setWindowTitle("코딩유치원 GUI")

 

3) 윈도우 크기 변경

 

QMainWindow 클래스에는 윈도우의 출력 위치 및 크기를 변경하는 메서드인 setGeometry( )가 정의되어 있습니다.

 

아래의 코드는 setGeometry( ) 메서드를 사용해서 창의 좌측상단 꼭지점의 좌표가 300, 300이며 창의 크기가 400x400이 되도록 윈도우를 셋팅하는 코드입니다.

 

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
		
        # 도화지 코드의 이 위치에 아래 코드 한 줄을 추가할 것
        self.setGeometry(300, 300, 400, 400) # 차례대로 창위치 x,y, 창크기 x,y

 

4) 윈도우에 예쁜 아이콘 넣기

 

구글에서 icon-icons 사이트를 검색하거나 아래의 링크에서 아이콘 이미지 다운로드합니다. 테스트 해보니, 이미지 사이즈는 상관 없습니다.

 

icon-icons.com/ko/

 

무료 아이콘 SVG, PNG, ICO 또는 ICNS

 

icon-icons.com

 

다운로드한 아이콘 파일을 파이썬 코드와 동일 디렉터리로 이동시킵니다.

 

다음으로는 코드로 돌아와서, QIcon( ) 클래스를 사용하기 위하여 from PyQt5.QtGui import * 를 추가해 줍니다.

 

윈도우에서 아이콘의 설정은 setWindowIcon() 메서드를 사용하며, QIcon 클래스의 인스턴스를 인자로 받습니다.

 

QIcon 클래스의 인스턴스를 생성할 때는 인자로 아이콘 파일의 경로를 문자열로 넘겨주면 됩니다.

현재 예에서는 소스코드와 아이콘 파일이 같은 디렉터리에 있기 때문에 파일 이름만 적어주면 됩니다.

 

# 아이콘 삽입 클래스(QIcon) 사용을 위한 PyQt5 패키지의 QtGui 모듈 import
from PyQt5.QtGui import *


class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        
        # 해당 위치에 아래 코드 추가
        self.setWindowIcon(QIcon("pie-chart.png")) 

 


오늘은 아주 PyQt의 아주 기초적인 창만들기에 대해서 배워보았습니다.

 

다음 시간에는 위젯과 이벤트에 대한 내용을 공부해보겠습니다.

반응형

+ Recent posts