GUI 텍스트 에디터를 구현하며 다양한 GUI 객체들을 활용해보자. 자주 쓰이는 객체들 위주로 다루어볼 예정이다.
QTextEdit
QTextEdit은 입출력 가능한 텍스트 창이다. 프로그램에서 텍스트를 출력할 수도 있고 사용자가 텍스트를 입력할 수도 있다. 우선 MainWindow에 QTextEdit을 추가해 화면에 띄워보자. 객체의 이름은 textEdit 그대로 두고 프로젝트 폴더에 text_editior.ui로 저장하여 스크립트로 변환하자. (변환은 터미널에서 다음 명령어를 입력)
.\.venv\Scripts\pyside6-uic.exe text_editor.ui -o text_editor.py

UI 스크립트를 이용해 GUI를 화면에 띄우는 간단한 코드를 작성한다.
import sys
from PySide6.QtWidgets import QMainWindow, QApplication
from text_editor import Ui_MainWindow
class MyWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self) # UI 초기화
def main():
app = QApplication(sys.argv)
editor = MyWindow()
editor.show()
app.exec()
if __name__ == "__main__":
main()
QTextEdit의 주요 함수들은 다음과 같다.
- setText(text): text를 화면에 표시
- str toPlainText(): 화면에 표시중인 텍스트를 리턴
- QCursor textCursor(): 현재 커서 정보를 담고 있는 QCursor 객체를 리턴
- setFontFamily(str font): 글꼴을 font로 바꿈
- setTextColor(QColor color): QColor 객체로 글꼴의 색을 지정
- setFontWeight(int weight): QFont 내부에 정의된 weight 상수로 글꼴의 굵기를 지정
- setFontItalic(bool set): True/False를 입력하여 글꼴의 기울기를 지정
- setFontPointSize(int size): 글꼴의 크기를 지정
QMenu, QAction
화면 상단에 파일을 열고 닫을 수 있는 메뉴를 만들고 기능을 구현한다. QtDesigner에서 윈도우 상단의 TypeHere에 File이란 메뉴(QMenu)를 추가하고 그 아래 Open과 Save라는 액션(QAction)을 추가한다. 그러면 Object Inspector 메뉴에 다음과 같이 객체 들이 추가된다.


수정했다면 ui 파일을 다시 저장해주고 스크립트도 업데이트해주자. 이제 코드에서 action을 클릭했을 때 실행할 Slot 함수를 연결하겠다.
configure_ui()라는 함수를 만들고 그 안에서 actionOpen.triggered는 open_file 함수와 연결했고 actionSave.triggered는 save_file 함수와 연결했다.
class MyWindow(QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self) # UI 초기화
self.configure_ui()
def configure_ui(self):
self.actionOpen.triggered.connect(self.open_file)
self.actionSave.triggered.connect(self.save_file)
open_file함수에서는 QFileDialog.getOpenFileName()를 써서 다이얼로그에서 파일을 선택하여 파일명을 받을 수 있게 했다. 이후 파일 내용을 읽어 textEdit객체에 쓰기 위해 setText()함수를 썼다.
def open_file(self):
filename = QFileDialog.getOpenFileName(filter="Text files (*.txt)")
filename = filename[0]
print("open file:", filename)
if not filename:
return
with open(filename, "r", encoding="utf8") as f:
text = f.read(10000)
self.textEdit.setText(text)
save_file 함수에서는 QFileDialog.getSaveFileName() 함수를 써서 다이얼로그에서 저장할 파일명을 지정하였다. 보통 텍스트 객체에서 현재 표시하고 있는 텍스트를 읽어오는 함수는 text()이지만 QTextEdit에서는 toPlainText()를 통해 현재 표시된 텍스트를 읽을 수 있다.
def save_file(self):
filename = QFileDialog.getSaveFileName(filter="Text files (*.txt)")
filename = filename[0]
print("open file:", filename)
if not filename:
return
with open(filename, "w", encoding="utf8") as f:
f.write(self.textEdit.toPlainText())
다음과 같은 텍스트를 One_more.txt로 저장한 후 텍스트를 프로그램에서 불러온 결과는 다음 그림과 같다.
헤이, 한번만 나의 눈을 바라봐
그대의 눈빛 기억이 안나, 이렇게 애원하잖아
헤이, 조금만 내게 가까이 와봐
그대의 숨결 들리지 않아, 마지막 한번만 더
그대의 가슴에 안기고 싶어

