QTreeWidget의 기본 동작을 살펴보는 예제이다.
- QTreeWidget에 데이터를 추가/수정/삭제하고,
- 현재 선택된 데이터의 값을 보여주고,
- 선택된 데이터의 행 위치를 옮긴다.(위로 올리거나 내림)
※ 데이터를 외부 데이터 소스(파일 등)에서 읽어오거나, 저장하는 기능은 생략하였다.
부분 소스코드 살펴보기
UI는 QtDesigner로 만들고, 각 버튼 클릭 시 slot을 연결해 주었다.
헤더 설정
QStringList headers;
headers << tr("Col 1") << tr("Col 2");
ui->treeWidget->setHeaderLabels(headers);
최상위 데이터 추가
col 1, col 2의 lineEdit에 입력한 값을 최상위 레벨에 추가해 준다.
QTreeWidgetItem *parent = new QTreeWidgetItem(ui->treeWidget);
parent->setText(0, ui->lineEditCol1->text());
parent->setText(1, ui->lineEditCol2->text());
하위 데이터 추가
col 1, col 2의 lineEdit에 입력한 값을, 선택된 부모의 자식으로 추가해 준다.
// QTreeWidget은 SingleSelection만 허용하도록 설정해놓았음
QList<QTreeWidgetItem*> parent = ui->treeWidget->selectedItems();
if (parent.size() > 0) {
QTreeWidgetItem *child = new QTreeWidgetItem(parent[0]);
child->setText(0, ui->lineEditCol1->text());
child->setText(1, ui->lineEditCol2->text());
child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
parent[0]->setExpanded(true);
}
else {
QMessageBox::information(this, tr("Info"), tr("Please select the parent item"), QMessageBox::Ok);
}
데이터 삭제
선택된 아이템을 삭제한다. (선택된 아이템 하위에 자식이 있는 경우, 자식도 모두 삭제됨)
QTreeWidgetItem *item = ui->treeWidget->currentItem();
int index;
if (item) {
QTreeWidgetItem *parent = item->parent();
if (parent) { // 하위 아이템 삭제
index = parent->indexOfChild(item);
delete parent->takeChild(index);
}
else { // 최상위 레벨 아이템 삭제
index = ui->treeWidget->indexOfTopLevelItem(item);
delete ui->treeWidget->takeTopLevelItem(index);
}
}
else {
QMessageBox::information(this, tr("Info"), tr("Please select the item"), QMessageBox::Ok);
}
데이터 수정
아이템에 Qt::ItemIsEditable 플래그를 설정해주면, 해당 아이템을 더블 클릭 시 수정 가능하게 된다.
child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
클릭한 데이터 정보 보기
itemClicked 시그널이 발생하면, 클릭한 아이템 정보를 보여주는 slot 함수를 호출하도록 한다.
connect(ui->treeWidget, &QTreeWidget::itemClicked, this, &TreeDialog::on_itemClicked);
on_itemClicked 함수
void TreeDialog::on_itemClicked(QTreeWidgetItem *item, int column)
{
displayCurrentItem(item, column);
}
displayCurrentItem 함수
void TreeDialog::displayCurrentItem(QTreeWidgetItem *item, int column)
{
if (item) {
ui->labelCurrentItem->setText(item->data(column, Qt::DisplayRole).toString());
}
}
클릭한 데이터 행을 위/아래로 옮기기
아이템 클릭 후, Up 또는 Down 버튼을 누르면, 해당 아이템을 위로 올리거나 아래로 내린다.
enum Direction {
Up = -1,
Down = 1
};
void TreeDialog::on_pushButtonUp_clicked()
{
moveItem(Direction::Up);
}
void TreeDialog::on_pushButtonDown_clicked()
{
moveItem(Direction::Down);
}
void TreeDialog::moveItem(Direction direction)
{
QTreeWidgetItem *item = ui->treeWidget->currentItem();
if (!item)
return;
int row = ui->treeWidget->currentIndex().row();
if ((direction == Direction::Up) && (row <= 0)) // 더 이상 올라갈 곳이 없음
return;
int lastRow = 0;
QTreeWidgetItem *parent = item->parent();
if (parent)
lastRow = parent->childCount() -1;
else
lastRow = ui->treeWidget->topLevelItemCount() - 1;
if ((direction == Direction::Down) && (row == lastRow)) // 더 이상 내려갈 곳이 없음
return;
int upDownIdx = static_cast<int>(direction);
int index;
if (parent) { // 하위 아이템의 경우
index = parent->indexOfChild(item);
QTreeWidgetItem *child = parent->takeChild(index); // 선택된 아이템을 부모에서 분리하고
parent->insertChild(index + upDownIdx, child); // 옮긴 위치에 다시 insert 한다
ui->treeWidget->setCurrentItem(child);
parent->setExpanded(true);
child->setExpanded(true);
}
else { // 최상위 레벨 아이템의 경우
index = ui->treeWidget->indexOfTopLevelItem(item);
QTreeWidgetItem *child = ui->treeWidget->takeTopLevelItem(index); // 선택된 아이템을 부모에서 분리하고
ui->treeWidget->insertTopLevelItem(index + upDownIdx, child); // 옮긴 위치에 다시 insert 한다
ui->treeWidget->setCurrentItem(child);
child->setExpanded(true);
}
}
전체 소스코드
treedialog.h
#ifndef TREEDIALOG_H
#define TREEDIALOG_H
#include <QDialog>
#include <QTreeWidgetItem>
enum Direction {
Up = -1,
Down = 1
};
namespace Ui {
class TreeDialog;
}
class TreeDialog : public QDialog
{
Q_OBJECT
public:
explicit TreeDialog(QWidget *parent = nullptr);
~TreeDialog();
void moveItem(Direction direction);
void displayCurrentItem(QTreeWidgetItem *item, int column);
private slots:
void on_pushButtonAddParent_clicked();
void on_pushButtonAddChild_clicked();
void on_pushButtonDel_clicked();
void on_pushButtonUp_clicked();
void on_pushButtonDown_clicked();
void on_itemClicked(QTreeWidgetItem *item, int column);
private:
Ui::TreeDialog *ui;
};
#endif // TREEDIALOG_H
treedialog.cpp
#include "treedialog.h"
#include "ui_treedialog.h"
#include <QMessageBox>
TreeDialog::TreeDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::TreeDialog)
{
ui->setupUi(this);
ui->treeWidget->setColumnCount(2); // QTreeWidget을 열을 2개로 설정
// 헤더 설정
QStringList headers;
headers << tr("Col 1") << tr("Col 2");
ui->treeWidget->setHeaderLabels(headers);
// 데이터(아이템) 추가
QTreeWidgetItem *cities = new QTreeWidgetItem(ui->treeWidget); // 첫번째 부모
cities->setText(0, tr("Cities"));
cities->setText(1, tr(" - "));
QTreeWidgetItem *osloItem = new QTreeWidgetItem(cities); // 첫번째 부모의 첫번째 자식(row 1)
osloItem->setText(0, tr("Oslo"));
osloItem->setText(1, tr("No"));
QTreeWidgetItem *seoulItem = new QTreeWidgetItem(cities); // 첫번째 부모의 두번째 자식(row 2)
seoulItem->setText(0, tr("Seoul"));
seoulItem->setText(1, tr("Yes"));
cities->setExpanded(true);
QTreeWidgetItem *colors = new QTreeWidgetItem(ui->treeWidget); // 두번째 부모
colors->setText(0, tr("Colors"));
// 아이템을 수정 가능하게 함 - ItemIsEditable 플래그를 설정해주면 아이템을 더블 클릭시 수정 가능해짐
colors->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
QTreeWidgetItem *redItem = new QTreeWidgetItem(colors); // 두번째 부모의 첫번째 자식(row 1)
redItem->setText(0, tr("Red"));
redItem->setText(1, tr("1"));
redItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
QTreeWidgetItem *yellowItem = new QTreeWidgetItem(colors); // 두번째 부모의 두번째 자식(row 1)
yellowItem->setText(0, tr("Yellow"));
yellowItem->setText(1, tr("2"));
yellowItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
yellowItem->setHidden(true); // 아이템을 숨김(화면에 표시 안함)
QTreeWidgetItem *greenItem = new QTreeWidgetItem(colors); // 두번째 부모의 첫번째 자식(row 1)
greenItem->setText(0, tr("Green"));
greenItem->setText(1, tr("1"));
greenItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
colors->setExpanded(true);
connect(ui->treeWidget, &QTreeWidget::itemClicked, this, &TreeDialog::on_itemClicked);
// ui->treeWidget->setSortingEnabled(true); // 헤더 클릭 시 오름/내림차순 정렬되게 함
displayCurrentItem(ui->treeWidget->currentItem(), 0);
}
TreeDialog::~TreeDialog()
{
delete ui;
}
void TreeDialog::on_pushButtonAddParent_clicked()
{
// 최상위 아이템을 추가함
QTreeWidgetItem *parent = new QTreeWidgetItem(ui->treeWidget);
parent->setText(0, ui->lineEditCol1->text());
parent->setText(1, ui->lineEditCol2->text());
}
void TreeDialog::on_pushButtonAddChild_clicked()
{
// 선택된 아이템 하위에 데이터를 추가함
// QTreeWidget은 SingleSelection만 허용하도록 설정해놓았음
QList<QTreeWidgetItem*> parent = ui->treeWidget->selectedItems();
if (parent.size() > 0) {
QTreeWidgetItem *child = new QTreeWidgetItem(parent[0]);
child->setText(0, ui->lineEditCol1->text());
child->setText(1, ui->lineEditCol2->text());
child->setFlags(Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsSelectable);
parent[0]->setExpanded(true);
}
else {
QMessageBox::information(this, tr("Info"), tr("Please select the parent item"), QMessageBox::Ok);
}
}
void TreeDialog::on_pushButtonDel_clicked()
{
QTreeWidgetItem *item = ui->treeWidget->currentItem();
int index;
if (item) {
QTreeWidgetItem *parent = item->parent();
if (parent) { // 하위 아이템 삭제
index = parent->indexOfChild(item);
delete parent->takeChild(index);
}
else { // 최상위 레벨 아이템 삭제
index = ui->treeWidget->indexOfTopLevelItem(item);
delete ui->treeWidget->takeTopLevelItem(index);
}
}
else {
QMessageBox::information(this, tr("Info"), tr("Please select the item"), QMessageBox::Ok);
}
}
void TreeDialog::on_pushButtonUp_clicked()
{
moveItem(Direction::Up);
}
void TreeDialog::on_pushButtonDown_clicked()
{
moveItem(Direction::Down);
}
void TreeDialog::on_itemClicked(QTreeWidgetItem *item, int column)
{
displayCurrentItem(item, column);
}
void TreeDialog::moveItem(Direction direction)
{
QTreeWidgetItem *item = ui->treeWidget->currentItem();
if (!item)
return;
int row = ui->treeWidget->currentIndex().row();
if ((direction == Direction::Up) && (row <= 0)) // 더 이상 올라갈 곳이 없음
return;
int lastRow = 0;
QTreeWidgetItem *parent = item->parent();
if (parent)
lastRow = parent->childCount() -1;
else
lastRow = ui->treeWidget->topLevelItemCount() - 1;
if ((direction == Direction::Down) && (row == lastRow)) // 더 이상 내려갈 곳이 없음
return;
int upDownIdx = static_cast<int>(direction);
int index;
if (parent) { // 하위 아이템의 경우
index = parent->indexOfChild(item);
QTreeWidgetItem *child = parent->takeChild(index); // 선택된 아이템을 부모에서 분리하고
parent->insertChild(index + upDownIdx, child); // 옮긴 위치에 다시 insert 한다
ui->treeWidget->setCurrentItem(child);
parent->setExpanded(true);
child->setExpanded(true);
}
else { // 최상위 레벨 아이템의 경우
index = ui->treeWidget->indexOfTopLevelItem(item);
QTreeWidgetItem *child = ui->treeWidget->takeTopLevelItem(index); // 선택된 아이템을 부모에서 분리하고
ui->treeWidget->insertTopLevelItem(index + upDownIdx, child); // 옮긴 위치에 다시 insert 한다
ui->treeWidget->setCurrentItem(child);
child->setExpanded(true);
}
}
void TreeDialog::displayCurrentItem(QTreeWidgetItem *item, int column)
{
if (item) {
ui->labelCurrentItem->setText(item->data(column, Qt::DisplayRole).toString());
}
}
main.cpp
#include "treedialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
TreeDialog w;
w.show();
return a.exec();
}
소스 코드 첨부
'개발 > Qt' 카테고리의 다른 글
[Qt] Qt 프레임워크란 (0) | 2022.01.25 |
---|---|
[Qt] QString을 Char*로 변경하는 방법 (0) | 2022.01.15 |
[Qt] QTreeWidget 과 QTreeView의 차이 (0) | 2022.01.04 |
해상도, DPI, PPI 개념 (0) | 2021.12.29 |
[Qt] QTextBrowser에 이미지 넣기 및 수직 정렬(vertical align) (0) | 2021.11.30 |