【課程設(shè)計(jì)|C++】C++程序設(shè)計(jì)基礎(chǔ):計(jì)算器(MFC)
1.設(shè)計(jì)目的和內(nèi)容
1.1.設(shè)計(jì)目的
學(xué)習(xí)Visual C++的MFC開發(fā)程序的步驟。 綜合運(yùn)用所學(xué)的類、繼承和多態(tài)的知識。 進(jìn)一步掌握程序的調(diào)試方法。
1.2.設(shè)計(jì)內(nèi)容
利用MFC的向?qū)В瑒?chuàng)建基于單文檔的應(yīng)用程序; 實(shí)現(xiàn)簡單的四則運(yùn)算 進(jìn)行科學(xué)運(yùn)算,如log、tan、sin 多項(xiàng)式運(yùn)算
2.基本功能描述
2.1.工程的新建
打開Microsoft?Visual?C++?6.0
點(diǎn)擊File?—>?New
在Projects中選擇?MFC?AppWizard?(exe)?;
在?Project?name中輸入工程的名字Graphic,在?Location中選擇工程存放的路徑,填完后點(diǎn)擊OK按鈕。

(如圖1)填完后點(diǎn)擊OK按鈕,彈出對話框(如圖2)。

彈出來的對話框中我們可以選擇生成三種不同類型的應(yīng)用程序
單文檔 多文檔 對話框。
單文檔程序如記事本,在一個(gè)應(yīng)用程序中只能對一個(gè)文檔進(jìn)行操作,降低了編程的復(fù)雜度并減少了運(yùn)行程序時(shí)所需的資源。對某些小型應(yīng)用(比如文本編輯器或小型圖像編輯器)可以采用這種類型的窗口應(yīng)用程序。
在這個(gè)程序中,我們就需要單文檔,選擇完后點(diǎn)擊Next,設(shè)置默認(rèn),最后點(diǎn)擊Finish,
完成工程的創(chuàng)建。
2.2.單對話框簡介
生成單文檔程序后,進(jìn)行編譯
再運(yùn)行,我們可以看到以下的結(jié)果。

2.3 界面布局
利用MFC自帶的按鈕、編輯框等組件,設(shè)計(jì)出計(jì)算器的初始界面。