QStatusBar
텍스트를 읽거나 수정할 때 글자 수와 현재 위치를 윈도우 아래 statusbar에 출력해보자. 새 UI를 만들 때 MainWindow를 선택하면 기본으로 윈도우 아래 statusbar 객체가 포함돼있다. 먼저 textEdit에서 커서가 이동할때 발생하는 Signal과 이를 처리하는 Slot함수를 연결해야 한다.
def configure_ui(self):
...
self.textEdit.cursorPositionChanged.connect(self.update_status)
update_status() 함수에서 현재 커서 정보를 받기 위해 textEdit.textCursor() 함수를 통해 QTextCursor 객체를 받아와 커서 정보를얻었다. position()은 현재 커서 위치고 anchor()는 drag를 시작했을 때의 커서 위치라 평소엔 두 함수가 같은 값을 리턴하고 drag를하면 다른 값을 리턴하게 된다.
def update_status(self):
text_len = len(self.textEdit.toPlainText())
cursor_pos = self.textEdit.textCursor().position()
cursor_anc = self.textEdit.textCursor().anchor()
if cursor_pos == cursor_anc:
status = f"text length:{text_len}, cursor position: {cursor_pos}"
else:
status = f"text length:{text_len}, cursor range: {cursor_anc}~{cursor_pos}"
self.statusbar.showMessage(status)

QComboBox
QComboBox는 여러개의 목록에서 하나를 선택할 수 있는 객체다. 이를 통해 텍스트의 폰트를 선택하는 기능을 구현할 것이다. QFontComboBox라는 클래스를 제공하긴하지만 이를 간단히 직접 구현하기위해 기본 QComboBox를 사용하겠다.
Input Widgets에서 Combo Box를 선택하여 다음 그림과 같이 배치하고 이름은 기본값으로 둔 후 변환을 해주자.

폰트를 선택하고 이를 반영하기 위해서는 다음과 같은 단계가 필요하다.
- comboBox 객체에 폰트 목록 추가
- 시작할 때 기본 서낵 폰트를 textEdit에 반영
- comboBox에서 폰트가 바뀔 때 자동으로 textEdit에 반영하기
이를 초기 설정하는 configure_ui() 함수에 반영하고 Slot 함수인 change_font() 함수를 만들었다.
def configure_ui(self):
...
self.comboBox.addItems(["굴림", "돋움", "바탕"])
self.textEdit.setFontFamily(self.comboBox.currentText())
self.comboBox.currentIndexChanged.connect(self.change_font)
def change_font(self, cur_index):
print("comboBox index:", cur_index)
self.textEdit.setFontFamily(self.comboBox.currentText())
- comboBox.addItems()로 폰트 목록 추가
- comboBox.currentText()로 현재 선택된 폰트를 읽어서 textEdit.setFontFamily() 함수로 폰트 변경
- comboBox.currentIndexChanged라는 Signal을 change_font()함수와 연결
실행 결과는 다음과 같다.

QGroupBox, QRadioButton
Radio button은 여러 개의 버튼 중에 하나만 선택할 수 있는 버튼이다. 이를 통해 글자의 색깔을 결정하고자 한다. 보통 group box와 함께 사용한다.
프로그램에서 한 가지 옵션만을 선택한다면 상관없으나 다수의 radio button으로 두 가지 옵션을 선택해야하 하는 경우 radio button들을 옵션별로 나눠야 한다.group box는 radio button들이 유일하게 선택되는 범위를 지정해주는 것이다.
또한 다수의 객체들이 한 화면에 있으면 가시성이 떨어지므로 비슷한 기능을 가진 객체들을 시각적으로 묶는 역할도 한다.
다음 그림과 같이 Group Box를 comboBox 아래에 추가해주자. 후에 객체 기본 텍스트와 객체 이름들을 수정하고 저장하여 변환해주자.


