手撸一个计算器(纯c++编写)

环境:

visual studio2019, EasyX 20210115

效果展示:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
此图是在进行代码书写之前进行绘制的,是为了提前预览最终的显示结果和对应像素大小。

设计思路:

  1. 首先考虑怎么来处理输入的数据?
  2. 怎么处理每次输入之后,需要的跟随的数据显示问题?
  3. 如何分别处理符号和数字问题?

解决方案:

  1. 使用队列(或者栈来处理需要处理的连续输入的数字)
  2. 使用每次都重新绘制的方法来实现
  3. 使用不同的对象来包含符号和数字

源文件的构成:

  1. queue.h(一个模板类用来实现需要的队列功能)
  2. ui.h ui.cpp(用来实现相应UI功能)
  3. main.cpp(用来实现相应的事务逻辑)
#ifndef QUEUE_H_
#define QUEUE_H_
#include<vector>
#include<math.h>

template<typename T> class queue
{
private:
	enum { maxNumber = 10};
	std::vector<T> queueData;
	int dataNumber;
public:
	queue();
	~queue() {};
	bool isEmpty() { return dataNumber == 0; }
	bool isFull() { return dataNumber == maxNumber; }
	void clear() { queueData.clear();  dataNumber = 0; }
	void deleteLast() { queueData.pop_back(); dataNumber--; }
	bool pop(T & data);
	T pop();
	bool push(const T& data);
	int length() { return dataNumber; }
	int value();
};


template<typename T> queue<T>::queue()
{
	dataNumber = 0;
}

template<typename T> bool queue<T>::pop(T & data)
{
	if (isEmpty())
	{
		return false;
	}
	else
	{
		data = queueData[0];
		for (int i = 0; i < dataNumber-1; i++)
		{
			queueData[i] = queueData[i + 1];
		}
		dataNumber--;
		return true;
	}
}

template<typename T> T queue<T>::pop()
{
	if (isEmpty())
	{
		return 0;
	}
	else
	{
		T result = queueData[0];
		for (int i = 0; i < dataNumber-1; i++)
		{
			queueData[i] = queueData[i + 1];
		}
		dataNumber--;
		return result;
	}
}

template<typename T> bool queue<T>::push(const T& data)
{
	if (maxNumber == dataNumber)
	{
		return false;
	}

	queueData.push_back(data);
	dataNumber++;
	return true;
}

template<typename T> int queue<T>::value()
{
	if (isEmpty())
	{
		return 0;
	}
	int result = 0;
	while (!isEmpty())
	{
		result += pow(10, this->length()-1) * this->pop();
	}
	return result;
}
#endif

此文件主要是实现需要用到的队,其中添加了在后续需要的一些功能,比如:删除最后一个压入队列中的数据,清空队列等

#pragma once
#include"queue.h"
#include<graphics.h>

class ui
{
private:
	void drawUIText(RECT rect, 	LPCTSTR text);
	void charQueueToLPCTSTR(queue<char>  firstData, TCHAR * buf, char ch = '\0');
	int getDataFromQueue(queue<char> queueData);

public:
	ui();
	~ui();
	void drawSecondPart(void);
	void drawFirstPart(queue<char> firstData);
	void drawFirstPart(queue<char> firstData, char chOperator);
	void drawFirstPart(queue<char> firstData, char chOperator, queue<char> secondData);
	void drawResult(queue<char> firstData, char chOperator, queue<char> secondData);
};

ui.h主要是规定了,需要实现的一些功能,由于下面的一些显示内容是固定的是不变的,而上面是随着输入的变化的,所以将上下两个部分进行分别显示,就是上面的drawFirsePart和drawSecondPart,还可以看到对于第一个函数一共有三个重载函数,分别对应于输入只有第一个数字的时候;输入为第一个数字和运算符的时候,输入为第一个数字,运算符和第二个数字的时候。

#include "ui.h"
#include"queue.h"
#include<cstring>
#include<graphics.h>


//创建一个800*600的显示界面
ui::ui()
{
	initgraph(800, 600);
	setbkcolor(WHITE);
	cleardevice();
	drawSecondPart();
}

ui::~ui()
{
	closegraph();
}

