주제: [PyQt6 GUI] QListWidget 및 QTableWidget 활용한 GUI구현 (코드 포함)
작성: 2023-10-25
수정: 2023-10-29
해당 포스팅은 "PyQt6로 쉽게 GUI 만들기" 시리즈의 2번째 글입니다.
🖥️ PyQt6로 쉽게 GUI 만들기
1. 구조 이해 - 2023.10.24 - [✔ Python/4. GUI Programming] - [PyQt6] 기본적인 구조부터 이해하기
2. 코드 구현 - 2023.10.25 - [✔ Python/4. GUI Programming] - [PyQt6] QListWidget 활용한 GUI 구현[1/2] (코드 포함)
3. 코드 개선 - 2023.10.24 - [✔ Python/4. GUI Programming] - [PyQt6] QListWidget 활용한 GUI구현 [2/2] (코드 포함)
4. 테마 적용 - 2023.10.25 - [✔ Python/4. GUI Programming] - [PyQt6] GUI Stylesheet Theme 적용하기 : qt_material
이전 포스팅에서는 PyQt의 기본적인 구조에 대해 알아봤습니다.
직접 해보면서 배우는 것이 가장 빠른 학습법이니 아래의 그림처럼 GUI을 한번 만들어보도록 하겠습니다.
1. 구현 방향
학생이름과 성적이 포함된 데이터가 있습니다.
이때, 학생들의 이름을 List형태로 자동으로 표출하며, 학생이름을 클릭하면 그 학생의 성적을 표출하는 GUI을 구현해야 한다면?
필자는 QListWidget 활용하여 학생의 이름은 리스트 형태로 표출하며, QTable을 통해서 성적데이터를 테이블형태로 표출하려고합니다.
2. 학생이름 리스트 형태로 표출 - QListWidget
2-1. 데이터 생성
데이터는 따로 없는 관계로 임의작성하도록 하겠습니다.
데이터명은 data로 정의하며, pandas 활용하여 dataframe으로 생성하겠습니다.
import pandas as pd
if __name__ == '__main__':
##### 임의의 데이터 입력 ########
data = {'이름': ['루카스', '오드리', '라트리스','커스틴'],
'설계': [80, 90, 85, 100],
'코딩': [100, 50, 85, 100],
'해석': [95,90,95, 100]}
df = pd.DataFrame(data)
##### 임의의 데이터 입력 ########
app = QApplication(sys.argv)
window = MyApp(df)
현재, 임의의 데이터를 수기로 작성하였으나, 추후 csv, excel, db 파일 등을 그대로 가져와서 사용할 수 있습니다.
데이터를 생성한 이후, 클래스 내에서도 해당 데이터를 사용하기 위해 다음과 같이 설정해줍니다.
def __init__(self, df): # df 추가
super().__init__()
self.layout = QVBoxLayout()
self.df = df # df 정의
self.initUi()
2-2. 체크박스 X, 리스트 위젯 O
앞선 포스팅에서 구현했던 체크박스를 제거하고, 리스트 위젯을 적용하도록 하겠습니다.
def initUi(self) :
self.setWindowTitle("pyqt6 위젯적용 테스트")
self.setGeometry(300,300,200,200)
self.name_listwidget = QListWidget() # 변경됨
self.name_listwidget.addItems(sorted(self.df['이름'])) # 변경됨
widget = QWidget()
widget.setLayout(self.layout)
self.layout.addWidget(self.name_listwidget) # 변경됨
self.setCentralWidget(widget)
.addItems(sorted(self.df['이름'])))
- self.df['이름'] : Pandas DataFrame의 '이름' 열에 있는 데이터를 가져옵니다.
- sorted : 파이썬의 내장함수인 sorted()함수를 이용하여 순서를 정렬합니다.
- .addItems : 정렬된 리스트는 addItems 메서드를 통해 QListWidget에 추가하는 과정입니다.
3. 학생 성적 테이블 위젯으로 데이터 표출 - QTable
3-1. QTableWidget
지금까지 생성한 리스트위젯 아래로 테이블을 생성하도록 하겠습니다.
def initUi(self) :
self.setWindowTitle("pyqt6 위젯적용 테스트")
self.setGeometry(1000,10,500,500)
# 레이아웃 및 라벨설정
layout = self.layout
layout.addWidget(QLabel("🧑🏻💻 WSCODE 수강생을 선택하시오"))
# 리스트 위젯
self.name_listwidget = QListWidget()
self.name_listwidget.addItems(sorted(self.df['이름']))
self.layout.addWidget(self.name_listwidget)
# 테이블 위젯
self.table_widget = QTableWidget()
self.table_widget.setColumnCount(self.df.shape[1])
layout.addWidget(QLabel("📋 수강생 성적관리 "))
layout.addWidget(self.table_widget)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
여기까지 구현했을 때는, 데이터에 있는 수강생들의 학생을 잘 가져와서 표출하고 있습니다.
3-2. QTableWidget
하지만, 수강생의 이름을 클릭해도 그 학생의 성적은 표출되지 않습니다. 왜냐하면, 시그널과 슬롯간의 연결이 되어있지않기때문입니다.
self.name_listwidget = QListWidget()
self.name_listwidget.addItems(sorted(self.df['이름']))
self.name_listwidget.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
self.name_listwidget.itemSelectionChanged.connect(self.update_table)
layout.addWidget(self.name_listwidget)
여기서 중요한 개념이 등장합니다. Signal, Slot, Connect 입니다.
시그널(Signal) - 객체에서 발생하는 이벤트나 상태변경
- itemSelectionChanged: QListWidget에서 선택된 리스트 아이템이 변경될 때마다 발생하는 시그널입니다.
슬롯(Slot) - 슬롯은 시그널을 처리하는 함수나 메서드
- self.update_table: 사용자가 리스트 위젯에서 다른 아이템을 선택했을 때 호출되어야 하는 메서드 또는 함수입니다.
연결(Connect) - 시그널과 슬롯은 connect 메서드를 사용하여 연결하며, 이를 통해 시그널이 발생하면 연결된 슬롯 호출
- connect(): 이 함수는 시그널을 슬롯에 연결합니다. 슬롯은 시그널이 발생했을 때 호출되는 함수 또는 메서드입니다.
3-3. Slot 함수 생성하기
그럼, 이제 원본데이터를 표출하는 슬롯 함수를 만들도록 하겠습니다.
def update_table(self):
# 초기 테이블 설정값
self.table_widget.setRowCount(0)
# Get the selected items from the QListWidget
selected_items = self.name_listwidget.selectedItems()
# 테이블의 열 수를 데이터프레임의 열 수에 맞추기
num_columns = self.df.shape[1]
self.table_widget.setColumnCount(num_columns)
self.table_widget.setHorizontalHeaderLabels(self.df.columns)
# 테이블의 행 수를 선택한 항목 수로 설정
num_rows = len(selected_items)
self.table_widget.setRowCount(num_rows)
for row, item in enumerate(selected_items):
name = item.text()
row_data = self.df[self.df['이름'] == name]
for col in range(num_columns):
data = row_data.iloc[0, col]
print(data)
self.table_widget.setItem(row, col, QTableWidgetItem(str(data)))
4. 전체코드
import sys
import pandas as pd
from PyQt6.QtGui import QFont
from PyQt6.QtWidgets import (QApplication,QMainWindow,QVBoxLayout,QWidget,QLabel,
QListWidget, QAbstractItemView, QTableWidgetItem,QTableWidget,QHBoxLayout)
class MyApp(QMainWindow):
def __init__(self, df):
super().__init__()
self.layout = QVBoxLayout()
self.df = df
self.initUi()
def initUi(self) :
self.setWindowTitle("수강생 성적정보 관리 어플리케이션")
self.setGeometry(2400,400,500,600)
layout = self.layout
layout.addWidget(QLabel("🧑🏻💻 WSCODE 수강생을 선택하시오"))
self.name_listwidget = QListWidget()
self.name_listwidget.addItems(sorted(self.df['이름']))
self.name_listwidget.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
self.name_listwidget.itemSelectionChanged.connect(self.update_table)
layout.addWidget(self.name_listwidget)
# Create a QTableWidget
self.table_widget = QTableWidget()
self.table_widget.setColumnCount(self.df.shape[1])
layout.addWidget(QLabel("📋 수강생 성적관리 "))
layout.addWidget(self.table_widget)
widget = QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
def update_table(self):
self.table_widget.setRowCount(0)
selected_items = self.name_listwidget.selectedItems()
num_columns = self.df.shape[1]
self.table_widget.setColumnCount(num_columns)
self.table_widget.setHorizontalHeaderLabels(self.df.columns)
num_rows = len(selected_items)
self.table_widget.setRowCount(num_rows)
for row, item in enumerate(selected_items):
name = item.text()
row_data = self.df[self.df['이름'] == name]
for col in range(num_columns):
data = row_data.iloc[0, col]
print(data)
self.table_widget.setItem(row, col, QTableWidgetItem(str(data)))
if __name__ == '__main__':
# dataset
data = {'이름': ['루카스', '오드리', '라트리스','커스틴'],
'설계': [80, 90, 85, 100],
'코딩': [100, 50, 85, 100],
'해석': [95,90,95, 100]}
df = pd.DataFrame(data)
app = QApplication(sys.argv)
window = MyApp(df)
window.show()
app.exec()
5. 다음 포스팅은...?
이번 글에서는 전반적인 GUI 구현을 완료했습니다. 하지만, 아직 일부 보완이 필요한 부분들이 있습니다.
다음 포스팅에서 해당 코드의 일부분을 개선하도록 하겠습니다.
해당 포스팅은 "PyQt6로 쉽게 GUI 만들기" 시리즈의 2번째 글입니다.
🖥️ PyQt6로 쉽게 GUI 만들기
1. 구조 이해 - 2023.10.24 - [✔ Python/4. GUI Programming] - [PyQt6] 기본적인 구조부터 이해하기
2. 코드 구현 - 2023.10.25 - [✔ Python/4. GUI Programming] - [PyQt6] QListWidget 활용한 GUI 구현[1/2] (코드 포함)
3. 코드 개선 - 2023.10.24 - [✔ Python/4. GUI Programming] - [PyQt6] QListWidget 활용한 GUI구현 [2/2] (코드 포함)
4. 테마 적용 - 2023.10.25 - [✔ Python/4. GUI Programming] - [PyQt6] GUI Stylesheet Theme 적용하기 : qt_material
Reference
- PyQt5 Tutorial - 파이썬으로 만들기: https://wikidocs.net/21933
'Python > 3️⃣ 프로그래밍' 카테고리의 다른 글
[PyQt6] GUI Stylesheet Theme 적용하기 : qt_material (6) | 2023.10.29 |
---|---|
[PyQt6] QListWidget 활용한 GUI구현 [2/2] (코드 포함) (2) | 2023.10.29 |
[PyQt6] 기본적인 구조부터 이해하기 (3) | 2023.10.24 |
QtWidegets 모듈 vs QtWidegets 클래스 (0) | 2023.10.23 |
PyQt5와 PyQt6의 주요 변경사항(표) (0) | 2023.10.23 |