QT 6 Programing [Chapter 13. Stream - Chapter 16. Model and View]
13. Stream
여기에서 Stream 이란 데이터를 특정 변수에 Write/Read 를 쉽게 하기 위한 방법을 말한다.
QDataStream 은 Binary 데이터를 Write/Read 하는데 사용하며 QTextStream 은 Text 기반의 데이터를 Write/Read 하는데 사용된다.
[QDataStream 상에 데이터를 Write/Read 하는 예제]
encoding( ) 함수에서는 quint32, quint8, quint32 타입의 데이터를 QDataStream을 이용해 QByteArray 에 저장할 것이다. 각 변수에는 123, 124, 125가 저장할 것이다.
#include <QCoreApplication>
#include <QIODevice>
#include <QDataStream>
#include <QDebug>
QByteArray encoding()
{
quint32 value1 = 123;
quint8 value2 = 124;
quint32 value3 = 125;
QByteArray outData;
QDataStream outStream(&outData, QIODevice::WriteOnly);
outStream << value1;
outStream << value2;
outStream << value3;
qDebug() << "outData size : " << outData.size() << " Bytes";
return outData;
}
void decoding(QByteArray _data)
{
QByteArray inData = _data;
quint32 inValue1 = 0;
quint8 inValue2 = 0;
quint32 inValue3 = 0;
QDataStream inStream(&inData, QIODevice::ReadOnly);
inStream >> inValue1; // 123
inStream >> inValue2; // 124
inStream >> inValue3; // 125
qDebug("[First : %d] [Second : %d] [Third : %d]"
, inValue1, inValue2, inValue3 );
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray encData = encoding();
decoding(encData);
return a.exec();
}
[QTextStream 상에 데이터를 Write/Read 하는 예제]
writeData( ) 함수에서는 QByteArray 에 저장된 값을 QTextStream 을 이용해 Write 할 것 이다.
readData( ) 함수에서는 반대로 QByteArray 에 저장된 값을 Read 할 것이다.
#include <QCoreApplication>
#include <QIODevice>
#include <QTextStream>
#include <QDebug>
QByteArray writeData(QByteArray _data)
{
QByteArray temp = _data;
QByteArray outData;
QTextStream outStream(&outData, QIODevice::WriteOnly);
for(qsizetype i = 0 ; i < temp.size() ; i++) {
outStream << temp.at(i);
}
outStream.flush();
return outData;
}
void readData(QByteArray _data)
{
QTextStream outStream(&_data, QIODevice::ReadOnly);
QByteArray inData;
for(qsizetype i = 0 ; i < _data.size() ; i++)
{
char data;
outStream >> data;
inData.append(data);
}
qDebug("READ DATA : [%s]", inData.data());
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QByteArray retData = writeData("Hello world."); // 12 Bytes
qDebug() << "WRITE DATA size : " << retData.size() << " Bytes";
readData(retData);
return a.exec();
}
=> writeData 함수에서는 첫 번째 인자로 “Hello world” 를 인자로 넘겨 줄 것이다. 이 문자열은 QByteArray 에 저장된다. 저장 된 이 데이터를 QTextStream 을 이용해QByteArray 에 저장한다. 그리고 readData( ) 함수에는 “Hello world.” 가 저장되어 있는 QByteArray 를 QTextStream 을 이용해 데이터를 읽어 올 것이다. 따라서 readData( ) 함수의 마지막 라인에서 “Hello world”를 출력할 것이다.
15. Qt Property
Qt에서 제공하는 Property System 은 C++에서 제공하는 Property System 과 비슷하다. Property는 객체에서 값을 설정하고 가져오는 경우에 사용된다.
[person.h]
#ifndef PERSON_H
#define PERSON_H
#include <QObject>
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER m_name READ getName WRITE setName
NOTIFY nameChanged)
// getName( ) 과 setName( ) 멤버 함수를 Q_PROPERTY 매크로에 등록하였다.
public:
explicit Person(QObject *parent = nullptr);
QString getName() const
{
return m_name;
}
void setName(const QString &n)
{
m_name = n;
emit nameChanged(n);
}
private:
QString m_name;
signals:
void nameChanged(const QString &n);
public slots:
};
#endif // PERSON_H
[widget.h]
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "person.h"
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
public slots:
void buttonPressed();
void nameChanged(const QString &n);
private:
Ui::Widget *ui;
Person *goodman;
};
#endif // WIDGET_H
[person.cpp]
#include "person.h"
Person::Person(QObject *parent) : QObject(parent)
{
}
[widget.cpp]
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include "person.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect(ui->pushButton, &QPushButton::pressed,
this, &Widget::buttonPressed);
goodman = new Person();
connect(goodman, &Person::nameChanged,
this, &Widget::nameChanged);
}
void Widget::buttonPressed()
{
QString name = ui->leName->text();
goodman->setProperty("name", name);
}
void Widget::nameChanged(const QString &n)
{
qDebug() << Q_FUNC_INFO << "Name Changed : " << n;
QVariant myName = goodman->property("name");
qDebug() << "My name is " << myName.toString();
}
// getName( ) 와 setName( ) 멤버 함수를 접근해 name 변수 값을 얻어오거나 설정할 수 있지만
// Q_PROPERTY 매크로를 사용하면 setProperty( ) 와 property( ) 를 사용해 값을 얻어오거나 설정할 수 있다.
Widget::~Widget()
{
delete ui;
}
[main.cpp]
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
[QPROPERTY 다양한 옵션]
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction |
WRITE setFunction)] )
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
=> MEMBER 키워드는 READ 키워드로부터 읽어 들일 값을 지정할 수 있다.
예를 들어 위 의 예제 소스코드에서 private 에서 선언한 m_name 변수를 다음과 같이 지정할 수 있다.
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER m_name READ getName WRITE setName)
...
Q_PROPERTY 매크로가 제공하는 키워드 중 NOTIFY 키워드는 시그널 지정할 수 있다.
class Person : public QObject
{
Q_OBJECT
Q_PROPERTY(QString name MEMBER m_name READ getName WRITE setName
NOTIFY nameChanged)
public:
explicit Person(QObject *parent = nullptr);
QString getName() const {
return m_name;
}
void setName(const QString &n)
{
m_name = n;
emit nameChanged(n);
}
private:
QString m_name;
signals:
void nameChanged(const QString &n);
...
[Change] 버튼을 클릭하면 Person클래스의 setName( ) 멤버 함수를 QObject 클래스에서 제공하는 setProperty( ) 멤버 함
수를 이용해 값을 변경 한다.
16. Model and View
** QListWidget 은 QListView와 UI가 동일하다. 하지만 QListWidget 과 QListView 는 데이터를 삽입/수정/삭제 하는데 차이가 있다.
[QListWidget]
클래스 이름의 마지막에 View 대신, Widget 이라는 단어를 사용한 클래스들은 아래 그림에서 보는 것과 같이 데이터를 직접 삽입/수정/삭제 할 수 있는 멤버 함수를 제공한다.
[QListView]
QListView, QTableView, QTreeView 클래스와 같이 마지막에 View 라는 단어를 사용하는 위젯 클래스들은 각각의 멤버 함수를 사용해 데이터를 삽입/수정/삭제 하지 않고 Model 클래스라는 매개체를 이용해 데이터를 삽입/수정/삭제 할 수 있다.
** 이 방식을 사용할 경우 QListView 를 사용하든지 QTableView 를 사용하든지 동일한 Model을 사용할 수 있다는 장점을 가지고 있다.
기능 | QListWidget | QListView |
데이터 관리 | 자체 저장 | Model/View |
사용 편의성 | 간편 | 복잡 |
기능 | 기본적인 기능 | 다양한 기능 |
성능 | 아이템 수가 적을 때 유리 | 아이템 수가 많을 때 유리 |
Qt 에서 제공하는 Model/View 는 다음 그림에서 보는 것과 같이 Delegate를 이용해 데이터를 핸들링 할 수 있다.
예를 들어 View 위젯 상에 표시된 데이터 항목 중 특정 항목을 마우스로 더블 클릭해 데이터를 수정하기 위해서 이벤트를 발생해야 하는데 Model/View 에서는 이러한 이벤트를 처리 하기 위해 Delegate를 사용할 수 있다.
** QSqlQueryModel 클래스를 이용하면 SQL 문을 직접 쿼리(QUERY) 할 수 있는 멤버 함수를 제공한다.따라서 별도의 데이터베이스 쿼리로 가져온 데이터를 편집 후에 Model을 이용해도 되지만 QSqlQueryModel 클래스를 이용하면 직접 데이터를 삽입할 수 있다. 이외에도 다음 그림에서 보는 것과 같이 다양한 Model 클래스를 제공한다.
QListView 클래스
QString 데이터 타입의 단순한 데이터 리스트를 관리할 있는 기능을 제공한다.
[widget.h]
#ifndef WIDGET_H
#define WIDGET_H
#include <QApplication>
#include <QVBoxLayout>
#include <QSplitter>
#include <QFileSystemModel>
#include <QTreeView>
#include <QListView>
#include <QLabel>
#include <QStringListModel>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
};
#endif // WIDGET_H
[main.cpp]
#include <QtWidgets/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
[widget.cpp]
#include "widget.h" // widget.h 헤더 파일을 포함합니다. 이 파일에는 Widget 클래스의 정의가 들어있습니다.
Widget::Widget(QWidget *parent) // Widget 클래스의 생성자입니다. 부모 위젯을 인자로 받습니다.
: QWidget(parent) // 부모 클래스인 QWidget의 생성자를 호출합니다.
{
resize(600, 300); // 위젯의 크기를 600x300 픽셀로 설정합니다.
QStringList strList; // QStringList는 QString(문자열)을 저장하는 리스트입니다.
strList << "Monday" << "Tuesday" << "Wedneday" // strList에 요일 문자열을 추가합니다.
<< "Thurday" << "Friday";
QAbstractItemModel *model = new QStringListModel(strList); // QStringListModel은 QStringList를 데이터로 사용하는 모델입니다.
// QAbstractItemModel은 Qt의 Model/View 프레임워크에서 모델을 나타내는 추상 클래스입니다.
QListView *view = new QListView(); // QListView는 리스트 형태로 데이터를 표시하는 위젯입니다.
view->setModel(model); // view에 model을 설정합니다. 이제 view는 model의 데이터를 표시합니다.
QModelIndex index = model->index(3, 0); // model에서 3번째 행, 0번째 열에 해당하는 인덱스를 가져옵니다.
QString text = model->data(index, Qt::DisplayRole).toString(); // 해당 인덱스의 데이터를 문자열로 변환합니다. Qt::DisplayRole은 표시할 데이터를 나타냅니다.
QLabel *lbl = new QLabel(""); // QLabel은 텍스트를 표시하는 위젯입니다.
lbl->setText(text); // lbl에 text를 설정합니다. 즉, "Thursday"가 표시됩니다.
QVBoxLayout *lay = new QVBoxLayout(); // QVBoxLayout은 위젯을 수직으로 배치하는 레이아웃입니다.
lay->addWidget(view); // view를 레이아웃에 추가합니다.
lay->addWidget(lbl); // lbl을 레이아웃에 추가합니다.
setLayout(lay); // 위젯의 레이아웃을 lay로 설정합니다.
}
Widget::~Widget() // Widget 클래스의 소멸자입니다.
{
}
QTreeView 와 QListView 클래스를 이용한 예제
파일로부터 데이터를 읽어와 Model 에 저장한 다음 Model 을 View 와 연결 해 파일 시스템을 표시하는 예제이다.
[widget.cpp]
#include "widget.h" // widget.h 헤더 파일을 포함합니다. 이 파일에는 Widget 클래스의 정의가 들어있습니다.
Widget::Widget(QWidget *parent) // Widget 클래스의 생성자입니다. 부모 위젯을 인자로 받습니다.
: QWidget(parent) // 부모 클래스인 QWidget의 생성자를 호출합니다.
{
resize(600, 300); // 위젯의 크기를 600x300 픽셀로 설정합니다.
QSplitter *splitter = new QSplitter(this);
// QSplitter는 위젯을 분할하여 크기를 조절할 수 있도록 하는 위젯입니다.
// Model class
QFileSystemModel *model = new QFileSystemModel;
// QFileSystemModel은 파일 시스템의 파일 및 디렉토리 정보를 제공하는 모델입니다.
model->setRootPath(QDir::currentPath());
// 모델의 루트 경로를 현재 경로로 설정합니다.
// View widget - QTreeView
QTreeView *tree = new QTreeView(splitter);
// QTreeView는 트리 형태로 데이터를 표시하는 위젯입니다. splitter를 부모 위젯으로 설정합니다.
tree->setModel(model);
// tree에 model을 설정합니다. 이제 tree는 파일 시스템을 트리 형태로 표시합니다.
tree->setRootIndex(model->index(QDir::currentPath()));
// tree의 루트 인덱스를 현재 경로로 설정합니다.
// View widget - QListView
QListView *list = new QListView(splitter); // QListView는 리스트 형태로 데이터를 표시하는 위젯입니다. splitter를 부모 위젯으로 설정합니다.
list->setModel(model); // list에 model을 설정합니다. 이제 list는 파일 시스템을 리스트 형태로 표시합니다.
list->setRootIndex(model->index(QDir::currentPath())); // list의 루트 인덱스를 현재 경로로 설정합니다.
QVBoxLayout *layout = new QVBoxLayout(); // QVBoxLayout은 위젯을 수직으로 배치하는 레이아웃입니다.
layout->addWidget(splitter); // splitter를 레이아웃에 추가합니다.
setLayout(layout); // 위젯의 레이아웃을 layout으로 설정합니다.
}
Widget::~Widget() // Widget 클래스의 소멸자입니다.
{
}
좌측은 QTreeView 클래스를 이용해 파일시스템으로부터 가져온 데이터를 표시하였다.
우측의 QListView 위젯은 현재 디렉토리에 존재하는 파일과 디렉토리를 표시하였다.
QTableView 클래스
표 형태의 데이터를 표시하는데 적합한 위젯이다.
[widget.h]
#ifndef WIDGET_H
#define WIDGET_H
#include <QAbstractItemModel>
#include <QStandardItemModel>
#include <QStandardItem>
#include <QVBoxLayout>
#include <QDateTime>
#include <QTableView>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
};
#endif // WIDGET_H
[widget.cpp]
#include "widget.h" // widget.h 헤더 파일을 포함합니다. 이 파일에는 Widget 클래스의 정의가 들어있습니다.
#include <QDate> // QDate 클래스를 사용하기 위해 헤더 파일을 포함합니다.
Widget::Widget(QWidget *parent) // Widget 클래스의 생성자입니다. 부모 위젯을 인자로 받습니다.
: QWidget(parent) // 부모 클래스인 QWidget의 생성자를 호출합니다.
{
QStandardItemModel *model = new QStandardItemModel(0, 3); // QStandardItemModel은 표 형태의 데이터를 표현하는 모델입니다.
// 0행 3열의 모델을 생성합니다.
// 헤더 설정
model->setHeaderData(0, Qt::Horizontal, QObject::tr("Subject")); // 0번째 열의 헤더를 "Subject"로 설정합니다.
model->setHeaderData(1, Qt::Horizontal, QObject::tr("Description")); // 1번째 열의 헤더를 "Description"으로 설정합니다.
model->setHeaderData(2, Qt::Horizontal, QObject::tr("Date")); // 2번째 열의 헤더를 "Date"로 설정합니다.
// 세로 헤더 설정
model->setVerticalHeaderItem(0, new QStandardItem("Col 1")); // 0번째 행의 세로 헤더를 "Col 1"로 설정합니다.
model->setVerticalHeaderItem(1, new QStandardItem("Col 2")); // 1번째 행의 세로 헤더를 "Col 2"로 설정합니다.
// 데이터 설정
model->setData(model->index(0, 0), "Monitor"); // (0, 0) 위치에 "Monitor" 데이터를 설정합니다.
model->setData(model->index(0, 1), "LCD"); // (0, 1) 위치에 "LCD" 데이터를 설정합니다.
model->setData(model->index(0, 2), QDate(2030, 10, 4)); // (0, 2) 위치에 QDate(2030, 10, 4) 데이터를 설정합니다.
model->setData(model->index(1, 0), "CPU"); // (1, 0) 위치에 "CPU" 데이터를 설정합니다.
model->setData(model->index(1, 1), "Samsung"); // (1, 1) 위치에 "Samsung" 데이터를 설정합니다.
model->setData(model->index(1, 2), QDate(2030, 10, 4)); // (1, 2) 위치에 QDate(2030, 10, 4) 데이터를 설정합니다.
QTableView *table = new QTableView(); // QTableView는 표 형태로 데이터를 표시하는 위젯입니다.
table->setModel(model); // table에 model을 설정합니다. 이제 table은 model의 데이터를 표 형태로 표시합니다.
QVBoxLayout *lay = new QVBoxLayout(); // QVBoxLayout은 위젯을 수직으로 배치하는 레이아웃입니다.
lay->addWidget(table); // table을 레이아웃에 추가합니다.
setLayout(lay); // 위젯의 레이아웃을 lay로 설정합니다.
}
Widget::~Widget() // Widget 클래스의 소멸자입니다.
{
}
[main.cpp]
#include <QtWidgets/QApplication>
#include "widget.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
QTableWidget
[checkboxhead.h]
#ifndef CHECKBOXHEADER_H // 헤더 파일 중복 포함 방지
#define CHECKBOXHEADER_H
#include <QHeaderView> // QHeaderView 클래스를 사용하기 위해 헤더 파일을 포함합니다.
#include <QObject> // QObject 클래스를 사용하기 위해 헤더 파일을 포함합니다.
#include <QPainter> // QPainter 클래스를 사용하기 위해 헤더 파일을 포함합니다.
#include <QMouseEvent> // QMouseEvent 클래스를 사용하기 위해 헤더 파일을 포함합니다.
class CheckBoxHeader : public QHeaderView // QHeaderView 클래스를 상속받는 CheckBoxHeader 클래스를 정의합니다.
{
Q_OBJECT // Qt의 메타 오브젝트 시스템을 사용하기 위한 매크로입니다.
public: // public 멤버
CheckBoxHeader(Qt::Orientation orientation, // 생성자: 헤더의 방향(수평 또는 수직)을 지정합니다.
QWidget* parent = nullptr); // 부모 위젯을 지정합니다.
bool isChecked() const { return isChecked_; } // 체크 박스가 체크되었는지 여부를 반환합니다.
void setIsChecked(bool val); // 체크 박스의 체크 상태를 설정합니다.
signals: // 시그널: 다른 객체에 이벤트를 알리기 위한 메커니즘입니다.
void checkBoxClicked(bool state); // 체크 박스가 클릭되었을 때 방출되는 시그널입니다.
protected: // protected 멤버: 파생 클래스에서 접근 가능합니다.
void paintSection(QPainter* painter, // 섹션을 그리는 함수입니다.
const QRect& rect, // 섹션의 사각형 영역입니다.
int logicalIndex) const; // 섹션의 논리적 인덱스입니다.
void mousePressEvent(QMouseEvent* event); // 마우스 클릭 이벤트를 처리하는 함수입니다.
private: // private 멤버: 클래스 내부에서만 접근 가능합니다.
bool isChecked_; // 체크 박스의 체크 상태를 저장하는 변수입니다.
void redrawCheckBox(); // 체크 박스를 다시 그리는 함수입니다.
};
#endif // CHECKBOXHEADER_H
[widget.h]
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QHeaderView>
#include <QPainter>
#include <QCheckBox>
#include <QDebug>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
public slots:
void checkBoxClicked(bool state);
};
#endif // WIDGET_H
[checkboxhead.cpp]
#include "checkboxheader.h" // checkboxheader.h 헤더 파일을 포함합니다.
CheckBoxHeader::CheckBoxHeader(Qt::Orientation orientation, // 생성자: 헤더의 방향(수평 또는 수직)을 지정합니다.
QWidget* parent) // 부모 위젯을 지정합니다.
: QHeaderView(orientation, parent) // 부모 클래스인 QHeaderView의 생성자를 호출합니다.
{
isChecked_ = true; // 체크 박스의 초기 상태를 체크된 상태로 설정합니다.
}
void CheckBoxHeader::paintSection(QPainter* painter, // 섹션을 그리는 함수입니다.
const QRect& rect, // 섹션의 사각형 영역입니다.
int logicalIndex) const // 섹션의 논리적 인덱스입니다.
{
painter->save(); // 현재 painter 상태를 저장합니다.
QHeaderView::paintSection(painter, rect, logicalIndex); // 부모 클래스의 paintSection 함수를 호출하여 기본적인 헤더 섹션을 그립니다.
painter->restore(); // 저장된 painter 상태를 복원합니다.
if (logicalIndex == 0) // 첫 번째 섹션(logicalIndex 0)에만 체크 박스를 그립니다.
{
QStyleOptionButton option; // 체크 박스를 그리기 위한 스타일 옵션입니다.
option.rect = QRect(1, 3, 20, 20); // 체크 박스의 위치와 크기를 설정합니다.
option.state = QStyle::State_Enabled | QStyle::State_Active; // 체크 박스를 활성화된 상태로 설정합니다.
if (isChecked_) // 체크 박스의 상태에 따라 스타일 옵션을 설정합니다.
option.state |= QStyle::State_On; // 체크된 상태
else
option.state |= QStyle::State_Off; // 체크되지 않은 상태
option.state |= QStyle::State_Off; // 이 부분은 불필요한 코드로 보입니다.
style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, // 체크 박스를 그립니다.
&option, // 스타일 옵션을 전달합니다.
painter); // painter를 전달합니다.
}
}
void CheckBoxHeader::mousePressEvent(QMouseEvent* event) // 마우스 클릭 이벤트를 처리하는 함수입니다.
{
Q_UNUSED(event) // event 변수를 사용하지 않음을 나타냅니다.
setIsChecked(!isChecked()); // 체크 박스의 상태를 반전시킵니다.
emit checkBoxClicked(isChecked()); // checkBoxClicked 시그널을 방출하여 체크 박스 상태 변경을 알립니다.
}
void CheckBoxHeader::redrawCheckBox() // 체크 박스를 다시 그리는 함수입니다.
{
viewport()->update(); // 뷰포트를 업데이트하여 다시 그리도록 합니다.
}
void CheckBoxHeader::setIsChecked(bool val) // 체크 박스의 체크 상태를 설정하는 함수입니다.
{
if (isChecked_ != val) // 현재 상태와 설정하려는 상태가 다를 경우에만 업데이트합니다.
{
isChecked_ = val; // 체크 박스 상태를 업데이트합니다.
redrawCheckBox(); // 체크 박스를 다시 그립니다.
}
}
[widget.cpp]
#include "widget.h" // widget.h 헤더 파일을 포함합니다.
#include "ui_widget.h" // ui_widget.h 헤더 파일을 포함합니다. (Qt Designer로 생성된 UI 파일)
#include "checkboxheader.h" // checkboxheader.h 헤더 파일을 포함합니다.
#include <QDebug> // 디버깅 메시지를 출력하기 위한 헤더 파일을 포함합니다.
Widget::Widget(QWidget *parent) : // Widget 클래스의 생성자입니다. 부모 위젯을 인자로 받습니다.
QWidget(parent), // 부모 클래스인 QWidget의 생성자를 호출합니다.
ui(new Ui::Widget) // Ui::Widget 클래스의 객체를 생성합니다. (Qt Designer로 생성된 UI)
{
ui->setupUi(this); // UI를 설정합니다.
ui->tableWidget->setRowCount(5); // 테이블 위젯의 행 개수를 5로 설정합니다.
ui->tableWidget->setColumnCount(2); // 테이블 위젯의 열 개수를 2로 설정합니다.
CheckBoxHeader* header = new CheckBoxHeader(Qt::Horizontal, ui->tableWidget); // CheckBoxHeader 객체를 생성합니다. (수평 방향)
ui->tableWidget->setHorizontalHeader(header); // 테이블 위젯의 헤더를 CheckBoxHeader로 설정합니다.
connect(header, &CheckBoxHeader::checkBoxClicked, // CheckBoxHeader의 checkBoxClicked 시그널을 Widget의 checkBoxClicked 슬롯에 연결합니다.
this, &Widget::checkBoxClicked); // 이렇게 하면 헤더의 체크 박스를 클릭했을 때 checkBoxClicked 슬롯이 호출됩니다.
QStringList nameList; // QStringList를 생성합니다.
nameList << "Notebook" << "Mobile" << "Desktop" << "Keyboard" << "Monitor"; // QStringList에 아이템을 추가합니다.
for(int i = 0; i < 5 ; i++) // 5개의 행을 생성하고 데이터를 추가합니다.
{
ui->tableWidget->insertRow(i); // i번째 행을 삽입합니다.
QTableWidgetItem *dateItem = new QTableWidgetItem("2025.05.07"); // "2025.05.07" 텍스트를 가진 QTableWidgetItem을 생성합니다.
dateItem->setCheckState(Qt::Checked); // 아이템의 체크 상태를 Qt::Checked로 설정합니다.
ui->tableWidget->setItem(i, 0, dateItem); // (i, 0) 위치에 dateItem을 설정합니다.
ui->tableWidget->setItem(i, 1, new QTableWidgetItem(nameList.at(i))); // (i, 1) 위치에 nameList의 i번째 아이템을 설정합니다.
}
}
void Widget::checkBoxClicked(bool state) // 헤더의 체크 박스 클릭 시 호출되는 슬롯입니다.
{
for(int i = 0 ; i < 5 ; i++) // 모든 행의 첫 번째 열 아이템의 체크 상태를 변경합니다.
{
QTableWidgetItem *item = ui->tableWidget->item(i, 0); // (i, 0) 위치의 아이템을 가져옵니다.
if(state) // state가 true이면 (헤더 체크 박스가 체크된 상태)
item->setCheckState(Qt::Checked); // 아이템의 체크 상태를 Qt::Checked로 설정합니다.
else // state가 false이면 (헤더 체크 박스가 체크되지 않은 상태)
item->setCheckState(Qt::Unchecked); // 아이템의 체크 상태를 Qt::Unchecked로 설정합니다.
}
}
Widget::~Widget() // Widget 클래스의 소멸자입니다.
{
delete ui; // ui 객체를 삭제합니다.
}
=> Model 을 사용하지 않고 QTableWidget 을 이용해 데이터를 삽입하는 예제를 다루어 볼 것이다. 그리고 첫 번째 Column 에 QCheckBox 위젯을 삽입하는 방법
[main.cpp]
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}