void ui::drawUIText(RECT rect, 	LPCTSTR text)
{
	setcolor(YELLOW);
	rectangle(rect.left, rect.top, rect.right, rect.bottom);
	settextcolor(BLACK);
	settextstyle(20, 0, TEXT("楷体"));
	drawtext(text, &rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
}

void ui::drawSecondPart(void)
{
	RECT clearRect{ 0, 100, 200, 150 };
	RECT resRect{ 200, 100,400, 150 };
	RECT delRect{ 400, 100,600, 150 };
	RECT rect;
	TCHAR buf[100];

	
	drawUIText(clearRect, TEXT("CLEAR"));
	drawUIText(resRect, TEXT("RESULT"));
	drawUIText(delRect, TEXT("DELETE"));
	int count = 0;
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			_stprintf(buf, TEXT("%d"), ++count);
			rect = { 200 * j, 150 + 150 * i, 200 * j + 200, 300 + 150 * i };
			drawUIText(rect, (LPCTSTR)buf);
		}
	}
	char specialCh[5] = { '0', '+', '-', '*', '/' };


	for (int i = 0; i < 5; i++)
	{
		rect = { 600, 150 + 90 * i, 800, 240 + 90 * i };
		_stprintf(buf, TEXT("%c"), specialCh[i]);
		drawUIText(rect, (LPCTSTR)buf);
	}
}


void ui::drawFirstPart(queue<char> firstData)
{
	RECT rect = { 0, 0, 800, 100 };
	clearrectangle(rect.left, rect.top, rect.right, rect.bottom);
	TCHAR buf[100];
	charQueueToLPCTSTR(firstData, buf);
	drawUIText(rect, (LPCTSTR)buf);
}

void ui::drawFirstPart(queue<char> firstData, char chOperator)
{
	RECT rect = { 0, 0, 800, 100 };
	clearrectangle(rect.left, rect.top, rect.right, rect.bottom);
	TCHAR buf[100];
	charQueueToLPCTSTR(firstData, buf, chOperator);
	drawUIText(rect, (LPCTSTR)buf);
}

void ui::drawFirstPart(queue<char> firstData, char chOperator, queue<char> secondData)
{
	RECT rect = { 0, 0, 800, 100 };
	clearrectangle(rect.left, rect.top, rect.right, rect.bottom);
	TCHAR buf[100];
	int data1, data2;
	data1 = getDataFromQueue(firstData);
	data2 = getDataFromQueue(secondData);
	_stprintf(buf, TEXT("%d%c%d"), data1, chOperator, data2);
	drawUIText(rect, (LPCTSTR)buf);
}

void ui::drawResult(queue<char> firstData, char chOperator, queue<char> secondData)
{
	RECT rect = { 0, 0, 800, 100 };
	clearrectangle(rect.left, rect.top, rect.right, rect.bottom);
	TCHAR buf[100];
	int data1, data2, result=0;
	data1 = getDataFromQueue(firstData);
	data2 = getDataFromQueue(secondData);
	switch (chOperator)
	{
	case '+': result = data1 + data2; break;
	case '-': result = data1 - data2; break;
	case '*': result = data1 * data2; break;
	case '/': result = data1 / data2; break;
	default: result = 0;
	}
	_stprintf(buf, TEXT("%d"), result);
	drawUIText(rect, (LPCTSTR)buf);

}
void ui::charQueueToLPCTSTR(queue<char> firstData, TCHAR * buf, char ch)
{
	int data = getDataFromQueue(firstData);
	_stprintf(buf, TEXT("%d%c"), data, ch);
}

int ui::getDataFromQueue(queue<char> queueData)
{
	int data = 0, length = queueData.length();
	for (int i = 0; i < length; i++)
	{
		data += pow(10, length - i - 1) * (queueData.pop()-0x30);
	}
	return data;
}

**当时一个比较难的点是对于将不同字符串的数据转化为LPCTSTR类型的数据,这里使用的方法是:前创建一个TCHAR类型的buffer,然后利用输入输出函数进行转化 **

TCHAR buf[100];
_stprintf(buf, TEXT("%d%c%d"), data1, chOperator, data2);	//利用格式化输出

main.cpp

#include<iostream>
#include<graphics.h>
#include"queue.h"
#include"ui.h"

enum functionButton { CLEAR, DEL, RESULT };

bool isNumberInput(const MOUSEMSG& msg);
char getChFromMsg(const MOUSEMSG& msg);
bool isOperator(const MOUSEMSG& msg);
char getOperatorFromMsg(const MOUSEMSG& msg);
bool isFunctionButton(const MOUSEMSG& msg);
functionButton getFunctionButtonFromMsg(const MOUSEMSG& msg);

