ホーム

OFF-SOFT.net

OFF-SOFT.net

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

Qt (9) QtScriptで画面を作成する

公開日| 2009年06月22日 | コメントはまだありません。
概要 :
 Qtでは、java scriptと同様にECMA-262に準拠したQtScriptが実装されています。
 つまり、java scriptと同じ文法で、書けるスクリプトが標準で備わっています。
 QtScriptでは、java scriptのように画面の各パーツをオブジェクトで認識して、動作を制御することも可能です。

 今回の記事では、QtScriptの簡単な動作を解説し、その後、QtScriptを用いて簡単な画面を作ってみましょう。

関連記事: http://doc.trolltech.com/4.5/qtscript.html

ここで使用したサンプルソースコード:

QtScriptを動作させる簡単な画面を作成しましょう。
まず、QtScriptの動作を確認するための簡単な画面を作成してみましょう。
作成する画面は、以下のような画面です。


画面上部にスクリプトを記述し、最後の出力結果を画面下部へ出力するように作成してみましょう。
メニューには、スクリプトの実行のみです。

ファイル
  • sample.cpp
    -- MainWindowを表示しているだけなのです省略します。
  • mainwindow.h
  • mainwindow.cpp

ここでは、画面構成に関しての説明は省きます。
以下は、メニューのスクリプトの実行をクリックした時の動作(slot)部分です。

