计算机用户经常把控制台应用程序作为一种“遗物”来看待,但是它们仍然还作为系统管理员的非常喜欢的一部分,而且还是高手用户的“工具箱”之一。另外,当你需要大量重复的脚本操作,当然还有可能的更复杂的操作时都会用到这种控制台应用程序。
在Visual Basic的早期版本中基本没有为创建控制台应用程序提供多大支持。而且,尽管VB 6及其早期版本能够创建控制台应用程序;但是,这不是一种简单的或直接的过程。在VB 6中创建一个控制台应用程序必须进行Win32 API调用;即使如此,你也不能控制光标位置或文本的颜色,而且在很大程度上仅能被限制进行从左到右和从上到下的编码。
如今,VB.net引入了新的控制台应用程序特征。它不仅在“New Project...”对话框中提供一种控制台应用程序工程,而且最重要的是,它还提供了一个控制台(Console)对象。因此,你不必再“困扰”于 Win32 API了。然而,你还是被限于“从左到右和从上到下”的编码。但是,VB.net仍然缺乏用于改变光标或文本的位置或颜色的方法或属性,还有其它许多更高级的特征。
一、 在VB 2005中的新型控制台应用程序特征
基于早期VB.NET版本中所提供的Console对象,如今的VB 2005又为控制台应用程序增加了许多优秀的特征。下面列出的仅是VB 2005中更为激动人心的功能中的一部分:
· 清除控制台窗口
· 得到并设定光标位置和大小
· 得到并设定窗口高度和宽度
· 得到并设定前景和背景颜色
· 选择并在控制台窗口内移动部分文本
本文中的其它部分将详细地分析一个控制台应用程序的创建过程,以便展示上面这些特征的使用。
二、 实例应用程序—DirCopy
我经常从控制台窗口中实现把文件从一个目录复制到另一个目录。当我复制一个含有大量文件的目录时,我经常希望得到一些提示—复制进程完成的怎么样了?复制快结束了还是再等待一会?为了实现这一问题,我构建了一个控制台应用程序,它能够在控制台窗口内显示一个进度条来以图形化显示复制进度。
三、 定义功能
为了简化本文中的演示目的,DirCopy将使用两个命令行参数:一个源目录和一个目的目录。然后,它把所有文件从源目录复制到目的目录。注意,这个简单的程序无法复制源目录下的子目录。
首先,我编写一个DisplayUsage子程序。如果使用太多或太少的命令行参数调用DirCopy,那么它将调用DisplayUsage,然后结束。图1显示了在没有任何命令行参数时运行DirCopy的结果。
图1:DisplayUsage子程序运行结果
下列是DisplayUsage子程序的代码: Private Sub DisplayUsage()
Dim originalForegroundColor As ConsoleColor = Console.ForegroundColor
Console.Clear()
Console.ForegroundColor = ConsoleColor.Green
Console.WriteLine("DirCopy 1.0")
Console.WriteLine("Written by Josh Fitzgerald")
Console.WriteLine(New String("-", Console.WindowWidth))
Console.WriteLine("DirCopy will copy all of the files from the
source folder to the")
Console.WriteLine("destination folder. While the files are
copying, a progress bar")
Console.WriteLine("will display the percent complete.")
Console.WriteLine()
Console.WriteLine("If a directory name contains spaces, enclose
it in double quotes.")
Console.WriteLine()
Console.Write("Example : ")
Console.ForegroundColor = ConsoleColor.Magenta
Console.WriteLine("DirCopy C:\MyFolder C:\MyNewFolder")
Console.ForegroundColor = ConsoleColor.Green
Console.WriteLine()
Console.Write("Example : ")
Console.ForegroundColor = ConsoleColor.Magenta
Console.WriteLine("DirCopy ""C:\My Folder"" ""C:\My New Folder""")
Console.ForegroundColor = originalForegroundColor
End Sub
该子程序做的第一事情是创建一个变量originalForegroundColor,然后它存储Console.ForegroundColor的值。在子程序的最后,代码把Console.ForegroundColor属性设置回originalForegroundColor。当你分析这部分代码时,你会注意到,在每个修改前景或背景颜色的子程序中都是这样操作的。在实际运行DirCopy之前,我想确保DirCopy总是让控制台显示相同的颜色。
DisplayUsage做的下一件事情是,使用Console.Clear方法清除控制台屏幕。这是在VB2005中的新方法之一;这样以来,程序员可以很容易地拥有一个干净的控制台窗口。
我想让帮助文本显眼一点,为此,我把ForegroundColor属性设置为绿色。然后,我使用Writeline和Write方法把几行文本输出到屏幕上。在描述的最后,我包括了一些怎样运行DirCopy的示例。我想使得这些示例突出一些;因此,我把ForegroundColor设置为品红色。
四、 引擎—CopyFiles
这个CopyFiles子程序负责完成这个应用程序中的绝大多数工作。它负责取得源目录下的一个文件列表,然后把它们复制到目的目录下。另外,它还创建了一个ConsoleProgressBar对象来管理进度条: Private Sub CopyFiles(ByVal srcDir As String, ByVal destDir As String)
Const BufferSourceTopLine As Integer = 8
Const BufferDestinationTopLine As Integer = 7
Dim rowIndex As Integer = 7
Dim originalForegroundColor As ConsoleColor = Console.ForegroundColor
Console.CursorVisible = False
Console.Clear()
Dim numberOfFiles As Integer
numberOfFiles = My.Computer.FileSystem.GetFiles(srcDir).Count
Dim PB As New ConsoleProgressBar(numberOfFiles)
DisplayHeader(srcDir, destDir)
Dim fileCounter As Integer = 1
For Each f As String In My.Computer.FileSystem.GetFiles(srcDir)
Dim fi As New System.IO.FileInfo(f)
Console.ForegroundColor = ConsoleColor.Green
Console.SetCursorPosition(0, rowIndex)
Console.Write(fi.Name)
If rowIndex < Console.WindowHeight - 1 Then
rowIndex += 1
Else
Console.MoveBufferArea(0,BufferSourceTopLine, _
Console.WindowWidth, _
Console.WindowHeight - _
BufferSourceTopLine, _
0, _
BufferDestinationTopLine)
End If
My.Computer.FileSystem.CopyFile(fi.FullName, destDir &"\" & fi.Name)
pb.Update( fileCounter)
fileCounter += 1
Next
Console.ForegroundColor = originalForegroundColor
Console.SetCursorPosition(0, Console.WindowHeight - 1)
Console.CursorVisible = True
End Sub
首先,该代码保存当前的ForegroundColor。然后,它使用另外一种新特征把CursorVisible属性设置为False。在清除控制台窗口后,它检索在源目录下的文件个数并且使用这个数字作为ConsoleProgressBar构造器的最大值。稍后,我还要讨论有关于 ConsoleProgressBar的细节信息。
我调用DisplayHeader子程序来把一些有关复制操作的信息打印到控制台窗口。由于其功能非常类似于DisplayUsage子程序,所以我在此省略对其细节的讨论。
我使用了一个“For...Each”循环来遍历在源目录下的所有文件,并使用了一个rowIndex变量来跟踪要把文件名打印到控制台的哪一行。随着循环的不断执行,rowIndex每次增加1,直到到达控制台窗口的底部为止。一旦到达控制台窗口的底部,我利用另外一个新控制台应用程序特征— MoveBufferArea方法(下一节讨论)。
在更新显示和复制文件后,我通过调用ConsoleProgressBar类的Update方法来更新进度条。
一旦循环结束并且文件复制结束,我再把ForegroundColor设置回其原来的颜色,并且把光标位置设置到控制台窗口的最下面一行,并且使之再次可见。
五、 移动控制台中的一个区域
MoveBufferArea方法允许我指定控制台窗口内的一个区域(或缓冲区),然后指定一组坐标来移动它。我想把文件名列表显示到一个滚动列表中,而同时还能维持头部信息及控制台窗口顶部的进度栏。一旦我把一个文件名打印到控制台中的最后一行,我就停止更新rowIndex变量并开始使用 MoveBufferArea方法。
MoveBufferArea使用了六个参数:
· 第一个参数指定你想选择区域的左边缘。
· 第二个参数指定你的缓冲区区域的最上边一行。
· 第三和第四个参数指定你的缓冲区区域的宽度和高度。
· 最后两个参数指定你想把你的缓冲区移往的区域的左边缘和最上边一行。
Console.MoveBufferArea(0, _
BufferSourceTopLine, _
Console.WindowWidth, _
Console.WindowHeight - BufferSourceTopLine, _
0, _
BufferDestinationTopLine)
这段代码告诉MoveBufferArea方法从第0列和第BufferSourceTopLine(一个常量,值为8)行开始。然后,它把缓冲区区域宽度设置为等于控制台窗口的宽度并且把缓冲区区域高度设置为等于控制台窗口高度和文件名列表的最上面一行(BufferSourceTopLine)之差。最后两个参数指定我的缓冲区区域的目标位置为第0列和第BufferDestinationTopLine(定义为常数7)行。
用更简单的描述来说就是,该代码通过最后一个名字选择在列表中的第二个文件名并且把该缓冲区往上移动一行,有效地删除了最上面的文件名并且为底部的下一个文件名留出了空间。
六、 ConsoleProgressBar类
我创建了ConsoleProgressBar类来处理初始化和更新进度条的细节问题。其构造器使用了一个参数—MaximumValue:
Public Sub New(ByVal MaximumValue As Long)
m_length = Console.WindowWidth - 10
m_left = 7
m_right = m_left + m_length + 1
m_progressBarRow = 1
m_messageBarRow = m_progressBarRow + 1
m_percentPosition = 4
m_maximumValue = MaximumValue
m_currentValue = 0
Initialize()
End Sub
我硬编码了一些值,并且基于这些硬编码值计算其它值。在本文中,我构造的这个类很小,但是你可以扩展这个构造器以便再加入其它参数—使得进度条更具配置性。
在初始化所有的成员变量以后,我调用Initialize方法,它又调用InitializePercentComplete, InitializeProgressBar和InitializeMessageBar方法。这些方法的任务并不多;它们仅打印一个百分号,一组表示进度条结束的方括号,以及该进度条的最大值和最小值。
七、 进度条进度显示
在Update方法被调用前,在ConsoleProgressBar对象中什么也没有发生:
Public Sub Update(ByVal CurrentValue As Long)
m_currentValue = CurrentValue
m_currentBarLength = CInt((m_currentValue / m_maximumValue) * m_length)
Refresh()
End Sub
这个Update方法使用一个值作参数(在此是指当前刚刚复制的文件数)。我设置成员m_currentValue,然后计算m_currentBarLength。计算的结果为进度条当前应该覆盖的列数。
最后,我调用Refresh方法,它又调用UpdatePercentComplete、UpdateProgressBar和UpdateMessageBar方法。
因为所有这三个方法功能相类似,所以我将集中讨论UpdateProgressBar方法: Private Sub UpdateProgressBar()
Dim originalForegroundColor As ConsoleColor = Console.ForegroundColor
Dim originalBackgroundColor As ConsoleColor = Console .BackgroundColor
Console.ForegroundColor = ConsoleColor.Black
Console.BackgroundColor = ConsoleColor.Green
Console.SetCursorPosition(m_left + 1 m_progressBarRow)
Dim progress As New String("O", m_currentBarLength)
Console.Write(progress)
Console.ForegroundColor =originalForegroundColor
Console.BackgroundColor = originalBackgroundColor
End Sub
首先,该代码保存当前的前景和背景颜色。然后,它把ForegroundColor属性设置为黑色,把BackgroundColor属性设置为绿色。在把光标放置到进度条的左边缘后,它打印一串长度为m_currentBarLength的“O”。
八、 运行DirCopy
你一定很想看到应用程序运行情况(参考图2和3),并想检查一下运行结果(参考图4)。我建立了一个目录,并使用一串哑文件来测试复制。我建议,在你使用DirCopy复制任何关键文件前,你也这样试验一下。
图2:开始DirCopy
图3:DirCopy运行中
图4:DirCopy运行完成
九、 其它问题
这个DirCopy应用程序,虽然有些用处,但是还远非成品。为了使其更为强壮,还需要增加大量的错误处理方式。你还可以改进ConsoleProgressBar类以实现更灵活的控制。下列是一些可能的改进:
· 允许控制进度条的位置和长度
· 允许百分比完成区域放到你选择的任何位置
· 允许定制进度条中的消息
· 添加一个选项以选择水平的或垂直的进度条
十、 小结
我希望,本文有助于你了解VB 2005所提供的部分新的控制台应用程序特征,尽管这些特征仅是其中的一部分。另外,我还鼓励你再分析一下其它一些控制台应用程序特征,并与本文介绍相结合以发现你更喜欢的特征。
评论