지식공유자 소개 ✒️
근무경력
현: Embedded 분야 SW Team leader
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수강평
- [입문] Qt 6 프로그래밍 2편
게시글
질문&답변
달력 31일까지 나오지 않음.
안녕하세요. 송인섭님, 소스코드를 설명하는데 있어 Calendar 예제를 한번에 설명하면 이해하는데 어려울것 같아 5단계로 나누어 설명했어요. 예제를 계속 듣다보면 5개로 소스코드가 되어 있는것을 알 수 있습니다. 차근차근 듣다보면 완성해 나가면서 Calendar 기능이 구현되는 것을 알 수 있습니다. 혹시 더 궁금한게 있으면 언제든 질문해 주세요. 감사합니다. 김대진 드림.
- 1
- 2
- 15
질문&답변
parent.width 관련 질문.
안녕하세요. 송인섭님,좋은 질문입니다! QML에서 Window를 루트로 선언하고 그 안에 Rectangle을 선언할 때, parent.width를 사용해도 문법적으로는 문제 없습니다. 다만 실제로는 parent가 무엇을 가리키는지에 따라 달라지며, 다음과 같은 이유들 때문에 종종 parent.width 대신 Window 혹은 root의 id를 사용하는 경우가 많습니다.Window { width: 400 height: 112 Rectangle { width: parent.width // 가능 height: 100 } }이 경우 Rectangle의 parent는 Window가 맞으므로 parent.width == 400이 됩니다. 정상 작동합니다.하지만 Rectangle이 중첩된 구조일 경우, 예를 들어 중간에 Item이 끼어 있다면 parent는 더 이상 Window가 아닐 수 있습니다. 개발자가 보기 쉽게 하기 위해 다음과 같이 명확하게 하는 경우가 많습니다:Window { id: root width: 400 height: 112 Rectangle { width: root.width height: 100 } } 혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 22
질문&답변
custom Widget 강의 에서 알려주신 promoted widgets 질문 드립니다.
안녕하세요. 공부중님, (문제 요약)Promote 버튼이 비활성화되어 있다.(원인)-> 이는 위젯을 promotion 대상으로 지정하지 않았기 때문에 발생합니다.(해결 방법)1. .ui 파일에서 Qt Designer를 엽니다.2. 위젯을 하나 추가합니다. (예: QWidget, QPushButton 등, 커스텀 클래스가 상속한 베이스 위젯)3. 해당 위젯을 선택한 상태에서 오른쪽 마우스 클릭 → "Promote to..." 선택4. Promoted class name과 Header file을 입력 후 Add → Promote 버튼이 이제 활성화됩니다.즉, promotion 목록에 추가만으로는 Promote 버튼이 활성화되지 않으며, UI 상에서 실제로 위젯을 선택하고 "Promote to..."를 눌러야 합니다.---------추가 질문: "Widget Box"에 커스텀 위젯을 직접 등록할 수 있나요?가능하지만 기본 Qt Designer만으로는 안 되고, 플러그인 개발이 필요합니다. 혹시더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진드림.
- 1
- 2
- 29
질문&답변
QT와 QT Designer에 대한 질문 사항
안녕하세요! 질문 주신 두 가지에 대해 자세히 설명드릴게요.1. 왜 Qt Designer 없이 직접 Python 코드로 UI를 작성할까요?Qt Designer는 GUI를 직관적으로 구성할 수 있어 매우 편리합니다. 하지만 강의에서 Python 코드로 직접 UI를 구현한 이유는 다음과 같은 장점 때문일 수 있습니다: 더 유연한 제어 Qt Designer로 만든 .ui 파일은 구조가 고정되어 있어 동적으로 UI를 바꾸기가 어렵습니다. 코드로 직접 작성하면 복잡한 UI 로직이나 동적 생성이 쉬워집니다.디버깅 및 유지보수 편의UI가 코드에 직접 들어있으면 디버깅과 버전 관리(Git 등)에서 유리할 수 있습니다. .ui는 XML 기반이라 diff 보기가 어렵습니다.의존성 제거.ui 파일을 사용하려면 pyuic6로 변환하거나 QUiLoader 등으로 로딩해야 하므로 추가적인 빌드 작업이 필요합니다. 코드 방식은 이 과정을 생략합니다. 정리: Qt Designer는 빠르고 간편하지만, 코드 방식은 더 강력하고 유연합니다. 실무에서는 두 방법을 혼용하는 경우가 많습니다. 2. Qt Designer를 더 깊게 배우고 싶습니다. 어떤 자료가 좋을까요?Qt Designer Manual (공식) 기능별 설명이 정리되어 있습니다.https://doc.qt.io/qt-5/qtdesigner-manual.html위의 자료를 둘러보시면 도움이 될것 같습니다. 무엇보다도 깊게 배우기를 원하시면 많이 써보는것이 자료를 보고 공부하는 것보다 더 많은 것을 배울 수 있을것 같습니다. 더 궁금한게 있으면 언제든 질문해 주세요. 감사합니다. 김대진 드림.
- 1
- 2
- 49
질문&답변
mutex, incNumber는 global 안붙여도 되는건가요?
global 없이도 잘 동작하는 경우가 있다?네, 이건 두 가지 이유 중 하나 때문입니다:① 이미 global이 코드에 명시되어 있다→ 예제 소스코드상에 global numUsed가 Producer와 Consumer 둘 다에 들어 있습니다.global numUsed위의 코드가 이미 선언되어 있음그래서 당연히 에러 없이 잘 동작합니다.만약 이걸 빼면 어떻게 될까요?② global을 빼면 실제로 에러가 발생한다예를 들어 아래처럼 Producer에서 global numUsed를 뺐다고 가정하면:class Producer(QThread):def run(self):for i in range(10):time.sleep(1)mutex.lock()numUsed += 1 # ⚠ 여기가 에러 발생incNumber.wakeAll()mutex.unlock()실행하면 아래와 같은 에러가 뜹니다:UnboundLocalError: cannot access local variable 'numUsed' where it is not associated with a value즉, 정상적인 Python 동작에서는 반드시 global numUsed가 필요합니다. 혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진 드림.
- 1
- 2
- 53
질문&답변
Qt Resource를 사용하는 예제 구현 10:15 구간 질의
안녕하세요. One님Visual Studio Code 에서 Extention 에서 "Better Align" 이라고 있는데 이걸 사용해서 맞추었습니다.(사진) 혹시 더 궁금한게 있으면 언제든 질문해 주세요.감사합니다. 김대진드림.
- 1
- 2
- 61
질문&답변
데코레이터 @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
- 71
질문&답변
그래프를 그리려면 어떤 모듈을 사용하는 것이 좋을까요?
안녕하세요. 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
- 79
질문&답변
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
- 134
질문&답변
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
- 72