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;
}



インデックスに戻る
トップページに戻る