int main(void)
{
	using std::cout;
	using std::cin;
	using std::endl;

	ui cal;
	queue<char> data1, data2;
	char temp, chOperator;
	//operatorReady用来判断输入数字为第一个还是第二个
	//secondStartInput用来判断是否已经开始了第二个数字的输入,在删除的时候使用
	bool operatorReady, secondStartInput;
	MOUSEMSG msg;
	
	operatorReady = false;
	secondStartInput = false;

	while (true)
	{
		msg = GetMouseMsg();
		//先判断是否为鼠标按键按下
		if (msg.mkLButton)
		{
			//判断是不是输入的数字
			if (isNumberInput(msg))
			{
				temp = getChFromMsg(msg);
				FlushMouseMsgBuffer();
				//判断第一个数字是否还在输入
				if (operatorReady)
				{
					data2.push(temp);
					secondStartInput = true;
					cal.drawFirstPart(data1, chOperator, data2);
				}
				else
				{
					if (!data1.isFull())
					{
						data1.push(temp);
						cal.drawFirstPart(data1);
					}
				}
			}
			else if (isOperator(msg))
			{
				chOperator = getOperatorFromMsg(msg);
				FlushMouseMsgBuffer();
				operatorReady = true;
				cal.drawFirstPart(data1, chOperator);
			}
			else if(isFunctionButton(msg))
			{
				functionButton button = getFunctionButtonFromMsg(msg);
				FlushMouseMsgBuffer();
				switch (button)
				{
				case CLEAR:
					data1.clear();
					data2.clear();
					operatorReady = false;
					secondStartInput = false;
					clearrectangle(1, 1, 799, 99);
					break;
				case DEL:
					if (!operatorReady && data1.length() != 0)
					{
						data1.deleteLast();
						cal.drawFirstPart(data1);
					}
					else if (operatorReady && !secondStartInput)
					{
						operatorReady = false;
						cal.drawFirstPart(data1);
					}
					else if (secondStartInput)
					{
						data2.deleteLast();
						if (data2.isEmpty())
						{
							cal.drawFirstPart(data1, chOperator);
							secondStartInput = false;
						}
						else 
						{
							cal.drawFirstPart(data1, chOperator, data2);
						}
					}
					break;
				case RESULT:
					if (secondStartInput)
					{
						cal.drawResult(data1, chOperator, data2);
						data1.clear();
						data2.clear();
						operatorReady = false;
						secondStartInput = false;
					}
					break;
				default:
					break;
				}
			}
		}
	}

	return 0;
}


bool isNumberInput(const MOUSEMSG& msg)
{ 
	int x = msg.x / 10; 
	int y = msg.y / 10;

	return (x >= 0 && x <= 60 && y >= 15 && y <= 60)
		|| (x >= 60 && x <= 80 && y >= 15 && y <= 24);
}


char getChFromMsg(const MOUSEMSG& msg)
{
	int x = msg.x / 10; 
	int y = msg.y / 10;
	if (x >= 60 && x <= 80 && y >= 15 && y <= 24)
	{
		return 0x30;
	}
	else
	{
		int x = msg.x / 200;
		int y = msg.y / 150;
		int pos = x + (y - 1) * 3 + 1;
		return 0x30 + pos;
	}
}

bool isOperator(const MOUSEMSG& msg)
{
		int x = msg.x / 100;
		int y = (msg.y - 240) / 90;

		return (x >= 6 && x < 8 && y >= 0 && y >= 0 && y < 4);
}

char getOperatorFromMsg(const MOUSEMSG& msg)
{
	int y = (msg.y - 240) / 90;
	char temp;
	switch (y)
	{
	case 0: temp = '+'; break;
	case 1: temp = '-'; break;
	case 2: temp = '*'; break;
	case 3: temp = '/'; break;
	default:
		break;
	}
	return temp;
}

bool isFunctionButton(const MOUSEMSG& msg)
{
	int y = msg.y;
	if (y < 100 || y > 150)
	{
		return false;
	}
	else
	{
		int x = msg.x / 200;
		if (x >= 0 && x < 3)
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}

functionButton getFunctionButtonFromMsg(const MOUSEMSG& msg)
{
	int x = msg.x / 200;
	switch (x)
	{
	case 0: return CLEAR;
	case 1: return RESULT;
	case 2: return DEL;
	default:
		break;
	}
	return CLEAR;
}
  • 12
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

able陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值