Qt/Gcc
2013.1.14作成
7-3 コントロールパネルからのメッセージ送信(slot,signalの利用)
コントロールパネルのボタンなど、コントロールが操作されたらそれに基づいて分割ウィンドウ上の描画が変化するようにしたいです。
そのためにここでは、コントロールパネルからメッセージをmainwindowに送信する方法を記載します。
具体的には、コントロールパネル(QFrameの派生クラス)に配置されたボタンを押す(signal送信)と、mainwindowの関数(slot関数)が
呼び出されるようにします。
そのために、Qtで良く使用されるsignal-slotを使います。
signal,slotを使う場合、送信側(元)、受信側のWidgetのポインタが必要となります。
このため、mainwindow内でコントロールパネルを生成するとき(コントロールパネルのコンストラクタを呼ぶときなど)などで、
コントロールパネルのクラスにmainwindowのポインタを渡す必要があります。もちろん、どこで処理するかによっては、
コントロールパネルのクラスのポインタをmainwindowクラスに渡してもよいです。
以下、実施するのに必要な項目を記載します。
1.signal,slotを処理するクラスにwidgetのポインタを渡す。
今回は、コントロールパネル側(以下ではCDrawFrame)で処理するため、mainwindowのポインタをコントロールパネル側に渡します。
・mainwindow.cpp、コントロールパネルクラスを確保するためにコンストラクタを呼び出す。
cotf = new
CDrawFrame(0,(QObject*)this);
このとき、CDrawFrameクラスのコンストラクタ宣言の「QWidget
*parent=0」の「=0」を削除し以下のようにします。
・cdrawframe.h
explicit
CDrawFrame(QWidget *parent,QObject* mainwin);
2.mainwindowクラスにスロット関数を定義する(今回はOnView1()という関数とする)
このとき、「public
slots:」というキーワードが必要。以下の記載をmainwindow.hに記載する。
・mainwindow.h
public
slots://スロットはpublic slotsという記述が必要
void
OnView1();
3.上記2で作成したスロット関数をmainwindow.cppに実装する。
・mainwindow.cpp
void
MainWindow::OnView1()
{
//ここに処理を記述
}
4.signal,slotを処理する関数をコントロールパネル側(以下ではCDrawFrame)のクラスで処理する。
今回は、コンストラクタ内で処理しています。デザインで作成したボタンをセンダーとする場合は、uiポインタから参照します。
以下の例では、View1Buttonという名前をつけたオブジェクト(テキスト名でなくオブジェクト名なので間違えない)を参照しています。
なお、下記の「wg」で一度受けているのは、おまじないです。wgはヘッダファイル内で定義しています。
・cdrawframe.h
private:
QObject
*wg;//signal,slotを扱うためにメッセージを送信する先のオブジェクト(Widget)をコピーする。おまじない
・cdrawframe.cpp
CDrawFrame::CDrawFrame(QWidget
*parent,QObject *mainwin) :
QFrame(parent),
ui(new
Ui::CDrawFrame)
{
ui->setupUi(this);
//以下、mainwindowクラスからのポインタを一度コピーして、signalの送信先オブジェクトとしている。
wg=new QObject();
wg =
mainwin;
//signal,slotをconnectしている。
QObject::connect(ui->View1Button,SIGNAL(clicked()),wg,SLOT(OnView1()));
}
以上でView1に対してメッセージを送信できるようになりました。ためしにスロット関数であるOnView1()にダイアログを
表示するようにします。以下OnView1()の部分です。
#include
<QtGui>//メッセージボックスのためのincludeファイル
void
MainWindow::OnView1()
{
//ここに処理を記述
QMessageBox::warning(0,"View1","View1message");
}
図1
以下、7-2章とほぼ同じソースですが、全部表示し、追加分のみ色を変えます。
★ソースコード
●mainwindow.h
#include
<QMainWindow>
#include <QGraphicsView>
#include
<QGraphicsScene>
#include <QSplitter>
#include
<QGraphicsItem>
#include
"cdrawframe.h"//QFrameを基底クラスとしたコントロールパネルのクラス宣言
namespace Ui {
class
MainWindow;
}
class MainWindow : public
QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent =
0);
~MainWindow();
private:
Ui::MainWindow *ui;
QGraphicsView *m_view1;//add
QGraphicsScene
*m_scene1;//add
QGraphicsView
*m_view2;//add
QGraphicsScene
*m_scene2;//add
QGraphicsView
*m_view3;//add
QGraphicsScene *m_scene3;//add
QSplitter
*vsplit2;
QSplitter *vsplit4;
QGraphicsEllipseItem
*item1;//描画用
QGraphicsEllipseItem
*item2;
QGraphicsEllipseItem *item3;
void InitView1();
void InitView2();
void InitView3();
QSplitter *getFGSplitter(QGraphicsView
*lview,CDrawFrame *cFrame);
QSplitter
*getGGSplitter(QGraphicsView *lview1,QGraphicsView
*lview2);
CDrawFrame *cotf;//コントロールパネルクラスの変数
public slots://スロットはpublic
slotsという記述が必要
void
OnView1();//View1に対してのslot関数
};
●mainwindow.cpp
#include "mainwindow.h"
#include
"ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new
Ui::MainWindow)
{
ui->setupUi(this);
// setGeometry(0,0,640,640);//main
windowのサイズはuiでのデザイン画面で大きさを変えてもよい。この関数を呼び出してもよい。今回はデザイン画面で大きさを変えた
//各viewとsceneを確保して、初期状態の描画をするための関数
InitView1();
InitView2();
InitView3();
cotf = new CDrawFrame(0,(QObject*)this);//コントロールパネルクラスを確保するためにコンストラクタを呼び出す。
vsplit2=getFGSplitter(m_view1,cotf);//それぞれのビューとコントロールパネルをsplite
windowに
vsplit4=getGGSplitter(m_view2,m_view3);//同上
//以下で上記でビューを貼り付けたsplite
windowをさらにsplite windowにはりつけて4分割している。
QSplitter *hsplit =
new QSplitter(Qt::Horizontal);
hsplit->addWidget(vsplit2);
QSplitter *hsplit1 = new
QSplitter(Qt::Horizontal);
hsplit1->addWidget(vsplit4);
hsplit->addWidget(hsplit1);//mainwindowのセントラルウィジェットとして4分割したsplite windowを貼り付ける。
setCentralWidget(hsplit);
}
MainWindow::~MainWindow()
{
delete
ui;
}
QSplitter *MainWindow::getFGSplitter(QGraphicsView *lview,CDrawFrame
*cFrame)
{
/**splitterの設定*/
QSplitter *vsplit = new QSplitter(Qt::Vertical);
vsplit->addWidget(lview);
QSplitter *vsplit1 = new
QSplitter(Qt::Vertical);
vsplit1->addWidget(cFrame);
vsplit->addWidget(vsplit1);
return
vsplit;
}
QSplitter *MainWindow::getGGSplitter(QGraphicsView
*lview1,QGraphicsView *lview2)
{
/**splitterの設定*/
QSplitter *vsplit = new
QSplitter(Qt::Vertical);
vsplit->addWidget(lview1);
QSplitter *vsplit1 = new
QSplitter(Qt::Vertical);
vsplit1->addWidget(lview2);
vsplit->addWidget(vsplit1);
return vsplit;
}
void
MainWindow::InitView1()
{
item1 = new
QGraphicsEllipseItem(100, 100, 200, 100);
item1->setBrush(QBrush(QColor("pink")));
m_scene1 = new QGraphicsScene();
// シーン矩形部分
m_scene1->setSceneRect(-20,-30,640,480);//set view size
,マイナス座標も設定可m_scene->setSceneRect(-320,-240,640,480);
//viewを大きめにとっておく。windowをドラッグしてviewの領域を超えると表示した画像がずれてくる
m_scene1->addItem(item1);
m_view1 = new
QGraphicsView();//viewの生成
m_view1->setScene(m_scene1);//viewにsceneをセット
}
void
MainWindow::InitView2()
{
item2 = new
QGraphicsEllipseItem(100, 100, 200, 100);
item2->setBrush(QBrush(QColor("blue")));
m_scene2 = new
QGraphicsScene(); // シーン矩形部分
m_scene2->setSceneRect(-20,-30,640,480);//set view size
,マイナス座標も設定可m_scene->setSceneRect(-320,-240,640,480);
//viewを大きめにとっておく。windowをドラッグしてviewの領域を超えると表示した画像がずれてくる
m_scene2->addItem(item2);
m_view2 = new
QGraphicsView();//viewの生成
m_view2->setScene(m_scene2);//viewにsceneをセット
}
void
MainWindow::InitView3()
{
item3 = new
QGraphicsEllipseItem(100, 100, 200, 100);
item3->setBrush(QBrush(QColor("red")));
m_scene3 = new
QGraphicsScene(); // シーン矩形部分
m_scene3->setSceneRect(-20,-30,640,480);//set view size
,マイナス座標も設定可m_scene->setSceneRect(-320,-240,640,480);
//viewを大きめにとっておく。windowをドラッグしてviewの領域を超えると表示した画像がずれてくる
m_scene3->addItem(item3);
m_view3
= new QGraphicsView();//viewの生成
m_view3->setScene(m_scene3);//viewにsceneをセット
}
#include <QtGui>//メッセージボックスのためのincludeファイル
void
MainWindow::OnView1()
{
//ここに処理を記述
QMessageBox::warning(0,"View1","View1message");
}
●cdrawframe.h
#ifndef CDRAWFRAME_H
#define
CDRAWFRAME_H
#include <QFrame>
namespace Ui {
class CDrawFrame;
}
class CDrawFrame : public QFrame
{
Q_OBJECT
public:
//explicit CDrawFrame(QWidget *parent = 0);
original
CDrawFrame(QWidget *parent,QObject*
mainwin);
~CDrawFrame();
private:
Ui::CDrawFrame *ui;
private:
QObject
*wg;//signal,slotを扱うためにメッセージを送信する先のオブジェクト(Widget)をコピーする。おまじない
};
#endif // CDRAWFRAME_H
●cdrawframe.cpp
#include
"cdrawframe.h"
#include "ui_cdrawframe.h"
CDrawFrame::CDrawFrame(QWidget
*parent,QObject *mainwin) :
QFrame(parent),
ui(new
Ui::CDrawFrame)
{
ui->setupUi(this);
//以下、mainwindowクラスからのポインタを一度コピーして、signalの送信先オブジェクトとしている。
wg=new QObject();
wg = mainwin;
//signal,slotをconnectしている。
QObject::connect(ui->View1Button,SIGNAL(clicked()),wg,SLOT(OnView1()));
}
CDrawFrame::~CDrawFrame()
{
delete ui;
}