スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
MFC 円を描く 驚いた!!
MFCで円の描き方について。

さて、四角形の書き方は

CRectが四角形の情報を持てるので

CRect masu;
//四角形の情報登録後
pDC->Rectangle(&masu);


といった形で四角形を描きましたが、、、
なんと円は Rectangel を Ellipse に書き換えるだけ!!!
えーー CRect って四角形用のクラスじゃないの!!??
となるが、その四角形に納まるように円を書いてねという意味でしょうね。ということで、この関数で楕円も書けることに納得。

よって 円を書くには、

CRect masu;
//四角形の情報登録後
pDC->Ellipse(&masu);


となる。これで 先の15マスパズルを書き換えると
図のようになった。
ellipse.jpg

スポンサーサイト
MFC キー入力処理
キーボードの押されたキーで処理を分けたいときについて。

キーが押されたとき メッセージが発行されるので そのメッセージハンドラで処理する。よって使うのは「Class Wizard」

手順:
「表示」→「Class Wizard」→「WM_KEYDOWN」→、「関数の追加」→「コード編集」

これで、


void CKEY_TRAININGView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: この位置にメッセージ ハンドラ用の
//コードを追加するかまたはデフォルトの処理を呼び出してください
CView::OnKeyDown(nChar, nRepCnt, nFlags);
}



ができあがるので ここに キー入力に対する処理を書いてやる。

Aが押された Bが押された といったことは nCharに保存されているのでswitch文で各々に対する処理をわけてやれねばならない。
たぶん このOnKeyDown( )でやりたい全ての処理を書かず、別の関数を呼び出して処理を任せる形になると思う。

次に、例を示す


void CKEY_TRAININGView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: この位置にメッセージ ハンドラ用の
//コードを追加するかまたはデフォルトの処理を呼び出してください
CDC* pDC = GetDC();

switch(nChar) {
case VK_LEFT:
pDC->TextOut(5,5,"左が押されました");
break;
case VK_RIGHT:
pDC->TextOut(5,5,"右が押されました");
break;
case VK_UP:
pDC->TextOut(5,5,"上が押されました");
break;
case VK_DOWN:
pDC->TextOut(5,5,"下が押されました");
break;
case 'A':
pDC->TextOut(5,5,"Aが押されました");
default:
break;
}

CView::OnKeyDown(nChar, nRepCnt, nFlags);
}


アルファベットや←キーごとに 別々のメッセージが発行されるのではなく、このように全て同じメッセージが発行されるので、switch文で処理を分けるのがポイントのようである。

参考資料:
http://homepage3.nifty.com/mitui707/VisualC/VCfunctionkey.html/
裏画面 ~メモリデバイスコンテキスト~
うーむ MFCで画像を動かしたい! なんとしても動かさないといけない!

4時間粘りました・・・・

http://www.geocities.jp/chiakifujimon/makesoft2/proc3.html
http://www.ne.jp/asahi/hishidama/home/tech/vcpp/dc.html

色々探しにいって以上の2つがよいと思える。しかし、どうも腑に落ちないところもあったので 折衷案を考えました。

いきなりコードを示します


CDC* pDC = GetDC();
CDC memDC; //メモリDCを作成

CRect cClient;

memDC.CreateCompatibleDC(pDC);
GetClientRect(&cClient);//クライアント領域(窓の大きさを取ってくる)


//メモリDCの実体となるビットマップを作成
CBitmap memBmp;
memBmp.CreateCompatibleBitmap(pDC,
cClient.Width(),cClient.Height());

//メモリDCにビットマップを選択
CBitmap *pOldBmp=memDC.SelectObject(&memBmp);

//メモリDC(即ちビットマップ)に描画
memDC.FillSolidRect(0,0,cClient.Width(),
cClient.Height(),RGB(255,255,255));

//↓ここの間に描画処理を書く

//!!!メモリデバイスコンテキストに書き込むのが重要!!!
//つまり、memDC.Rectangle(); みたいに書く!!!!

//↑ここの間に描画処理を書く



//メモリDCの画像(即ちビットマップの内容)を実際の画面に転送
pDC->BitBlt(0,0,
cClient.Width(),cClient.Height(),&memDC,0,0,SRCCOPY);

