지식공유자 소개 ✒️
근무경력
현: Embedded 분야 Senior software developer
LG전자, VS사업부 IVI선행플랫폼/모듈개발
SW마에스트로, SW 멘토
강의경력
삼성전자, Qt & QML 강의
LG전자, Qt & QML 분야 사내 강사
한컴아카데미 Qt 강의 출강
다수의 IT기업 Qt 강의 출강
저서
Qt 프로그래밍
Qt Quick 프로그래밍
Qt5 프로그래밍 가이드
MeeGo 프로그래밍 완벽 가이드
Qt 실전 프로그래밍
SW커뮤니티 운영
Qt 개발자 커뮤니티 운영자 ( www.qt-dev.com )
안녕하세요. 김대진 입니다.
Qt/QML 을 이용해 SW개발하는 경우, 궁금하시거나 멘토링이 필요하시면 언제든 연락주세요. ^^
강의
로드맵
전체 1수강평
- [Level 1] Qt를 이용한 Python 프로그래밍: 입문편
- [초급] QML 프로그래밍 2편
- [입문] Qt 6 프로그래밍 1편
게시글
질문&답변
데코레이터 @Slot을 꼭 써줘야 하는 건가요?
안녕하세요. @Slot을 사용하면 다음과 같은 최적화 및 안정성 이점이 있습니다.(1) 성능 최적화@Slot을 사용하면 C++ 쪽에서 직접 슬롯을 등록하여 Python의 동적 바인딩보다 빠르게 호출할 수 있습니다.Qt는 내부적으로 Python 함수를 일반적인 동적 호출로 처리하지만, @Slot을 사용하면 C++의 정적 슬롯처럼 동작하여 속도가 향상됩니다. (2) 메모리 관리 최적화Qt는 QObject과 관련된 시그널-슬롯 연결을 자동으로 관리합니다.@Slot을 사용하면 Python의 가비지 컬렉터(GC)에서 해당 슬롯을 적절히 관리할 수 있어 메모리 누수를 방지하는 데 도움이 됩니다. (3) 명시적 타입 지정 가능@Slot을 사용하면 파라미터 타입을 명시할 수 있습니다. 이렇게 하면 Qt에서 타입 변환을 자동으로 처리해 주기 때문에 오류를 줄일 수 있습니다.from PySide6.QtCore import QObject, Signal, Slot class MyObject(QObject): my_signal = Signal(int) @Slot(int) def my_slot(self, value): # int 타입 지정 print(f"Received value: {value}") obj = MyObject() obj.my_signal.connect(obj.my_slot) obj.my_signal.emit(42) # "Received value: 42" 출력됨@Slot(int)을 사용하지 않으면, value에 대한 타입이 암시적이므로 의도치 않은 데이터 타입 문제(예: str이 들어옴)가 발생할 수도 있습니다. (4) 다중 슬롯(Overloaded Slots) 지원같은 이름의 슬롯을 여러 타입으로 오버로딩할 수 있습니다.class MyObject(QObject): @Slot(int) def my_slot(self, value): print(f"Integer slot called with {value}") @Slot(str) def my_slot(self, value): print(f"String slot called with {value}") obj = MyObject() obj.my_slot(10) # "Integer slot called with 10" obj.my_slot("Qt") # "String slot called with Qt"이처럼 @Slot을 사용하면 같은 이름의 함수를 다른 타입으로 오버로딩할 수 있습니다.혹시 더 궁금한게 있으면 언제 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 25
질문&답변
그래프를 그리려면 어떤 모듈을 사용하는 것이 좋을까요?
안녕하세요. Son님,성능 적인 측면에서 QPainter 와 QOpenGLWidget 모두 GPU를 지원하므로 성능적인 장정은 모두 동일합니다. 하지만 그래프에 3D를 사용해야 한다면 QOpenGLWidget 을 사용하는 것을 추천드립니다. 복잡한 Chart 를 그려야 하는 경우이 경우에는 보통 Qt Graphics View Framework를 사용합니다. 또한 Qt Graphics View Framework는 확대/축소 또한 지원합니다. QML에서는 QPainter를 직접할 수 없습니다. 하지만 QQuickPaintedItem 클래스를 이용하면 QPainter를 동일하게 사용할 수 있습니다. 이 클래스의 사용방법은 "[초급] QML프로그래밍 2편" 에서 "섹션 9. QQuickPaintedItem 클래스를 이용해 QML Type 구현" 을 참조하면 어떻게 사용하는지 방법을 학습하실 수 있습니다. 혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 0
- 2
- 34
질문&답변
TableModel(QAbstractTableModel) 에서 질문입니다.
안녕하세요. TaeJoon Park 님,PySide6의 Model/View 프레임워크에서는 QTableView가 QAbstractTableModel의 데이터를 표시하기 위해 자동으로 해당 함수들을 호출합니다. 따라서 Widget 클래스에서 data, rowCount, columnCount, headerData 등을 명시적으로 호출하지 않아도, QTableView가 모델을 설정하는 과정에서 이 함수들을 내부적으로 호출합니다.실제 호출 시점 분석1. rowCount(None), columnCount(None) 호출QTableView가 QAbstractTableModel의 데이터를 불러올 때 가장 먼저 호출됩니다.rowCount()는 행의 개수를 반환하며, columnCount()는 열의 개수를 반환합니다.즉, QTableView가 데이터의 크기를 알아야 테이블을 렌더링할 수 있기 때문에 가장 먼저 실행됩니다.2. headerData(section, orientation, role) 호출테이블의 헤더를 표시할 때 호출됩니다.orientation == Qt.Horizontal인 경우 컬럼 헤더를 가져오고, orientation == Qt.Vertical인 경우 행 헤더를 가져옵니다.3. data(index, role) 호출각 셀에 데이터를 표시할 때 호출됩니다.index.row()와 index.column() 값을 기반으로 해당 데이터를 self._data에서 가져옵니다.디버깅을 위한 print문 추가함수들이 언제 호출되는지 확인하려면 print()를 추가해서 실행해보면 호출 순서를 확인할 수 있습니다.class TableModel(QAbstractTableModel): def __init__(self, data): super(TableModel, self).__init__() self._data = data self._headerColumn = [] self._headerRow = [] def data(self, index, role): if role == Qt.DisplayRole: print(f"data() called: row={index.row()}, column={index.column()}") return self._data[index.row()][index.column()] def rowCount(self, index): print("rowCount() called") return len(self._data) def columnCount(self, index): print("columnCount() called") return len(self._data[0]) def setTitleColumn(self, list): self._headerColumn = list def setTitleRow(self, list): self._headerRow = list def headerData(self, section, orientation, role): if role == Qt.DisplayRole: if orientation == Qt.Horizontal: print(f"headerData() called for column={section}") return self._headerColumn[section] if orientation == Qt.Vertical: print(f"headerData() called for row={section}") return self._headerRow[section]이 코드를 실행하면 콘솔에서 함수 호출 순서를 확인할 수 있습니다.rowCount(), columnCount() → headerData() → data() 순으로 호출됩니다.QTableView가 setModel()을 호출하는 순간 TableModel의 함수들이 자동으로 실행됩니다.따라서 Widget 클래스에서 직접 호출하지 않아도 QTableView 내부에서 필요한 정보를 얻기 위해 자동으로 호출됩니다.혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 50
질문&답변
self가 있는 거와 없는 버튼
안녕하세요. TaeJoon Park 님, hBtn1 = QPushButton("One")이 경우, hBtn1은 지역 변수입니다. 즉, 이 변수를 선언한 함수나 메서드가 끝나면 더 이상 참조할 수 없습니다.이 버튼은 특정 위젯(부모)에 자동으로 추가되지 않습니다.부모 위젯을 설정하지 않으면, 이 버튼은 독립적인 위젯이 되며, 따로 layout.addWidget(hBtn1) 같은 코드로 추가해야 합니다.함수가 종료되면 hBtn1이 소멸될 가능성이 있습니다.self.pbtShowDialog = QPushButton(self) 여기서 self는 **현재 클래스의 인스턴스(예: QMainWindow 또는 QWidget)**를 의미합니다.이 버튼은 self(즉, 부모 위젯)의 자식 위젯이 됩니다.부모가 삭제되면, 자식 위젯도 자동으로 삭제됩니다.self.pbtShowDialog라는 인스턴스 변수가 되므로, 다른 메서드에서도 접근할 수 있습니다.self.pbtShowDialog.setText("Click Me") 혹시 더 궁금한게 있으면 언제든 질문해 주세요. 감사합니다. 김대진 드림.
- 1
- 2
- 32
질문&답변
Qt creator 환경문제
안녕하세요! 안녕하세요. 이 강의에 최소 버전은 6.x 버전 입니다. 따라서 Qt 6.x.x 버전을 사용하시는 것을 추천합니다. Qt 5 버전은 다소 호환이 안될 수 도 있습니다. 그리고 해당 문제는 Qt Creator가 컴파일러(g++)와 qmake를 제대로 찾지 못하거나 환경 설정이 잘못되어 발생하는 경우가 많습니다. 아래에 문제를 해결하기 위한 단계별 가이드 입니다.1. Qt Creator에서 컴파일러 설정 확인Qt Creator를 실행합니다.Tools -> Options -> Kits 메뉴로 이동합니다.Kits 탭에서 사용 중인 Kit를 확인하고, 아래 사항을 점검하세요.Compiler: g++ 컴파일러가 올바르게 설정되어 있는지 확인합니다. 없다면, 아래의 방법으로 추가하세요.Debugger: 디버거가 설정되어 있는지 확인합니다.Qt Version: 사용하려는 Qt 버전이 제대로 등록되었는지 확인합니다.2. g++ 컴파일러 경로 확인g++ 컴파일러가 설치되어 있고, Qt Creator에서 이를 인식하고 있는지 확인해야 합니다.g++ 설치 경로 확인:Qt 설치 디렉터리 안의 mingw 폴더에 g++.exe 파일이 있는지 확인합니다.기본 경로: C:\Qt\Qt5.11.3\Tools\mingw53_32\bin\g++.exe컴파일러를 수동으로 추가:Tools -> Options -> Compilers 탭으로 이동합니다.**Add -> MinGW**를 선택하고, g++의 경로를 지정합니다.3. Qt 버전 설정 확인Qt Creator가 올바른 Qt 버전을 찾지 못하면 qmake 에러가 발생할 수 있습니다.**Tools -> Options -> Qt Versions**로 이동합니다.Qt 버전이 제대로 등록되어 있는지 확인하고, 누락된 경우 수동으로 추가합니다:Add를 눌러 qmake 경로를 지정합니다.예: C:\Qt\Qt5.11.3\5.11.3\mingw53_32\bin\qmake.exeKit에서 해당 Qt 버전을 선택했는지 확인합니다.4. 환경 변수 확인Qt Creator가 g++와 qmake를 찾으려면 환경 변수도 제대로 설정되어야 합니다.환경 변수에 PATH 추가:C:\Qt\Qt5.11.3\Tools\mingw53_32\binC:\Qt\Qt5.11.3\5.11.3\mingw53_32\bin시스템 재부팅 후 다시 실행해 보세요.5. 간단한 예제 프로젝트 다시 생성기존 프로젝트가 깨졌을 가능성이 있으니, 새 프로젝트를 생성해서 테스트해 보세요.새 프로젝트 생성:**File -> New File or Project -> Qt Console Application**을 선택합니다.새 프로젝트 생성 후, main.cpp 파일을 아래와 같이 수정합니다:#include int main() { std::cout 복사편집#include int main() { std::cout Build and Run 버튼을 눌러 실행해 보세요.6. 문제가 지속될 경우 로그 확인컴파일 에러 메시지와 로그를 다시 확인해보세요.주요 로그:Compile Output 탭Issues 탭
- 1
- 2
- 366
질문&답변
선호하는 GUI 개발 방법이 있으신가요
안녕하세요. Nole 님,프로젝트가 Desktop(MS Windows, Linux, MacOS)과 같은 PC에서 동작하는 것이라면 복잡한 GUI가 필요하므로 Qt Designer 또는 하드코딩(Qt Designer 를 사용하지 않고 QWidget 을 직접 소스코드로 작성)하는 방식으로 하는 것을 선호합니다. Embedded 와 같이 터치를 사용하거나 화려한 애니메이션 UI를 적용한 Modern한 UI를 사용한다면QML을 선호합니다. 따라서 저는 주로 위와 같이 프로젝트 특성에 따라 QML을 사용할지 그렇지 않은지 선택합니다.혹시더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 63
질문&답변
가장 큰 위젯의 너비와 같은 너비를 차지하는 2열 짜리 컬럼
안녕하세요. monkey-k 777님, QGridLayout에서 위젯들이 같은 너비를 가지면서 윈도우 크기 변경에 따라 크기가 변하지 않도록 설정하려면, QWidget의 setSizePolicy() 메서드를 활용할 수 있습니다. QSizePolicy를 사용하여 위젯의 크기 조정 방식(확장/축소)을 제어할 수 있습니다. 또한, QGridLayout 내에서 가장 넓은 위젯에 맞춰 다른 위젯들의 너비를 맞추려면 QGridLayout의 setColumnStretch() 기능을 사용할 수 있습니다.from PySide6.QtWidgets import QApplication, QWidget, QGridLayout, QPushButton, QSizePolicy app = QApplication([]) window = QWidget() layout = QGridLayout(window) # 위젯 생성 button1 = QPushButton("Button 1") button2 = QPushButton("Button 2") button3 = QPushButton("Button 3") button4 = QPushButton("Button 4") # 위젯의 사이즈 정책을 'Fixed'로 설정하여 크기가 변하지 않도록 설정 button1.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button2.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button3.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) button4.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) # QGridLayout에 위젯 추가 layout.addWidget(button1, 0, 0) layout.addWidget(button2, 0, 1) layout.addWidget(button3, 1, 0) layout.addWidget(button4, 1, 1) # 두 번째 열의 열 크기 비율을 1로 설정 layout.setColumnStretch(0, 1) layout.setColumnStretch(1, 1) window.show() app.exec()여기서 QSizePolicy.Fixed는 위젯의 크기를 고정시켜줍니다. 그리고 setColumnStretch()를 사용해 두 열의 크기를 동일하게 맞출 수 있습니다. 이 방법을 적용하면, 윈도우 크기에 상관없이 위젯들의 너비가 일정하게 유지됩니다. 필요에 따라 위젯들의 크기나 레이아웃을 더 조정할 수 있습니다.혹시 더 궁금한게 있으면 언제든 질문해주세요.감사합니다. 김대진드림.
- 1
- 2
- 74
질문&답변
Qt6 우분투에서 컴파일 안됨.
설치가 안되는 경우는 설치 시 설치 항목(Kit)을 선택하지 않은 경우가 있을 수 있을 것 같습니다.혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 66
질문&답변
QML로 만든 파일도 똑같이 설치판 제작하면 되나요?
네 그렇게 하시면 됩니다. ^^
- 0
- 2
- 69
질문&답변
exe 배포 시 .ui 파일 처리하는 권장하는 방법이 있나요?
안녕하세요. PySide6 프로젝트에서 .ui 파일을 배포하는 방식에 따라 두 가지 접근 방식을 비교해 보겠습니다.1. uic를 통해 .ui 파일을 .py로 변환 후 포함하여 배포장점단일 코드 파일: .ui 파일이 .py 파일로 변환되기 때문에 별도의 .ui 파일을 관리할 필요가 없습니다.성능: 런타임에 .ui 파일을 읽고 파싱하는 작업이 생략되므로 약간의 성능 이점이 있습니다.코드 일관성: UI 구성 요소를 Python 코드로 변환하면 IDE의 코드 탐색 및 자동 완성 기능을 사용할 수 있어 개발 편의성이 증가합니다.단점변경 시 번거로움: .ui 파일을 수정할 경우, 다시 uic를 사용해 .py로 변환해야 하며, 이는 반복 작업을 초래할 수 있습니다.가독성 저하: 변환된 .py 파일은 사람이 읽기 어렵고 유지보수 시 불편할 수 있습니다.소스 코드 확장성 제한: .ui 파일을 Python 코드로 변환하면 디자인이 코드로 하드코딩되어, 나중에 .ui 파일 기반으로 디자인을 변경하려면 추가 작업이 필요합니다.2. PyInstaller의 --add-data 옵션을 사용해 .ui 파일을 포함하여 배포장점디자인 파일 유지: .ui 파일을 그대로 포함하므로, UI 수정이 필요할 경우 .ui 파일만 수정하면 됩니다. 이로 인해 디자인 변경이 빠르고 편리합니다.분리된 코드와 디자인: UI 파일과 Python 코드가 명확히 분리되므로, 유지보수성과 협업 효율성이 높아집니다.변환 과정 생략: .ui 파일을 변환하지 않아도 되므로 반복 작업이 줄어듭니다.단점런타임 파일 로드: .ui 파일은 런타임에 읽고 파싱해야 하므로, 배포 후 처음 UI를 로드할 때 약간의 지연이 있을 수 있습니다.추가 파일 관리: .ui 파일을 포함하는 방식이므로 PyInstaller에 포함시키기 위한 경로 설정이나 관리가 필요합니다.권장 방법상황에 따른 선택프로젝트가 단순하고 변경 가능성이 적은 경우:uic를 통해 .ui 파일을 .py로 변환하여 사용하는 것이 적합합니다.이유: 실행 속도와 단일 파일 관리 측면에서 유리하며, 초기 개발 후 큰 변경이 없는 경우 효율적입니다.프로젝트가 복잡하고 UI 변경이 자주 발생하거나 디자이너와 협업이 필요한 경우:PyInstaller의 --add-data 옵션을 사용하여 .ui 파일을 포함하는 방식을 추천합니다.이유: 디자인과 로직이 분리되어 유지보수성과 확장성이 뛰어나며, 수정이 발생해도 빠르게 대응할 수 있습니다.개인적인 추천대부분의 경우, --add-data 옵션을 활용한 .ui 파일 배포 방식을 권장합니다. 이유는 다음과 같습니다:Qt Designer로 UI를 변경할 수 있는 자유를 유지할 수 있습니다.유지보수가 용이하며, 파일 구조가 명확합니다.UI를 .ui 파일로 유지하면 협업 시 디자이너와의 역할 분담이 쉬워집니다.다만, 특정 상황(예: 단순 도구 제작, 변경 가능성 없음 등)에서는 변환 방식을 고려해볼 수도 있습니다. 장기적인 확장성과 유지보수성을 중요시한다면 .ui 파일 배포 방식을 선택하세요.
- 1
- 1
- 75