Zurück zur Homepage

Fortschrittsanzeige in Statusleiste mit Prozentangabe

Ein länger laufendes Makro blockiert in Excel so ziemlich alles.
Damit der User erkennt, dass sich noch was tut, kann man in der Statusleiste Text ausgeben. Wenn man die richtigen Zeichen nimmt, kann man sogar so etwas wie Laufbalken erzeugen. Professioneller dagegen sieht ein gemalter Laufbalken aus, mit einer Prozentanzeige daneben. Das Ganze ist verpackt in eine Prozedur, der folgende Parameter übergeben werden können: Breite in Prozent, Farbe des Fortschrittsbalken, Rahmenfarbe des Balkens, dann Textfarbe, Schriftart, Schriftdicke und Schriftgröße der Prozentanzeige. Es wird das Fensterhandle der Statusleiste ermittelt, der freien Platz darin wird abgeschätzt, der DC wird ausgeliehen und mit ein paar API-Funktionen wird ein gefülltes Rechteck, der Rahmen und der Prozenttext gezeichnet.

Beispieldatei (Fortschritt.zip 16 kB)

Private Declare Function DeleteObject Lib "gdi32" _
  (ByVal hObject As Long) As Long

Private Declare Function GetDC Lib "user32" _
  (ByVal hwnd As Long) As Long

Private Declare Function ReleaseDC Lib "user32" _
  (ByVal hwnd As Long, ByVal hdc As Long) As Long

Private Declare Function CreateSolidBrush Lib "gdi32" _
  (ByVal crColor As Long) As Long

Private Declare Function GetWindowRect Lib "user32" _
  (ByVal hwnd As Long, lpRect As RECT) As Long

Private Declare Function FillRect& Lib "user32" _
  (ByVal hdc As Long, lpRect As RECT, ByVal hBrush As Long)

Private Declare Function GetSystemMetrics Lib "user32" _
  (ByVal nIndex As Long) As Long

Private Declare Function FindWindowEx Lib "user32" _
  Alias "FindWindowExA" (ByVal hwnd1 As Long, _
  ByVal hWnd2 As Long, ByVal lpsz1 As String, _
  ByVal lpsz2 As String) As Long

Private Declare Function GetWindow Lib "user32" _
  (ByVal hwnd As Long, ByVal wCmd As Long) As Long

Private Declare Function FrameRect Lib "user32" _
  (ByVal hdc As Long, lpRect As RECT, _
  ByVal hBrush As Long) As Long

Private Declare Function DrawText Lib "user32" _
  Alias "DrawTextA" (ByVal hdc As Long, _
  ByVal lpStr As String, ByVal nCount As Long, _
  lpRect As RECT, ByVal wFormat As Long) As Long

Private Declare Function SetTextColor Lib "gdi32" _
  (ByVal hdc As Long, ByVal crColor As Long) As Long

Private Declare Function GetTextColor Lib "gdi32" _
  (ByVal hdc As Long) As Long

Private Declare Function CreateFontIndirect Lib "gdi32" _
  Alias "CreateFontIndirectA" (lpLogFont As LOGFONT) As Long

Private Declare Function SelectObject Lib "gdi32" _
  (ByVal hdc As Long, ByVal hObject As Long) As Long

Private Const LF_FACESIZE = 32
Private Const DT_CENTER = &H1
Private Const SM_CXSCREEN = 0
Private Const PS_SOLID = 0
Private Const GW_CHILD = 5&
Private Const FW_BOLD = 700&
Private Const FW_LIGHT = 300&
Private Const FW_MEDIUM = 500&
Private Const FW_NORMAL = 400&
Private Const FW_THIN = 100&

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Type LOGFONT
  lfHeight As Long
  lfWidth As Long
  lfEscapement As Long
  lfOrientation As Long
  lfWeight As Long
  lfItalic As Byte
  lfUnderline As Byte
  lfStrikeOut As Byte
  lfCharSet As Byte
  lfOutPrecision As Byte
  lfClipPrecision As Byte
  lfQuality As Byte
  lfPitchAndFamily As Byte
  lfFaceName(LF_FACESIZE) As Byte
End Type

Sub test()
Dim zähler%
  For zähler = 1 To 100 Step 3
    Fortschritt _
      BreiteProzent:=zähler, _
      FarbeFortschrittsbalken:=vbGreen, _
      Textfarbe:=vbRed, _
      Schriftart:="Times New Roman", _
      Schriftdicke:=6, _
      Schriftgrösse:=15
    Application.Wait (Now + TimeSerial(0, 0, 1))
  Next
  Application.StatusBar = False
End Sub

 

Sub Fortschritt(ByVal BreiteProzent, _
  Optional FarbeFortschrittsbalken As Long, _
  Optional Rahmenfarbe As Long, _
  Optional Textfarbe As Long, _
  Optional Schriftart As String, _
  Optional Schriftdicke As Byte, _
  Optional Schriftgrösse As Long)