[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
   :
   :
void MainWindow::excuteScript()
{
	QString sscript=m_script->toPlainText();
	if(!sscript.isEmpty()){
		QScriptEngine engine;
		m_output->append( engine.evaluate(sscript).toString() );
	}
}

簡単に解説します。
最初にQTextEditで入力されている文字列(QtScript情報)を取得し、 その情報が、空でなければ、スクリプトを実行しています。
スクリプトの実行は、"evaluate"のメソッドへ、先の文字列(QtScript情報)を渡して実行されるだけです。

ここでは、その実行結果をm_output(画面下のQTextEdit)へ出力しています。

make時は、以下の点に注意します。

qmake実行時に、以下のように入力するか、xxx.proへ"QT+=script"を追加します。
> qmake "QT+=script"
では、この画面から簡単な計算を実行してみましょう。

画面の上部に、以下のように入力して、"Ctrl+G"をタイプします。


画面の下部に、以下のように入力して、出力されたと思います。


これだけのものでも、単純なQtScriptで閉じたツールを作成するには、十分かもしれません。

続けて、QtアプリケーションのパーツへQtScriptから出力させてみましょう。

QtScriptでデバッグ情報を出力しましょう。
QtScriptの中で、情報を出力する場合、デバッグ機能の中にprintというfunctionが使えます。 ただし、通常、これは、QtScriptのデバッガの出力部分に出力されますので、デバッガを起動していないと見れません。

そこで、QtScriptから簡単に画面へ出力するようにしてみましょう。
※通常は、printを独自の関数へ割り当てなおして、printを使えるようにしますが、ここでは、QtScriptとQtアプリケーション との連動を説明するために、異なる方法で実現します。

QtScriptへ画面にパーツ(m_output(画面下のQTextEdit))を認識させ、そのパーツへスクリプトから出力するようにしてみます。

[mainwindow.cpp]
1
2
3
4
5
6
7
8
9
10
11
12
   :
   :
void MainWindow::excuteScript()
{
	QString sscript=m_script->toPlainText();
	if(!sscript.isEmpty()){
		QScriptEngine engine;
		QScriptValue scriptTextEdit = engine.newQObject(m_output);
		engine.globalObject().setProperty("debugPrint", scriptTextEdit);
		m_output->append( engine.evaluate(sscript).toString() );
	}
}

上記の行数で、8行目、9行目の2行が追加されただけです。
QScriptEngineで、新しいオブジェクトとしてm_output(画面下のQTextEdit)を宣言し、そのオブジェクトの名前を"debugPrint"と定義しています。
つまり、m_output(画面下のQTextEdit)をアクセスするためにQtScriptで"debugPrint"として記述しればアクセスできるということです。

では、この画面から簡単なスクリプトを記述して、出力させてみましょう。

画面の上部に、以下のように入力して、"Ctrl+G"をタイプします。


画面の下部に、以下のように入力して、出力されたと思います。


"undefined"は、スクリプトの結果がなかったことを意味します。
(上記のスクリプトでは、単純にm_output(画面下のQTextEdit)へ出力しているのみで結果がありません。)

通常、print文で、独自の画面へ出力させたい場合、以下のように実施します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
QScriptValue scriptPrintFunction(QScriptContext *context, QScriptEngine *engine)
{
	QString result;
	for (int i = 0; i < context->argumentCount(); ++i) {
		if (i > 0){
			result.append(" ");
		}
		result.append(context->argument(i).toString());
	}
 
	QScriptValue calleeData = context->callee().data();
	QTextEdit *edit = qobject_cast<QTextEdit*>(calleeData.toQObject());
	edit->append(result);
 
	return engine->undefinedValue();
}
 
   :
   :
 
 
QScriptValue printfunc = m_engine->newFunction(scriptPrintFunction);
printfunc.setData(m_engine->newQObject(m_output));
m_engine->globalObject().setProperty("print", printfunc);

ここでは、オブジェクトでなく関数(function)を新たに定義して、その名前を"print"としています。
また、その関数にm_outputを関連付けています。
これで、QtScriptの中で"print"と記載すると、m_outputへ出力されます。

このようにQtアプリケーションの画面オブジェクトをQtScriptの中で利用することができます。

では、続けて、Qtアプリケーションの画面オブジェクトでないものを、QtScriptで作成してみましょう。

QtScriptで扱えるメソッドの範囲
Qtアプリケーションの画面オブジェクトをQtScriptで利用することができろことは、先に記述しました。
まずは、その利用できる範囲を、確認しておきましょう。

QObjectを継承したクラスで、signals, slots, propertiesは、全て使えます。
また、通常のメソッドでも、先頭に"Q_INVOKABLE" というキーワードを指定すると使えるようになります。

簡単な、QTextEditを継承したクラスを作成し、appendするだけのメソッドを用意してみましょう。

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
#ifndef DEBUGWIDGET_H
#define DEBUGWIDGET_H
 
#include <QtGui>
#include <QtScript>
 
class DebugWidget : public QTextEdit
{
	Q_OBJECT
public :
	DebugWidget(QWidget *parent=0);
	Q_INVOKABLE void output_invoke(const QString &text) { append(text); };
	void output_noinvoke(const QString &text) { append(text); };
 
protected :
	Q_INVOKABLE void output2_invoke(const QString &text) { append(text); };
 
private :
	Q_INVOKABLE void output3_invoke(const QString &text) { append(text); };
 
public slots:
	void output(const QString &text) { append(text); };
 
protected slots:
	void output2(const QString &text) { append(text); };
 
private slots:
	void output3(const QString &text) { append(text); };
};
#endif

output_noinvoke以外は、public,protected,privateに差があるだけです。
これをそれぞれ実行してみましょう。

debugPrint.output("test");
debugPrint.output2("test");
debugPrint.output3("test");
debugPrint.output_invoke("test");
debugPrint.output2_invoke("test");
debugPrint.output3_invoke("test");
debugPrint.output_noinvoke("test");
最後だけが失敗します。
つまり、public,protected,privateなどは、全く関係なく使用できます。

propertiesは、ここまであまり登場していませんが、他のサイトなどでのQtスクリプトの説明やチュートリアルで頻繁に説明があります。
この考え方は、VCLにそっくりです。
登録の仕方は、以下のように登録します。(QWidgetを継承しているクラス全てで使えます)
class DebugWidget : public QTextEdit
{
Q_OBJECT
Q_PROPERTY( bool visible WRITE setVisible READ isVisible )
 :
この例では、"visible"というプロパティを定義しています。
書き込み時は、"setVisible"メソッドを使い、読み出しの時は、"isVisible"メソッドを使うように宣言しています。

このように宣言すると、QtScriptの中では、以下のように記述できます。
if(obj.visible==false) { // =isVisible()
   obj.visible = true;   // =show
} else {
   obj.visible = false;  // =hide
}

QtScriptでダイアログを作る
オブジェクトの使えるメソッドが、大方理解できたと思います。
早速、QtScriptでダイアログを作ってみましょう。
あらかじめQtアプリで用意されたものを利用するのは、理解できたと思います。 では、QtScriptの中で新しくオブジェクトを作成するには、どうしたらよいでしょう。

以下にその方法を例で記述します。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Q_SCRIPT_DECLARE_QMETAOBJECT(QDialog, QWidget*)
 
  :
  :
 
void MainWindow::excuteScript()
{
	QString sscript=m_script->toPlainText();
	if(!sscript.isEmpty()){
		QScriptEngine engine;
		QScriptValue objectwin= engine.scriptValueFromQMetaObject<QDialog>();
		engine.globalObject().setProperty("Dialog", objectwin);
		m_output->append( engine.evaluate(sscript).toString() );
	}
}

1行目、cpp先頭で、QtScriptで、Metaオブジェクトを使うことを宣言してる文が追加されました。
11 - 12行目、QScriptEngineで、新しいMetaオブジェクトを作成し、その名前を"Dialog"と宣言しています。

画面の上部に、以下のように入力して、"Ctrl+G"で実行してみましょう。


以下のような大きなダイアログ画面が表示されたと思います。


ここで、画面サイズを指定したいところですが、slotの中には、 画面サイズを変更するメソッドはありません。
そこで、QDialogを継承させたクラスで、画面サイズと位置を指定できるsetGeometryをコールするメソッドを追加してみましょう。

1
2
3
4
5
6
7
8
9
10
11
class SDialog : public QDialog
{
	Q_OBJECT
public:
	SDialog(QWidget *parent) : QDialog(parent) {};
 
public slots:
	void setPosition(int x, int y, int w, int h ){
		setGeometry ( x, y, w, h );
	};
};

このクラスを使えば、"setPosition"がQtScriptで使用できるようになります。

画面の上部に、以下のように入力して、"Ctrl+G"で実行してみましょう。


以下のようなダイアログ画面が小さく表示されたと思います。


このようにして、QLabel,QPushButton,QTextEdit を同様にQtScriptで使用できるようにすれば、 以下のようなスクリプトで、簡単な画面を作成できます。

var win=new Dialog;
var btn=new Button(win);
var txt=new TextEdit(win);
var lbl=new Label(win);
win.setPosition(100,100,200,100);
btn.setPosition(150,40,40,25);
txt.setPosition(10,40,130,25);
lbl.setPosition(10,15,130,25);
lbl.setText("Hellow Script Window!!");
win.exec();

上記のスクリプトで作成された画面です。


QtScriptでシグナルとスロットを制御する
最後に、QtScriptで作成した画面でシグナルとスロットを制御してみましょう。
先にも記述したとおり、QtScriptの中では、 QObjectを継承したクラスのsignals, slots, propertiesは、全て使えます。

つまり、シグナルとスロットもコントロールできるわけです。

では、connectの仕方、desiconnect、signalを発生させるには、どうしたらよいでしょう。

QtScriptでは、connectする際、signalをメンバーとして扱います。
例えば、PushButtonのクリックsignalは、以下のようになります。
var btn=new Button(win);
btn.clicked.connect(cleckButton);
ここでは、PushButtonのクリックsignalをcleckButtonという関数(function)へコネクトしています。
disconnectも同様に行うことができます。

var btn=new Button(win);
btn.clicked.connect(cleckButton);
 :
 :
btn.clicked.disconnect(cleckButton);
signalを発生させる場合は、signal用のメソッドをコールするだけです。
var btn=new Button(win);
btn.clicked();
では、先のスクリプトで作成したダイアログ画面で、ボタンをクリックしたら、 TextEditへ"append"させましょう。

var win=new Dialog;
var btn=new Button(win);
var txt=new TextEdit(win);
var lbl=new Label(win);
win.setPosition(100,100,200,100);
btn.setPosition(150,40,40,25);
txt.setPosition(10,40,130,25);
lbl.setPosition(10,15,130,25);
lbl.setText("Hellow Script Window!!");

function cleckButton()
{
	txt.append("Clicked!!");
}

btn.clicked.connect(cleckButton);

print(win.exec());

上記のスクリプトで作成された画面です。


ボタンをクリックすると右のTextEditへ、"Clicked!!"と表示されたことと思います。

QtScriptは、良くできています。
簡単なツールであれば、このスクリプトで、ほとんど実現できてしまいます。
また、Qtアプリケーションに組み込めば、更に面白いこともできそうです。

最後にQtScriptには、デバッグツールもあります。デバッグ実行すれば、ステップ実行などもできます。
サンプルソースには、デバッグ実行まで含まれていますので、ご参考ください。




もっと、Qt関連について詳しく知りたい方は、以下の本なども良いと思います。
Qtに関する日本語の本が少ないですね。「入門書」は、さすがに、このページを読まれるくらいの方は不要だと思います。
やっぱり、本+ネット+試してみる!!の3本柱でやっていく以外にないように思います。


コメント

コメントをどうぞ







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