簡易ペイント

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
kokosan60

簡易ペイント

#1

投稿記事 by kokosan60 » 16年前

現在、簡易ペイントプログラムを作成しているのですが、
点、線、円、四角形を選択するときに、
1度選択して1回描画してしまったら再度選択しなければ
描画されません。
1度選択したらほかのものを選択するまでは描画可能にするには
どのようにすればいいのでしょうか。
ヒントのみでもかまいません。
よろしくお願いします。

環境
Windows XP SP3
Visual Studio 2005

プログラム
#include "dxLib.h"
#include <math.h>

#define N 20 /*メニュー縦*/
#define M 55 /*メニュー横*/
#define COLOR_TYPE 4 /*色の種類*/
#define MENU_TYPE 6 /*メニューの種類*/
#define COLOR_PLACE 121 /*カラー変更Y座標上*/

int string_color;/*文字列色*/
int menu_color;/*メニュー背景色*/
int menu_out_color;/*メニュー枠色*/
char *string[/url]={"点","線","円","四角形","クリア","終了"};/*メニュー文字列*/
int color_type[COLOR_TYPE]; /*色*/
int loop_flag=0; /*終了フラグ*/
int color=0; /*色番号*/
int menu; /*現在のメニュー番号*/


void menu_display();
void Color(int m_x,int m_y);
void Menu(int menu);
void square();
void circle();

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
				   LPSTR lpCmdLine,int nShowCmd){

	int i;/*ループ変数*/
	int m_x,m_y; /*終了時マウス座標*/

	/*初期化*/
	SetMainWindowText("簡易ペイント");
	ChangeWindowMode(TRUE);
	SetBackgroundColor(255,255,255);
	if(DxLib_Init()==-1) return -1;
	SetDrawScreen(DX_SCREEN_BACK);

	/*色取得*/
	string_color=GetColor(0,0,0);
	menu_color	=GetColor(127,127,127);
	menu_out_color=GetColor(255,255,255);
	color_type[0]=GetColor(0,0,0);
	color_type[1]=GetColor(255,0,0);
	color_type[2]=GetColor(0,255,0);
	color_type[3]=GetColor(0,0,255);
	
	while(ProcessMessage()==0){
		while(1){
			/*エラー*/
			if(ProcessMessage()==-1){
				DxLib_End();
					exit(1);
			}

			menu_display();
			
			if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
				/*マウス座標取得*/
				GetMousePoint(&m_x,&m_y);

				if(1<=m_x&&54>=m_x){

					/*点*/
					if(1<=m_y&&19>=m_y){
						menu=0;
					}

					/*線*/
					if(21<=m_y&&39>=m_y){
						menu=1;
					}

					/*円*/
					if(41<=m_y&&59>=m_y){
						menu=2;
					}

					/*四角形*/
					if(61<=m_y&&79>=m_y){
						menu=3;
					}

					/*画面クリア*/
					if(81<=m_y&&99>=m_y){
						menu=4;
					}

					/*終了*/
					if(101<=m_y&&119>=m_y){
						menu=5;
					}
					if(120<=m_y&&199>=m_y){
						menu=6;
						Color(m_x,m_y);
					}
					if(menu!=6){ 
						Menu(menu);
					}

				}
			}
		}

	}
	
	DxLib_End();
	return 0;
}

/*メニュー表示関数*/
void menu_display(){
	int i;
	/*メニュー表示*/
	for(i=0;i<MENU_TYPE;i++){
		DrawBox(0,N*i,M,N*(i+1),menu_color,TRUE);
		DrawBox(0,N*i,M,N*(i+1),menu_out_color,FALSE);
		DrawString(2,N*i+2,string,string_color);
	}

	/*色表示*/
	for(i=0;i<COLOR_TYPE;i++){
		DrawBox(1,COLOR_PLACE+N*i,M-1,COLOR_PLACE+N*(i+1),color_type,TRUE);
	}
	ScreenFlip();
}

