かなたん さんが書きました:C++の書き方―グローバル変数ではなく、クラスのメンバ変数にするってことですよね?
C++でそういうことをしたことはあるのですが、MFCではメンバ変数を作るということを習ってなくて、授業で先生もグローバル変数を使っていました。
グローバル変数だとそのcpp内のどこでも使えて、メンバ変数だとそのクラスでしか使えないんですよね?
グローバル変すよりもメンバ変数でって言うのは、範囲を制限した変数も使えるようになった方がいいとかってことですか?
MFCはC++で構成されたフレームワークライブラリにすぎませんので純粋なC++です。
グローバル変数で組んでしまうと1つしかインスタンスが作れませんので、継承や多数のインスタンスが作れない問題が出てきてしまいますよ。
小規模な内は良いかもしれませんが。
とりあえず動くようにして、チラつきを出来るだけ抑えてみました。
次の点が変わっています。
・こちらの都合で 落書きMusicView → MFCsdiView になっています。
・CDC canvasDC;がグローバル変数になっています。
・OnDrawでsetの方法の変更とpDC->BitBlt(0,0,500,500,&canvasDC,0,0,SRCCOPY);が毎回行われるようになっています。
・OnMouseMoveで描画時にInvalidate(); //再描画しています。
・OnTimerでif( playing ) Invalidate(); //再描画(というか線との合成)を指示に変更しました。
・OnEraseBkgndを追加して毎回背景クリアをしないようにしました。ゴミが残る部分はOnDrawで自分でクリアして下さい。
コード:
// MFCsdiView.cpp : CMFCsdiView クラスの実装
//
#include "stdafx.h"
#include "MFCsdi.h"
#include "MFCsdiDoc.h"
#include "MFCsdiView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
CRect button[12]; //ボタンの位置を記憶
COLORREF color[9]; //描画で使用できる色を記憶
int set_color=0; //何番目の色を使用するのか記憶
CRect canvas(0,0,500,500); //描画可能範囲を記憶
CBitmap canvas_Bit; //描画時等に使用したいビットマップ
CDC canvasDC; //ビットマップ読み込んだりとか用CDCを作成
bool paint=false; //描画可能かどうかを記憶
CPoint pointed; //移動前の座標を記憶
int timer; //なんとなくSetTimerの戻り値を受け取ってみる
int x,y; //線の座標等を記憶
bool set=false; //ビットマップを作成したかどうかを記憶
bool playing=false; //再生中かどうかを記憶
// CMFCsdiView
IMPLEMENT_DYNCREATE(CMFCsdiView, CView)
BEGIN_MESSAGE_MAP(CMFCsdiView, CView)
// 標準印刷コマンド
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview)
ON_WM_TIMER()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONUP()
ON_WM_KEYDOWN()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
// CMFCsdiView コンストラクション/デストラクション
CMFCsdiView::CMFCsdiView()
{
// TODO: 構築コードをここに追加します。
}
CMFCsdiView::~CMFCsdiView()
{
}
BOOL CMFCsdiView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: この位置で CREATESTRUCT cs を修正して Window クラスまたはスタイルを
// 修正してください。
return CView::PreCreateWindow(cs);
}
// CMFCsdiView 描画
void CMFCsdiView::OnDraw(CDC* pDC)
{
CMFCsdiDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: この場所にネイティブ データ用の描画コードを追加します。
CPen edge(PS_SOLID,1,RGB(0,0,0)); //画面を分割したいので黒いペンを作成
pDC->SelectObject(&edge);
pDC->MoveTo(500,0); //画面(500×600)を描画可能部分とボタン配置部分とに分けるように縦線を引く
pDC->LineTo(500,500);
for(int n=0;n<9;n++){ //9色のボタンを描画
CBrush pen(color[n]);
pDC->SelectObject(pen);
pDC->Ellipse(button[n]);
}
//以下3つのボタンは本来は(リソース内の)画像を使用しているが、今回は画像がなくても再現できるよう四角い図形を描くことに変更
CBrush white(RGB(255,255,255));
pDC->SelectObject(&white);
pDC->Rectangle(button[9]);
CBrush red(RGB(255,0,0));
pDC->SelectObject(&red);
pDC->Rectangle(button[10]);
CBrush blue(RGB(0,0,255));
pDC->SelectObject(&blue);
pDC->Rectangle(button[11]);
//変更ここまで
if(set==false){ //ビットマップを作成していないなら
canvasDC.CreateCompatibleDC(pDC);
canvas_Bit.CreateCompatibleBitmap(pDC,500,500); //ビットマップ作成
CPen white(PS_SOLID,1,RGB(255,255,255));
canvasDC.SelectObject(&white);
canvasDC.SelectObject(&canvas_Bit); //ビットマップを読み込んで
canvasDC.Rectangle(canvas); //白く塗っておく 出ないと再生時にその部分が真っ黒に・・・;
set=true;
}
// 毎回画面にコピーして
pDC->BitBlt(0,0,500,500,&canvasDC,0,0,SRCCOPY);
if(playing==true){ //再生中なら
CPen line(PS_SOLID,5,RGB(0,0,0));
pDC->SelectObject(line);
pDC->MoveTo(x,0); //その上から縦線を引く
pDC->LineTo(x,500);
}
}
// CMFCsdiView 印刷
BOOL CMFCsdiView::OnPreparePrinting(CPrintInfo* pInfo)
{
// 既定の印刷準備
return DoPreparePrinting(pInfo);
}
void CMFCsdiView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 印刷前の特別な初期化処理を追加してください。
}
void CMFCsdiView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: 印刷後の後処理を追加してください。
}
// CMFCsdiView 診断
#ifdef _DEBUG
void CMFCsdiView::AssertValid() const
{
CView::AssertValid();
}
void CMFCsdiView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMFCsdiDoc* CMFCsdiView::GetDocument() const // デバッグ以外のバージョンはインラインです。
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCsdiDoc)));
return (CMFCsdiDoc*)m_pDocument;
}
#endif //_DEBUG
// CMFCsdiView メッセージ ハンドラ
void CMFCsdiView::OnInitialUpdate()
{
CView::OnInitialUpdate();
// TODO: ここに特定なコードを追加するか、もしくは基本クラスを呼び出してください。
color[0]=RGB(255,0,0); //描画時に使用できる色を設定
color[1]=RGB(255,95,0);
color[2]=RGB(255,255,0);
color[3]=RGB(0,255,0);
color[4]=RGB(0,128,0);
color[5]=RGB(0,255,255);
color[6]=RGB(0,0,255);
color[7]=RGB(255,0,255);
color[8]=RGB(255,255,255);
for(int n=0;n<12;n++){ //ボタンの座標を設定
button[n].top=4+n*41;
button[n].bottom=44+n*41;
button[n].left=530;
button[n].right=570;
}
}
void CMFCsdiView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
CView::OnLButtonDown(nFlags, point);
for(int n=0;n<9;n++){
if(PtInRect(button[n],point)==1){ //色のボタンが押されたら
set_color=n; //使用する色の番号を変更
}
}
if(PtInRect(button[9],point)==1){ //今までの描画をすべてクリアするためのボタンが押されたら
CPen white(PS_SOLID,1,RGB(255,255,255));
canvasDC.SelectObject(&white);
canvasDC.SelectObject(&canvas_Bit); //ビットマップとともに
canvasDC.Rectangle(canvas); //描画範囲を白く塗りつぶす
}
if(PtInRect(button[10],point)==1){ //再生ボタンが押されたら
x=0; //初期座標を左上に設定し
y=0;
playing=true; //再生中だといい
timer=SetTimer(1,100,NULL); //タイマー作動
}
if(PtInRect(button[11],point)==1){ //停止ボタンが押されたら
playing=false; //再生中でないといい
timer=KillTimer(1); //タイマー停止
}
if(PtInRect(canvas,point)==1){ //描画可能範囲が押されたら
paint=true; //描画可能だといい
pointed=point; //今の座標は次には過去のもの
}
}
void CMFCsdiView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
CView::OnMouseMove(nFlags, point);
if(paint==true&&PtInRect(canvas,point)==1){ //描画可能で範囲内なら
CPen pen(PS_SOLID,5,color[set_color]); //今の色のペンを作成し
canvasDC.SelectObject(&pen);
canvasDC.SelectObject(&canvas_Bit); //ビットマップとともに
canvasDC.MoveTo(pointed); //前の座標から今の座標まで線を引く
canvasDC.LineTo(point);
pointed=point; //今の座標は次には過去のもの
Invalidate(); //再描画
}
if(PtInRect(canvas,point)!=1){ //範囲外なら
paint=false; //描画不可にする
}
}
void CMFCsdiView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
CView::OnLButtonUp(nFlags, point);
paint=false; //マウスの左ボタンが離されたら描画不可にする
}
void CMFCsdiView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
CView::OnTimer(nIDEvent);
if( playing ) Invalidate(); //再描画(というか線との合成)を指示
COLORREF get_color; //取得した色を記憶
if((x%5)==0){
for(y=0;y<500;y++){
get_color=canvasDC.GetPixel(x,y); //指定の座標の色を取得
if(get_color==RGB(255,0,0)){ //色によってきまった音を鳴らしたい
;//c4
}
else if(get_color==RGB(255,98,0)){
;//d4
}
else if(get_color==RGB(255,255,0)){
;//e4
}
else if(get_color==RGB(0,255,0)){
;//f4
}
else if(get_color==RGB(0,128,0)){
;//g4
}
else if(get_color==RGB(0,255,255)){
;//a4
}
else if(get_color==RGB(0,0,255)){
;//b4
}
else if(get_color==RGB(255,0,255)){
;//c5
}
}
}
if(x<500){ //終わりでないなら
x++; //次へ行く
}
else{ //終わりなら
x=0; //先頭へ戻る
}
}
BOOL CMFCsdiView::OnEraseBkgnd(CDC* pDC)
{
// TODO: ここにメッセージ ハンドラ コードを追加するか、既定の処理を呼び出します。
// 背景のクリアを抑止する。
//return CView::OnEraseBkgnd(pDC);
return FALSE;
}