空の領域

又一个坑爹的神站 大人說:要清爽 要低調

0%

[VB]写计算器的一点感受

2013-12-21_233146图为计算器V2版OTZ

总共换了三种姿势总算有个稍微入目点的计算器了……虽然代码依旧那么不忍直视,我有种莫名的悲伤感。

- -计算器背后的故事不多说,最近一篇日志就谈到了。

BUG这种东西永远抓不完,更何况我技术本来就不好。

It’s传送门:

成品.exe:http://pan.baidu.com/s/1dD9oE8D

源代码:http://pan.baidu.com/s/1ntyjbhn

作为一个懒人,相信大家以前(几乎)没有见过这个分类,没错,这个分类当时就是为了现在这种时候设定的OTZ,只是我实在太懒的学习就成了现在这个样子,而已。以后更新应该还会挺多的。

首先来说一下整体的感想,V2的版本虽然思路上面高档了点,可是还是有很多地方不足的,最坑爹的是,没有注释我自己都看不懂写的是个鸟了啊啊啊,改起来完全无法下手有木有,注释果然还是边写边加比较好……毕竟第一次用VB写东西。

全部代码:

Dim status, condition, mast, Minus As Boolean ‘是否能增加小数点
Dim sum, b, c As Double ‘b是加上的值,sum为运算结果
Dim operator_point, operator, operator2 As String ‘operator用于第一次运算,operator2用于重复点击按钮
Dim a, i, countor, loop_array As Integer ‘a是数字按钮,loop_array 用于数组循环

Private Sub BtnAbout_Click()
MsgBox (“累得半死的节奏中,重构版” & vbCrLf & “小天出品,必属渣品”), , “About” ‘vbCrLf 换行加回车
End Sub

Private Sub BtnBackSpace_Click()
‘View 部分
If Len(ShowNum.Caption) = 1 Then ‘如果只有一位数则删除后显示为0
ShowNum.Caption = “0”
ElseIf Right(ShowNum.Caption, 1) = “.” Then
ShowNum.Caption = Left(ShowNum.Caption, Len(ShowNum.Caption) - 1)
status = False
BtnPoint.Enabled = True
Else
ShowNum.Caption = Left(ShowNum.Caption, Len(ShowNum.Caption) - 1) ‘屏幕中删除最后一位数
End If

‘Controller 部分
If operator = “none” Then
If Int(sum) = sum Then
If mast = True Then
sum = sum
mast = False
Else
sum = Int(sum / 10)
If status = True & Abs(sum) < 10 Then
Else
status = False
End If
End If
ElseIf Int(sum * 10) = sum * 10 Then
If i > 0 Then
i = i - 1
sum = Int(sum)
b = sum
End If
If i = 0 Then
mast = True
End If
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = False
End If
Else
sum = Int(sum * 10 ^ (i - 1)) / 10 ^ (i - 1)
b = sum
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = False
End If
i = i - 1
End If
Else
If Int(b) = b Then
If mast = True Then
b = b
mast = False
Else
b = Int(b / 10)
If status = True & Abs(b) < 10 Then
Else
status = False
End If
End If
ElseIf Int(b * 10) = b * 10 Then
If i > 0 Then
i = i - 1
b = Int(b)
End If
If i = 0 Then
mast = True
End If
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = False
End If
Else
b = Int(b * 10 ^ (i - 1)) / 10 ^ (i - 1)
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = False
End If
i = i - 1
End If
c = b
End If
End Sub

Private Sub BtnBlog_Click()
Shell “explorer.exe http://xsky.me", vbNormalFocus ‘连接至博客
End Sub

Private Sub BtnClear_Click()
Call restart
End Sub

