我用Dev-C++写了一个的非可视化编程条件下的windows窗口计算器例程,在此分享给广大初学者。其运行效果如下图:
所有框架和单目运算已经做好,+-*/暂未完成,代码还有改进空间......
#include <iostream> #include <iomanip> #include <sstream> #include <string> #include <array> #include <cmath> #include <windows.h> using namespace std; #define myClassName "WindowCalculator" #define NUM (sizeof Buttons / sizeof Buttons[0]) #define WarningBeep Beep(400,100) #define OutErrorText(s) SetWindowText(tHwnd[1], TEXT(s)) #define OutResultText SetWindowText(tHwnd[2], tmp.c_str()) #define ClearText SetWindowText(tHwnd[1],"");SetWindowText(tHwnd[2],"0") #define AboutMe ShellAbout(hwnd, "我的计算器",\ "我的Windows窗口计算器 by Hann Yang, 2021.2.21", NULL) struct button { int x; int y; //坐标 int w; int h; //宽高 const char *szText; //Caption } Buttons[] = { 30, 370,0,0,TEXT("0"), 30, 310,0,0,TEXT("1"), 90, 310,0,0,TEXT("2"), 150,310,0,0,TEXT("3"), 30, 250,0,0,TEXT("4"), 90, 250,0,0,TEXT("5"), 150,250,0,0,TEXT("6"), 30, 190,0,0,TEXT("7"), 90, 190,0,0,TEXT("8"), 150,190,0,0,TEXT("9"), 150,370,0,0,TEXT(" ."), 210,370,0,0,TEXT("+"), 210,310,0,0,TEXT("-"), 210,250,0,0,TEXT("×"), 210,190,0,0,TEXT("÷"), 210,130,0,0,TEXT("±"), 270,310,0,0,TEXT("="), 270,250,0,0,TEXT("1/x"), 270,190,0,0,TEXT("√x"), 270,130,0,0,TEXT("y2"), 150,130,0,0,TEXT("%"), 90, 130,0,0,TEXT("C"), 30, 130,0,0,TEXT("←") }; HFONT hFont[3]; HWND tHwnd[3], bHwnd[NUM]; string GetStaticText(short i=2) { char buf[64] = {0}; GetWindowText(tHwnd[i], buf, 64); return string(buf); } void myCreateFont() { hFont[0] = (HFONT)GetStockObject(SYSTEM_FIXED_FONT); /* windows系统基本字体:ANSI_FIXED_FONT DEFAULT_GUI_FONT ANSI_VAR_FONT DEVICE_DEFAULT_FONT SYSTEM_FIXED_FONT SYSTEM_FONT OEM_FIXED_FONT */ hFont[1] = CreateFont( -15, -8, /* 字符的逻辑单位高宽值(也被称为em高度) >0:字体映射器转换这个值以设备单位,并和已有字体的单元高度相匹配。 =0:字体映射器转换在选择匹配时用一个缺省的高度值。 <0:字体映射器转换这个值到设备单位,并将它的绝对值和已有字体的字符高度相匹配。 */ 0, /*指定移位向量和设备X轴之间的一个角度,以十分之一度为单位*/ 0, /*指定每个字符的基线和设备X轴之间的角度*/ 400, /*字体权值:400表示标准体,700表示黑(粗)体*/ FALSE, FALSE, FALSE, /*字体样式参数对应:斜体、下划线、删除线*/ DEFAULT_CHARSET, /*默认字符集*/ OUT_DEFAULT_PRECIS, /*默认裁剪状态*/ CLIP_DEFAULT_PRECIS, /*默认输出精度*/ DEFAULT_QUALITY, /*默认输出质量*/ DEFAULT_PITCH|FF_DONTCARE, /*默认字体间距|不关心字体族*/ TEXT("微软雅黑") ); /*字体名称*/ hFont[2] = CreateFont( 30, 10, 0, 0, 700, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_DONTCARE, TEXT("仿宋") ); } void myCreateWindow(HWND hwnd, LPARAM lParam) { tHwnd[0] = CreateWindow( TEXT("button"),NULL, WS_CHILD | WS_VISIBLE | BS_GROUPBOX, /*分组框*/ 30, 25, 290, 80, hwnd,(HMENU)31, ((LPCREATESTRUCT) lParam)->hInstance,NULL); if (!tHwnd[0]) MessageBox(NULL,"创建分组框失败","Message",MB_OK|MB_ICONERROR); ShowWindow(tHwnd[0], SW_SHOW); UpdateWindow(tHwnd[0]); tHwnd[1] = CreateWindow( TEXT("static"),NULL, WS_CHILD | WS_VISIBLE , 36, 40, 278, 22, hwnd,(HMENU)32, ((LPCREATESTRUCT) lParam)->hInstance,NULL); if (!tHwnd[1]) MessageBox(NULL,"创建文本框失败","Message",MB_OK|MB_ICONERROR); ShowWindow(tHwnd[1],SW_SHOW); SendMessage(tHwnd[1], WM_SETFONT, (WPARAM)hFont[1], lParam); //设置控件字体 SetWindowLong(tHwnd[1], GWL_STYLE, GetWindowLong(tHwnd[1], GWL_STYLE)|ES_RIGHT|SS_CENTERIMAGE); //设置右对齐、垂直居中 UpdateWindow(tHwnd[1]); tHwnd[2] = CreateWindow( TEXT("static"),"0", WS_CHILD | WS_VISIBLE , 36, 62, 278, 35, hwnd,(HMENU)33, ((LPCREATESTRUCT) lParam)->hInstance,NULL); if (!tHwnd[2]) MessageBox(NULL,"创建文本框失败","Message",MB_OK|MB_ICONERROR); ShowWindow(tHwnd[2],SW_SHOW); SetWindowLong(tHwnd[2], GWL_STYLE, GetWindowLong(tHwnd[2], GWL_STYLE) | ES_RIGHT); SendMessage(tHwnd[2], WM_SETFONT, (WPARAM)hFont[2], lParam); UpdateWindow(tHwnd[2]); for(int i = 0; i < NUM; i++) { Buttons[i].w = 50; Buttons[i].h = 50; Buttons[0].w = 110; //0双倍宽 Buttons[16].h = 110; //=双倍高 bHwnd[i] = CreateWindow( TEXT("button"), Buttons[i].szText, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_FLAT, Buttons[i].x, Buttons[i].y, Buttons[i].w, Buttons[i].h, hwnd, (HMENU)(WPARAM)i, //(WPARAM)强制转换用于消除警告 ((LPCREATESTRUCT) lParam)->hInstance, NULL); if (!bHwnd[i]) MessageBox(NULL,"创建命令按钮失败","Message",MB_OK|MB_ICONERROR); ShowWindow(bHwnd[i],SW_SHOW); SendMessage(bHwnd[i], WM_SETFONT, (WPARAM)hFont[0], lParam); //设置控件字体 UpdateWindow(bHwnd[i]); } } template<typename T>string num2str(T d) { string s; stringstream ss; ss<<setprecision(15)<<d; s=ss.str(); ss.clear(); return s; } template<typename T>T str2num(string s) { T d; stringstream ss; ss<<s; ss>>setprecision(15)>>d; ss.clear(); return d; } LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) { string tmp; array <string,4> strSign={"+","-","*","/"}; static bool num_input_state = true; static bool sgn_input_state = false; unsigned int lWord = LOWORD(wParam); switch(Message) { case WM_CREATE: // WM_CREATE事件中创建所有子窗口控件 myCreateFont(); myCreateWindow(hwnd, lParam); break; case WM_COMMAND: // WM_COMMAND响应的wParam值对应控件的(HMENU)(WPARAM)i参数 tmp = GetStaticText(); if(lWord>=0 && lWord<=10){ //0~9、. if (lWord==10 && tmp.find(".")!=tmp.npos){ OutErrorText("无效输入:已有小数点"); WarningBeep; break; } if (sgn_input_state) tmp=""; sgn_input_state = false; tmp = (tmp=="0"&&lWord!=10?"":tmp) + (lWord==10?".":num2str<int>(lWord)); if (num_input_state) OutResultText; } else if(lWord>=11 && lWord<=14){ //+、-、*、/ num_input_state = true; sgn_input_state = true; if (GetStaticText(1).back()=='+'){ //MessageBox(hwnd, "+++", NULL, 0); } tmp = tmp + strSign.at(lWord-11); OutErrorText(tmp.c_str()); } else{ num_input_state = false; switch (lWord){ case 15: //± OutErrorText(("-("+tmp+")").c_str()); if (tmp.substr(0, 1) == "-") tmp.erase(tmp.begin(),tmp.begin()+1); else if (tmp!="0") tmp = "-" + tmp; OutResultText; break; case 16: // = num_input_state = true; break; case 17: //1/x if (tmp=="0") { OutErrorText("除0错:#DIV/0!"); WarningBeep; break; } OutErrorText(("1/"+tmp).c_str()); tmp = num2str<long double>(1/str2num<long double>(tmp)); OutResultText; break; case 18: //sqrt(x) if (str2num<long double>(tmp)<0) { OutErrorText("无效输入:负数开平方"); WarningBeep; break; } OutErrorText(("sqrt("+tmp+")").c_str()); tmp = num2str<long double>(sqrt(str2num<long double>(tmp))); OutResultText; break; case 19: //y^2 OutErrorText(("pow("+tmp+",2)").c_str()); tmp = num2str<long double>(pow(str2num<long double>(tmp),2.0)); OutResultText; if (GetStaticText()=="inf"){ OutErrorText("无效输入:平方值超出允许范围"); WarningBeep; tmp="0"; OutResultText; } break; case 20: //% if (tmp.find("e")==tmp.npos) OutErrorText((tmp+"%").c_str()); else OutErrorText(("0.01*("+tmp+")").c_str()); tmp = num2str<long double>(str2num<long double>(tmp) * 0.01); OutResultText; break; case 21: //C clear ClearText; num_input_state = true; break; case 22: //BackSpace tmp = tmp.substr(0, tmp.size()-1); if (tmp.empty()) tmp = "0"; OutResultText; num_input_state = true; break; default: MessageBox(hwnd, num2str<int>(lWord).c_str(), NULL, 0); } } break; //end case WM_COMMAND case WM_KEYDOWN: //返回的wParam为按键的虚拟键码: 110(orNumPAD190)=='.' 48~57(orNumPAD96~105)=='0'~'9' tmp = num2str<int>(LOWORD(wParam)).c_str(); OutResultText; break; case WM_SYSCHAR: //返回的wParam为按键的虚拟键码: 110(orNumPAD190)=='.' 48~57(orNumPAD96~105)=='0'~'9' tmp = num2str<int>(LOWORD(wParam)).c_str(); OutResultText; break; case WM_CLOSE: if (IDYES==MessageBox(hwnd, "是否真的要退出?", "确认", MB_ICONQUESTION | MB_YESNO)) DestroyWindow(hwnd); //销毁窗口 return 0; case WM_HELP: //响应 F1功能键 AboutMe; break; case WM_DESTROY: AboutMe; PostQuitMessage(0); return 0; default: return DefWindowProc(hwnd, Message, wParam, lParam); } return 0; } ATOM myRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wc; memset(&wc, 0, sizeof(wc)); wc.cbSize = sizeof(WNDCLASSEX); wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; //无菜单;MAKEINTRESOURCE(IDC_MYMENU); wc.lpszClassName = myClassName; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return RegisterClassEx(&wc); } BOOL myInitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hwnd; RECT rect; int dtWidth, dtHeight; hwnd = GetDesktopWindow(); //取桌面句柄 GetWindowRect(hwnd,&rect); //取桌面范围 dtWidth = rect.right-rect.left; //桌面宽度 dtHeight = rect.bottom-rect.top; //桌面高度 hwnd = CreateWindowEx(WS_EX_CLIENTEDGE, myClassName, TEXT("我的计算器"), WS_VISIBLE|WS_OVERLAPPED|WS_SYSMENU|WS_MINIMIZEBOX, (dtWidth-360)/2, /*窗体居中*/ (dtHeight-480)/2, 360, 480, NULL,NULL,hInstance,NULL); if (!hwnd) return false; ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); return true; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { MSG msg; HWND hwnd; if(!myRegisterClass(hInstance)) { MessageBox(NULL, "Window Registration Failed!","Error!", MB_ICONEXCLAMATION|MB_OK); return 0; } if(!myInitInstance(hInstance, nCmdShow)) { MessageBox(NULL, "Window Creation Failed!","Error!", MB_ICONEXCLAMATION|MB_OK); return 0; } while(GetMessage(&msg, NULL, 0, 0) > 0) { if(!IsDialogMessage(hwnd, &msg)){ TranslateMessage(&msg); DispatchMessage(&msg); } //IsDialogMessage使得TAB和ARROW键可切换控件焦点,前提是控件有设WS_TABSTOP参数 } return msg.wParam; }