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();
}

 

소스 코드 첨부

main.cpp
0.00MB
treedialog.cpp
0.01MB
treedialog.h
0.00MB
treedialog.ui
0.00MB

+ Recent posts