Private Sub BtnEqual_Click()
Select Case operator
Case “plus”
sum = c + sum
Case “minus”
sum = sum - c
Case “times”
sum = sum * c
Case “divide”
If c = 0 Then
MsgBox (“不做死就不会死怎么就是不明白”), , “作死警告”
Else
sum = sum / c
End If
Case “equal”
Select Case operator2
Case “plus”
sum = sum + c
Case “minus”
sum = sum - c
Case “times”
sum = sum * c
Case “divide”
sum = sum / c
End Select
End Select
operator = “equal”
status = False
ShowNum.Caption = strnum(sum)
BtnBackSpace.Enabled = False
BtnPoint.Enabled = False
b = 0
Minus = False
i = 0
End Sub

Private Sub BtnNum_Click(Index As Integer)
a = Val(BtnNum(Index).Caption)
CalNumViewer (a)
CalController (a)
BtnBackSpace.Enabled = True
End Sub

Public Function CalNumViewer(a)
If operator = “none” Or operator = “equal” Then
If ShowNum.Caption = “0” Or ShowNum.Caption = “” Then ‘如果显示为”0”或空
If operator = “none” Then
If BtnPoint.Enabled = False Then
ShowNum.Caption = “0” & a
Else
ShowNum.Caption = a
End If
Else
If BtnPoint.Enabled = False Then
ShowNum.Caption = a
Else
ShowNum.Caption = ShowNum.Caption & a

        End If
    End If
    Else
    If operator = "equal" Then
    ShowNum.Caption = a
    Else
    ShowNum.Caption = ShowNum.Caption & a
    End If
End If

ElseIf ShowNum.Caption = “-“ Or ShowNum.Caption = “-0” Or ShowNum.Caption = “-0.” Then
If ShowNum.Caption = “-0” Or ShowNum.Caption = “-“ Then ‘如果显示为”0”或空
If BtnPoint.Enabled = False Then
ShowNum.Caption = “-0” & a
Else
ShowNum.Caption = “-“ & a
End If
Else
ShowNum.Caption = ShowNum.Caption & a
End If
ElseIf b = 0 Then
If condition = True Then
ShowNum.Caption = a
If ShowNum.Caption = “0” Or ShowNum.Caption = “” Then
If BtnPoint.Enabled = False Then
ShowNum.Caption = “0” & a
Else
ShowNum.Caption = a
End If
End If
condition = False
Else
If ShowNum.Caption = “0” Or ShowNum.Caption = “” Then ‘如果显示为”0”或空
If BtnPoint.Enabled = False Then
ShowNum.Caption = “0” & a
Else
ShowNum.Caption = a
End If
Else
ShowNum.Caption = ShowNum.Caption & a
End If
End If
Else
If ShowNum.Caption = “0” Or ShowNum.Caption = “” Then ‘如果显示为”0”或空
If BtnPoint.Enabled = False Then
ShowNum.Caption = “0” & a
Else
ShowNum.Caption = a
End If
Else
ShowNum.Caption = ShowNum.Caption & a
End If
End If
End Function

Private Sub BtnOff_Click()
If BtnOff.Caption = “Off” Then

ShowNum.BackStyle = Transparent
ShowNum.Caption = "天家的计算器标准版V2"
ShowNum.BorderStyle = none
BtnOff.Caption = "On"
    
For loop\_array = 0 To 3
Btnoperator(loop\_array).Enabled = False
Next loop\_array

For loop\_array = 0 To 9
BtnNum(loop\_array).Enabled = False
Next loop\_array

BtnSqr.Enabled = False
BtnEqual.Enabled = False
BtnBackSpace.Enabled = False
BtnClear.Enabled = False

Else

ShowNum.BackColor = vbWhite
BtnOff.Caption = "Off"
ShowNum.BackStyle = 1
ShowNum.BorderStyle = 1
BtnOff.Caption = "Off"
Call restart
    
For loop\_array = 0 To 3
Btnoperator(loop\_array).Enabled = True
Next loop\_array

For loop\_array = 0 To 9
BtnNum(loop\_array).Enabled = True
Next loop\_array

BtnSqr.Enabled = True
BtnEqual.Enabled = True
BtnBackSpace.Enabled = True
BtnClear.Enabled = True

End If
End Sub

