非可视化编程的windows窗口 C++ 代码设计:附例程并多多知识点

简介: 非可视化编程的windows窗口 C++ 代码设计:附例程并多多知识点

我用Dev-C++写了一个的非可视化编程条件下的windows窗口计算器例程,在此分享给广大初学者。其运行效果如下图:

20210223230120377.png


所有框架和单目运算已经做好,+-*/暂未完成,代码还有改进空间......

#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;
}


目录
相关文章
|
2月前
|
存储 C++ UED
【实战指南】4步实现C++插件化编程,轻松实现功能定制与扩展
本文介绍了如何通过四步实现C++插件化编程,实现功能定制与扩展。主要内容包括引言、概述、需求分析、设计方案、详细设计、验证和总结。通过动态加载功能模块,实现软件的高度灵活性和可扩展性,支持快速定制和市场变化响应。具体步骤涉及配置文件构建、模块编译、动态库入口实现和主程序加载。验证部分展示了模块加载成功的日志和配置信息。总结中强调了插件化编程的优势及其在多个方面的应用。
354 66
|
2月前
|
安全 程序员 编译器
【实战经验】17个C++编程常见错误及其解决方案
想必不少程序员都有类似的经历:辛苦敲完项目代码,内心满是对作品品质的自信,然而当静态扫描工具登场时,却揭示出诸多隐藏的警告问题。为了让自己的编程之路更加顺畅,也为了持续精进技艺,我想借此机会汇总分享那些常被我们无意间忽视却又导致警告的编程小细节,以此作为对未来的自我警示和提升。
267 11
|
1月前
|
消息中间件 存储 安全
|
2月前
|
存储 搜索推荐 C++
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
59 2
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器2
|
3月前
|
存储 算法 C++
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
文章详细探讨了C++中的泛型编程与STL技术,重点讲解了如何使用模板来创建通用的函数和类,以及模板在提高代码复用性和灵活性方面的作用。
58 2
C++提高篇:泛型编程和STL技术详解,探讨C++更深层的使用
|
2月前
|
安全 程序员 编译器
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则
90 11
|
2月前
|
存储 C++ 容器
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器1
【C++篇】深度剖析C++ STL:玩转 list 容器,解锁高效编程的秘密武器
64 5
|
2月前
|
编译器 C语言 C++
C++入门6——模板(泛型编程、函数模板、类模板)
C++入门6——模板(泛型编程、函数模板、类模板)
60 0
C++入门6——模板(泛型编程、函数模板、类模板)
|
2月前
|
算法 编译器 C++
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
【C++篇】领略模板编程的进阶之美:参数巧思与编译的智慧
88 2
|
2月前
|
存储 编译器 C++
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
【C++篇】引领C++模板初体验:泛型编程的力量与妙用
45 2
下一篇
DataWorks