이번 포스팅에서는 Tableview 위에 ComboBox를 추가한 후 각 Cell 별로 다른 데이터를 추가하는 방법을 알려드리겠습니다. 

이전에 "QTableView에 CheckBox 및 ComboBox 삽입하기" 주제에서 ComboBox와 ComboBoxDelegate 클래스를 다룬적이 있지만,

추가로 ComboBox 부분을 더욱 자세하게 다뤄보겠습니다.

 

QComboboxdelegate 클래스를 이용하면 QTableview에 ComboBox를 생성할 수 있습니다.
단순히 QComboboxdelegate 클래스로 생성만 하는 경우 해당 Cell을 클릭해야만 ComboBox가 생성되고 선택 후에는 다시 선택했던 값만을 저장한 후 ComboBox가 사라지는 문제가 발생합니다.

프로그램이 종료될 때 까지 생성한 ComboBox를 Tableview에 고정하기 위해서는 openPersistentEditor() 함수를 사용하여야 합니다. 

 

1. 우선, ComboBox를 생성할 Tableview와 각 데이터의 항목을 표시할 Header를 만들어보도록 하겠습니다.
Tableview의 Geometry는 임의로 정한 값이므로 UI에 맞게 setGeometry() 함수로 수정하시면 됩니다.

    // QStandardItemModel & QTableView Init
    gridmodel = new QStandardItemModel(ROW_MAX, COL_MAX, this);
    tableview = new QTableView(this);
    tableview->setGeometry(10, 25, 591, 481);
    tableview->setModel(gridmodel);

    // Gridmodel Header Init

    gridmodel->setHorizontalHeaderItem(0, new QStandardItem(QString("Data")));
    gridmodel->setHorizontalHeaderItem(1, new QStandardItem(QString("ComboBox")));
    gridmodel->setHorizontalHeaderItem(2, new QStandardItem(QString("ComboBox")));
    gridmodel->setHorizontalHeaderItem(3, new QStandardItem(QString("Data")));
    gridmodel->setHorizontalHeaderItem(4, new QStandardItem(QString("Data")));

    // Grid Row & Column
    for (int row = 0; row < ROW_MAX; row++)
    {
        for (int col = 0; col < COL_MAX; col++)
        {
            index = gridmodel->index(row, col, QModelIndex());
            gridmodel->setData(index,"");
            tableview->setColumnWidth(col, WIDTH);
        }
            tableview->setRowHeight(row, HEIGHT);
    }


2. 아래와 같이 ComboBoxDelegate를 통해 ComboBox을 Cell에 삽입할 경우는 해당 Cell을 마우스로 클릭하면,

그 순간 ComboBox가 나타나는 형태로 처음부터 ComboBox의 모양을 띄고 있지 않습니다.
또한, ComboBox를 만들 경우 Default로 선택하고 싶은 데이터가 있더라도 표시할 방법이 없는 Model입니다.

    // ComboBoxDelegate Init
    ComboBoxDelegate *f_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(1, f_combodelegate);

    ComboBoxDelegate *s_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(2, s_combodelegate);

    for(int nrow = 0; nrow < ROW_MAX; nrow++)
    {
        // First Column ComboBox Section
        QString str = "";
        str.sprintf("ComboBox%d", nrow);
        index = gridmodel->index(nrow, 1, QModelIndex());
        gridmodel->setData(index, str);

        // Second Column ComboBox Section
        str.sprintf("ComboBox%d", nrow + ROW_MAX);
        index = gridmodel->index(nrow, 2, QModelIndex());
        gridmodel->setData(index, str);
    }


3. ComboBox를 Tableview에 계속 유지하고 싶을 경우, openPersistentEditor(const QModelIndex &index)라는 함수를 사용할 수 있습니다. 특정 Cell의 Index를 매개변수로 전달하면 해당 Cell의 Combox는 프로그램이 종료되기 전까지 유지됩니다.

    // ComboBoxDelegate Init
    ComboBoxDelegate *f_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(1, f_combodelegate);

    ComboBoxDelegate *s_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(2, s_combodelegate);

    for(int nrow = 0; nrow < ROW_MAX; nrow++)
    {
        // First Column ComboBox Section
        QString str = "";
        str.sprintf("ComboBox%d", nrow);
        index = gridmodel->index(nrow, 1, QModelIndex());
        gridmodel->setData(index, str);
        tableview->openPersistentEditor(gridmodel->index(nrow, 1)); // 추가

        // Second Column ComboBox Section
        str.sprintf("ComboBox%d", nrow + ROW_MAX);
        index = gridmodel->index(nrow, 2, QModelIndex());
        gridmodel->setData(index, str);
        tableview->openPersistentEditor(gridmodel->index(nrow, 2)); // 추가
    }