Dim hPinsel As Long, hFenster As Long
Dim lngDcFenster As Long, strKlassenname As String
Dim lngTextColorOld As Long
Dim udtSchriftart As LOGFONT
Dim udtBalkengrösse As RECT
Dim udtRahmengrösse As RECT
Dim udtRahmenText As RECT
Dim udtGesamtgrösse As RECT
Dim lngGesamtBreite As Long, lngBreite As Long
Dim lngGesamtHöhe As Long
Dim lngVerfügbareBreite As Long, lngFortschrittsleiste As Long
Dim lngFreihalten As Long, lngTextFreihalten As Long
Dim strBeschriftung As String
Dim arrFontname() As Byte
Dim lngFont As Long, lngFontOld As Long
Dim i As Long
  ReDim arrFontname(0)
  strKlassenname = "XLMAIN"
  '*****Fenster Statusleiste finden*****
  hFenster = FindWindowEx(0&, 0&, strKlassenname, Application.Caption)
  'Excel97
  'strKlassenname = "EXCEL4"
  'hFenster = FindWindowEx(hFenster, 0&, strKlassenname, vbNullString)
  'oder auf anderen Versionen (ungetestet <> XL97)
  hFenster = GetWindow(hFenster, GW_CHILD)
  '*****Größe Festlegen*****
  GetWindowRect hFenster, udtGesamtgrösse
  With udtGesamtgrösse
    lngGesamtBreite = .Right - .Left
    lngGesamtHöhe = .Bottom - .Top
  End With
  'Hier eventuell etwas experimentieren.
  lngFreihalten = GetSystemMetrics(SM_CXSCREEN) * 0.35
  lngVerfügbareBreite = lngGesamtBreite - lngFreihalten
  lngTextFreihalten = 100
  If lngVerfügbareBreite < lngTextFreihalten Then Exit Sub
  lngVerfügbareBreite = lngVerfügbareBreite - lngTextFreihalten
  If BreiteProzent > 100 Then BreiteProzent = 100
  If BreiteProzent < 0 Then BreiteProzent = 0
  lngBreite = CLng((lngVerfügbareBreite / 100) * BreiteProzent)
  With udtRahmenText
    .Left = lngVerfügbareBreite + 3
    .Top = 0
    .Right = lngVerfügbareBreite + 3 + lngTextFreihalten
    .Bottom = lngGesamtHöhe - 3
  End With
  With udtBalkengrösse
    .Left = 3
    .Top = 3
    .Right = lngBreite
    .Bottom = lngGesamtHöhe - 2
  End With
  With udtRahmengrösse
    .Left = 3
    .Top = 3
    .Right = lngVerfügbareBreite
    .Bottom = lngGesamtHöhe - 2
  End With
  With udtSchriftart
    .lfHeight = Schriftgrösse * -1
    Select Case Schriftdicke
      Case Is >= 7
        .lfWeight = FW_BOLD
      Case Is >= 5
        .lfWeight = FW_MEDIUM
      Case 4
        .lfWeight = FW_NORMAL
      Case 3
        .lfWeight = FW_LIGHT
      Case Else
        .lfWeight = FW_THIN
    End Select
    If Schriftart = "" Then 'default
      'arrFontname = StrConv("Times New Roman" & _
        Chr$(0), vbFromUnicode)
      'arrFontname = StrConv("MS Sans Serif" & _
        Chr$(0), vbFromUnicode)
    Else
      Schriftart = Left$(Schriftart, 31)
      arrFontname = StrConv(Schriftart & _
        Chr$(0), vbFromUnicode)
    End If
    For i = 0 To UBound(arrFontname)
      .lfFaceName(i) = arrFontname(i)
    Next
  End With
  Application.StatusBar = ""
  '*****Fenster DC ausleihen*****
  lngDcFenster = GetDC(hFenster)
  '*****Fortschrittsbalken Malen in DC*****
  hPinsel = CreateSolidBrush(FarbeFortschrittsbalken)
  FillRect lngDcFenster, udtBalkengrösse, hPinsel
  DeleteObject hPinsel
  '*****Rahmen Malen in DC*****
  hPinsel = CreateSolidBrush(Rahmenfarbe)
  FrameRect lngDcFenster, udtRahmengrösse, hPinsel
  DeleteObject hPinsel
  '*****Beschriftung Malen in DC*****
  strBeschriftung = Format$(BreiteProzent, "0.00") & " %"
  lngFont = CreateFontIndirect(udtSchriftart)
  lngFontOld = SelectObject(lngDcFenster, lngFont)
  lngTextColorOld = GetTextColor(lngDcFenster)
  SetTextColor lngDcFenster, Textfarbe
  DrawText lngDcFenster, strBeschriftung, _
    Len(strBeschriftung), udtRahmenText, DT_CENTER
  SetTextColor lngDcFenster, lngTextColorOld
  SelectObject lngDcFenster, lngFontOld
  DeleteObject lngFont
  '*****DC zurückgeben*****
  ReleaseDC hFenster, lngDcFenster
End Sub