Qt (B2) QTableWidgetで複数行のテキスト入力
概要 :
今回のテーマは、QTableWidgetの入力についてです。QTableWidgetでは、デフォルトで、QLineEditが入力用のWidgetとして
用意されています。QTableWidgetを入力可能状態で、作成するとマウスのダブルクリックなどで、入力できるようになります。
今回は、その入力をQTextEditやQPlainTextEditなどの複数行入力できるWidgetへ切り替える方法について記述したいと思います。
ここで使用したサンプルソースコード:
簡単なQTableWidgetの画面
単純なQTableWidgetのサンプル画面を作ってみましょう。
以下のコードでは、3x3の簡単なQTableWidgetの画面を作成しています。
[main.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
| #include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget tableWidget(3, 3);
// set edit trigger event
tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked
| QAbstractItemView::SelectedClicked
| QAbstractItemView::EditKeyPressed );
// set title
QStringList headerLabels;
headerLabels << "Name" << "Attribute" << "Comment";
tableWidget.setHorizontalHeaderLabels(headerLabels);
QTableWidgetItem *item[3];
// set sample data values.
for (int nrow = 0; nrow<3; nrow++ ) {
item[0] = new QTableWidgetItem(QString("sample item name #%1").arg(nrow+1));
item[1] = new QTableWidgetItem(QString("att #%1").arg(nrow+1));
item[2] = new QTableWidgetItem(QString("comment #%1\nreturn ").arg(nrow+1));
for(int ncol=0;ncol<3;ncol++){
tableWidget.setItem(nrow, ncol, item[ncol]);
}
}
// fit of column size at contents.
tableWidget.resizeColumnsToContents();
tableWidget.resize(500, 300);
// table show.
tableWidget.show();
return app.exec();
}
|
10行目から12行目で、入力可能な状態へするときの動作を定義しています。
ここでは、ダブルクリックと、選択状態で1クリックとF2などの入力キー操作で、入力可能な状態へ遷移します。
33行目は、セルの多いさを内容にあわせて縦横ともに拡大・縮小するように指示しています。
これをコンパイルして、実行すると、以下のような画面が表示されます。
3カラム目は、情報の中に改行情報が含まれていますが、QLineEditでは、それが無視されます。
では、これを入力できるようにするには、ドキュメントから、すぐに見つかるのは、
QTableWidgetのvoid setCellWidget () だと思います。
では、このメソッドを使った場合、どのようになるか見てましょう。
setCellWidgetを使って、複数行の入力画面を作成
先の単純なQTableWidgetのサンプル画面を変更してみましょう。
以下のコードでは、3x3の簡単なQTableWidgetの画面を作成しています。
[main.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
| #include <QtGui>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget tableWidget(3, 3);
// set edit trigger event
tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked
| QAbstractItemView::SelectedClicked
| QAbstractItemView::EditKeyPressed );
// set title
QStringList headerLabels;
headerLabels << "Name" << "Attribute" << "Comment";
tableWidget.setHorizontalHeaderLabels(headerLabels);
QTableWidgetItem *item[3];
// set sample data values.
for (int nrow = 0; nrow<3; nrow++ ) {
item[0] = new QTableWidgetItem(QString("sample item name #%1").arg(nrow+1));
item[1] = new QTableWidgetItem(QString("att #%1").arg(nrow+1));
item[2] = new QTableWidgetItem(QString("comment #%1\nreturn ").arg(nrow+1));
for(int ncol=0;ncol<3;ncol++){
tableWidget.setItem(nrow, ncol, item[ncol]);
QPlainTextEdit *ptext=new QPlainTextEdit(&tableWidget);
ptext->setPlainText(item[ncol]->text());
tableWidget.setCellWidget(nrow, ncol, ptext);
}
}
// fit of column size at contents.
tableWidget.resizeColumnsToContents();
tableWidget.resize(500, 300);
// table show.
tableWidget.show();
return app.exec();
}
|
簡単ですね。
29行目から31行目で、QPlainTextEditをsetCellWidgetで各セルに関連付けを行っています。
これをコンパイルして、実行すると、以下のような画面が表示されます。
全てのセルが、常に複数行のテキストの入力が行える状態ですが、恐らく、期待していた画面と違うと思います。
これでは、QGridLayoutでQPlainTextEditを貼り付けた画面と同じような画面です。
では、最初のサンプルの動作と同じような(入力状態が切り替わるような)動作で、単純にQLineEditを
QPlainTextEditへ切り替えるには、どうすれば良いでしょう。
Delegateを継承したクラスを使うのですが、
次は、QStyledItemDelegateを継承したクラスを作成して、QTableWidgetをコントロールしてみましょう。
QStyledItemDelegateの継承を利用する
Delegateとは、直訳すると"委任する"という感じでしょうか。
つまりは、一部の基幹制御を委託されるクラスということにでしょうか。
ここで使用するQStyledItemDelegateは、QTableWidgetにも使用できますが、
QTreeWidgetにも使用できます。全く同じクラスが、再利用できるのです。
では、QStyledItemDelegateを継承して、クラスを作成してみましょう。
[multidelegate.h]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| #include <QStyledItemDelegate>
class MultiDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
MultiDelegate(QWidget *parent = 0);
virtual QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
virtual void setEditorData(QWidget *editor, const QModelIndex &index) const;
virtual void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const;
}
|
[multidelegate.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
| #include <QtGui>
#include "MultiDelegate.h"
MultiDelegate::MultiDelegate(QWidget *parent)
: QStyledItemDelegate(parent)
{
}
QWidget *MultiDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem & /*option*/,
const QModelIndex &/*index*/) const
{
QPlainTextEdit *editor = new QPlainTextEdit(parent);
return editor;
}
void MultiDelegate::setEditorData(QWidget *editor,
const QModelIndex &index) const
{
QPlainTextEdit *mEditor = qobject_cast<QPlainTextEdit *>(editor);
mEditor->setPlainText(index.data().toString());
}
void MultiDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex &index) const
{
QPlainTextEdit *mEditor = qobject_cast<QPlainTextEdit *>(editor);
model->setData(index, mEditor->toPlainText());
}
|
これは、3つの仮想関数をオーバーライドして、それぞれで、QPlainTextEditの制御を行っています。
-
createEditor
-- このメソッドは、入力可能な状態になるときにコールされ、このメソッドで渡されたQWidgetが
そのまま入力画面として表示されます。
-
setEditorData
-- このメソッドは、入力画面の初期設定を行うときにコールされます。
ここでは、現在のQTableWidgetのセルの情報を初期値として設定しています。
-
setModelData
-- このメソッドは、入力画面が編集を終えたときにコールされます。
ここでは、入力情報を現在のQTableWidgetのセルへ出力しています。
では、main.cppの変更をもて見ましょう。
[main.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
| #include <QtGui>
#include "MultiDelegate.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QTableWidget tableWidget(3, 3);
tableWidget.setItemDelegate(new MultiDelegate);
// set edit trigger event
tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked
| QAbstractItemView::SelectedClicked
| QAbstractItemView::EditKeyPressed );
// set title
QStringList headerLabels;
headerLabels << "Name" << "Attribute" << "Comment";
tableWidget.setHorizontalHeaderLabels(headerLabels);
QTableWidgetItem *item[3];
// set sample data values.
for (int nrow = 0; nrow<3; nrow++ ) {
item[0] = new QTableWidgetItem(QString("sample item name #%1").arg(nrow+1));
item[1] = new QTableWidgetItem(QString("att #%1").arg(nrow+1));
item[2] = new QTableWidgetItem(QString("comment #%1\nreturn ").arg(nrow+1));
for(int ncol=0;ncol<3;ncol++){
tableWidget.setItem(nrow, ncol, item[ncol]);
}
}
// fit of column size at contents.
tableWidget.resizeColumnsToContents();
tableWidget.resize(500, 300);
// table show.
tableWidget.show();
return app.exec();
}
|
10行目に、setItemDelegateで、Delegateクラスとの関連付けを行っているだけです。
これをコンパイルして、実行すると、以下のような画面が表示されます。
動作も、マウスのダブルクリックなどで、入力状態になり、期待通りの画面動作です。
実際に操作を試してみあると、残念ながら、"Enter"を入力すると入力画面が閉じてしまいます。
QPlainTextEditでなくQTextEditを使うと、"Enter"を入力しても入力画面は閉じません。
これを閉じなくするためには、eventFilterをオーバーライドして、キー入力イベントを
横取りすれば良いです。
例えば、以下のように、追加します。
[multidelegate.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
| bool MultiDelegate::eventFilter ( QObject * editor, QEvent * oevent )
{
QPlainTextEdit *mEditor = qobject_cast<QPlainTextEdit *>(editor);
if (!mEditor || !oevent)
return false;
int nevent_type=oevent->type();
if (
nevent_type== QEvent::KeyPress ||
nevent_type== QEvent::KeyRelease
) {
QKeyEvent *keyevt=static_cast<QKeyEvent *>(oevent);
if(keyevt){
switch(keyevt->key()){
case Qt::Key_Enter:
case Qt::Key_Return:
if(nevent_type==QEvent::KeyRelease){
return true;
}
mEditor->insertPlainText("\n");
return true;
break;
default:
break;
}
}
}
return QStyledItemDelegate::eventFilter( editor,oevent );
}
|
eventFilterで入ってきたイベントが、キーイベントで、"Enter"キー入力の場合、
QPlainTextEditへ改行情報を追加して、処理を終了しています。
戻り値にtrueを指定すると、ここで、イベントが処理されたことを意味しますので、
このイベントh、破棄されます。
これをコンパイルして、実行すると、改行を入力しても入力画面が閉じなくなると思います。
今回は、QTableWidgetの入力のカスタマイズ処理を行いました。
上記を更にEXCELのようにCtrl+Enterで改行するようにもできます。(サンプルソースに含まれています)
また、QPlainTextEditをQComboBoxの置き換えて使用することもできます。(基本的にQWidgetの派生クラスであれば、独自のクラスでも使えます)
QTableWidgetは、良く使うクラスですので、色々と応用範囲は広がると思います。
このようなやり方は、ドキュメントをよく読んだ方には、当たり前のことです。
ただ、筆者のようにマニュアルを走り読みしている者には、意外と、はまってしまうのかもしれません。
何かお気づきの点があれば、コメントいただければ幸いです。
もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。
2019年04月28日 @ 18:48:24
33行目は、セルの多いさを内容にあわせて縦横ともに拡大・縮小するように指示しています。
-> 大きさ
2019年04月28日 @ 18:53:46
2頁目は同じ内容に見受けられます。
戻り値にtrueを指定すると、ここで、イベントが処理されたことを意味しますので、 このイベントh、破棄されます。
-> このイベントは、
2019年05月02日 @ 11:44:33
また、QPlainTextEditをQComboBoxの置き換えて使用することもできます。(基本的にQWidgetの派生クラスであれば、独自のクラスでも使えます)
助詞と句点の位置がおかしいと思います。
-> また、QPlainTextEditをQComboBoxに置き換えて使用することもできます(基本的にQWidgetの派生クラスであれば、独自のクラスでも使えます)。