Qt勉強会@名古屋 #27 参加したので
Qt勉強会@名古屋に参加して、ふむふむした内容を雑にまとめます。
ubuntu 18.04.2でやっています。
・環境構築
こちらqt.ioから
Download. Try. Buy. -> go open source -> download
を選択。
Downloadディレクトリにqt〜〜.runファイルがあるので
chmod +x qt〜〜.run
で実行権を与え
sudo qt〜〜.run
とかってやると、インストーラが起動するので従います。
これで、qtのいろいろがDLされます。
・Qt
QtCreatorと呼ばれる、Qtに特化してる(と思う)統合開発環境を使います。
QtCreator、Qt使わなくてもいけちゃうので普段遣いにも良さそうです。かなり動きが軽くサクサク動く印象があります。
左の「ようこそ」 -> +新しいプロジェクト
でプロジェクト作成画面へ。
今回、ウィジェットの説明を勉強会中に聞いたので「Qtウィジェットアプリケーション」を選択。
後は適当に選びます。
Formsフォルダに「.ui」ファイルが入っていますが、これを選んで左の「デザイン」を選ぶとGUIでグリグリとパーツ配置ができます。
ソースが自動生成されているかと思いますが、
ui->setupUi(this);
みたいなソースがあるので、この辺りのコードで何かいい感じに読み込んでくれるのでしょう。
・今回作ったものと知見
今日Qt勉強会@名古屋で作ってた、キー押すと動く船です。 ブログも久々に書いてます。#Qt #qtjp #プログラミング #C pic.twitter.com/QdbGNTNENK
— せかるる(T.Katsuragi) (@kamiyomokikanu) 2019年5月18日
これをC++/Qtで作ってました。
・Widgetへの画像表示
.uiのデザイン画面で、Graphic Viewがあるので、それを適当に貼り付けます。
右上から貼ったGraphic Viewを選び、右下でobject nameをわかりやすい感じに変更します。
.proに
RESOURCES += \ 画像ディレクトリ
とかって追加すると、左のプロジェクト一覧に画像が追加されていい感じになります。
自動生成したソースだと、MainWindowクラス(名前は違うかも)のインスタンスを作り、showメソッドを実行しているかと思います。
このMainWindowにゴリゴリ書いていきます。
ui->setupUi(this); ui->forwardview->setScene(&forwardScene); ziki = new QImage(); ziki->load(ファイルパス); Qziki=QPixmap::fromImage(*ziki); forwardScene.addPixmap(Qziki); ※ forwardviewはGraphic Viewの名前 forwardSceneはQGraphicsSceneの名前 zikiはQImage*の名前 QzikiはQPixmapの名前
これで画像表示ができるはずです。
QPixmapに一度変換するのがミソでしょうか。
・画像加工
QImage自体は、(多分)ただの画素データの集合なので、直接弄ったり、用意されているメソッドで加工できます。
・大きさ変更
*ziki=ziki->scaled(ZIKI_SIZE_W,ZIKI_SIZE_H,Qt::KeepAspectRatio); ※ ZIKI_SIZE_W、ZIKI_SIZE_Hは#define定数
・反転
こちらはメソッドがないぽかったので、作りました。
QImage MainWindow::reverseQImage(QImage Qi){ QImage *retQImage; *etQImage=Qi; for(int i=0;i<ZIKI_SIZE_H;i++){ for(int j=0;j<ZIKI_SIZE_W;j++){ QRgb tmpRGB=Qi.pixel(ZIKI_SIZE_W-j-1,i); retQImage->setPixel(j,i,tmpRGB); } } return *retQImage; }
こんな感じで、pixelで取得してsetPixcelで設定すれば加工できます。
QImageのサイズには注意です。
QImage::pixel: coordinate (50,90) out of range
って怒られます。
・キー取得
eventFilter使いました。
protected: bool eventFilter(QObject* widget, QEvent* event);
と宣言します(protectedでないとダメらしい)
bool MainWindow::eventFilter(QObject * obj, QEvent * event) { QKeyEvent * keyEvent; //キーが押されている時のイベントの処理 if(event->type() == QEvent::KeyPress){ 処理内容 } }
とかって書き、MainWindowのコンストラクタらへんに
installEventFilter(this);
と書くと、キー入力を受け取れるようになります。
・画像の移動
Graphic Viewの好きなとこにQPixmapを貼りたかったのですが失敗。
中央寄せ、左寄せ...など、上下左右中央に寄せて表示しかできなかったです。
なので、
①Graphic View自体を動かす
②でかいQImageの背景を作り、そこにゴリゴリ書いていく
の2つを考え②を採用しました。
・詳細
QImage MainWindow::reverseQImage(QImage Qi){ QImage *retQImage; retQImage=new QImage(QSize(1000,1000),QImage::Format_RGBA8888); for(int i=0;i<ZIKI_SIZE_H;i++){ for(int j=0;j<ZIKI_SIZE_W;j++){ QRgb tmpRGB=Qi.pixel(ZIKI_SIZE_W-j-1,i); retQImage->setPixel(j+zikiX,i+zikiY,tmpRGB); } } return *retQImage; }
さっきの反転プログラムを変えました。
QImageを作る際にQSize(1000,1000)を指定して、大きいサイズのQImageを作ります。
Format_RGBA8888はよくわかってないです(宿題)。
zikiXとzikiYに座標情報を入れ、さっきのeventFilter実行時に値を変えてやります。
・定期的な実行
ここでQtのsignal、slotを使います。
cycleTimer->setInterval(100); cycleTimer->setSingleShot(false); connect(cycleTimer,SIGNAL(timeout()), this,SLOT(slotCycleEvent())); cycleTimer->start(); ※ cycleTimerはTimerの名前
setIntervalとすることで、Nミリ秒ごとにtimeoutシグナルを発行するようになります。
setSingleShotをtrueにすると一回のみになります。
このTimerクラスのtimeoutシグナルと、描画処理のあるスロットをconnectして、タイマーを走らせば定期処理の完成です。
とても簡単でいいですね!!
あとは描画処理に
for(int i=0;i<1000;i++){ for(int j=0;j<1000;j++){ Dziki->setPixel(j,i,0); } } *Dziki=reverseQImage(*ziki); Qziki=QPixmap::fromImage(*Dziki); forwardScene.clear(); forwardScene.addPixmap(Qziki); ※ DzikiはQImage*の名前
と書きます。
zikiには、読み込んだ画像データが入っています。
それを0埋めした*Dzikiに入れ、QPixmapに変換します。
forwardScene.clear()でwidgetの描画を消し、addPixmapで描画します。
以上で、動く船の完成です。
・やり残し
・もっと簡単な方法がありそう
・QImage::pixel: coordinate (N,N) out of range
のお怒りが毎ミリ秒ごとに流れてるので、どこか直す
・押したキーの種類を受け取って、戦艦を上下左右に動かす。
・最後に
www.irasutoya.com
今回、イラスト屋の素材を借りました。
統一感を出すため、イラスト屋オンリーのシューティングゲームを作るのが目標です。
来週の勉強会では、少しでもQtのスキルアップがしたいですね。(わからないことがあれば、#qtjpに投げるので、よろしくお願いします。)