9.11 문자 포멧
728x90

1. 목표
더보기
- 메뉴 Format 의 Bold, Italic, Underline 액션을 이용해서
선택한 문자 또는 커서 위치 이후에 입력되는 문자에
굵게, 기울임, 밑줄 스타일을 적용하는 기능을 구현한다. - QTextEdit 전체에 폰트를 바꾸는 방식이 아니라
QTextCharFormat 과 QFont 를 사용하여
선택된 문자 영역에만 서식을 적용하는 방법을 이해한다. - 현재 상태를 토글 형태로 구현해서
Bold 버튼을 한 번 누르면 굵게, 한 번 더 누르면 원래 두께로 돌아가는
사용성 좋은 편집 기능을 구현한다. - Qt Designer 에서 만든 QAction(actionBold, actionItalic, actionUnderline)을
메인 윈도우 슬롯 메서드와 연결하는 패턴을 익힌다. - 문서 내용은 QTextEdit 내부의 QTextDocument 안에서만 다룹니다
2. 전체 로직
더보기
# mainwindow.py
from PySide6.QtGui import QFont, QTextCharFormat
. . .
class MainWindow(QMainWindow):
def __init__(self, parent=None):
. . .
self.ui.actionBold.triggered.connect(self.text_bold)
self.ui.actionItalic.triggered.connect(self.text_italic)
self.ui.actionUnderline.triggered.connect(self.text_underline)
. . .
def _merge_format_on_selection(self, fmt: QTextCharFormat):
cursor = self.editor.textCursor()
if cursor.hasSelection():
cursor.mergeCharFormat(fmt)
else:
self.editor.mergeCurrentCharFormat(fmt)
def text_bold(self):
cursor = self.editor.textCursor()
fmt = cursor.charFormat()
is_bold = fmt.fontWeight() > QFont.Normal
fmt.setFontWeight(QFont.Normal if is_bold else QFont.Bold)
self._merge_format_on_selection(fmt)
def text_italic(self):
cursor = self.editor.textCursor()
fmt = cursor.charFormat()
current_italic = fmt.fontItalic()
fmt.setFontItalic(not current_italic)
self._merge_format_on_selection(fmt)
def text_underline(self):
cursor = self.editor.textCursor()
fmt = cursor.charFormat()
current_underline = fmt.fontUnderline()
fmt.setFontUnderline(not current_underline)
self._merge_format_on_selection(fmt)
# main.py
import sys
from PySide6.QtWidgets import QApplication
from mainwindow import MainWindow
if __name__ == "__main__":
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec())
3. 필요한 import + 주석 설명
더보기
from PySide6.QtGui import QFont, QTextCharFormat
# QFont
# 글꼴 이름, 크기, 굵기, 기울임 등 폰트 정보를 표현하는 클래스
# 여기서는 굵게 여부를 확인하고, 굵게 또는 일반 두께로 설정할 때 사용한다
#
# QTextCharFormat
# 개별 문자에 대한 서식 정보를 표현하는 클래스
# 굵게, 기울임, 밑줄, 글자색 등 스타일을 담고
# 선택된 텍스트에 병합 적용할 수 있다
4. 메뉴 액션과 슬롯 연결하기
더보기
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
# 중앙 편집기 QTextEdit 에 자주 접근하므로 별칭을 만들어 둔다
self.editor = self.ui.textEdit
# 9.10 문자 스타일 편집 기능 구현
# Format 메뉴의 Bold, Italic, Underline 액션을
# MainWindow 의 슬롯 메서드에 연결한다
# Bold 메뉴와 툴바 아이콘을 text_bold 함수에 연결
self.ui.actionBold.triggered.connect(self.text_bold)
# Italic 메뉴와 툴바 아이콘을 text_italic 함수에 연결
self.ui.actionItalic.triggered.connect(self.text_italic)
# Underline 메뉴와 툴바 아이콘을 text_underline 함수에 연결
self.ui.actionUnderline.triggered.connect(self.text_underline)
- 메뉴 Format 에서 Bold, Italic, Underline 을 클릭했을 때
- 툴바의 굵게/기울임/밑줄 버튼을 눌렀을 때
- 단축키 Ctrl+B, Ctrl+I, Ctrl+E 를 눌렀을 때
5. 문자 포멧 기능 구현 함수
더보기
5-1. 선택 영역에 서식 병합을 도와주는 헬퍼 메서드
def _merge_format_on_selection(self, fmt: QTextCharFormat):
# 현재 QTextEdit 의 텍스트 커서를 가져온다
cursor = self.editor.textCursor()
# 선택된 텍스트가 있을 경우
if cursor.hasSelection():
# 선택된 문자들에 문자 서식을 병합 적용한다
# 이미 존재하는 서식 위에 변경된 부분만 덮어쓴다
cursor.mergeCharFormat(fmt)
else:
# 선택 영역이 없으면
# 이후에 입력될 텍스트의 기본 문자 서식을 변경한다
self.editor.mergeCurrentCharFormat(fmt)
이 함수 덕분에
- 선택이 있을 때는 그 부분에만 스타일을 적용하고
- 선택이 없을 때는 커서 이후에 입력되는 문자에 스타일을 적용
5-2. 굵게 토글 기능
def text_bold(self):
# 현재 텍스트 커서를 가져온다
cursor = self.editor.textCursor()
# 현재 커서 위치의 문자 서식을 가져온다
fmt = cursor.charFormat()
# 현재 글자가 굵은 상태인지 확인한다
# QFont.Normal 보다 크면 굵게라고 판단할 수 있다
is_bold = fmt.fontWeight() > QFont.Normal
# 이미 굵게라면 일반 두께로,
# 일반 두께라면 굵게로 토글한다
fmt.setFontWeight(QFont.Normal if is_bold else QFont.Bold)
# 선택된 영역 또는 이후 입력될 문자에 서식을 병합 적용한다
self._merge_format_on_selection(fmt)
- 버튼을 누를 때마다 현재 상태를 읽어서 반대로 바꾸는 토글 방식이다.
- 이렇게 하면 사용자가 Bold 버튼을 한 번 더 눌러 굵게 상태를 해제할 수 있다.
5-3. 기울임 토글 기능
def text_italic(self):
# 현재 텍스트 커서를 가져온다
cursor = self.editor.textCursor()
# 현재 문자 서식을 가져온다
fmt = cursor.charFormat()
# 현재 기울임 상태를 읽어 온다
current_italic = fmt.fontItalic()
# True 는 False 로, False 는 True 로 반대로 토글한다
fmt.setFontItalic(not current_italic)
# 선택 영역 또는 이후 입력될 문자에 서식을 병합 적용한다
self._merge_format_on_selection(fmt)
- 문자 서식 객체에서 기울임 여부를 읽어오고
- not 연산으로 반전시키는 전형적인 토글 패턴을 사용한다.
5-4. 밑줄 토글 기능
def text_underline(self):
# 현재 텍스트 커서를 가져온다
cursor = self.editor.textCursor()
# 현재 문자 서식을 가져온다
fmt = cursor.charFormat()
# 현재 밑줄 상태를 읽어 온다
current_underline = fmt.fontUnderline()
# 밑줄 상태를 반대로 토글한다
fmt.setFontUnderline(not current_underline)
# 선택 영역 또는 이후 입력될 문자에 서식을 병합 적용한다
self._merge_format_on_selection(fmt)
- 기울임과 동일한 패턴으로 밑줄 여부를 토글한다.
- QTextCharFormat 이 밑줄, 취소선 등 다양한 효과를 모두 담당한다는 점을 보여준다.
6. 실행 테스트
7. 학습 주요 포인트
더보기
QTextEdit 전체 폰트 변경과 문자 서식 변경의 차이
- setFont 를 사용하면 편집기 전체 기본 폰트가 변경된다.
- QTextCharFormat 과 mergeCharFormat 을 사용하면 선택된 문자에만 서식을 적용할 수 있다.
- 워드 프로세서와 같은 리치 텍스트 편집 기능을 구현할 때는 문자 단위 서식이 필수적이다.
토글 방식으로 상태를 제어하는 패턴
- 현재 상태를 읽어서 반대로 설정하는 토글 패턴은
Bold, Italic, Underline 이 모두 동일한 구조를 가진다. - 학생들에게 상태 기반 UI 구현의 전형적인 예제로 설명하기 좋다.
커서와 선택 영역의 역할
- cursor.hasSelection 을 통해
선택이 있는지 없는지에 따라 동작을 다르게 할 수 있다. - 선택이 있으면 그 영역에만 스타일을 적용하고
없으면 이후 입력될 문자에 스타일을 적용하는 UX는 대부분의 텍스트 편집기와 동일한 동작이다.
QAction 과 슬롯 연결 구조
- ui_form.py 에서 QAction 들이 이미 생성되어 있고
메인 코드에서는 그 액션의 triggered 시그널만 슬롯 메서드에 연결하면 된다. - 이 덕분에 메뉴, 툴바, 단축키가 모두 같은 기능을 공유하게 된다.
파일 입출력과의 분리
- 이 단계는 어디까지나 문서 내용의 스타일 편집만 다루고 디스크 파일 저장과는 분리되어 있다.
- 파일 저장과 읽기는 다른 단계에서 QFile, QTextStream 을 사용하는 것으로 묶고
스타일 편집은 메모리 상의 QTextDocument 만 다루는 구조가 설계 측면에서 깔끔하다.
단계별 완성 파일
