リナザウのソフトウェア開発


○ 第5章 フォトメモリーをつくってみる「画面に絵をかく」






前回、ツールボックスを作成しました。
でも、これではまったくペイントソフトっぽくないので、今度はペンで絵をかけるようにします。線の太さも変えられます。
ここでは、ペンを使うための「マウスイベント」や、線の太さなどを変えられる「QPen」を使っています。




<CPPファイル名 main.cpp>

#include <qpe/qpeapplication.h>   // 使用するクラスを指定する

#include "mainwindow.h"   // 使用するプログラムを指定する

int main(int argc, char *argv[])
{
	QPEApplication a(argc,argv);
	Mainwindow *mw = new Mainwindow();
	a.showMainWidget(mw);
	return a.exec();
}


(解説は、かきかけ)



<ヘッダーファイル名 mainwindow.h>

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <qmainwindow.h>   // 使用するクラスを指定する
#include <qapplication.h>
#include <qtextcodec.h>
#include <qfont.h>
#include <qmenubar.h>
#include <qcombobox.h>
#include <qlabel.h>
#include <qpushbutton.h>
#include <qpixmap.h>
#include <qpainter.h>
#include <qpicture.h>
#include <qpen.h>

class Mainwindow : public QWidget{
	Q_OBJECT

public:
	Mainwindow(QWidget *parent = 0, const char *name = 0);

protected:
	void paintEvent( QPaintEvent * );  // 描画時に用いる
    	void mousePressEvent( QMouseEvent *e );  // マウスがおされた時のイベント
    	void mouseMoveEvent( QMouseEvent *e );  // マウスがうごかされた時のイベント
    	void mouseReleaseEvent( QMouseEvent *e );  // マウスがはなされた時のイベント

private:
	
	int mx, my; // マウスポインタの座標
	int mx_pre, my_pre; // 直前のマウスポインタの座標
	int index;  // 選択しているペンのタイプ
	int pen_size;  // ペンのサイズ
	
	QTextCodec *codec; // テキストコーデック
	QMenuBar *menubar; // メニューバー
	QComboBox *pen_type, *bar_type, *c_type, *bg_type; // コンボボックス
	QPushButton *erase, *color, *bgcolor;
	QPixmap fm_pen, fm_line, fm_rightangle, fm_rectangle, fm_paintrectangle, fm_eraser, fm_stamp, fm_range, fm_thickline, fm_normalline, fm_thinline, fm_paint, fm_minieraser;
	QPixmap buffer;
	QPen pen;

private slots :
	void slot_setPen();
	void slot_change_PenSize();
};

#endif //MAINWINDOW_H


(解説は、かきかけ)



<CPPファイル名 mainwindow.cpp>

#include "mainwindow.h"  // mainwindow.cpp のヘッダーファイル mainwindow.h を読み込み

