MFCでの電卓作成で質問です

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

MFCでの電卓作成で質問です

#1

投稿記事 by あっしゅ » 6年前

visual studio communityを導入し、参考書を見ながら日々C言語の勉強をしております。

学校でC++(MFC)を使って電卓を作るという課題が出まして、早速行き詰ってしまい頭を抱えております。
電卓のフォームは完成したのですが、

「ボタンを押した際にラベルに表示する」

これ単体では表示できるのですが(1や2や+や×など)、連続した数字や種類の違う数字を表示させることがまだできておりません。

参考までに1、とか2の数字の表示は色々なサイトを見ながら下記の2つの方法で今のところ試しています。

コード:

~~~略~~~

int z = 0;


void CMFCApplication1Dlg::OnBnClicked1()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	z = 10 * z;
	z = z + 1;

	gamen.SetWindowTextA("1"); 
}
	


void CMFCApplication1Dlg::OnBnClicked2()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	z = 10 * z;
	z = z + 2;

	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT2);
	pStatic->SetwindowtextA("2");
}


ボタンを押すたびに変数zを10倍して、そこに数値を足すというものです。

理想は1とか2とか入ってる場所に変数zを入れて表示させられれば理想なのですが、どうもうまくいきません。(ポインタの理解が足りていない?)

一番わかりやすいところですと

z=10*z;
z=z+5;
textBox1->Text=z.ToString();

のような表記をしていてわかりやすいのですが、MFCだとこれをそのまま使用できないようです。(textboxがないので、labelに当てはめてみてもうまくいかない)


上記のほかにわかりやすくて簡単に文字を入力する方法があれば教えていただきたいです。
また、数字を入力した後、四則演算子を押して表示させて、次の数との計算の方法のヒントもあれば教えていただきたいです。

宜しくお願いします。

かずま

Re: MFCでの電卓作成で質問です

#2

投稿記事 by かずま » 6年前

あっしゅ さんが書きました:理想は1とか2とか入ってる場所に変数zを入れて表示させられれば理想なのですが、どうもうまくいきません。(ポインタの理解が足りていない?)
ポインタの問題ではないでしょう。文字列を表示したいん
だったら、int の z を文字列に変換するだけのことです。

コード:

    char buf[32];
	sprintf_s(buf, 32, "%d", z);
	pStatic->SetWindowTextA(buf);

あっしゅ

Re: MFCでの電卓作成で質問です

#3

投稿記事 by あっしゅ » 6年前

かずま さんが書きました:
あっしゅ さんが書きました:理想は1とか2とか入ってる場所に変数zを入れて表示させられれば理想なのですが、どうもうまくいきません。(ポインタの理解が足りていない?)
ポインタの問題ではないでしょう。文字列を表示したいん
だったら、int の z を文字列に変換するだけのことです。

コード:

    char buf[32];
	sprintf_s(buf, 32, "%d", z);
	pStatic->SetWindowTextA(buf);
使っている環境でSetWindowTextAが使えないようなのでWにしました。
(WだとSetWindowText(L"buf");やSetWindowText(_T("buf"));になる)

pStatic->SetWindowTextA(buf);で実行しようとした場合は

「class "CStatic"にメンバー"SetTextWindowA"がありません」

と表示され、

pStatic->SetWindowText(buf);で実行しようとした場合は

「char buf[32]

型"char"の引数は型"LPCTSTR"のパラメーターと互換性がありません」

と表示されます。

コード:

/* 9が押された場合 */
void C電卓アプリDlg::OnBnClickedButton15()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	z = 10 * z;
	z = z + 9;
	
	char buf[32];
	sprintf_s(buf, 32, "%d", z);
	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
	pStatic->SetWindowTextW(_T("buf"));

}

このように修正した場合エラーがなく実行できたのですが、9のボタンを押した際、bufがそのまま表示されてしまいます。
これは変数ではなくて文字列がそのまま表示されてしまっているということなのでしょうか。
どうしたらよろしいでしょうか。

アバター
usao
記事: 1887
登録日時: 11年前

Re: MFCでの電卓作成で質問です

#4

投稿記事 by usao » 6年前

オフトピック
> pStatic->SetWindowTextW(_T("buf"));

「buf」 っていう文字列 を指定したら,結果として「buf」って表示されますよね.

