Qt/Gcc


3.画像表示
 画像を読み込み、描画と再描画を実施します。画像読み込みはダイアログを表示して実施します。

 3-1 概要
 以下のような順番で実装します。
  1.画像読み込み用のバッファであるQImageクラスを定義する。
  2.オフスクリーンでデバイス依存のバッファである、QPixmapを定義する。
  3.QImageに読み込んだ画像データをQPixmapに変換する。
  4.QPixmapをsceneに結びつける。色々方法はあるがここでは、QGraphicsPixmapItemを使う。
 上記4をもう少し詳しく記載すると、以下のようになる。

  PixmapをQGraphicsPixmapItemとして登録->sceneにItemを追加->
  sceneをviewに結びつける->描画

 ここで注意が必要なのは、Itemに追加した場合、次に追加(変更)する前にremoveしないと、Itemが何度も追加されて大きなデータのItemができてしまいます。

 3-2 mainwindow.hの実装
  mainwindow.hの編集をします。Imageとpixmap用のincludeファイルを追加します。

   #include<qimage.h>//pixmap用のincludeファイル設定
   #include<qpixmap.h>//image用のincludeファイル設定

  以下のメンバー変数を追加する。ここでは、publicにする。
  Public:
      QImage inImage;//画像読み込み、保持用
      QPixmap pixmap_in;//デバイス依存のオフスクリーン構造体

  QgraphicsPixmapItemの変数を追加する。ここではprivateとする。

  private:
     QGraphicsPixmapItem *gpmapI;

  画像が読み込まれたかを判断するflagを定義します。後で不要になるかもしれませんが、
  今回は定義して置きます。
   
   int flag;//

  再描画のためのpaintEventをオーバライドします。Qtは描画イベントが発生するとpaintEventを
  読み出す。任意のタイミングで再描画したいときは、update()関数を呼び出す。

 private:
    void paintEvent(QPaintEvent*);


 3-3 mainwindow.cppの編集をします。
    ファイルダイアログを使用するため、includeファイルを設定します。

        #include<qfiledialog.h>//ファイルダイアログ用のincludeファイル設定

    コンストラクタに以下のコードを追加します。画像がまだ読み込まれてない場合はflagが0
   で画像が読み込まれたらflagを1にします。また、 QgraphicsPixmapItemの変数であるgpmapIの
   確保をします。これはコンストラクタでなくてもよいです。ただし、最後にdeleteでかならず開放してく
   ださい。

     flag = 0;//画像読み込み用のフラグ
     gpmapI=new QGraphicsPixmapItem();//pixmap描画用のItemの確保

   以下にnewFile()のインプリメントを記載します。この関数でファイルをイメージデータへ読み込んで、
   イメージデータをピックスマップにします。そして、ピックスマップをsceneに結びつけて、そのsceneを
   viewにセットします。最後にflagの処理と再描画のイベントを発行します。

    QString fName = QFileDialog::getOpenFileName(this, tr("Open File"),"/home",tr("Images (*.png *.xpm *.jpg *.bmp)"));//ファイルダイアログを表示して、ファイル名を取得する。
 
     //以下でファイルからデータを読み込む
     if(!inImage.load(fName)){
            QMessageBox::warning(0,"No file",fName);//ファイルが読み込めなかった場合メッセージを表示する。
            return;//読み込めなかった場合はなにもせずに関数から抜け出す。
       }
     pixmap_in.convertFromImage(inImage);//読み込んだイメージデータをピックスマップに変換する。
     gpmapI->setPixmap(pixmap_in);//GraphicsPixmapItemに上記のピックスマップをセットする。

   以下は、flag=1の場合、すでに一度sceneにPixmapItem(ピックスマップに変換したイメージ)が登録
   されているので、新しいイメージを読み込んだ場合を考えて、すでにセットされているpixmapを取り
   除きます。取り除かないと同じItemが次々と追加されます。
   
    if(flag==1)
         m_scene->removeItem(gpmapI);//一度ファイルを読み込んでいたらItemをsceneから取り除く

  以下はsceneとviewの関係を定義しています。viewに対してpixmapItemを追加したsceneをセット
  します
     m_scene->addItem(gpmapI);//sceneにピックスマップを追加する。
     m_view->setScene(m_scene);//viewにsceneをセットする。

  イメージの読み込みが成功したら、flagを立てます。flag=0:初期値、あるいはsceneに対して新しい
  データを追加する必要がない場合です。つまり、sceneからpixmapItemを取り除く必要がない場合
  です。

     flag=1;//flagを変更

  すべてが成功したら、描画するためpaintEventを呼び出します。私が試したかぎりだとこのコードが
  なくても再描画するようですが、明示的に記載してpaintEventを呼び出すことにしました。
  
    this->update();//再描画する。PaintEventを呼び出す

  再描画用のpaintEventを実装します。ここでは、ファイルが読み込まれている場合のみ、viewを
  再描画するようにします。

  void MainWindow::paintEvent(QPaintEvent*)
  {
    if(flag==1)//ファイルが読み込まれている場合はviewを描画する
        m_view->show();
  }

 以下が画像になります。この例はビットマップ画像を読み込んだ例です。jpegも読み込めます。


メニューのコードを含めたソースコードは以下です
imageviewソース

注:このプログラムはsceneとviewの座標系が異なったままです。sceneは左上が(0,0)で下側がプラスです。しかし、viewは中心が(0,0)で上側がプラスです。
目的は描画なので今はこのままとします。


トップページに戻る