Private Sub Btnoperator_Click(Index As Integer)
Call Changenum
i = 0
b = 0
BtnPoint.Enabled = True
condition = True
Select Case Index
Case 0
operator = “plus”
Case 1
If operator = “none” Or operator = “equal” & b = 0 & ShowNum.Caption = “0” & Minus = False Then
ShowNum.Caption = “-“
End If
Minus = True
operator = “minus”
Case 2
operator = “times”
Case 3
operator = “divide”
End Select

BtnBackSpace.Enabled = True
status = False
BtnPoint.Enabled = True
countor = 0

End Sub

Private Sub BtnPoint_Click()
status = True
BtnPoint.Enabled = False
operator_point = “.”
CalNumViewer (operator_point)
End Sub

Private Sub BtnSqr_Click()
Call Changenum
If sum < 0 Then
MsgBox (“不作死就不会死怎么就是不明白”), , “作死警告”
Else
sum = Sqr(sum)
ShowNum.Caption = strnum(sum)
End If
End Sub

Private Sub BtnHelp_Click()
MsgBox (“这还需要帮助?你在逗我?不如寻找彩蛋吧”), , “Help”
End Sub

Private Sub Form_KeyPress(KeyAscii As Integer)
Dim numkeyloop As Integer
numkeyloop = 48
For loop_array = 0 To 9
If KeyAscii = numkeyloop Then
Call BtnNum_Click(loop_array)
End If
numkeyloop = numkeyloop + 1
Next loop_array

If KeyAscii = 46 Then
Call BtnPoint_Click
End If

If KeyAscii = 45 Then
Call Btnoperator_Click(1)
End If

If KeyAscii = 43 Then
Call Btnoperator_Click(0)
End If

If KeyAscii = 61 Or KeyAscii = 13 Or KeyAscii = 32 Then
Call BtnEqual_Click
End If

If KeyAscii = 47 Then
Call Btnoperator_Click(3)
End If

If KeyAscii = 42 Then
Call Btnoperator_Click(2)
End If

If KeyAscii = 8 Then
Call BtnBackSpace_Click
End If

If KeyAscii = 27 Then
Call BtnOff_Click
End If
End Sub

Private Sub Form_Load()
status = False
operator = “none”
sum = 0
End Sub

Private Function CalController(a)
If status = True And operator = “none” Then
countor = countor + 1
b = sum + a * (0.1 ^ countor)
sum = b
i = i + 1
ElseIf status = True Then
countor = countor + 1
b = b + a * (0.1 ^ countor)
i = i + 1
Else
Select Case operator
Case “equal”
sum = a
operator = “none”
BtnPoint.Enabled = True
Case “none”
sum = sum * 10 + a
Case Else
b = b * 10 + a
End Select
End If
c = b
operator2 = operator

End Function

Public Function strnum(X)
If Abs(X) < 1 And X <> 0 Then
If X > 0 Then
strnum = “0” & Trim(X)
Else
strnum = “-0” & Trim(Abs(X))
End If
Else
strnum = X
End If
End Function

Public Function Changenum()
BtnBackSpace.Enabled = True
Select Case operator
Case “plus”
sum = b + sum
Case “minus”
sum = sum - b
Case “times”
sum = sum * b
Case “divide”
If b = 0 Then
MsgBox (“不作死就不会死怎么就是不明白”), , “作死警告”
Else
sum = sum / b
End If
End Select
ShowNum.Caption = strnum(sum)
End Function

Private Sub ShowNum_Click()
Clipboard.Clear
Clipboard.SetText ShowNum.Caption
MsgBox (“成功将输出结果复制到剪贴板”), , “Big Surprise!”
End Sub

Public Function restart()
ShowNum.Caption = “0”
status = False
sum = 0
b = 0
c = 0
operator = “none”
operator2 = “none”
a = 0
i = 0
BtnPoint.Enabled = True
countor = 0
loop_array = 0
End Function