/*色変更関数*/
void Color(int m_x,int m_y){
	/*黒*/
	if(1<=m_x&&54>=m_x&&121<=m_y&&140>=m_y){
		color=0;
	}

	/*赤*/
	if(1<=m_x&&54>=m_x&&141<=m_y&&160>=m_y){
		color=1;
	}

	/*緑*/
	if(1<=m_x&&54>=m_x&&161<=m_y&&180>=m_y){
		color=2;
	}

	/*青*/
	if(1<=m_x&&54>=m_x&&181<=m_y&&2000>=m_y){
		color=3;
	}
}

kokosan60

Re:簡易ペイント

#2

投稿記事 by kokosan60 » 16年前

プログラム続き
void Menu(int menu){
	int x1,x2,y1,y2; /*描画時マウス座標*/
	switch(menu){
		case 0:
			do{
				WaitKey();
				/*左クリック中*/
				while((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
					GetMousePoint(&x1,&y1);
					/*点描画*/
					if(!(0<=x1&&55>=x1)){
						DrawPixel(x1,y1,color_type[colo[/url]);
						ScreenFlip();
					}else{
						Color(x1,y1);
					}

				}
			}while(0<=x1&&55>=x1);
			break;
		case 1:
			/*始点*/
			do{
				if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
					GetMousePoint(&x1,&y1);
				}
				if(0<=x1&&55>=x1) Color(x1,y1);
			}while(0<=x1&&55>=x1);
			WaitKey();
			/*終点*/
			do{
				if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
					GetMousePoint(&x2,&y2);
				}
				if(0<=x1&&55>=x1) Color(x1,y1);
			}while(0<=x2&&55>=x2);

			/*線描画*/
			DrawLine(x1,y1,x2,y2,color_type[colo[/url]);
			ScreenFlip();
			break;
		case 2:
			circle();
			break;
		case 3:
			square();
			break;
		case 4:
			DrawBox(55,0,641,481,menu_out_color,TRUE);
			break;
		case 5:
			DxLib_End();
			exit(0);
			break;
		default:
			DxLib_End();
			exit(1);
	}
}

/*円描画関数*/
void circle(){
	int x1,x2,y1,y2; /*描画時マウス座標*/
	int c_x,c_y; /*中心座標*/
	int r; /*半径*/
	/*始点*/
	do{
		if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
			GetMousePoint(&x1,&y1);
		}
		if(0<=x1&&55>=x1) Color(x1,y1);
	}while(0<=x1&&55>=x1);
	WaitKey();
	/*終点*/
	do{
		if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
			GetMousePoint(&x2,&y2);
		}
		if(0<=x1&&55>=x1) Color(x1,y1);
	}while(0<=x2&&55>=x2);

	/*中心、半径計算*/
	c_x=(x1+x2)/2;
	c_y=(y1+y2)/2;
	r=(int)sqrt(pow((x1-x2),2.0)+pow((y1-y2),2.0))/2;

	/*円描画*/
	DrawCircle(c_x,c_y,r,color_type[colo[/url],FALSE);
	DrawBox(0,0,55,480,menu_out_color,TRUE);
	menu_display();
	ScreenFlip();
}

/*四角形描画関数*/
void square(){
	int x1,x2,y1,y2; /*描画時マウス座標*/
	/*始点*/
	do{
		if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
			GetMousePoint(&x1,&y1);
		}
		if(0<=x1&&55>=x1) Color(x1,y1);
	}while(0<=x1&&55>=x1);
	WaitKey();
	/*終点*/
	do{
		if((GetMouseInput()&MOUSE_INPUT_LEFT)!=0){
			GetMousePoint(&x2,&y2);
		}
		if(0<=x1&&55>=x1) Color(x1,y1);
	}while(0<=x2&&55>=x2);

	/*四角形描画*/
	DrawBox(x1,y1,x2,y2,color_type[colo[/url],FALSE);
	ScreenFlip();
}

MNS

Re:簡易ペイント

#3

投稿記事 by MNS » 16年前

