1. 복사

copy [src 파일 경로] [dst 파일 경로]

참고 : %cd% 는 현재 배치파일이 실행되는 경로를 가리키는 변수

@echo off
:: C 드라이브의 text.txt 파일을 D 드라이브로 복사하는 경우
copy C:\text.txt D:\text.txt

:: C 드라이브의 text.txt 파일을, 현재 bat 파일이 실행되는 경로로 복사하는 경우
copy C:\text.txt %cd%\text.txt

 

2. 디렉토리 생성

md [생성할 디렉토리 경로]

- md 대신 mkdir을 써도 된다. (make directory의 약자)

@echo off
:: C 드라이브 안에 test라는 폴더를 생성한다
md C:\test
 
:: 현재 배치파일이 실행되는 경로 안에, test라는 폴더를 생성한다.
md %cd%\test
 
:: 디렉토리가 없는 경우 생성한다.
if not exist "%cd%\test" (
 md %cd%\test
)

 

3. 디렉토리 삭제

rd [삭제할 디렉토리 경로]

- rd 대신 rmdir을 써도 된다. (remove directory의 약자)

- rd는 디렉토리가 비어 있는 경우만 삭제된다.

- /s 옵션 : 디렉토리가 비어 있지 않은 경우에도 삭제한다. (삭제 여부 물음)

- /q 옵션 : 삭제 여부를 묻지 않고 삭제한다.

@echo off
:: C 드라이브의 test라는 폴더 삭제 (디렉토리가 비어있는 경우만 삭제됨)
rd C:\test

:: C 드라이브의 test라는 폴더와, 그 안의 내용까지 모두 삭제 (삭제 여부 물음, y 입력 시 삭제됨)
rd /s C:\test

:: C 드라이브의 test라는 폴더와, 그 안의 내용까지 모두 삭제 (삭제 여부 묻지 않고 삭제함)
rd /s /q C:\test

 

4. 파일 삭제

개별 파일을 삭제하는 방법이다. (디렉토리 삭제를 원하는 경우, 위의 rd 명령어 사용)

del [삭제할 파일 경로]

- 삭제할 파일 경로에 와일드 카드를 사용하면, 여러 개의 파일 삭제 가능 (예: *.exe 는 확장자가 exe인 모든 파일 삭제)

- 삭제할 파일 경로에 디렉토리명을 지정하면, 해당 디렉토리 내의 모든 파일 삭제(디렉토리는 남아있음)

- /P 옵션 : 각 파일 삭제 전에 삭제여부를 묻게 함 (y 입력 시 삭제됨)

- /F 옵션 : 읽기전용 파일 삭제함

@echo off
:: C 드라이브 안의 test.txt라는 파일 삭제
del C:\test.txt

:: 현재 디렉토리 안의 모든 exe 파일 삭제
del %cd%\*.exe

:: C:\BAT 라는 폴더 안의 모든 파일 삭제 (BAT이라는 폴더 자체는 삭제되지 않고 남아있음)
del C:\BAT

:: C 드라이브 안의 test.txt라는 파일 삭제시, 삭제 여부 물음 (y 입력 시 삭제됨)
del /P C:\test.txt

:: C 드라이브 안의 test.txt라는 읽기 전용 파일 삭제 (그냥 del 명령만으로는 읽기전용 파일은 삭제 안됨)
del /F C:\test.txt

 

5. 배치파일 실행 인자 받기

배치파일 실행 시 인자를 넘겨 받으려면, %1 ~ %9의 특수한 환경변수를 사용하면 된다.

(첫 번째 인자는 %1에, 두번째는 %2에, ... 9번째는 %9에 들어간다.)

@echo off
echo first : %1
echo second : %2

 

'개발' 카테고리의 다른 글

인코딩과 디코딩  (0) 2023.02.10
GUI 라이브러리/프레임워크  (0) 2022.02.02

QPushButton의 background color를 설정하고/가져오는 방법입니다.

 

1. QPushButton의 background color 설정하기

QColor color(Qt::red);
ui->pushButton->setStyleSheet(QString("background-color: %1;").arg(color.name()));

 

2. QPushButton의 background color 가져오기

// C++ code
QColor Panel::buttonColor() const
{
    return ui->pushButton->palette().background().color();
}