这次写计算器的目的:

  • 帮忙……这是初衷,后来不知道为什么就变成自己写了,简直在逗我,而且不知道那货什么时候准备开始写
  • 体验一下VB编程,一个只点网络线的偶尔也想体验一下软编的感受
  • 熟悉语法,这个学期教学内容就凑合着认识一下吧,虽然还没有克服完全

不过,最终的收获远远比目的多,这点让我觉得相当不愧。

注释问题确实是很蛋疼,因为我发现没有注意以后我的Viewer部分在Debug时完全不知道是什么意思,当时为什么这么写,只是凭着:应该可以这么用,这段代码起到的应该是这种效果之类的来判断,所以你会看到无数这样的重复代码,因为我已经忘了当时的思路,当我还不会代码在修改别人的东西的时候,也有这种经历,不过这也就导致了很多“不可克服”,修完一个又来一个。

幸好只是用完就丢的小成品,如果真的是长期修改,维护性极差,如果是多人合作,估计要被队友喷死了。

函数调用方面,在添加过程里添加完函数那些没有形参的无法直接调用也让我蛋疼了一会儿,最终还是要通过搜索引擎和课件(虽然课件有点蛋疼,但还是能用的)

Public Function restart()
ShowNum.Caption = “0”
status = False
sum = 0
b = 0
c = 0
operator = “none”
operator2 = “none”
a = 0
i = 0
BtnPoint.Enabled = True
countor = 0
loop_array = 0
End Function

比如说上面的restart函数,我曾经想用restart()来调用,未果,后来终于Call成了(其实上课又讲过是没听讲吧=_=)

Private Sub BtnClear_Click()
Call restart
End Sub

封装成函数的优点在这次中非常明显,以前HTML时没这东西,PHP刚开始没学到这个,后来用了MVC的框架,也没这体验,这次还是比较深刻的感受到了。

当然,在restart中,再次暴露了没写注释和前后没有仔细考虑的短处——我写到restart的时候已经忘了我应该初始化哪些变量了……

当然,幸好我把按钮的Name定义的我自己看得懂,如果是默认的Commandx的话,我估计我更看不懂了(但部分变量当时急得没注释又随便起了个名,结果又悲剧了……)。

为了追求代码的一致性和美观,变量、控件Name(应当注意)都大写,这样代码会显得好看一点,但当时我明显没考虑那么多……

VB在属性的改变上似乎是很简单的,本身就是可视化的,刚开始我只知道:

ShowNum.Caption = "天家的计算器标准版V2"
ShowNum.Text = "天家的计算器标准版V2"    '或者

后来在想,是不是直接是Name.xxx就可以改变控件的属性,结果确实是这样,从自己折腾的角度似乎VB确实挺简单的。

当我刚接触VB时,很喜欢用Msgbox(事实上是我只会用……),但当时并没有想过太多……,其实Title什么的可以改变当时也没有注意过:

MsgBox ("不作死就不会死怎么就是不明白"), , "作死警告"

更多姿势在接下来一个程序中有使用,关于Msgbox的用法,这篇文章写的很好:http://it-easy.tw/msgbox/

boxmessage = MsgBox(“真的要走了吗”, 4 + 64, “退出?”)

关于变量,我很矛盾于,声明东一处西一出的很难看以及全部放在通用中全局控制又觉得不舒服的矛盾之中,通用中的声明专门拿来干这个事情,刚开始我以为这样定义的就是全局变量,结果这只是相对于本窗体(Me)而言的,如果需要全局变量,声明并不是:

Dim status, condition, mast, Minus As Boolean ‘是否能增加小数点
Dim sum, b, c As Double ‘b是加上的值,sum为运算结果
Dim operator_point, operator, operator2 As String ‘operator用于第一次运算,operator2用于重复点击按钮
Dim a, i, countor, loop_array As Integer ‘a是数字按钮,loop_array 用于数组循环

多窗体传值上,似乎有两种方法可以传递,第一是新建模块,在模块中定义Public(果然和其他语言一样)

Public U_Turn, Com_Turn As Boolean
Public Name1p As String

调用时直接把变量写为U_Turn之类的

或者在窗体的通用-声明中不使用Dim,而使用Public