3.設(shè)計(jì)思路
計(jì)算器的整個(gè)思想就是通過圖形化界面,獲取用戶進(jìn)行的操作和輸入的數(shù)據(jù),并按照要求進(jìn)行相應(yīng)的數(shù)字邏輯運(yùn)算。
設(shè)計(jì)的要素就是通過按下不同的按鈕,程序可以獲取不同的數(shù)值,同時(shí)判斷數(shù)的位置,最后通過確定鍵的確認(rèn),在屏幕上輸出答案。
設(shè)計(jì)的難點(diǎn)有幾個(gè)。
第一,數(shù)值的確定與傳統(tǒng)方法不一樣,比如,我們在計(jì)算器中輸入123,按下的鍵依次是1,2,3.而每次讀出的數(shù)據(jù)也是相應(yīng)的單數(shù)字。
為此獲取到的數(shù)字為123,我們必須設(shè)計(jì)一個(gè)算法,即每次輸入數(shù)之前,先用前一次的數(shù)(第一次的數(shù)為0)乘以10,加上剛剛按下的數(shù)。
在按下符號鍵或復(fù)位鍵時(shí),flag變換,標(biāo)記是否數(shù)字輸入完畢。同時(shí)符號鍵的設(shè)計(jì)也就是簡單的為一個(gè)符號變量賦值,因?yàn)槌绦蚴枪潭ǖ倪M(jìn)行兩個(gè)數(shù)的運(yùn)算,只是中間的符號不同。
在這里有點(diǎn)區(qū)別的是,常規(guī)符號如此,科學(xué)運(yùn)算符號并不如此。一般的科學(xué)運(yùn)算數(shù)只有一位,所以在進(jìn)行科學(xué)運(yùn)算的時(shí)候,需要特別標(biāo)記。
多項(xiàng)式運(yùn)算采用的是中綴算法,也就是先對輸入的多項(xiàng)式進(jìn)行中綴變換,然后利用中綴優(yōu)先級法則進(jìn)行運(yùn)算。這里是整個(gè)計(jì)算器設(shè)計(jì)的難點(diǎn)。
4.軟件設(shè)計(jì)
4.1.設(shè)計(jì)步驟及關(guān)鍵代碼
①所需變量的定義與聲明
m_display2 = 0.0;
num1 = 0;
num2 = 0;
result = 0.0;
str = "";
str_flag = FALSE;
continue_flg = FALSE;
downDot = FALSE;
count = 1;
//{{AFX_DATA_INIT(CMyDlg)
m_display = _T("");
m_display1 = 0.0;
m_display2 = 0.0;
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
②判斷數(shù)值是否結(jié)束
double CMyDlg::buttonDownNum(int numSize)
{
if (!str_flag) //運(yùn)算符沒有被按下,那就是num1
{
if (!continue_flg) //按下一次
{
num1 = numSize;
continue_flg = TRUE;
}
else
{
num1 = num1 * pow(10, count) + numSize;
if (downDot)
{
num1 = num1 / (pow(10, count));
count++;
}
}
return num1;
}
else //有運(yùn)算符被按下
{
if (!continue_flg) //是否連續(xù)按下
{
num2 = numSize;
continue_flg = TRUE;
}
else
{
num2 = num2 * pow(10, count) + numSize;
if (downDot)
{
num2 = num2 / (pow(10, count));
count++;
}
}
return num2;
}
}
③優(yōu)先級判斷
void CMyDlg::OnButton1()
{
UpdateData(true);
CString aa = m_display;
Stack<int> number; //數(shù)字棧
Stack<char> character; //運(yùn)算符棧
character.Push('=');
// CString aa="1+(1*2)+2#";
int numaa = strlen(aa);
int kk = 0;
//cout<<numaa;
int ch = aa[kk++];
// int ch = getchar();
//它從標(biāo)準(zhǔn)輸入里讀取下一個(gè)字符。返回類型為int型,返回值為用戶輸入的ASCⅡ碼,出錯(cuò)返回-1,比如輸入a ,返回97,輸入3,返回51
char b;
b = static_cast<char>(ch); //b是ch轉(zhuǎn)換的字符
while (b != '=' || character.getTop() != '=')
{
if (ch > 48 && ch <= 57)
{ //這里非常容易寫錯(cuò)啊!不是ch>0 && ch<=9,或者b>0 && b<=9;
number.Push(ch - 48);
ch = aa[kk++]; // getchar();
b = static_cast<char>(ch);
}
else
{
switch (Priority(character.getTop(), b))
{
case '<': //棧頂元素優(yōu)先級低
character.Push(b);
ch = aa[kk++]; //getchar();
b = static_cast<char>(ch);
break;
case '=': //脫一個(gè)'('括號 并且接收下一個(gè)字符
character.Pop();
ch = aa[kk++]; //getchar();
b = static_cast<char>(ch);
break;
case '>': //出棧并且把運(yùn)算結(jié)果入棧
number.Push(Compute(number.Pop(), number.Pop(), character.Pop()));
/*int result=number.Pop()+number.Pop();
cout<<result;
number.Push(result);*/
break;
}
}
}
// cout<<"運(yùn)算結(jié)果是"<<" "<<number.getTop()<<'\n';
// cout<<"運(yùn)算結(jié)果是:"<<number.getTop()<<endl;
//printf("運(yùn)算結(jié)果是 %d \n",number.getTop());
// CString bb=CString.Format(_T("%d"),2);
m_display1 = number.getTop();
UpdateData(false);
//return 0;
}
④優(yōu)先級設(shè)計(jì)
char CMyDlg::Priority(char ch1, char ch2)
{
int a;
int b;
switch (ch1)
{
case '#':
a = 0;
break;
case '(':
a = 1;
break;
case '+':
a = 3;
break;
case '-':
a = 3;
break;
case '*':
a = 5;
break;
case '/':
a = 5;
break;
case '%':
a = 5;
break;
case '^':
a = 7;
break;
case ')':
a = 8;
break;
}
switch (ch2)
{
case '#':
b = 0;
break;
case '(':
b = 8;
break;
case '+':
b = 2;
break;
case '-':
b = 2;
break;
case '*':
b = 4;
break;
case '/':
b = 4;
break;
case '%':
b = 4;
break;
case '^':
b = 6;
break;
case ')':
b = 1;
break;
}
if (a < b)
return '<';
else if (a == b)
return '=';
else
return '>';
}
⑤多項(xiàng)式結(jié)果運(yùn)算
int CMyDlg::Compute(int a, int b, char sign)
{
int result;
switch (sign)
{
case '+':
result = a + b;
break;
case '-':
result = a - b;
break;
case '*':
result = a * b;
break;
case '/':
result = a / b;
break;
case '%':
result = a % b;
break;
case '^':
result = a ^ b;
break;
}
return result;
// TODO: Add your control notification handler code here
}
⑥常規(guī)按鈕
void CMyDlg::OnButton2()
{
m_display2 = buttonDownNum(1);
UpdateData(false);
// TODO: Add your control notification handler code here
}
void CMyDlg::OnButton3()
{
m_display2 = buttonDownNum(2);
UpdateData(false);
}
void CMyDlg::OnButton4()
{
m_display2 = buttonDownNum(3);
UpdateData(false);
}
void CMyDlg::OnButton5()
{
m_display2 = buttonDownNum(4);
UpdateData(false);
}
void CMyDlg::OnButton6()
{
m_display2 = buttonDownNum(5);
UpdateData(false);
}
void CMyDlg::OnButton7()
{
m_display2 = buttonDownNum(6);
UpdateData(false);
}
void CMyDlg::OnButton8()
{
m_display2 = buttonDownNum(7);
UpdateData(false);
}
void CMyDlg::OnButton9()
{
m_display2 = buttonDownNum(8);
UpdateData(false);
}
void CMyDlg::OnButton10()
{
m_display2 = buttonDownNum(9);
UpdateData(false);
}
void CMyDlg::OnButton11()
{
m_display2 = buttonDownNum(0);
UpdateData(false);
}
void CMyDlg::OnButton13()
{
str = "+";
str_flag = TRUE;
continue_flg = FALSE;
downDot = FALSE;
count = 1;
UpdateData(FALSE);
}
⑦運(yùn)算法則定義
void CMyDlg::OnButton16()
{
if (str == "+")
result = num1 + num2;
else if (str == "-")
result = num1 - num2;
else if (str == "*")
result = num1 * num2;
else if (str == "/")
{
result = double(num1) / double(num2);
}
else if (str == '^')
result = pow(num1, num2);
else if (str == 'k')
result = pow(num1, 1.0 / num2);
else if (str == 's')
result = sin(num2 * 3.1415926 / 180);
else if (str == 'c')
result = cos(num2 * 3.1415926 / 180);
else if (str == 't')
result = tan(num2 * 3.1415926 / 180);
else if (str == 'l')
result = log(num2);
else if (str == 'e')
result = exp(num2);
num1 = result;
m_display2 = result;
str_flag = FALSE;
continue_flg = FALSE;
downDot = FALSE;
count = 1;
UpdateData(FALSE);
}
編寫其函數(shù):
pCmdUI->SetCheck(shape==1); //顯示 圖標(biāo)的樣式
⑧顏色板的調(diào)用
CColorDialog Color; //定義畫框
if (Color.DoModal() == IDOK)
{
m_ncolor = Color.GetColor();
}
4.2.界面設(shè)計(jì)