QMessageBox 안에 html 태그를 포함한 텍스트를 쓰고 싶은 경우가 있다.

예) <strong> 태그를 써서 특정 글자를 진하게 표현하고 싶다던가, <h4> 등의 제목 태그를 쓰고 싶다던가, <br/> 태그를 써서 줄바꿈을 하고 싶다던가..

 

이럴 때에는 setTextFormat(Qt::RichText); 함수로, 텍스트 포맷을 RichText로 설정해 주면 된다.

QMessageBox msg(this);
msg.setIcon(QMessageBox::Information);
msg.setTextFormat(Qt::RichText);
msg.setWindowTitle(tr("Title"));
msg.setText(tr("<strong>Hello!</strong><br/>World!");
msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
if (msg.exec() == QMessageBox::Yes) {
	// do something on Yes
}
else {
	// do something on No
}

 

가끔, 위젯의 상태를 변경하지만, 변경시 발생하는 시그널은 블럭해야 하는 경우가 있다.

(변경 시그널은 발생시키지 않아야 하는 경우 = 변경 시그널에 connect 되어 있는 함수를 실행하면 안되는 경우)

이럴 경우, SignalBlocker를 사용하면 된다.

 

방법 1. blockSignals 함수 사용

blockSignals(True) blockSignals(False) 사이에서 실행되는 코드는 signal을 발생시키지 않는다.

 

아래는 checkBox에서, 시그널을 블럭하면서 체크 상태를 바꾸는 예이다.

# Python code
self.checkBox.blockSignals(True)
self.checkBox.toggle()
self.checkBox.blockSignals(False)

 

방법 2. QSignalBlocker 사용

위와 동일한 기능을 하는 QSignalBlocker라는 클래스를 사용할 수도 있다. 

중괄호 안에서 QSignalBlocker를 생성하면, 해당 범위 안에서 시그널을 막아준다.

  • 시그널 블럭 대상 : QSignalBlocker 인자로 넘어온 오브젝트 (예: 체크박스)
  • 시그널 블럭 범위 : QSignalBlocker 생성 후, 중괄호가 끝날때까지 (QSignalBlocker 가 생성된 후, 소멸되기 전까지 시그널을 막음)
// C++ code
#include <QSignalBlocker>

ui->checkBox->setChecked(true); // 시그널 발생함

if (wantToBlockSignal) 
{
    const QSignalBlocker blocker(ui->checkBox);	// if문 범위 내에서, ui->checkBox의 시그널을 block한다
    ui->checkBox->setChecked(false); // 시그널 발생 안함
}

ui->checkBox->setChecked(true); // 시그널 발생함

참고 : https://doc.qt.io/qt-5/qobject.html#blockSignals

 

GUI(Graphical User Interface)란?

그래픽 아이콘의 클릭을 통해 기기와 상호작용 하는 방식이다. 문자 입/출력으로 상호작용하는 CLI(Command Line Interface) 방식보다 쉬운 인터페이스를 만들고자 등장하였다.

 

GUI 라이브러리란?

GUI(Graphical User Interface) 환경에서 실행되는 응용 프로그램의 화면 출력부를 구현하기 위하여 사용되는 라이브러리이다.

쉽게 말하면, 그래픽 기반의 어플리케이션을 만들기 위한 많은 부분을 구현하여 라이브러리로 제공하는 것이다. 혹은 GUI 프레임워크라 부르는 것들도 있다.

(라이브러리와 프레임워크는 엄밀히는 다른 용어로, 이 둘을 구분하기 위해서는 제어의 역전이 일어나는가를 따지기도 하는데.. 일단은 둘 다 남이 만들어놓은 코드를 가져다 쓸 수 있다라는 점에서 동일하다고 간주하도록 하겠다.)

 

GUI 라이브러리의 종류

GUI 라이브러리의 종류는 크게 운영체제에 종속이 되는가/되지 않는가로 구분할 수 있다.

1. 운영체제에 종속

Microsoft Windows

  • Windows API - 윈도우에서 제공되는 기본 API 세트. C언어 함수들을 기반으로, C++ 객체와 COM 개체를 사용할 수 있다.
  • MFC - C++ 라이브러리. Windows API를 기반으로 한다.
  • WTL - MS에서 제공하는 ATL 기반의 경량 GUI 라이브러리. 이쪽은 MFC와 달리 오픈 소스이다.
  • .NET Framework WinForms / WPF(Windows Presentation Foundation)
    • .NET Framework 플랫폼에는 Windows Forms와 WPF의 두 가지 GUI 라이브러리가 포함되어 있다.
    • Windows Forms는 쉬운 난이도 덕분에 초보자가 접하기에도 용이하다. 또한 C# C++과는 비교도 되지 않는 높은 생산성을 자랑하는 언어이며, 기존 윈도용 C/C++ 프로젝트나 라이브러리와의 연동도 수월하므로 일단 핵심 코드는 그대로 둔 채 껍데기부터 차차 교체할 수도 있다.
    • WPF(Windows Presentation Foundation)은 무료 오픈소스 그래픽 라이브러리로, .Net Framework 3.0의 일부로 처음 출시되었다.

macOS & iOS

  • Cocoa API - Apple 운영 체제용 어플리케이션을 제작할 때 사용하는 프레임워크이다. 
  • SwiftUI - iOS, tvOS, macOS, 및 watchOS용 유저 인터페이스 개발을 위한 크로스 플랫폼 프레임워크이다. Apple이 2019년 첫 출시한 이후 가파르게 진화하고 있다. 

2. 운영체제 비 종속

Java

Java 언어를 위하여 개발된 GUI 라이브러리. 다른 GUI 라이브러리의 Java 언어 바인딩은 여기에 추가하지 않는다.

  • AWT / Swing - Java 런타임 기본 내장 GUI 라이브러리.
  • JavaFX - AWT와 Swing을 대체하기 위해 만들어진 표준 GUI 라이브러리.
  • SWT - 이클립스에서 사용된다. 홈페이지

크로스 플랫폼

다양한 운영체제/동작 환경을 지원하는 라이브러리들이다. 상용으로 쓰려면 라이선스를 확인해야 한다.

GUI 라이브러리 가격 플랫폼 언어 바인딩 라이선스 특징
Qt 무료/유료 UNIX/Unix-like (X11, Wayland), macOS, Windows, Windows UWP, Android, IOS/tvOS/watchOS, WebAssembly, Haiku, Plasma Mobile, Blackbery C++, Python, QML GPL/LGPL/상용 - 오픈소스 C++개발 프레임워크
- C++ 개발에 필요한 온갖 기능(UI, XML, 네크워크 등)을 제공하는 종합 프레임워크
- 모듈별 라이센스 상이
wxWidgets 무료 Windows, Linux, Mac, BSD, Solaris, AIX, OS2 wxPython, wxLua, wxRuby, more.. wxWidgets Licence 30년된 오픈소스 라이브러리
Avalonia 무료 Windows, Linux, Mac, Pi, Android, iOS C#, .NET, XAML MIT .NET 기반 UI framework
Quasar Framework 무료 Windows, Linux, Mac, Web, Android, Blueberry, iOS, Windows Phone Javascript, Typescript MIT 오픈소스 Vue.JS 기반 프레임워크
(Vue.JS는 컴포넌트 기반 프론트엔드 JavaScript 프레임워크로, 웹 개발에 사용됨)
Kivy 무료 Windows, Linux, Mac, iOS, Android, Raspberry Pi Python MIT 오픈 소스 파이썬 프레임워크
GTK+ 무료 Windows, Linux, Mac C, JavaScript, Perl, Python, Rust, Vala LGPL GNOME 프로젝트에서 주로 개발됨
Flutter 무료 Android, iOS, Linux, Mac, Windows, Google Fuchsia, Web platform Dart New BSD Google에서 만든 오픈소스 UI software development kit
Electron 무료 Windows, Linux, Mac JavaScript, HTML, CSS MIT - GitHub에서 만든 오픈소스 소프트웨어 프레임워크
- 웹 기술을 이용하여 Desktop GUI Application을 개발할 수 있게 함
React Native 무료 Android, Android TV, iOS, macOS, tvOS, Web, Windows, UWP, VR JavaScript MIT 페이스북에서 만든 오픈소스 UI 소프트웨어 프레임워크
FLTK 무료 Windows, macOS, UNIX/Linux (X11) C++, Lua, Perl, Python, Ruby LGPL 경량 위젯 라이브러리

 

참고

https://namu.wiki/w/GUI%20%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC

https://en.wikipedia.org/wiki/Graphical_user_interface

https://en.wikipedia.org/wiki/Windows_Presentation_Foundation

https://cocoacasts.com/swiftui-fundamentals-what-is-swiftui

https://www.slant.co/topics/983/~best-cross-platform-gui-toolkits#12

Qt 프레임워크란


Qt는 컴퓨터 프로그래밍에서 GUI 프로그램 개발에 널리 쓰이는 오픈 소스 C++ 개발 프레임워크이다. C++와 QML이라는 자체 스크립트 언어를 기반으로 한다. 회사 내부에서는 Qt를 "cute"로 발음하고 있으며 비공식적으로는 "큐티"로 발음한다. Qt는 KDE, Qtopia, OPIE에 이용되고 있다.

 

"Write once, compile anywhere"를 표방하는 크로스 플랫폼 프레임워크이며, 현존하는 주요 플랫폼(Windows, Linux, OSX, Android, iOS 등)을 거의 대부분 지원한다. 초기에는 크로스플랫폼 GUI 라이브러리로 시작하였으나, 점점 기능이 확대되어 각종 UI 개발 도구, 번역 작업을 위한 도구와 C++ 개발에 필요한 온갖 기능(UI, XML, 네트워크, SVG, Animation, Container Class 등등)을 제공하는 종합 프레임워크가 되었다

 

Qt는 C++를 주로 사용하지만, 파이썬, 루비, C, , 파스칼과도 연동된다. 수많은 플랫폼에서 동작하며, 상당히 좋은 국제화를 지원한다. SQL 데이터베이스 접근, XML 처리, 스레드 관리, 단일 크로스 플랫폼 파일 관리 API를 제공한다.

 

Qt 6 지원 플랫폼


데스크탑 플랫폼 : Linux, macOC, Windows

모바일 플랫폼 : Android, iOS

임베디드 플랫폼

지원되는 플랫폼 자세히 보기 : https://doc.qt.io/qt-6/supported-platforms.html

 

라이선스


오픈소스 라이선스(무료)상용 라이선스(유료) 중 선택 가능하다. 

모듈별로 지원되는 라이선스가 다르니 확인이 필요하다. (모듈에 따라서는 Third-party License가 적용되기도 한다.)

오픈소스 라이선스 중에서도 GPL과 LGPL, BSD 라이센스 등이 섞여있으므로.. 잘 확인해야 한다. GPL 라이선스가 적용되는 모듈을 쓰면 전체 소스코드 공개 의무를 지게 된다.

 

라이선스 확인하기 :

Qt 5 : https://doc.qt.io/qt-5/licenses-used-in-qt.html

 

Licenses Used in Qt | Qt 5.15

Licenses Used in Qt Qt contains some code that is not provided under the GNU Lesser General Public License (LGPL) or the Qt Commercial License, but rather under specific licenses from the original authors. The Qt Company gratefully acknowledges these and o

doc.qt.io

Qt 6 : https://doc.qt.io/qt-6/licenses-used-in-qt.html

 

Licenses Used in Qt | Qt 6.2

Licenses Used in Qt Qt contains some code that is not provided under the GNU Lesser General Public License (LGPL) or the Qt Commercial License, but rather under specific licenses from the original authors. The Qt Company gratefully acknowledges these and o

doc.qt.io

 

참고:

https://ko.wikipedia.org/wiki/Qt_(%EC%86%8C%ED%94%84%ED%8A%B8%EC%9B%A8%EC%96%B4) 

https://namu.wiki/w/Qt(%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC)

방법 1. toStdString().c_str() 사용

QString text = "AAA";
const char* p = text.toStdString().c_str();
qDebug("text : %s", p);

이는 아래 코드와 동일하다.

QString text = "AAA";
std::string str = text.toStdString();
const char* p = str.c_str();
qDebug("text : %s", p);

방법 2. qPrintable() 사용

QString text = "AAA";
qDebug("text : %s", qPrintable(text));

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