プログラムの構造が悪いのだと思います。

 ⇒ユーザーが、x座標が1以上54以下の場所をクリック
 ⇒y座標によってmenuの値を決定
 ⇒menuの値によって条件分岐
 ⇒(例えば、点を選択した場合)ユーザーから入力を待つ
 ⇒マウスの位置が不正でなければ、点を描画
 ⇒ループを抜ける

このような構造になっているため、
ユーザーがx座標が1以上54以下の場所をクリックしない限り、
絵を描く処理が行われません。

基盤となるループの中に、また新たなループが作られているため、
(そもそも、ループの中にWaitKeyがあるのはどうなんでしょう)
プログラムの基盤となるループが活かされて無いと思います。

正直、このプログラムの構造でその問題を解決するのは難しいのではないのでしょうか。
一つのアプローチとして、
if(1<=m_x&&54>=m_x){

	~略~

}
else if(menu >= 0 && menu <= 6) Menu(menu);

とやることでこの問題は回避可能かもしれませんが、
抜本的な解決とは成らないと思いますし、
いずれまた問題が生じるだろうと予測できるため、
プログラムの構造を見直すことをお勧めいたします。

kokosan60

Re:簡易ペイント

#4

投稿記事 by kokosan60 » 16年前

返信有難うございます。
確かにプログラムの構造自体が原因のようです。
最初からプログラムの構造を見直したいと思います。

ねこ

Re:簡易ペイント

#5

投稿記事 by ねこ » 16年前

何か書いてたら終わっちゃってた・・・一応張っておこう、ペタペタ

○ whileの外に追加
menu = 0;
int sts = 0;

typedef struct {
	int type;
	int x1;
	int y1;
	int x2;
	int y2;
	int r;
	int color;
} DRAW_DATA;

DRAW_DATA g_ArrDrawData[ 200 ];
int g_iDrawCnt = 0;

BOOL g_bPrevMouse = FALSE;

======================================
=処理部分に追加
======================================
menu_display();

for( int ii = 0; ii < g_iDrawCnt; ii++ )
{
	DRAW_DATA DrawData = g_ArrDrawData[ ii ];
	switch( DrawData.type )
	{
	case 0: // 点
		DrawPixel( DrawData.x1, DrawData.y1, DrawData.color );
		break;
	case 1:	// 線
		DrawLine( DrawData.x1, DrawData.y1, DrawData.x2, DrawData.y2, DrawData.color );
		break;
	}
}
// 線分の補助表示
if( menu == 1 && sts == 1 )
{
	int x = 0; int y = 0;
	GetMousePoint( &x, &y );
	DrawLine( g_ArrDrawData[ g_iDrawCnt ].x1, g_ArrDrawData[ g_iDrawCnt ].y1, x, y, color_type[ color ] );
}	