5.結(jié)論與心得體會
通過這次的課設(shè),自己學(xué)到了很多,比如團(tuán)隊(duì)之間的合作,還有一些自己以前不是很了解的知識。
通過團(tuán)隊(duì)合作,可以得到很多不一樣的思路,不一樣的算法,每個(gè)人的思維是不一樣的,所以,我們應(yīng)該要吸取不同人的優(yōu)點(diǎn),吸收理解成自己的優(yōu)點(diǎn)。
在這次合作的過程中,產(chǎn)生了很多的好點(diǎn)子,盡管最后有很多的功能沒有實(shí)現(xiàn),畢竟自己的技術(shù)還是不行,但是,有一些很好的想法也是不錯(cuò)了,可以鍛煉我們的思維。
在這次的課設(shè)題目中,充分的將自己平時(shí)所學(xué)應(yīng)用到實(shí)踐中,比如棧還有java html css js等一些新語言,在這次的課設(shè)中,雖然很累,但是也還是很值得的,從剛開始的一頭霧水,通過查閱資料和在老師的指導(dǎo)下,慢慢的懂了,慢慢的理解了其本質(zhì)。希望在今后的日子里,自己的編程能力會越來越強(qiáng),可以寫出自己滿意的代碼!
6.參考文獻(xiàn)
PDF:Windows編程基礎(chǔ)andMFC PDF:MFC入門 PDF:深入淺出MFC
項(xiàng)目源碼
下載路徑:
結(jié)語
代碼均為原創(chuàng)
版權(quán)歸原作者所有
「僅供小伙伴們學(xué)習(xí)參考使用」
請勿用作其余用途!
創(chuàng)作不易
如果您覺得寫的不錯(cuò)的話
「點(diǎn)贊+在看+收藏」 ??
