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)で上側がプラスです。
目的は描画なので今はこのままとします。