//メモリDCのビットマップを戻す
memDC.SelectObject(pOldBmp);

//ビットマップを削除
memBmp.DeleteObject();

//メモリDCを削除
memDC.DeleteDC();

ReleaseDC( pDC );



直に画面(ウィンドウ)に書き込むのではなく 「裏画面」というところに書き込まないと、物体を動かした際、チラついてしまいます。これを回避するため頑張りました。
「裏画面」で検索するより「メモリデバイスコンテキスト」で検索した方が明らかに資料が多かったです。始からわかっていれば・・・

まあ それは置いておいて、少しだけ上のコードの説明を、

要は CDC *pDC で pDC->hoge( ) みたく描画していましたが、
前処理でメモリデバイスコンテキストを作って、そっちのメンバー関数で描画処理すると仮想的な画面(つまりメモリ)に書き込まれる。ということです。 ここでは、あくまで雛形を置くため、何故、直接画面に書き込みに行ってはいけないのかなどの説明は、はしょります すみません。

では、
//↓ここの間に描画処理を書く

//!!!メモリデバイスコンテキストに書き込むのが重要!!!
//つまり、memDC.Rectangle(); みたいに書く!!!!

//↑ここの間に描画処理を書く


の間に描画処理を書いたものをサンプルとして以下に載せます。これはSetTimer(1,10,NULL)により発行されたメッセージを受け取るメッセージハンドラとなっています。 では、長くなりますが、、、
C言語の乱数について
http://www9.plala.or.jp/sgwr-t/lib/srand.html
を参考に乱数について書かせてもらいます。


C言語で乱数を使いたいとき

時間を種にして、乱数を発生させるという処理が必要です。

時間の確保なんですが、

time(NULL)

で、できます。

そして 乱数の発生には srand( )という関数を使います。

よって 合わせて、

srand((unsigned) time(NULL));

という方法で、乱数を発生させます。

この2つの関数を呼び出すために、以下のように
2つのヘッダーをインクルードしなければなりません

#include <stdlib.h>
#include <time.h>


で、この乱数の取得方法なんですがちょっとだけコツがいります。

引用です
-------------------------
【使用例2】


#include <stdlib.h>
#include <stdio.h>
#include <time.h>

int main(void)
{
int i,j;

/* 乱数系列の変更 */
srand((unsigned) time(NULL));

/* 1~100の擬似乱数を10個ずつ10行発生 */
for (i=1; i<=10; i++) {
for (j=0; j<10; j++) {
printf("%3d ",rand()%100+1);
}
printf("\n");
}
return 0;
}


-------------------------


のように、プログラムの一番初めにsrand( )してやらなければなりません。

え!では どうやって複数の乱数を獲得するの??

と、なるのですが 
まあ、上記のソースに答えが載ってるんですが、

rand( )関数 を使います。

先ほどの2つに加えて必要なヘッダーファイルはないので
インクルードの心配は要りません。

srand( )をfor文の中に入れると はまります(泣)
初めて乱数を発生させたとき 何時間も悩みました・・・

上記の参考とさせていただいているサイトに詳しい説明がありますので詳しいことは そちらを参照していただきたいのですが、

ちょっと rand( )関数で なんで毎回違った数値を獲得できるか という僕なりの考えを書かせてもらうと、、、

srand((unsigned) time(NULL));

で、

(1,3,6,19,39,2,1,5,7)

みたいに 適当な乱数のリストが作られて
rand( )はそれを 呼ばれるたびに頭からとる関数と考えると 毎回違った数字を取ってくる理由がわかります。(もしかしたら間違ってるかもしれませんが・・・)

また、
rand( )の最大の返却値は 通常、
short int で表現できる最大値32767のようです。

参考資料:
http://www.st.rim.or.jp/~phinloda/cqa/cqa5.html
http://www005.upp.so-net.ne.jp/h-masuda/grwin/rand01.html

で、何故か32767だと、signed int型 なので 
rand( )の返却値の最小値は -32768 ではないのか? 
と思いきや!

最小値は 0 だったりする!!

ということで、C言語での乱数発生は なかなか手強い。。。。。
マウスクリックで描画処理
さて、マウスで左クリックされたら 描画処理をしたい!

