[英]How can I create a progress bar in Excel VBA?
我正在做一个需要从数据库更新大量数据的 Excel 应用程序,因此需要时间。 我想在用户窗体中制作一个进度条,并在数据更新时弹出。 我想要的条只是一个蓝色的小条,左右移动并重复直到更新完成,不需要百分比。
我知道我应该使用progressbar
控件,但我尝试了一段时间,但无法做到。
我的问题是progressbar
条控件,我看不到进度条。 它只是在表单弹出时完成。 我使用循环和DoEvent
但这不起作用。 另外,我希望该过程重复运行,而不仅仅是一次。
有时状态栏中的一条简单消息就足够了:
这很容易实现:
Dim x As Integer
Dim MyTimer As Double
'Change this loop as needed.
For x = 1 To 50
' Do stuff
Application.StatusBar = "Progress: " & x & " of 50: " & Format(x / 50, "0%")
Next x
Application.StatusBar = False
这是使用 StatusBar 作为进度条的另一个示例。
通过使用一些 Unicode 字符,您可以模仿进度条。 9608 - 9615 是我为条形尝试的代码。 只需根据要在条形之间显示多少空间来选择一个。 您可以通过更改 NUM_BARS 来设置条的长度。 此外,通过使用类,您可以将其设置为自动处理初始化和释放状态栏。 一旦对象超出范围,它将自动清理并将状态栏释放回 Excel。
' Class Module - ProgressBar
Option Explicit
Private statusBarState As Boolean
Private enableEventsState As Boolean
Private screenUpdatingState As Boolean
Private Const NUM_BARS As Integer = 50
Private Const MAX_LENGTH As Integer = 255
Private BAR_CHAR As String
Private SPACE_CHAR As String
Private Sub Class_Initialize()
' Save the state of the variables to change
statusBarState = Application.DisplayStatusBar
enableEventsState = Application.EnableEvents
screenUpdatingState = Application.ScreenUpdating
' set the progress bar chars (should be equal size)
BAR_CHAR = ChrW(9608)
SPACE_CHAR = ChrW(9620)
' Set the desired state
Application.DisplayStatusBar = True
Application.ScreenUpdating = False
Application.EnableEvents = False
End Sub
Private Sub Class_Terminate()
' Restore settings
Application.DisplayStatusBar = statusBarState
Application.ScreenUpdating = screenUpdatingState
Application.EnableEvents = enableEventsState
Application.StatusBar = False
End Sub
Public Sub Update(ByVal Value As Long, _
Optional ByVal MaxValue As Long= 0, _
Optional ByVal Status As String = "", _
Optional ByVal DisplayPercent As Boolean = True)
' Value : 0 to 100 (if no max is set)
' Value : >=0 (if max is set)
' MaxValue : >= 0
' Status : optional message to display for user
' DisplayPercent : Display the percent complete after the status bar
' <Status> <Progress Bar> <Percent Complete>
' Validate entries
If Value < 0 Or MaxValue < 0 Or (Value > 100 And MaxValue = 0) Then Exit Sub
' If the maximum is set then adjust value to be in the range 0 to 100
If MaxValue > 0 Then Value = WorksheetFunction.RoundUp((Value * 100) / MaxValue, 0)
' Message to set the status bar to
Dim display As String
display = Status & " "
' Set bars
display = display & String(Int(Value / (100 / NUM_BARS)), BAR_CHAR)
' set spaces
display = display & String(NUM_BARS - Int(Value / (100 / NUM_BARS)), SPACE_CHAR)
' Closing character to show end of the bar
display = display & BAR_CHAR
If DisplayPercent = True Then display = display & " (" & Value & "%) "
' chop off to the maximum length if necessary
If Len(display) > MAX_LENGTH Then display = Right(display, MAX_LENGTH)
Application.StatusBar = display
End Sub
示例用法:
Dim progressBar As New ProgressBar
For i = 1 To 100
Call progressBar.Update(i, 100, "My Message Here", True)
Application.Wait (Now + TimeValue("0:00:01"))
Next
过去,在 VBA 项目中,我使用带有背景颜色的标签控件并根据进度调整大小。 可以在以下链接中找到一些具有类似方法的示例:
这是使用 Excel 的 Autoshapes 的一种:
我喜欢这里发布的所有解决方案,但我使用条件格式作为基于百分比的数据栏解决了这个问题。
这适用于一行单元格,如下所示。 包含 0% 和 100% 的单元格通常是隐藏的,因为它们只是为了提供“ScanProgress”命名范围(左)上下文。
在代码中,我在一个表中循环做一些事情。
For intRow = 1 To shData.Range("tblData").Rows.Count
shData.Range("ScanProgress").Value = intRow / shData.Range("tblData").Rows.Count
DoEvents
' Other processing
Next intRow
最少的代码,看起来不错。
============== This code goes in Module1 ============
Sub ShowProgress()
UserForm1.Show
End Sub
============== Module1 Code Block End =============
在工作表上创建一个按钮; 将按钮映射到“ShowProgress”宏
创建一个带有 2 个按钮、进度条、条形框、文本框的 UserForm1:
UserForm1 = canvas to hold other 5 elements
CommandButton2 = Run Progress Bar Code; Caption:Run
CommandButton1 = Close UserForm1; Caption:Close
Bar1 (label) = Progress bar graphic; BackColor:Blue
BarBox (label) = Empty box to frame Progress Bar; BackColor:White
Counter (label) = Display the integers used to drive the progress bar
======== Attach the following code to UserForm1 =========
Option Explicit
' This is used to create a delay to prevent memory overflow
' remove after software testing is complete
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Private Sub UserForm_Initialize()
Bar1.Tag = Bar1.Width
Bar1.Width = 0
End Sub
Sub ProgressBarDemo()
Dim intIndex As Integer
Dim sngPercent As Single
Dim intMax As Integer
'==============================================
'====== Bar Length Calculation Start ==========
'-----------------------------------------------'
' This section is where you can use your own '
' variables to increase bar length. '
' Set intMax to your total number of passes '
' to match bar length to code progress. '
' This sample code automatically runs 1 to 100 '
'-----------------------------------------------'
intMax = 100
For intIndex = 1 To intMax
sngPercent = intIndex / intMax
Bar1.Width = Int(Bar1.Tag * sngPercent)
Counter.Caption = intIndex
'======= Bar Length Calculation End ===========
'==============================================
DoEvents
'------------------------
' Your production code would go here and cycle
' back to pass through the bar length calculation
' increasing the bar length on each pass.
'------------------------
'this is a delay to keep the loop from overrunning memory
'remove after testing is complete
Sleep 10
Next
End Sub
Private Sub CommandButton1_Click() 'CLOSE button
Unload Me
End Sub
Private Sub CommandButton2_Click() 'RUN button
ProgressBarDemo
End Sub
================= UserForm1 Code Block End =====================
============== This code goes in Module1 =============
Sub ShowProgress()
UserForm1.Show
End Sub
============== Module1 Code Block End =============
我喜欢这个页面的状态栏:
https://wellsr.com/vba/2017/excel/vba-application-statusbar-to-mark-progress/
我更新了它,以便它可以用作被调用的过程。 对我没有信用。
showStatus Current, Total, " Process Running: "
Private Sub showStatus(Current As Integer, lastrow As Integer, Topic As String)
Dim NumberOfBars As Integer
Dim pctDone As Integer
NumberOfBars = 50
'Application.StatusBar = "[" & Space(NumberOfBars) & "]"
' Display and update Status Bar
CurrentStatus = Int((Current / lastrow) * NumberOfBars)
pctDone = Round(CurrentStatus / NumberOfBars * 100, 0)
Application.StatusBar = Topic & " [" & String(CurrentStatus, "|") & _
Space(NumberOfBars - CurrentStatus) & "]" & _
" " & pctDone & "% Complete"
' Clear the Status Bar when you're done
' If Current = Total Then Application.StatusBar = ""
End Sub
您可以在 VBA 中创建一个表单,使用代码随着代码的进展增加标签控件的宽度。 您可以使用标签控件的宽度属性来调整其大小。 您可以将标签的背景颜色属性设置为您选择的任何颜色。 这将让您创建自己的进度条。
调整大小的标签控件是一个快速解决方案。 然而,大多数人最终会为他们的每个宏创建单独的表单。 我使用 DoEvents 函数和一个无模式表单来为您的所有宏使用一个表单。
这是我写的一篇博客文章: http : //strugglingtoexcel.wordpress.com/2014/03/27/progress-bar-excel-vba/
您所要做的就是将表单和模块导入到您的项目中,并使用以下命令调用进度条: Call modProgress.ShowProgress(ActionIndex, TotalActions, Title.....)
我希望这有帮助。
Sub ShowProgress()
' Author : Marecki
Const x As Long = 150000
Dim i&, PB$
For i = 1 To x
PB = Format(i / x, "00 %")
Application.StatusBar = "Progress: " & PB & " >>" & String(Val(PB), Chr(183)) & String(100 - Val(PB), Chr(32)) & "<<"
Application.StatusBar = "Progress: " & PB & " " & ChrW$(10111 - Val(PB) / 11)
Application.StatusBar = "Progress: " & PB & " " & String(100 - Val(PB), ChrW$(9608))
Next i
Application.StatusBar = ""
End SubShowProgress
嗨, Marecki的另一篇文章的修改版。 有4种款式
1. dots ....
2 10 to 1 count down
3. progress bar (default)
4. just percentage.
在你问我为什么不编辑那个帖子之前,我做了并且它被拒绝了被告知要发布一个新的答案。
Sub ShowProgress()
Const x As Long = 150000
Dim i&, PB$
For i = 1 To x
DoEvents
UpdateProgress i, x
Next i
Application.StatusBar = ""
End Sub 'ShowProgress
Sub UpdateProgress(icurr As Long, imax As Long, Optional istyle As Integer = 3)
Dim PB$
PB = Format(icurr / imax, "00 %")
If istyle = 1 Then ' text dots >>.... <<'
Application.StatusBar = "Progress: " & PB & " >>" & String(Val(PB), Chr(183)) & String(100 - Val(PB), Chr(32)) & "<<"
ElseIf istyle = 2 Then ' 10 to 1 count down (eight balls style)
Application.StatusBar = "Progress: " & PB & " " & ChrW$(10111 - Val(PB) / 11)
ElseIf istyle = 3 Then ' solid progres bar (default)
Application.StatusBar = "Progress: " & PB & " " & String(100 - Val(PB), ChrW$(9608))
Else ' just 00 %
Application.StatusBar = "Progress: " & PB
End If
End Sub
关于用户窗体中的progressbar
控件,如果您不使用repaint
事件,它将不会显示任何进度。 您必须在循环内对此事件进行编码(并且显然会增加progressbar
值)。
使用示例:
userFormName.repaint
只需将我的部分添加到上述集合中。
如果您追求更少的代码和可能很酷的 UI。 查看我的GitHub for Progressbar for VBA
一个可定制的:
Dll 是为 MS-Access 考虑的,但应该可以在所有 VBA 平台上工作,只需稍作改动。 还有一个带有示例的 Excel 文件。 您可以自由扩展 vba 包装器以满足您的需要。
该项目目前正在开发中,并未涵盖所有错误。 所以期待一些!
您应该担心 3rd 方 dll,如果您担心,请在实施 dll 之前随意使用任何可信赖的在线防病毒软件。
还有许多其他很棒的帖子,但是我想说的是,理论上您应该能够创建一个真正的进度条控件:
CreateWindowEx()
创建进度条一个 C++ 示例:
hwndPB = CreateWindowEx(0, PROGRESS_CLASS, (LPTSTR) NULL, WS_CHILD | WS_VISIBLE, rcClient.left,rcClient.bottom - cyVScroll,rcClient.right, cyVScroll,hwndParent, (HMENU) 0, g_hinst, NULL);
hwndParent
应该设置为父窗口。 为此,可以使用状态栏或自定义表单! 这是从 Spy++ 中找到的 Excel 的窗口结构:
因此,使用FindWindowEx()
函数应该相对简单。
hwndParent = FindWindowEx(Application.hwnd,,"MsoCommandBar","Status Bar")
创建进度条后,您必须使用SendMessage()
与进度条交互:
Function MAKELPARAM(ByVal loWord As Integer, ByVal hiWord As Integer)
Dim lparam As Long
MAKELPARAM = loWord Or (&H10000 * hiWord)
End Function
SendMessage(hwndPB, PBM_SETRANGE, 0, MAKELPARAM(0, 100))
SendMessage(hwndPB, PBM_SETSTEP, 1, 0)
For i = 1 to 100
SendMessage(hwndPB, PBM_STEPIT, 0, 0)
Next
DestroyWindow(hwndPB)
我不确定这个解决方案有多实用,但它可能看起来比这里提到的其他方法更“官方”。
如果您有大量数据需要处理,@ eykanal发布的解决方案可能不是最好的,因为启用状态栏会减慢代码执行速度。
以下链接说明了构建进度条的一种好方法。 适用于高数据量(约250K条记录+):
http://www.excel-easy.com/vba/examples/progress-indicator.html
您可以添加一个 Form 并将其命名为 Form1,也可以将一个 Frame 添加为 Frame1 以及 Label1。 将 Frame1 宽度设置为 200,将背景颜色设置为蓝色。 将代码放在模块中并检查它是否有帮助。
Sub Main()
Dim i As Integer
Dim response
Form1.Show vbModeless
Form1.Frame1.Width = 0
For i = 10 To 10000
With Form1
.Label1.Caption = Round(i / 100, 0) & "%"
.Frame1.Width = Round(i / 100, 0) * 2
DoEvents
End With
Next i
Application.Wait Now + 0.0000075
Unload Form1
response = MsgBox("100% Done", vbOKOnly)
End Sub
如果要在状态栏上显示,则可以使用其他更简单的方式:
Sub Main()
Dim i As Integer
Dim response
For i = 10 To 10000
Application.StatusBar = Round(i / 100, 0) & "%"
Next i
Application.Wait Now + 0.0000075
response = MsgBox("100% Done", vbOKOnly)
End Sub
我知道这是一个旧线程,但我问过一个类似的问题,但不知道这个问题。 我需要一个 Excel VBA 进度条并找到此链接: Excel Z6E3EC7E6A9F6007B4838FC0EE7 。 这是我写的一个通用版本。 有 2 种方法,一个简单版本 DisplaySimpleProgressBarStep,默认为 '[|| ] 20% Complete' 和一个更通用的版本 DisplayProgressBarStep,它包含一个可选 arguments 的洗衣清单,这样您就可以让它看起来像您想要的任何东西。
Option Explicit
' Resources
' ASCII Chart: https://vbaf1.com/ascii-table-chart/
Private Enum LabelPlacement
None = 0
Prepend
Append
End Enum
#If VBA7 Then
Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As LongPtr) 'For 64 Bit Systems
#Else
Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) 'For 32 Bit Systems
#End If
Public Sub Test()
Call ProgressStatusBar(Last:=10)
End Sub
Public Sub Test2()
Const lMilliseconds As Long = 500
Dim lIndex As Long, lNumberOfBars As Long
Dim sBarChar As String
sBarChar = Chr$(133) ' Elipses …
sBarChar = Chr$(183) ' Middle dot ·
sBarChar = Chr$(176) ' Degree sign °
sBarChar = Chr$(171) ' Left double angle «
sBarChar = Chr$(187) ' Right double angle »
sBarChar = Chr$(166) ' Broken vertical bar ¦
sBarChar = Chr$(164) ' Currency sign ¤
sBarChar = Chr$(139) ' Single left-pointing angle quotation mark ‹
sBarChar = Chr$(155) ' Single right-pointing angle quotation mark ›
sBarChar = Chr$(149) ' Bullet •
sBarChar = "|"
For lIndex = 1 To 10
Call DisplayProgressBarStep(lIndex, 10, 50, LabelPlacement.Append, sBarChar)
Call Sleep(lMilliseconds)
Next
Call MsgBox("Status bar test completed.", vbOKOnly Or vbInformation, "Test2 Completed")
Call DisplayProgressBarStep(lIndex, 10, bClearStatusBar:=True)
End Sub
Public Sub Test2Simple()
Const lMilliseconds As Long = 500
Dim lIndex As Long, lNumberOfBars As Long
For lIndex = 1 To 10
Call DisplayProgressBarStep(lIndex, 10, 50)
Call Sleep(lMilliseconds)
Next
Call MsgBox("Status bar test completed.", vbOKOnly Or vbInformation, "Test2Simple Completed")
Call DisplayProgressBarStep(lIndex, 10, bClearStatusBar:=True)
End Sub
''' <summary>
''' Method to display an Excel ProgressBar. Called once for each step in the calling code process.
''' Defaults to vertical bar surrounded by square brackets with a trailing percentage label (e.g. [|||||] 20% Complete).
'''
''' Adapted
''' From: Excel VBA StatusBar
''' Link: https://www.wallstreetmojo.com/vba-status-bar/
''' </summary>
''' <param name="Step">The current step count.</param>
''' <param name="StepCount">The total number of steps.</param>
''' <param name="NumberOfBars">Optional, Number of bars displayed for StepCount. Defaults to StepCount. The higher the number, the longer the string.</param>
''' <param name="LabelPlacement">Optional, Can be None, Prepend or Append. Defaults to Append.</param>
''' <param name="BarChar">Optional, Character that makes up the horizontal bar. Defaults to | (Pipe).</param>
''' <param name="PrependedBoundaryText">Optional, Boundary text prepended to the StatusBar. Defaults to [ (Left square bracket).</param>
''' <param name="AppendedBoundaryText">Optional, Boundary text appended to the StatusBar. Defaults to ] (Right square bracket).</param>
''' <param name="ClearStatusBar">Optional, True to clear the StatusBar. Defaults to False.</param>
Private Sub DisplayProgressBarStep( _
lStep As Long, _
lStepCount As Long, _
Optional lNumberOfBars As Long = 0, _
Optional eLabelPlacement As LabelPlacement = LabelPlacement.Append, _
Optional sBarChar As String = "|", _
Optional sPrependedBoundaryText As String = "[", _
Optional sAppendedBoundaryText As String = "]", _
Optional bClearStatusBar As Boolean = False _
)
Dim lCurrentStatus As Long, lPctComplete As Long
Dim sBarText As String, sLabel As String, sStatusBarText As String
If bClearStatusBar Then
Application.StatusBar = False
Exit Sub
End If
If lNumberOfBars = 0 Then
lNumberOfBars = lStepCount
End If
lCurrentStatus = CLng((lStep / lStepCount) * lNumberOfBars)
lPctComplete = Round(lCurrentStatus / lNumberOfBars * 100, 0)
sLabel = lPctComplete & "% Complete"
sBarText = sPrependedBoundaryText & String(lCurrentStatus, sBarChar) & Space$(lNumberOfBars - lCurrentStatus) & sAppendedBoundaryText
Select Case eLabelPlacement
Case LabelPlacement.None: sStatusBarText = sBarText
Case LabelPlacement.Prepend: sStatusBarText = sLabel & " " & sBarText
Case LabelPlacement.Append: sStatusBarText = sBarText & " " & sLabel
End Select
Application.StatusBar = sStatusBarText
''Debug.Print "CurStatus:"; lCurrentStatus, "PctComplete:"; lPctComplete, "'"; sStatusBarText; "'"
End Sub
''' <summary>
''' Method to display a simple Excel ProgressBar made up of vertical bars | with a trailing label. Called once for each step in the calling code process.
'''
''' Adapted
''' From: Excel VBA StatusBar
''' Link: https://www.wallstreetmojo.com/vba-status-bar/
''' </summary>
''' <param name="Step">The current step count.</param>
''' <param name="StepCount">The total number of steps.</param>
''' <param name="NumberOfBars">Optional, Number of bars displayed for StepCount. Defaults to StepCount. The higher the number, the longer the string.</param>
''' <param name="ClearStatusBar">Optional, True to clear the StatusBar. Defaults to False.</param>
Private Sub DisplaySimpleProgressBarStep( _
lStep As Long, _
lStepCount As Long, _
Optional lNumberOfBars As Long = 0, _
Optional bClearStatusBar As Boolean = False _
)
Call DisplayProgressBarStep(lStep, lStepCount, lNumberOfBars, bClearStatusBar:=bClearStatusBar)
End Sub
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.