4. 이제 ComboBox가 마우스 선택시에만 생성되는 문제는 해결하였지만, 모든 Cell의 ComboBox 값이 첫번째 값으로 시작되는 문제가 발생합니다. 이를 해결하지 위해서는 comboboxdelegate.cpp 파일 내에서 원하는 값을 구현해주어야 합니다.

각 Cell의 Index만을 가져와 해당하는 Row, Column에 ComboxBox를 생성하는 방식이기 때문에,

추가로 QStandardItemModel의 주소 값을 매개변수로 넘겨주도록 합니다.

 

* mainwindow.cpp 부

    ...
    ComboBoxDelegate *s_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    ...

 

* comboboxdelegate.cpp 생성자

    ComboBoxDelegate::ComboBoxDelegate(QObject* parent, QStandardItemModel *gridmodel)
        : QStyledItemDelegate(parent)
    {
        parentGridModel = gridmodel;
    }

 

* comboboxdelegate.cpp 부 createEditor 함수

    ...
    QString strpindata = parentGridModel[0].index(index.row(), index.column()).data().toString();
    cb->setCurrentText(strpindata);
    ...

 

생성자에서 받은 parentGridModel 변수를 통해 현재 mainwindow의 gridmodel에 설정되어 있는 값을 알 수 있기 때문에,
ComboBox 생성 후 단순히 첫번째 값을 반환하지 않고 현재 설정된 값을 반환할 수 있습니다.

 

* mainwindow.h 및 mainwindow.cpp 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
 
#include <QMainWindow>
#include <QStandardItemModel>
#include <QTableView>
 
#define ROW_MAX     15
#define COL_MAX     5
#define WIDTH       120
#define HEIGHT      30
 
namespace Ui {
class MainWindow;
}
 
class MainWindow : public QMainWindow
{
    Q_OBJECT
 
public:
    explicit MainWindow(QWidget *parent = 0);
    void GridTableView();
    ~MainWindow();
 
private:
    Ui::MainWindow *ui;
    QStandardItemModel *gridmodel;
    QTableView *tableview;
    QModelIndex index;
};
 
#endif // MAINWINDOW_H
 
// mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "comboboxdelegate.h"
 
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    GridTableView();
}
 
MainWindow::~MainWindow()
{
    delete ui;
}
 
void MainWindow::GridTableView()
{
    // QStandardItemModel & QTableView Init
    gridmodel = new QStandardItemModel(ROW_MAX, COL_MAX, this);
    tableview = new QTableView(this);
    tableview->setGeometry(1025591481);
    tableview->setModel(gridmodel);
 
    // Gridmodel Header Init
    gridmodel->setHorizontalHeaderItem(0new QStandardItem(QString("Data")));
    gridmodel->setHorizontalHeaderItem(1new QStandardItem(QString("ComboBox")));
    gridmodel->setHorizontalHeaderItem(2new QStandardItem(QString("ComboBox")));
    gridmodel->setHorizontalHeaderItem(3new QStandardItem(QString("Data")));
    gridmodel->setHorizontalHeaderItem(4new QStandardItem(QString("Data")));
 
    // Grid Row & Column
    for (int row = 0; row < ROW_MAX; row++)
    {
        for (int col = 0; col < COL_MAX; col++)
        {
            index = gridmodel->index(row, col, QModelIndex());
            gridmodel->setData(index,"");
            tableview->setColumnWidth(col, WIDTH);
        }
            tableview->setRowHeight(row, HEIGHT);
    }
 
    // ComboBoxDelegate Init
    ComboBoxDelegate *f_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(1, f_combodelegate);
 
    ComboBoxDelegate *s_combodelegate = new ComboBoxDelegate(tableview, gridmodel);
    tableview->setItemDelegateForColumn(2, s_combodelegate);
 
    for(int nrow = 0; nrow < ROW_MAX; nrow++)
    {
        // First Column ComboBox Section
        QString str = "";
        str.sprintf("ComboBox%d", nrow);
        index = gridmodel->index(nrow, 1, QModelIndex());
        gridmodel->setData(index, str);
        tableview->openPersistentEditor(gridmodel->index(nrow, 1));
 
        // Second Column ComboBox Section
        str.sprintf("ComboBox%d", nrow + ROW_MAX);
        index = gridmodel->index(nrow, 2, QModelIndex());
        gridmodel->setData(index, str);
        tableview->openPersistentEditor(gridmodel->index(nrow, 2));
    }
}

 