우선 Black 버튼을 눌렀을 때 반응하는 slot 함수 하나를 만들어보자.
def configure_ui(self):
...
self.radioButton_black.pressed.connect(self.set_color_black)
def set_color_black(self):
print("black color selected")
QRadioButton의 pressed 라는 Signal을 사용한다. Qt에서 다양한 버튼들(QPushButton, QCheckBox, QRadioButton)은 같은 부모 클래스인 QAbstractButton으로부터 파생되어있는데 여기에 여러가지 버튼에서 공통으로 사용되는 Signal들이 있다.
clicked: 버튼을 클릭하면 발생, Slot 함수에서 체크 상태를 나타내는 bool 타입의 입력인자를 받을 수 있다.
pressed: 버튼을 눌러서 체크가 되면 발생
released: 버튼을 눌러서 체크가 해제되면 발생
toggled: 버튼을 눌러서 체크 상태가 변하면 발생, Slot 함수에서 체크 상태를 나타내는 bool 타입의 입력인자를 받을 수 있다.
위 코드 방식으로 세 개의 radio button을 각각의 Slot 함수에 연결해야 할것이다. 그러나 이렇게하면 코드가 상당히 길어진다. 이때 세 개의 버튼을 하나의 QbuttonGroup 객체에 담으면 한 번의 connect로 세 개의 버튼을 모두 처리할 수 있다.
아래 코드를 보면 QButtonGroup 클래스의 rb_color_group이라는 객체를 만들고 세 개의 버튼을 담았다. 그런뒤 buttonPressed라는 Signal을 change_color() 함수에 연결하였다.
from PySide6.QtWidgets import QMainWindow, QApplication, QFileDialog, QButtonGroup
from PySide6.QtGui import QColor
def configure_ui(self):
...
self.rb_color_group = QButtonGroup()
self.rb_color_group.addButton(self.radioButton_black)
self.rb_color_group.addButton(self.radioButton_red)
self.rb_color_group.addButton(self.radioButton_blue)
self.rb_color_group.buttonPressed.connect( self.change_color)
def change_color(self, rbutton):
print("change color to", rbutton.text())
if rbutton is self.radioButton_black:
self.textEdit.setTextColor(QColor(0, 0, 0))
elif rbutton is self.radioButton_red:
self.textEdit.setTextColor(QColor(255, 0, 0))
elif rbutton is self.radioButton_blue:
self.textEdit.setTextColor(QColor(0, 0, 255))
QButtonGroup의 Signal들은 그룹에 속한 버튼을 하나라도 클릭하면 발생하므로 Slot 함수를 버튼만다 따로 만들지 않아도 된다. change_color() 함수에서 이벤트를 발생시킨 버튼 객체를 입력인자로 받고 이 객체가 어떤 것인지 is 연산자를 통해 확인한다. 객체를 확인하면 QTextEdit.setTextColor() 함수를 통해 앞으로 입력될 글자 색을 변경한다.
QColor 객체를 받기 때문에 from PyQt5.QtGui import QColor를 추가하였다.

QCheckBox
Check box는 각 버튼을 독립적으로 체크할 수 있는 버튼의 한 종류다. Check box도 radio button과 마찬가지로 QAbstractButton을 상속 받으며 QButtonGroup에 넣을 수 있다. Check box를 이용해 새로 입력될 글자의 굵기와 기울기를 조절할 것이다. 다음 그림과 같이 group box안에 check box를 추가하고 기본 텍스트와 객체 이름을 수정 저장하여 변환까지 해주자.