Public sum, b, c As Double ‘Form1中定义

然后在其他窗体调用的时候使用

Form1.sum

关于换行,曾经脑补过是不是也用\n之类的,结果……我想多了。

“累得半死的节奏中,重构版” & vbCrLf & “小天出品,必属渣品”

VB的连接是用& 而不是用 . .(偶尔会很习惯的……),而换行(其实是换行加上回车)则是vbCrLf。

一般来说,都会很习惯的使用If,但是这次用Select Case比较多(来复习一下 JS、PHP叫Switch)

    Select Case operator2
        Case "plus"
        sum = sum + c
        Case "minus"
        sum = sum - c
        Case "times"
        sum = sum \* c
        Case "divide"
        sum = sum / c
    End Select

在JS\PHP中的Default在VB中是Case Else,相比很多次的if else,这货确实更直观一点,可读性更强。

计算器嘛,总得有键盘输入,找了半天终于知道Form中的KeyPress

If KeyAscii = 46 Then
Call BtnPoint_Click
End If

通过Ascii或者自带的按键表来确定按键,总体来说,这就是按键的本质?其实还有KeyUp和KeyDown,这应该是做蓄力的时候用的吧……

通用的声明中只能声明变量,如果设定运行初值,就得选择Form的Load

Private Sub Form_Load()
status = False
operator = “none”
sum = 0
End Sub

吸取了第一次的教训,在按钮只能怪终于开始使用了按钮组,很方便的解决了一个个按钮定义代码却几乎一个样的烦恼,尤其是连index都对应着按钮的时候:

Private Sub BtnNum_Click(Index As Integer)
a = Val(BtnNum(Index).Caption)
CalNumViewer (a)
CalController (a)
BtnBackSpace.Enabled = True
End Sub

虽然还不大清楚控件组的Array到底是怎么用的……不过我竟然还使用了。

If KeyAscii = 45 Then
Call Btnoperator_Click(1)
End If

或者

Dim numkeyloop As Integer
numkeyloop = 48
For loop_array = 0 To 9
If KeyAscii = numkeyloop Then
Call BtnNum_Click(loop_array)
End If
numkeyloop = numkeyloop + 1
Next loop_array

BtnNum(loop\_array).Enabled = False

总体来说调用起来还是差不多的。

VB并没有直接输出整个数组的循环,所以用index做循环很方便,如果是Key的话就会比较麻烦,虽然貌似VB同样也可以用字符串(键值)。

VB数组的姿势也可以是酱紫的:

Dim Count(100 to 500) As Integer

相比之下,果然还是更喜欢PHP呢。

在吸取了第一版本的经验和教训之后,我突然想到了把显示和运算分离(传说中的MVC思想?咳咳),然后就装模作样的写了View和Controller。

这样就能有效避免了删除之后结尾都是0位数就变了(数值的问题),因为按键显示才用的是字符串的方式。这样判断的方法就从:

Private Sub Backspace_Click()
If operator = “none” Then
If Int(sum) = sum Then
sum = Int(sum / 10)
If status = “point” & sum < 10 Then
Else
status = “none”
End If
ElseIf Int(sum * 10) = sum * 10 Then
sum = Int(sum)
b = sum
i = 1
Else
sum = Int(sum * 10 ^ (i - 1)) / 10 ^ (i - 1)
b = sum
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = “none”
End If
If Int(sum * 10 ^ (i - 2)) = sum * 10 ^ (i - 2) Then
Else

        End If
    i = i - 1
End If
            ShowNum.Caption = strnum(sum)

Else
If Int(b) = b Then
b = Int(b / 10)
Print b
ElseIf Int(b * 10) = b * 10 Then
b = Int(b)
countor = countor - 1
i = 1
Print i
Else
Print i
b = Int(b * 10 ^ (i - 1)) / 10 ^ (i - 1)
i = i - 1
If countor > 0 Then
countor = countor - 1
Else
countor = 0
status = “none”
End If
End If
ShowNum.Caption = strnum(b)
c = b
End If
End Sub

不断的做减法改成了:

‘View 部分
If Len(ShowNum.Caption) = 1 Then ‘如果只有一位数则删除后显示为0
ShowNum.Caption = “0”
ElseIf Right(ShowNum.Caption, 1) = “.” Then
ShowNum.Caption = Left(ShowNum.Caption, Len(ShowNum.Caption) - 1)
status = False
BtnPoint.Enabled = True
Else
ShowNum.Caption = Left(ShowNum.Caption, Len(ShowNum.Caption) - 1) ‘屏幕中删除最后一位数
End If

Len也是现场百度的OTZ……VB的教程实在没有像W3School那样的,幸好VBScript也能参考一下的样子。

Right(ShowNum.Caption, 1) ‘从右边开始数第一个字符
Len(ShowNum.Caption) ‘计算字符串长度
Left(ShowNum.Caption, Len(ShowNum.Caption) - 1) ‘从左边开始取到倒数第二个字符

VB还有一大蛋疼的地方就在于如果是0.x,那么是不显示0的,直接搜了一个函数用……其实当时也想到了类似的,但没想到绝对值……(用于答案上的显示,答案是数值型的)

Public Function strnum(X)
If Abs(X) < 1 And X <> 0 Then
If X > 0 Then
strnum = “0” & Trim(X)
Else
strnum = “-0” & Trim(Abs(X))
End If
Else
strnum = X
End If
End Function

最后很蛋疼的一点是减号问题,因为是字符,所以minus的两个功能就得分开来处理了,这点目前还是没有能很好的解决(因为View那边的那坨代码已经一团糟了啊啊啊——当我想到要写注释的时候已经晚了,可见好的习惯很重要)

If operator = "none" Or operator = "equal" & b = 0 & ShowNum.Caption = "0" & Minus = False Then
ShowNum.Caption = "-"

ElseIf ShowNum.Caption = “-“ Or ShowNum.Caption = “-0” Or ShowNum.Caption = “-0.” Then
If ShowNum.Caption = “-0” Or ShowNum.Caption = “-“ Then ‘如果显示为”0”或空
If BtnPoint.Enabled = False Then
ShowNum.Caption = “-0” & a
Else
ShowNum.Caption = “-“ & a
End If
Else
ShowNum.Caption = ShowNum.Caption & a
End If

另外还有两个现度娘的代码:

Private Sub ShowNum_Click()
Clipboard.Clear
Clipboard.SetText ShowNum.Caption
MsgBox (“成功将输出结果复制到剪贴板”), , “Big Surprise!”
End Sub

Private Sub BtnBlog_Click()
Shell “explorer.exe 网址”, vbNormalFocus ‘连接至博客
End Sub

Shell貌似也有很多用处,暂时没有了解。

VB6.0最蛋疼的功能是撤销和重做,我移动了控件位置之后,总是习惯性的Ctrl+Z结果没有发生什么,然后我又习惯性的按了重做,结果更不知道他到底干了些什么……结果好不容易改完的又悲剧了……

总体而言,收获并不在VB本身,而在于更好的理解编码这个过程:

  1. 比如说,注释(好吧我承认这是我第一次认清注释的重要性),可读性和可维护性。
  2. 再比如说考虑好了再动键盘也不迟,有的时候写完要写另一块的时候会想到这块完全可以这么写…之类的,总体而言,没有从整体的角度来思考一个问题。
  3. 刚开始的时候觉得,这东西就应该是酱紫酱紫就OK,感觉想的也满细致的,结果实际写的时候才知道自己想的依旧只是一个模糊的框架罢了,这点在写Lost&Found的时候(没写完),也有些体会,我知道大概要用到什么东西,但具体操作起来,还是感觉不明白。
  4. 还有对一些功能和概念,原本不知道这货的优点在什么地方。

果然还是写实际的东西最开心啦,比起做那些什么算法题什么高数线代开心多了。

下次我会认真写注释的!

欢迎关注我的其它发布渠道