环境:
visual studio2019, EasyX 20210115
效果展示:
此图是在进行代码书写之前进行绘制的,是为了提前预览最终的显示结果和对应像素大小。
设计思路:
- 首先考虑怎么来处理输入的数据?
- 怎么处理每次输入之后,需要的跟随的数据显示问题?
- 如何分别处理符号和数字问题?
解决方案:
- 使用队列(或者栈来处理需要处理的连续输入的数字)
- 使用每次都重新绘制的方法来实现
- 使用不同的对象来包含符号和数字
源文件的构成:
- queue.h(一个模板类用来实现需要的队列功能)
- ui.h ui.cpp(用来实现相应UI功能)
- 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;
}