Mainwindow::Mainwindow(QWidget *parent, const char *name)
		: QWidget(parent, name), buffer( 640, 480 )
{
	// テキストコーデック「codec」を作成
	// 以降、codec->toUnicode("ここに書いたことは日本語で表示できる")
	codec = QTextCodec::codecForName("ShiftJIS");

	// ウィンドウのタイトルを設定
	setCaption(codec->toUnicode("サンプル12「画面にタッチペンで絵をかく」"));

	// 使用するフォントを設定
	QFont f("lcfont",18);
	setFont(f);
	
	QLabel *ql = new QLabel(this);
	ql -> setBackgroundColor(QColor::QColor( 100, 150, 200 ) );
	ql -> setGeometry(0,0,640,70);
	
	// 描画のタイプの画像ロード
	fm_pen.load("/mnt/card/fm_pen.jpg");
	fm_line.load("/mnt/card/fm_line.jpg");
	fm_rightangle.load("/mnt/card/fm_rightangle.jpg");
	fm_rectangle.load("/mnt/card/fm_rectangle.jpg");
	fm_paintrectangle.load("/mnt/card/fm_paintrectangle.jpg");
	fm_eraser.load("/mnt/card/fm_eraser.jpg");
	fm_stamp.load("/mnt/card/fm_stamp.jpg");
	fm_range.load("/mnt/card/fm_range.jpg");
	
	// 直線のタイプの画像ロード
	fm_thickline.load("/mnt/card/fm_thickline.jpg");
	fm_normalline.load("/mnt/card/fm_normalline.jpg");
	fm_thinline.load("/mnt/card/fm_thinline.jpg");
	
	// ぬりつぶし四角のタイプの画像ロード
	fm_paint.load("/mnt/card/fm_paint.jpg");
	
	// 消ゴムのタイプの画像ロード
	fm_minieraser.load("/mnt/card/fm_minieraser.jpg");
	
	pen_type = new QComboBox( this );
	pen_type -> insertItem(fm_pen, codec->toUnicode("ペン"));
	pen_type -> insertItem(fm_line, codec->toUnicode("直線"));
	pen_type -> insertItem(fm_rightangle, codec->toUnicode("直角"));
	pen_type -> insertItem(fm_rectangle, codec->toUnicode("四角"));
	pen_type -> insertItem(fm_paintrectangle, codec->toUnicode("四角"));
	pen_type -> insertItem(fm_eraser, codec->toUnicode("消ゴム"));
	pen_type -> insertItem(fm_stamp, codec->toUnicode("スタンプ"));
	pen_type -> insertItem(fm_range, codec->toUnicode("範囲"));
	pen_type -> setGeometry(10,35,145,30);
	
	bar_type = new QComboBox( this );
	bar_type -> insertItem(fm_thinline, codec->toUnicode("細線"));
	bar_type -> insertItem(fm_normalline, codec->toUnicode("太線"));
	bar_type -> insertItem(fm_thickline, codec->toUnicode("極太"));
	bar_type -> setGeometry(165,35,145,30);
	
	color = new QPushButton(this);
	color -> setText(codec->toUnicode("色"));
	color -> setGeometry(320,35,100,30);
	
	bgcolor = new QPushButton(this);
	bgcolor -> setText(codec->toUnicode("背景色"));
	bgcolor -> setGeometry(430,35,100,30);
	bgcolor -> hide(); // 初期設定はペンモードなので背景色ボタンは非表示
	
	erase = new QPushButton(this);
	erase -> setText(codec->toUnicode("取消"));
	erase -> setGeometry(540,35,90,30);

	// メニューバーを画面上に配置
	menubar = new QMenuBar( this );
	QPopupMenu *m_edit = new QPopupMenu(this);  // メニュー項目「m_customize」を作成
	m_edit->insertItem( codec->toUnicode("削除"), this, SLOT(slot_delete()) );
	m_edit->insertItem( codec->toUnicode("カット"), this, SLOT(slot_cut()) );
	m_edit->insertItem( codec->toUnicode("コピー"), this, SLOT(slot_copy()) );
	m_edit->insertItem( codec->toUnicode("ペースト"), this, SLOT(slot_paste()) );
	m_edit->insertSeparator();
	m_edit->insertItem( codec->toUnicode("画像調整"), this, SLOT(slot_adjustment()) );
	m_edit->insertItem( codec->toUnicode("減色"), this, SLOT(slot_decrease()) );
	m_edit->insertItem( codec->toUnicode("画像効果"), this, SLOT(slot_effect()) );
	
	QPopupMenu *m_menu = new QPopupMenu(this);  // メニュー項目「m_menu」を作成
	m_menu->insertItem( codec->toUnicode("開く"), this, SLOT(slot_open()) );
	m_menu->insertItem( codec->toUnicode("保存"), this, SLOT(slot_save()) );
	m_menu->insertSeparator();
	m_menu->insertItem( codec->toUnicode("終了"), qApp, SLOT(quit()) );
	
	// メニューバー「menubar」に項目を追加する。ここで追加した順に左から表示される。
	menubar->insertItem( codec->toUnicode("メニュー"), m_menu );  // メニューバー「menubar」に「m_menu」を「メニュー」という表示で追加
	menubar->insertItem( codec->toUnicode("編集"), m_edit );  // メニューバーに「m_edit」を「編集」という表示で追加
	menubar->setSeparator( QMenuBar::InWindowsStyle );  // ウィンドウズみたいなスタイル
	
	index = 0;
	pen_size = 0;
	
	// ペンのタイプが変わったときのシグナルの設定
	QObject::connect( pen_type, SIGNAL(activated(int)), this, SLOT(slot_setPen()) );
	QObject::connect( bar_type, SIGNAL(activated(int)), this, SLOT(slot_change_PenSize()) );
	
	buffer.fill( colorGroup().base() );
	setBackgroundMode( QWidget::PaletteBase );
}



// ペンのサイズが選択された時の設定
void Mainwindow::slot_change_PenSize()
{
	pen_size = bar_type -> currentItem();  // 現在、コンボボックス「bar_type」で選択している項目の番号
}



