本文使用EmWin,如果不使用EmWin,本文也很有参考价值,只是将触摸屏拆解成键盘和显示而已。
我使用的是安富莱V6的板子,如果是其他板子的话,参照进行最基础的EmWin的移植就可以使用EmWin。
总体来说,代码分为两部分,一部分是GUI,负责算式的输入和结果的显示,用GUIBuilder做,做好了以后就是一个带有Button的window:
写好之后就是一个没有功能的壳子,所以我们要给壳子赋予功能:先建立一个储存中间算式字符串的栈,然后在按键按下的时候把输入的字符入栈(对于非EmWin的,就是键盘驱动以后,检测到相应的按键按下就入栈就好)
typedef struct
{
char symbol[maxSize];
int top ; //头地址
} Stack_symbol;
Stack_symbol* inputstack;
inputstack = (Stack_symbol *)malloc(sizeof(Stack_number));
/* 输入算式字符栈出栈 */
char pop_symbol(Stack_symbol *ss)
{
int p;
char symbol;
if(ss->top == 0)
{
return 0;
}
p = ss -> top - 1;
symbol = ss -> symbol[p];
--(ss -> top);
ss -> symbol[p] = '\0';
return symbol;
}
/* 输入算式字符栈入栈 */
void push_symbol(char symbol,Stack_symbol *ss)
{
int p;
if(ss->top == maxSize)
{
errorflag = 1;
}
else
{
p = ss -> top;
ss -> symbol[p] = symbol;
++(ss -> top);
}
}
在按键按下的时候(就是回调函数里面检测到按键按下或者是非EmWin的朋友扫描到相应的按键按下),进行字符的入栈,为了按下一个键子就能相应的显示输入的字符,每次入栈之后还要显示字符串栈:
这个函数的作用就是刷新显示: GUI_show_num_briefLiu(pMsg);
case WM_NOTIFY_PARENT:
Id = WM_GetId(pMsg->hWinSrc);
NCode = pMsg->Data.v;
switch(Id) {
case ID_BUTTON_0: // Notifications sent by 'B2'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
push_symbol('2',(Stack_symbol *)inputstack);
GUI_show_num_briefLiu(pMsg);//每一次都要显示一次输入字符串
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
case ID_BUTTON_1: // Notifications sent by 'B3'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message
push_symbol('3',(Stack_symbol *)inputstack);
GUI_show_num_briefLiu(pMsg);//每一次都要显示一次输入字符串
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
代码分的第二部分就是运算部分:
输入字符串,摘出来数字和运算符,进行运算符的优先级排序,按照运算符优先级顺序进行计算:
/**********************************************************************
* void final_result(Stack_number *num,Stack_symbol *sym,char *expression)
* 输入:num, 数字栈,分开字符串的数字符号的时候储存数字
* 输入:sym, 符号栈,分开字符串的数字符号的时候储存符号
* 输入:expression,输入字符串,本函数进行加工的原料
***********************************************************************/
void final_result(Stack_number *num,Stack_symbol *sym,char *expression)
{
int length = getLength(expression);
int i = 0,zero = 1;
int t;
char temp,st,num_temp[maxSize];
long x,y,result;
//初始化符号栈和数字栈
num->top = 0;
sym->top = 0;
push_symbol('=',sym);
while(i < length && zero == 1)
{
temp = expression[i];
if(!(temp >= '0' && temp <= '9')) //遇到运算符时
{
char cmp;
t = sym->top;
-- t;
s t = sym->symbol[t];
cmp = symbol_priority(temp,st);
if( cmp == '>')
{
push_symbol(temp,sym);
}
else if(cmp == '<')
{
y = pop_number(num); //操作数1出栈
if (st == '/' && y == 0) //除数不能为0的校验
{
zero = 0;
break;
}
else
{
x = pop_number(num);//操作数2出栈
result = out_result(x,y,st); //计算结果
pop_symbol(sym);//运算符出栈
push_number(result, num);//运算结果入栈
-- i;
//此时i自减,在判断执行完后再i自加,则i不变,下一步还是从这个字符开始判断
//当遇到多个操作符需要计算时需要这样
}
}
else // 当cmp == '=' 时
{
pop_symbol(sym);
}
++ i;
}
else //遇到数字时
{
int count = 0;
int j;
num_temp[count] = expression[i];//将数字字符赋给temp字符数组
j = i + 1;//j是从i的下一个字符开始的下标,一次向后遍历,直到遇到的不是数字字符
while(j < length)
{
//若遍历到的是数字字符,则进行相应的处理
if(expression[j] >= '0' && expression[j] <= '9')
{
count ++;//数字字符个数加1
num_temp[count] = expression[j];//将数字字符赋给temp字符数组
j ++;//j相应自增
}
else
{
break;//一旦遇到的是非数字字符,则跳出循环
}
}
num_temp[count + 1] = '\0';//给temp字符数组赋上一个结束字符
i = j;//外层循环从j的位置开始
push_number(atoi(num_temp), num);
}
}
if(zero == 1)
{
rusultnum = pop_number(num);//printf("计算结果为%ld\n",pop_number(num));
}
else
{
// printf("除数不能为0,请重新输入需要计算的表达式!\n");
}
}
得到长整型结果进行显示,在按下等号之后进行运算和显示:
case ID_BUTTON_13: // Notifications sent by 'B_eql'
switch(NCode) {
case WM_NOTIFICATION_CLICKED:
// USER START (Optionally insert code for reacting on notification message)
push_symbol('=',(Stack_symbol *)inputstack);
startcul();
GUI_show_briefLiu(pMsg);
// USER END
break;
case WM_NOTIFICATION_RELEASED:
// USER START (Optionally insert code for reacting on notification message)
// USER END
break;
// USER START (Optionally insert additional code for further notification handling)
// USER END
}
break;
void GUI_show_briefLiu(WM_MESSAGE * pMsg)
{
WM_HWIN hWinOld;
char testsring[50];
sprintf(testsring,"The answer IS %ld",rusultnum);
hWinOld = WM_SelectWindow(WM_GetClientWindow(pMsg->hWin));
GUI_SetFont(&GUI_Font8x16x1x2);
GUI_SetColor(GUI_RED);
GUI_SetTextMode(GUI_TM_TRANS);
GUI_DispStringAt((char*)testsring,0,50);
WM_SelectWindow(hWinOld);
}
成品图: