表达式求值 wpf
主要思想:表达式递归切割求值。
主要分成三个类。Expression,item和factor。

Expression(+/-)
由divStringExp类的divexp()方法分割字符串
将表达式中的加法和减法消除。
先用栈找出最外层的括号:

然后往括号两端扩展

切割加号得到两个items
Item
把字符串分成被除数和除数
分两种情况:有括号和无括号
有括号的情况:
同样是用栈判断最外层的括号

把括号内的乘号和除号省略,分割外面的乘号和除号
并把除数之间和被除数之间相连(或者用两个数组将分子和分母保存起来)

没括号的情况:
遇到除号将后面的除数加到除数字符串
Factor
拆开最外层括号外的乘号
剩下的元素分成5种情况
函数
一元函数
递归求括号内的值,再代入函数
例如sin(exp)
多元函数(目前只有log(a,b)函数)
例如log(a,log(b,c)),将括号内提出来“a,log(b,c)”
将没在括号内的,分割
分成“a“和”log(b,c)”再分别递归求值。
次方
求最外层括号外的次方
最外层是括号:
拆括号后递归求值
注意:次方内可能也有多个表达式
例如:2^sin(a)
参数
找coefficient类将值返回
数字
用table.Compute()方法转化
参数(Coefficient)类
正则表达式找变量并忽略掉所有的函数名,并初始赋值1
装有静态的函数名对象,方便外界访问
界面设计
Stackpanel中嵌套三个Grid布局

Grid布局1
计算结果用label显示
Grid布局2
四个listbox分别显示变量名,范围,滑块,变量值
Grid布局3
输入栏和确定按钮
事件
确定按钮click事件
初始化动态添加元素到四个listbox
变量范围keydown事件
判断输入是否是数字
四个listbox滑动条同步事件
1 2 3 4 5 6 7 8 9 10 11 12
| VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(this.listBox4, 0), 0) as ScrollViewer; sv4.ScrollChanged += newScrollChangedEventHandler(listBox4_ScrollChanged);
private void listBox4_ScrollChanged(object sender, ScrollChangedEventArgs e) { if (sv4 != null) { sv3.ScrollToVerticalOffset(sv4.VerticalOffset); sv2.ScrollToVerticalOffset(sv4.VerticalOffset); sv1.ScrollToVerticalOffset(sv4.VerticalOffset); } }
|
双击变量名产生滑块动画事件
System.Windows.Threading.DispatcherTimer类用于动画制作
该类用Interval方法设置事件的发生间隔
tmr.Interval = TimeSpan.FromSeconds(0.01);
给他的tick事件添加委托threads方法
start方法启用
判断条件满足后停止
end方法终止
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| private void animation(object sender, RoutedEventArgs e) { Label label = sender as Label; int count = 0; foreach(Label l1 in listBox1.Items) { count++; if (l1 == label) break; } ProcessToanimation = 0; CountToAnimation = count; System.Windows.Threading.DispatcherTimer tmr = new System.Windows.Threading.DispatcherTimer(); tmr.Interval = TimeSpan.FromSeconds(0.01); tmr.Tick += new EventHandler(threads); tmr.Start(); } private void threads(object c,EventArgs e) { try { int count = CountToAnimation; slidersList[count-1].Value = ProcessToanimation; double td = (slidersList[count - 1].Value - 5) * Convert.ToDouble(rangesList[count - 1].Text); td = td / 5; valuesList[count - 1].Content = td; variableCollection.vlist[count - 1].value = td; exp.setVariables(variableCollection); result.Content = exp.getValue(); ProcessToanimation += 0.025; if (ProcessToanimation >= 10) { slidersList[count-1].Value = 6; double ts = (slidersList[count - 1].Value - 5) * Convert.ToDouble(rangesList[count - 1].Text)/5; valuesList[count - 1].Content = ts; variableCollection.vlist[count - 1].value = ts; exp.setVariables(variableCollection); result.Content = exp.getValue(); (c as System.Windows.Threading.DispatcherTimer).Stop(); } } catch (Exception e1) {
} }
|
本文链接:
https://ioaol.github.io/ExpressionToValue.html