#単なるうっかりミスなのか,そうではない状態なのか

あっしゅ

Re: MFCでの電卓作成で質問です

#5

投稿記事 by あっしゅ » 6年前

usao さんが書きました:
オフトピック
> pStatic->SetWindowTextW(_T("buf"));

「buf」 っていう文字列 を指定したら,結果として「buf」って表示されますよね.

#単なるうっかりミスなのか,そうではない状態なのか
そうですよね。いろいろエラーが出ないように模索中です。


pStatic->SetWindowTextA(buf);で実行しようとした場合は

「class "CStatic"にメンバー"SetTextWindowA"がありません」

と表示され、

pStatic->SetWindowText(buf);で実行しようとした場合は

「char buf[32]

型"char"の引数は型"LPCTSTR"のパラメーターと互換性がありません」

これが出てきてしまうので、これの解決方法を知りたいです。
宜しくお願いします

かずま

Re: MFCでの電卓作成で質問です

#6

投稿記事 by かずま » 6年前

ソリューションエクスプローラーで、プロジェクト名を
右クリックして、一番下のプロパティを選択。
構成プロパティの全般で、プロジェクトの規定値の文字セットが

- UNICODE文字セットを使用する
- マルチバイト文字セットを使用する

のどちらになっていますか?

マルチバイトなら SetWindowsTestA や char や "..."が使え
UNICODE なら SetWindowSTextW や wchar_t や L"..." が使えます。
どちらでもよい書き方が、
SetWindowsText や TCHAR や _T("...") です。

最初の質問で SetWindowsTextA が使えたというので
文字セットはマルチバイトだと思っていましたが、
No.3 では UNICODE になったのですか?

どちらでも使えるようにするには、

コード:

    TCHAR buf[32];
    _stprintf_s(buf, 32, _T("%d"), 123);
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
_stprintf_s も、sprintf_s か swprintf_s のどちらかになります。

かずま

Re: MFCでの電卓作成で質問です

#7

投稿記事 by かずま » 6年前

1行抜けました。

コード:

    TCHAR buf[32];
    _stprintf_s(buf, 32, _T("%d"), 123);
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
    pStatic->SetWindowText(buf);

あっしゅ

Re: MFCでの電卓作成で質問です

#8

投稿記事 by あっしゅ » 6年前

かずま さんが書きました:ソリューションエクスプローラーで、プロジェクト名を
右クリックして、一番下のプロパティを選択。
構成プロパティの全般で、プロジェクトの規定値の文字セットが

- UNICODE文字セットを使用する
- マルチバイト文字セットを使用する

のどちらになっていますか?

マルチバイトなら SetWindowsTestA や char や "..."が使え
UNICODE なら SetWindowSTextW や wchar_t や L"..." が使えます。
どちらでもよい書き方が、
SetWindowsText や TCHAR や _T("...") です。

最初の質問で SetWindowsTextA が使えたというので
文字セットはマルチバイトだと思っていましたが、
No.3 では UNICODE になったのですか?

どちらでも使えるようにするには、

コード:

    TCHAR buf[32];
    _stprintf_s(buf, 32, _T("%d"), 123);
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
_stprintf_s も、sprintf_s か swprintf_s のどちらかになります。

2種類の文字セットが存在したのですね…勉強になります。
家の環境ではマルチバイト、学校の環境ではUnicodeになっていたようです、お手数おかけしました。

無事に連続した数値やいろんな数字を表示させることができました。ありがとうございます。

質問なのですが、

TCHAR buf[32];
_stprintf_s(buf, 32, _T("%d"), 123);


ここの配列の32と123という数字はどのような意味があるのでしょうか?
実行時に10桁以上の数値(1111111111は表示できたので上限はわかりません)を入力したときに出力がおかしくなるのは数値の範囲が上限を超えているからなのでしょうか。

明日は四則演算の方にも挑戦してます。

ここでは簡単な計算と表示ができる電卓が完成するまで解決チェックせずに質問させていただきます。
宜しくお願いします。

かずま

Re: MFCでの電卓作成で質問です

#9

投稿記事 by かずま » 6年前

あっしゅ さんが書きました:ここの配列の32と123という数字はどのような意味があるのでしょうか?
32 ですが、4バイトの int は -2147483648~2147483647 の値なので負号も
含めて 11桁。文字列の終端の '\0' も入れて、12バイト確保すればいいん
ですが、2のべき乗のほうがキリがいいと思って 16にしようとしました。

しかし、int が 4バイトとは限らず、倍の 8バイトだとしたら、桁数も
倍になるとして、32 にしました。

123のほうは、本来 z と書くべきところを int だったらなんでもいいや
と、123 と書いてしまいました。

あっしゅ

Re: MFCでの電卓作成で質問です

#10

投稿記事 by あっしゅ » 6年前

かずま さんが書きました:
あっしゅ さんが書きました:ここの配列の32と123という数字はどのような意味があるのでしょうか?
32 ですが、4バイトの int は -2147483648~2147483647 の値なので負号も
含めて 11桁。文字列の終端の '\0' も入れて、12バイト確保すればいいん
ですが、2のべき乗のほうがキリがいいと思って 16にしようとしました。

しかし、int が 4バイトとは限らず、倍の 8バイトだとしたら、桁数も
倍になるとして、32 にしました。

123のほうは、本来 z と書くべきところを int だったらなんでもいいや
と、123 と書いてしまいました。

なるほどですね、参考になります。
そのデータ型ごとの数値の範囲が頭に入らないんですがなんかいい覚えた方でもありますかね?笑


かずまさんの教えを参考に簡単な四則演算ができる電卓が完成しました。ありがとうございます。

今はここ
http://www5b.biglobe.ne.jp/~suugaku/vc+ ... ai6wa.html

を参考しながら作成しているのですが、そのページの1つ前の

最後の3行は、=のボタンを押して後すべての値を0にしています。
これが、2×3=6とし、次に×5などとすると答えは0になってしまう原因です。
電卓では2→×→3→=→×5→=とおすと、30となりなります。
では皆さん、この欠点を改善して電卓と同じように動くようにするにはどうしたらよいでしょうか。

というところと、そのページ以降の小数点を含んだ表示がうまくいきません。
文字を1つ戻って消すキーと符号を反転させるキーもあるので、そこもアドバイスいただきたいです。よろしくお願いします。

以下、今作っているもののソースの一部です。
(小数点表示の部分はいじっていない状態のものです)

コード:


int yy;
int z = 0;
int w;


/* =が押された場合 */
void C電卓アプリDlg::OnBnClickedButton3()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
	{
		char buf[32];
		if (yy == 1) {
			sprintf_s(buf, 32, "%d", w + z);
			pStatic->SetWindowTextA(buf);
		}

		if (yy == 2) {
			sprintf_s(buf, 32, "%d", w - z);
			pStatic->SetWindowTextA(buf);
		}

		if (yy == 3) {
			sprintf_s(buf, 32, "%d", w*z);
			pStatic->SetWindowTextA(buf);
		}

		if (yy == 4) {
			sprintf_s(buf, 32, "%10.2f", ((double)w / (double)z));
			pStatic->SetWindowTextA(buf);
		}

		w = 0;
		z = 0;
		yy = 0;
	}
}

/* +が押された場合 */
void C電卓アプリDlg::OnBnClickedButton4()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	yy = 1;
	w = z;
	z = 0;
	gamenn.SetWindowTextA(_T("+"));
}

/* 1が押された場合 */
void C電卓アプリDlg::OnBnClickedButton5()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。	
	z = 10 * z;
	z = z + 1;
	CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
	char buf[32];
	sprintf_s(buf, 32, "%d", z);
	pStatic->SetWindowTextA(buf);
}

/* ACが押された場合 */
void C電卓アプリDlg::OnBnClickedButton17()
{
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	{
		z = 0;
		CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
		char buf[32];
		sprintf_s(buf, 32, "%d", z);
		pStatic->SetWindowTextA(buf);
	}
}

かずま

Re: MFCでの電卓作成で質問です

#11

投稿記事 by かずま » 6年前

