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


○ 第5章 フォトメモリーをつくってみる「色をつけよう!」






今回は、ペンに色を付けられるようにしました。
また、ウィンドウが閉じられる時のイベントや、画面上の色を取得する方法についてもふれています。メニューに「新規」を追加してみました。




<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 <qpen.h>
#include <qdialog.h>
#include <qtimer.h>
#include <qiconset.h>

#include "colordialog.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 );  // マウスがはなされた時のイベント
    	void closeEvent(QCloseEvent *e);  //  ウィンドウが閉じられる時のイベント

private:
	
	int mx, my; // マウスポインタの座標
	int mx_pre, my_pre; // 直前のマウスポインタの座標
	int index;  // 選択しているペンのタイプ
	int pen_size;  // ペンのサイズ
	int r, g, b;  // カラー
	
	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;
	QPixmap color_view;
	QPen pen;
	QIconSet color_view_icon;
	
	ColorDialog *c_dialog;

private slots :
	void slot_setPen();
	void slot_change_PenSize();
	void slot_change_PenColor();
	void color_set();
	void slot_new();
};

#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("サンプル13「ペンに色をつける」"));

	// 使用するフォントを設定
	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_new()) );
	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()) );
	
	// 「色」ボタンをおしたとき
	QObject::connect( color, SIGNAL(clicked()), this, SLOT(slot_change_PenColor()) );
	
	buffer.fill( colorGroup().base() );
	setBackgroundMode( QWidget::PaletteBase );
	
	// 初期設定
	r=0;
	g=0;
	b=0;
	
	// カラービュー
	color_view.fill(QColor::QColor(r, g, b));
	color_view.resize(16, 16);
	color_view_icon.setPixmap(color_view, QIconSet::Automatic);
	color -> setIconSet( color_view_icon );
	
	c_dialog = new ColorDialog();
	
	// 常にカラーダイアログから色を受け付けるようにする
	QTimer *timer = new QTimer(this);
    connect( timer, SIGNAL(timeout()), SLOT(color_set()) );
    timer->start( 100 );
}



// ペンのサイズが選択された時の設定
void Mainwindow::slot_change_PenSize()
{
	if(index==0) 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(r, g, b));
	qp.setBrush(QColor::QColor(r, g, b));
	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(r, g, b));
	pen.setCapStyle(Qt::RoundCap);
	
	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 );
}



// カラーダイアログの表示
void Mainwindow::slot_change_PenColor()
{
	c_dialog -> show();
}



// カラーダイアログからの色の受け付け
void Mainwindow::color_set()
{
	if((r != c_dialog -> r)||(g != c_dialog -> g)||(b != c_dialog -> b)){
		r = c_dialog -> r;
		g = c_dialog -> g;
		b = c_dialog -> b;
		
		color_view.fill(QColor::QColor(r, g, b));
		color_view_icon.setPixmap(color_view, QIconSet::Automatic);
		
		color -> setBackgroundColor(QColor::QColor(r, g, b));  // 「色」ボタンに現在の色が反映されていない問題の改善のために挿入
	}
}



// 新規作成
void Mainwindow::slot_new()
{
	buffer.fill(QColor::QColor(255, 255, 255));
	repaint();
}



void Mainwindow::closeEvent(QCloseEvent *e)
{
	c_dialog -> hide();
	e->accept();
}


(解説は、かきかけ)



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

#ifndef COLORDIALOG_H
#define COLORDIALOG_H

#include <qmainwindow.h>   // 使用するクラスを指定する
#include <qapplication.h>
#include <qtextcodec.h>
#include <qfont.h>
#include <qdialog.h>
#include <qpixmap.h>
#include <qpainter.h>
#include <qcolor.h>
#include <qimage.h>

class ColorDialog : public QDialog{
	Q_OBJECT

public:
	ColorDialog(QWidget *parent = 0, const char *name = 0, bool modal=FALSE);
	int r, g, b;

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

private:
	QTextCodec *codec; // テキストコーデック
	QPixmap c;
	
	int mx, my;
};

#endif //COLORDIALOG_H


(解説は、かきかけ)



<CPPファイル名 colordialog.cpp>

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

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

	// ダイアログのタイトルを設定
	setCaption(codec->toUnicode("色"));
	resize(217,172);

	// 使用するフォントを設定
	QFont f("lcfont",18);
	setFont(f);
	
	// カラーパターン画像を読み込む
	c.load("/mnt/card/color.bmp");
	
	r=0;
	g=0;
	b=0;
}



void ColorDialog::paintEvent( QPaintEvent * )
{
	QPainter p(this);
	p.drawPixmap( 0, 0, c );
}



// マウスがおされたときのイベント
void ColorDialog::mousePressEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
	
	if((mx>=0) && (my>=0) && (mx<217) && (my<172)){
		QRgb co = c.convertToImage().pixel(mx, my);
		r = qRed(co);
		g = qGreen(co);
		b = qBlue(co);
	}
}



// マウスがうごかされたときのイベント
void ColorDialog::mouseMoveEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
	
	if((mx>=0) && (my>=0) && (mx<217) && (my<172)){
		QRgb co = c.convertToImage().pixel(mx, my);
		r = qRed(co);
		g = qGreen(co);
		b = qBlue(co);
	}
}



// マウスがはなされたときのイベント
void ColorDialog::mouseReleaseEvent( QMouseEvent *e )
{
	mx = e -> QMouseEvent::x();  // マウスのX座標
	my = e -> QMouseEvent::y();  // マウスのY座標
	
	if((mx>=0) && (my>=0) && (mx<217) && (my<172)){
		QRgb co = c.convertToImage().pixel(mx, my);
		r = qRed(co);
		g = qGreen(co);
		b = qBlue(co);
	}
}


QRgb co = c.convertToImage().pixel(mx, my);

これで、ピクスマップ「c」上の(mx,my)座標の色を取得できます。
取得した色「co」の各色の成分は、

r = qRed(co);
g = qGreen(co);
b = qBlue(co);

という形で取得できます。

(解説は、かきかけ)




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


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



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



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




実行する場合は、画像ファイルを「/mnt/card/」においてください。
これで、手書きペイントとしてはそれなりの形になりましたね。今度は、いろんな形を描けるようにしてみましょう。
ちなみに、次々回には、画像ファイルとしての保存について扱ってみたいと思います。その次の回あたりでオリジナルのファイルリストから画像を読み込められるようにしたいですね。




<ソース>

sample0013.tar.gz




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






inserted by FC2 system