Check box도 QButtonGroup에 넣어 하나의 함수로 처리할 수 있지만 check box는 각각의 체크 여부에 따라 설정이 달라지므로 하나의 함수로 처리하는 것이 별 이득이 없다. 그렇기에 각 check box마다 따로 Slot함수를 만들어주자. 상태가 변할 때마다 반응해야하니 toggled Slot을 썼고 Slot 함수는 체크 상태를 확인할 수 있는 checked라는 입력인자를 넣어준다.
set_bold() 함수에서 글자의 굵기를 조절하기 위해 QTextEdit.setFontWeight() 함수를 사용한다. 입력인자로 QFont에 속하는 상수를 입력한다. QFont를 쓰기위해 import 해주었다.
set_italic() 함수에서 글자의 기울기를 조절하기 위해 QTextEdit.setFontItalic() 함수를 사용한다. 입력이 bool 타입이므로 입력인자로 받은 checked 변수를 그대로 전달한다.

QSlider
Slider 객체는 가로축이나 세로축 홈(groove)을 따라 핸들을 움직이며 제한된 범위 내의 숫자를 조절할 수 있는 GUI 객체다. 대부분의 기능을 부모 클래스인 QAbstractSlider로부터 물려받기에 참고할때도 부모 클래스의 문서를 찾아보는 것이 낫다. 주요 함수는 다음과 같다.
- minimum(), maximum(): 현재 최소, 최대 값 읽기
- setMinimum(), setMaximum(): 최소, 최대 값 설정
- singleStep(), setSingleStep(): 슬라이더 한 칸 이동 값 읽기, 쓰기
- value(), setValue(): 현재 핸들 위치 읽기, 쓰기
이 슬라이더를 통해 텍스트의 크기를 조절해보자 다음 그림과 같이 Horizontal Slider를 윈도우에 추가해보자. 그리고 그 아래 Label도 추가하여 기본 텍스트와 객체 이름을 저장 수정하여 변환까지 해주자.


슬라이더에 따라 입력 글자 크기가 변하는 에디터를 만들기 위해 코드를 수정하자. 폰트 크기의 최소, 최대 값을 지정하고 valueChanged() Signal을 change_font_size()함수와 연결한다. 이벤트가 발생하면 label_slider_value에 현재 폰트 크기를 표시하고 QTextEdit.setFontPointSize() 함수를 통해 폰트 크기를 조절한다.
def configure_ui(self):
# ... 중략 ...
self.horizontalSlider.setMinimum(10)
self.horizontalSlider.setMaximum(20)
self.horizontalSlider.valueChanged.connect( self.change_font_size)
def change_font_size(self, size):
print("font size:", size)
self.label_slider_value.setText(f"Font size: {size}")
self.textEdit.setFontPointSize(size)

QLineEdit
QLineEdit 클래스는 한 줄짜리 단순한 텍스트 입출력을 하는데 사용된다. 여기서 두 개의 line edit 객체로 두 개의 단어를 받아서 textEdit의 텍스트 내의 첫 번째 단어를 두 번째 단어로 교체하는 Replace 기능을 구현하려한다.
다음 그림과 같이 Line Edit을 윈도우에 두 개 추가하고 Push Button도 하나 추가해주자. 기본 텍스트와 객체 이름을 다음 그림과 같이 설정 후 저장하여 변환해주자.


코드에서 QPushButton의 clicked Signal을 이용하여 버튼이 눌렸을 때 replace() 함수를 실행하게 한다.
def configure_ui(self):
...
self.pushButton_replace.clicked.connect(self.replace)
def replace(self):
text = self.textEdit.toPlainText()
text = text.replace(self.lineEdit_replace_src.text(), self.lineEdit_replace_dst.text())
self.textEdit.setText(text)
textEditPlainText()로 현재의 텍스트를 문자열로 받고 이 문자열에서 두 개의 line edit으로 입력받은 두 단어를 교체하였다. lineEdit_replace_src.text()가 기존 텍스트에서 검색할 기존 단어이고 lineEdit_replace_dst.text()는 새로운 텍스트에서 기존 단어 대신 들어갈 단어다. One_more.txt를 열어서 다른 단어로 바꾸어 보았다.

'학부 생활 + 랩실 > PySide' 카테고리의 다른 글
| PySide(1) - Signal & Slot, Qt Designer (0) | 2026.05.01 |
|---|