あっしゅ さんが書きました:最後の3行は、=のボタンを押して後すべての値を0にしています。
これが、2×3=6とし、次に×5などとすると答えは0になってしまう原因です。
電卓では2→×→3→=→×5→=とおすと、30となりなります。
では皆さん、この欠点を改善して電卓と同じように動くようにするにはどうしたらよいでしょうか。
原因が分かっているのなら、対処できるでしょう。
w = 0; を削除してみてください。
あっしゅ さんが書きました:というところと、そのページ以降の小数点を含んだ表示がうまくいきません。
z と w を int ではなく、double にすればよいでしょう。
表示は、"%d" でも "%4.2f" でもなく、"%.15g"
あっしゅ さんが書きました:文字を1つ戻って消すキーと符号を反転させるキーもあるので、そこもアドバイスいただきたいです。
次のコードは、コンパイルもしていないので、エラーが出る
可能性がありますが、これを参考にできませんか?

コード:

int yy;
double z = 0;
double w;
 
// 次のメンバ関数を追加する
// ヘッダファイルの class C電卓アプリDlg にも宣言を追加する
void C電卓アプリDlg::SetWindowDouble(double x)
{
    char buf[32];
    sprintf_s(buf, 32, "%.15g", x);
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
    pStatic->SetWindowText(buf);
}

void C電卓アプリDlg::OnBnClickedButton3() /* =が押された場合 */
{
    if (yy == '+') w += z;
    else if (yy == '-') w -= z;
    else if (yy == '*') w *= z;
    else if (yy == '/') w /= z;
    else return;

    SetWindowDouble(w);

    // w = 0;
    z = 0;
    yy = 0;
}
 
void C電卓アプリDlg::OnBnClickedButton4() /* +が押された場合 */
{
    yy = '+';
    w = z;
    z = 0;
    gamenn.SetWindowText("+");
}
 
void C電卓アプリDlg::OnBnClickedButton5() /* 1が押された場合 */
{
    z = z * 10 + 1;
    SetWindowDouble(z);
}
 
void C電卓アプリDlg::OnBnClickedButton17() /* ACが押された場合 */
{
    w = z = 0;
    SetWindowDouble(0);
}

void C電卓アプリDlg::OnBnClickedButton18() /* 符号反転が押された場合 */
{
    z = -z
    SetWindowDouble(z);
}

void C電卓アプリDlg::OnBnClickedButton19() /* 一文字削除が押された場合 */
{
    char buf[32];
    CStatic* pStatic = (CStatic*)GetDlgItem(IDC_EDIT1);
    pStatic->GetWindowText(buf, 32);
    int len = strlen(buf);
    if (len > 0) buf[len-1] = '\0';
    z = atof(buf);  // #include <stdlib.h> はあるものとして
    SetWindowDouble(z);
}

かずま

Re: MFCでの電卓作成で質問です

#12

投稿記事 by かずま » 6年前

かずま さんが書きました: 次のコードは、コンパイルもしていないので、エラーが出る
可能性がありますが、これを参考にできませんか?
ちょっと間違っていたので、次のようにしてみてください。

yy, z, w はグローバル変数にせずに、
class C電卓アプリDlg のメンバ変数にしましょう。

コード:

class C電卓アプリDlg : CDialogEx
{

protected:
    int yy;
    double z;
    double w;
    bool input;

    void SetWindowDouble(double x);

};
そして、C電卓アプリDlg::OnInitDialog() で、
AC が押されたことにして初期化しましょう。

コード:

BOOL C電卓アプリDlg::OnInitDialog()
{

    // TODO: 初期化をここに追加します。
    OnBnClickedButton17();  // AC が押されたことにする

    return TRUE;
}

void C電卓アプリDlg::OnBnClickedButton3() /* =が押された場合 */
{
    input = false;

    if (yy == '+') w += z;
    else if (yy == '-') w -= z;
    else if (yy == '*') w *= z;
    else if (yy == '/') w /= z;
    else w = z;

    SetWindowDouble(w);
}
 
void C電卓アプリDlg::OnBnClickedButton4() /* +が押された場合 */
{
    if (input) OnBnClickedButton3();  // = を呼び出す
    yy = '+';
    gamenn.SetWindowText("+");
}
 
void C電卓アプリDlg::OnBnClickedButton5() /* 1が押された場合 */
{
    if (!input) {
        input = true;
        z = 0;
    }
    z = z * 10 + 1;
    SetWindowDouble(z);
}
 
void C電卓アプリDlg::OnBnClickedButton17() /* ACが押された場合 */
{
    input = false;
    yy = 0;
    w = z = 0;
    SetWindowDouble(0);
}
input は、現在、数字入力中かどうかを表しています。

返信

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