* comboboxdelegate.h 및 comboboxdelegate.cpp 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125 126

// comboboxdelegate.h
#ifndef COMBOBOXDELEGATE_H
#define COMBOBOXDELEGATE_H
 
#include <QStyledItemDelegate>
#include <QComboBox>
#include <QStandardItemModel>
 
class ComboBoxDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    ComboBoxDelegate(QObject* parent=0, QStandardItemModel *gridmodel=0);
    ~ComboBoxDelegate();
 
    QWidget *createEditor( QWidget *parent,
                           const QStyleOptionViewItem &option,
                           const QModelIndex &index) const;
 
    void setEditorData( QWidget *editor,
                        const QModelIndex &index ) const;
 
    void setModelData( QWidget *editor,
                       QAbstractItemModel *model,
                       const QModelIndex &index ) const;
 
    void updateEditorGeometry( QWidget *editor,
                               const QStyleOptionViewItem &option,
                               const QModelIndex &index ) const;
 
    QStringList comboItems;
    mutable QComboBox *combo;
 
private:
    QStandardItemModel *parentGridModel;
};
 
#endif // COMBOBOXDELEGATE_H
 
// comboboxdelegate.cpp
#include "comboboxdelegate.h"
#include <QComboBox>
 
ComboBoxDelegate::ComboBoxDelegate(QObject* parent, QStandardItemModel *gridmodel)
    : QStyledItemDelegate(parent)
{
    parentGridModel = gridmodel;
}
 
ComboBoxDelegate::~ComboBoxDelegate()
{
 
}
 
QWidget* ComboBoxDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    // ComboBox ony in column 2
    if ((index.column() != 1&& (index.column() != 2))
        return QStyledItemDelegate::createEditor(parent, option, index);
 
    // Create the combobox and populate it
    QComboBox* cb = new QComboBox(parent);
 
    if(index.column() == 1)
    {
        cb->addItem(QString("ComboBox0"));
        cb->addItem(QString("ComboBox1"));
        cb->addItem(QString("ComboBox2"));
        cb->addItem(QString("ComboBox3"));
        cb->addItem(QString("ComboBox4"));
        cb->addItem(QString("ComboBox5"));
        cb->addItem(QString("ComboBox6"));
        cb->addItem(QString("ComboBox7"));
        cb->addItem(QString("ComboBox8"));
        cb->addItem(QString("ComboBox9"));
        cb->addItem(QString("ComboBox10"));
        cb->addItem(QString("ComboBox11"));
        cb->addItem(QString("ComboBox12"));
        cb->addItem(QString("ComboBox13"));
        cb->addItem(QString("ComboBox14"));
    }
 
    else if(index.column() == 2)
    {
        cb->addItem(QString("ComboBox15"));
        cb->addItem(QString("ComboBox16"));
        cb->addItem(QString("ComboBox17"));
        cb->addItem(QString("ComboBox18"));
        cb->addItem(QString("ComboBox19"));
        cb->addItem(QString("ComboBox20"));
        cb->addItem(QString("ComboBox21"));
        cb->addItem(QString("ComboBox22"));
        cb->addItem(QString("ComboBox23"));
        cb->addItem(QString("ComboBox24"));
        cb->addItem(QString("ComboBox25"));
        cb->addItem(QString("ComboBox26"));
        cb->addItem(QString("ComboBox27"));
        cb->addItem(QString("ComboBox28"));
        cb->addItem(QString("ComboBox29"));
    }
 
    QString strpindata = parentGridModel[0].index(index.row(), index.column()).data().toString();
    cb->setCurrentText(strpindata);
 
    return cb;
}
 
void ComboBoxDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
    QString text = index.model()->data( index, Qt::DisplayRole ).toString();
 
        int comboIndex = comboItems.indexOf(QRegExp(text));
 
        if(comboIndex>=0)
            (static_cast<QComboBox*>( editor ))->setCurrentIndex(comboIndex);
}
 
void ComboBoxDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
    model->setData( index, static_cast<QComboBox*>( editor )->currentText() );
}
 
void ComboBoxDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    editor->setGeometry( option.rect );
}