// ペンが選択された時の設定
void Mainwindow::slot_setPen()
{
	index = pen_type -> currentItem();  // 現在、コンボボックス「pen_type」で選択している項目の番号
	
	if(index == 0) {
		// ペンが選択されている場合
		color -> show();
		bgcolor -> hide();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_thinline, codec->toUnicode("細線"));
		bar_type -> insertItem(fm_normalline, codec->toUnicode("太線"));
		bar_type -> insertItem(fm_thickline, codec->toUnicode("極太"));
	} else if(index == 1) {
		// 直線が選択されている場合
		color -> show();
		bgcolor -> show();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_thinline, codec->toUnicode("細線"));
		bar_type -> insertItem(fm_normalline, codec->toUnicode("太線"));
		bar_type -> insertItem(fm_thickline, codec->toUnicode("極太"));
	} else if(index == 2) {
		// 直角が選択されている場合
		color -> show();
		bgcolor -> show();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_thinline, codec->toUnicode("細線"));
		bar_type -> insertItem(fm_normalline, codec->toUnicode("太線"));
		bar_type -> insertItem(fm_thickline, codec->toUnicode("極太"));
	} else if(index == 3) {
		// 四角(ぬりつぶしなし)が選択されている場合
		color -> show();
		bgcolor -> show();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_thinline, codec->toUnicode("細線"));
		bar_type -> insertItem(fm_normalline, codec->toUnicode("太線"));
		bar_type -> insertItem(fm_thickline, codec->toUnicode("極太"));
	} else if(index == 4) {
		// 四角(ぬりつぶしあり)が選択されている場合
		color -> show();
		bgcolor -> show();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_paint, codec->toUnicode("ベタ"));
	} else if(index == 5) {
		// 消ゴムが選択されている場合
		color -> hide();
		bgcolor -> hide();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(fm_minieraser, codec->toUnicode("細"));
		bar_type -> insertItem(fm_eraser, codec->toUnicode("太"));
	} else if(index == 6) {
		// スタンプが選択されている場合
		color -> hide();
		bgcolor -> hide();
		bar_type -> hide();
		
	} else if(index == 7) {
		// 範囲が選択されている場合
		color -> hide();
		bgcolor -> hide();
		bar_type -> show();
		
		bar_type -> clear();
		bar_type -> insertItem(codec->toUnicode("削除"));
		bar_type -> insertItem(codec->toUnicode("カット"));
		bar_type -> insertItem(codec->toUnicode("コピー"));
		bar_type -> insertItem(codec->toUnicode("ペースト"));
		bar_type -> insertItem(codec->toUnicode("左回転"));
		bar_type -> insertItem(codec->toUnicode("右回転"));
		bar_type -> insertItem(codec->toUnicode("上下反転"));
		bar_type -> insertItem(codec->toUnicode("左右反転"));
		bar_type -> insertItem(codec->toUnicode("文字入力"));
	}
}



// マウスがおされたときのイベント
void Mainwindow::mousePressEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
	
	QPainter qp;
	qp.begin(&buffer);
	qp.setPen(QColor::QColor(0, 0, 0));
	qp.setBrush(QColor::QColor(0, 0, 0));
	qp.drawEllipse( mx, my, 1+pen_size*3, 1+pen_size*3);
	qp.end();
	bitBlt( this, 0, 0, &buffer, 0, 0, 640, 480 );
	
	mx_pre = mx;
	my_pre = my;
}



// マウスがうごかされたときのイベント
void Mainwindow::mouseMoveEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
	
	pen.setWidth(1+pen_size*3);
	pen.setColor(QColor::QColor(0, 0, 0));
	
	QPainter qp;
	qp.begin(&buffer);
	qp.setPen(pen);
	qp.drawLine(mx_pre, my_pre, mx, my);
	qp.end();
	bitBlt( this, 0, 0, &buffer, 0, 0, 640, 480 );
	
	mx_pre = mx;
	my_pre = my;
}



// マウスがはなされたときのイベント
void Mainwindow::mouseReleaseEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
}



// 描画するときのイベント
void Mainwindow::paintEvent( QPaintEvent * )
{
	bitBlt( this, 0, 0, &buffer, 0, 0, 640, 480 );
}


普通にウィジットに絵を描いても、メニューやコンボボックスなどの陰にかくれるとその部分が消えてしまいます。
それを回避するために、ここでは「buffer」と名付けた「QPixmap」に「QPainter」を使って絵を描き、「bitBlt()」を使って「buffer」を画面上に呼び出す手法をとっています。


(解説は、かきかけ)




というわけで、さっそくコンパイルして実行してみましょう。
ここでは、「~/SLZaurus/」以下に「sample0012」フォルダを作成し、その中にソースがあることを前提にしています。


Cygwinを起動して、次のコマンドを実行してください。



. ~/SLZaurus/bin/dev-arm-qpe.sh
cd ~/SLZaurus/sample0012
progen -o sample0012.pro
tmake -o Makefile sample0012.pro
make



これでエラーが出なければ、「sample0012」というファイルがソースと同一のフォルダに作成されているので、それをリナザウに移してターミナルから実行してみてください。
エラーが出た場合は、もう一度ソースを見直して、問題のある個所を修正しましょう。問題のある個所は、「make」後のエラー情報でも最低限のことは提供されます。




実行する場合は、画像ファイルを「/mnt/card/」においてください。
絵を描けるようになりましたが、黒だけではやはりまだまだペイントソフトとはいえません。次回は、色をつけられるようにします。




<ソース>

sample0012.tar.gz




前へ ○○○ 「リナザウのソフトウェア開発」 ○○○ 次へ






inserted by FC2 system