ホーム

OFF-SOFT.net

OFF-SOFT.net

ウェブやソフトウェアに関するサポート&情報サイトです。サイト構築からソフトウェアの作成、利用まであなたの助けになるかも・・・・しれません。たぶん・・。

Qt (B2) QTableWidgetで複数行のテキスト入力

公開日| 2009年06月18日 | 3 のコメントがあります。
概要 :
 今回のテーマは、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本柱でやっていく以外にないように思います。


コメント

3 のコメントがあります。 “Qt (B2) QTableWidgetで複数行のテキスト入力”


  1. 通りすがり
    2019年04月28日 @ 18:48:24

    33行目は、セルの多いさを内容にあわせて縦横ともに拡大・縮小するように指示しています。
    -> 大きさ

  2. 通りすがり
    2019年04月28日 @ 18:53:46

    2頁目は同じ内容に見受けられます。

    戻り値にtrueを指定すると、ここで、イベントが処理されたことを意味しますので、 このイベントh、破棄されます。
    -> このイベントは、

  3. 通りすがり
    2019年05月02日 @ 11:44:33

    また、QPlainTextEditをQComboBoxの置き換えて使用することもできます。(基本的にQWidgetの派生クラスであれば、独自のクラスでも使えます)

    助詞と句点の位置がおかしいと思います。
    -> また、QPlainTextEditをQComboBoxに置き換えて使用することもできます(基本的にQWidgetの派生クラスであれば、独自のクラスでも使えます)。

コメントをどうぞ







  • はてなブックマークへ追加する
  • Facebookでシェアする
  • twitter でつぶやく
  • Google Plusでシェアする
  • Pocketでシェアする
ページトップへ