int Mouse = GetMouseInput() & MOUSE_INPUT_LEFT;
if( Mouse && g_bPrevMouse == 0 )
{
	GetMousePoint( &m_x, &m_y );
	if(1<=m_x&&54>=m_x)
	{
		/*点*/
		if(1<=m_y&&19>=m_y){
			menu=0;
		}
			/*線*/
		if(21<=m_y&&39>=m_y){
			menu=1;
		}
			/*円*/
		if(41<=m_y&&59>=m_y){
			menu=2;
		}
			/*四角形*/
		if(61<=m_y&&79>=m_y){
			menu=3;
		}
			/*画面クリア*/
		if(81<=m_y&&99>=m_y){
			menu=4;
		}
			/*終了*/
		if(101<=m_y&&119>=m_y){
			menu=5;
		}
			if(120<=m_y&&199>=m_y){
			menu = 6;
			Color(m_x,m_y);
		}
		/*
		if( menu != 6 ){ 
			Menu( menu );
		}
		*/
	}
	else
	{
		switch( menu )
		{
		case 0:
			g_ArrDrawData[ g_iDrawCnt ].type = 0;
			g_ArrDrawData[ g_iDrawCnt ].x1   = m_x;
			g_ArrDrawData[ g_iDrawCnt ].y1   = m_y;
			g_ArrDrawData[ g_iDrawCnt ].color= color_type[colo[/url];
			g_iDrawCnt++;
			break;
		case 1:
			if( sts == 0 )
			{
				g_ArrDrawData[ g_iDrawCnt ].type = 1;
				g_ArrDrawData[ g_iDrawCnt ].x1   = m_x;
				g_ArrDrawData[ g_iDrawCnt ].y1   = m_y;
				sts = 1;
			}
			else
			{
				g_ArrDrawData[ g_iDrawCnt ].x2   = m_x;
				g_ArrDrawData[ g_iDrawCnt ].y2   = m_y;
				g_ArrDrawData[ g_iDrawCnt ].color= color_type[colo[/url];
				g_iDrawCnt++;
				sts = 0;
			}
		}
	}
}
g_bPrevMouse = Mouse;

ScreenFlip();

ねこ

Re:簡易ペイント

#6

投稿記事 by ねこ » 16年前

スレッドには関係無いのですが、管理人様へ

添付のファイルサイズ上限ってあげれないのでしょうか。
DXLIB使ってるとデフォルトでコンパイルしても500KBくらいになるので、800~1MBくらいまで許容されるとEXEも同梱出来てわかりやすいかなぁと思うのですが、どうでしょう?

DVDM

Re:簡易ペイント

#7

投稿記事 by DVDM » 16年前

>>ねこさん
1MBくらいなら登録制(無料)ですがこちらは如何でしょう。
http://www.uploader.jp/ は長期間保存で15MBまでならアップロードできます。

ねこ

Re:簡易ペイント

#8

投稿記事 by ねこ » 16年前

>DVDM様
おお、わざわざありがとうございます。

ロダはそのうち消えるもんかと思ってました。よく調べ物で添付は消えてるパターン多かったので^^;
実行ファイルあたりはロダ推奨って認識が普通なんでしょうか。
掲示板側が無理でしたら是非使わせてもらいます~。

DVDM

Re:簡易ペイント

#9

投稿記事 by DVDM » 16年前

>>ねこさん
>実行ファイルあたりはロダ推奨って認識が普通なんでしょうか。
良く使われているのは、一時的にファイルが上げられる場所を提供して頂けるからではないでしょうか。
パスワード等の設定や容量的な問題もクリアできるサーバーがあるため使いやすいのではいかなぁと思います。

ここの掲示板は添付ファイルが過去ログに行くと消える仕組みだったような気がします。
添付ファイルを残しておきたいのであれば、上記のような長期間保存に対応したアップローダをお使い頂くか
HPを作成してアップロードするなどがいいのではないでしょうか。
私はそうしています。

ねこ

Re:簡易ペイント

#10

投稿記事 by ねこ » 16年前

あ、過去ログいくと消えちゃうんですね^^;それじゃぁ駄目か。
折角添付機能があるのにな~と思っての質問でした。

回答ありがとうございます。

やそ

Re:簡易ペイント

#11

投稿記事 by やそ » 16年前

void Color(int m_x,int m_y)
について。

この関数で塗る色をセットしているようですが、戻り値がvoidって大丈夫?
かと思ったら、変数colorがグローバル変数だったのね^^;
余計な心配でした。

if(1<=m_x&&54>=m_x&&181<=m_y&&2000>=m_y){
は2000じゃなくて200じゃないですか?

座標判定のif文はもう少しスッキリ!できそうです。
void Color(int m_x,int m_y){

    if(1<=m_x&&54>=m_x&&121<=m_y&&200>=m_y)/* 範囲に入っていれば */
	    	color=(m_y - 121)/20;    /* 0 - 3 を計算      */
}
とか?
【検証】
(121 -121)/20 ・・・  0/20 = 0
(140 -121)/20 ・・・ 19/20 = 0
(141 -121)/20 ・・・ 20/20 = 1
(160 -121)/20 ・・・ 39/20 = 1
(161 -121)/20 ・・・ 40/20 = 2
(180 -121)/20 ・・・ 59/20 = 2
(181 -121)/20 ・・・ 60/20 = 3
(200 -121)/20 ・・・ 79/20 = 3

という強引な計算式です。

閉鎖

“C言語何でも質問掲示板” へ戻る