http://www.geocities.co.jp/SiliconValley-Bay/4543/Osero/Osero/Osero-7.html

こちらの書式をそのまま適用させてもらうと、


CDC* pDC = GetDC(); //画面を再描画
NakanishiDraw( pDC );
ReleaseDC( pDC );



というのを マウスの左クリックがされたとき、
つまり、WM_LBUTTONDOUNメッセージを受け取ったとき処理するメッセージハンドラ(メンバー関数)に書けばよいことになる。

「表示」→「Class Wizard」で、

オブジェクトIDは「CDfdsfadfaView」(変な名前でごめんなさい 要はViewクラス)のままで、メッセージからWM_LBUTTONDOUNを選んで、「関数の追加」→「コード編集」で、
OnLButtonDownメンバー関数ができあがるので、


void CDfdsfadfaView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するか
//またはデフォルトの処理を呼び出してください
CDC* pDC = GetDC(); //画面を再描画
NakanishiDraw( pDC );
ReleaseDC( pDC );

CView::OnLButtonDown(nFlags, point);
}


としてやった。

なお、マウスのクリックでちゃんと処理されてるか確認したいため、
NakanishiDrawメンバー関数(自作したのね)に

static int mouse = 0;

と、1行宣言を足し。これを
四角形に描画される数字に変わるように書き換えてやる。
要は k の代わりに mouse にする。

全体ソースは以下

void CDfdsfadfaView::NakanishiDraw(CDC *pDC)
{
int tate=50,yoko=50;
int y=5,x=5;
int i,j;
int k=0;
static mouse=0;

CString str;
CRect masu;
CBrush *oldBrush, masuBrush;
COLORREF masuColor[4];

masu.left = x;
masu.top = y;
masu.right = x+yoko;
masu.bottom = y+tate;
pDC->Rectangle(&masu);
// 赤、緑、青、黄色を設定
masuColor[0] = RGB(255, 0, 0);
masuColor[1] = RGB(0, 255, 0);
masuColor[2] = RGB(0, 0, 255);
masuColor[3] = RGB(255, 255, 0);

//描画処理
for(i=0; i<4; i++){
for (j = 0; j < 4; j++)
{
masuBrush.CreateSolidBrush(masuColor[j]);
oldBrush = pDC->SelectObject(&masuBrush);
// 四角形を描画する。
pDC->Rectangle(&masu);
mouse++;
str.Format("%d",mouse);
pDC->DrawText(str, -1, &masu,
DT_SINGLELINE | DT_CENTER | DT_VCENTER);

// もとのブラシに戻す。
pDC->SelectObject(oldBrush);
masuBrush.DeleteObject();
masu.left += yoko;
masu.right += yoko;
}
//次の行へ座標更新
masu.left = x;
masu.top += tate;
masu.right = x + yoko;
masu.bottom += tate;
}
}


なお、ウィンドウを小さくするなどの処理も、
OnDraw関数が呼ばれているらしく、
そのたびに mouse++ されてるので 窓を小さくしたりすると
数字が増えまくるが、今回 僕がやりたいことには支障がないので
これでいく。

sikaku_mfc4.jpg



なお、支障があるなら、
NakanishiDrawメンバー関数の引数を

NakanishiDraw(CDC *pDC, int i)

などとして、引数として、

OnLButtonDownの方に

static int mouse = 0;
mouse++;

などして

void CDfdsfadfaView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: この位置にメッセージ ハンドラ用のコードを追加するか
//またはデフォルトの処理を呼び出してください
    static int mouse=0;
    mouse++;
CDC* pDC = GetDC(); //画面を再描画
NakanishiDraw( pDC , mouse);
ReleaseDC( pDC );

CView::OnLButtonDown(nFlags, point);
}


と してやればいいのではなかろうか?
あくまで試してないのでなんとも言えませんが。。。
ブログ検索

プロフィール

ビンゴ中西
Perlが好きである。
プログラミング言語のほとんどは独学。独学の過程で多くのプログラム仲間にも色々教わりました。

FC2カウンター

カレンダー

09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -

ブロとも申請フォーム

この人とブロともになる

| ホーム | 次のページ
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。