How can I use a meter-style progress bar?
Asked Answered
P

1

10

In Vista/7, the Windows Explorer shell window makes use of a special kind of static progress bar to display hard drive space.

With default styles, this bar is blue colored and non-animated. It also turns red colored when it gets close to being full (low disk space).

Using messaging, I can tell the Windows Forms ProgressBar control to update its state to Paused and Error (yellow and red colored, respectively), which works fine, but these are still specific to progress.

In the Windows User Experience Guidelines, it specifically points out this "meter" variant of the Progress Bar:

This pattern isn't a progress bar, but it is implemented using the progress bar control. Meters have a distinct look to differentiate them from true progress bars.

They say it "is implemented using the progress bar control", so... how? What message could I send to the control to have it behave this way?

I've seen that you can send messages for setting the bar color, but the documentation says these calls are ignored when visual styles are enabled. Nothing else in the Windows API documentation for raw ProgressBar controls seemed to suggest a way to do this. Am I just stuck making a custom drawn bar? I'd really like to utilize the OS whenever possible so that the application will appear consistent throughout different OS versions. I realize that pre-Vista versions probably won't support this, though.

I'm looking for a Windows Forms solution, but I wonder if it is even exposed at all via Win32 API.

Perrault answered 19/4, 2010 at 22:29 Comment(1)
Looking back after quite a few years, FWIW, it's my opinion that the guidelines on that page from Microsoft haven't aged well, and even at the time they came out they were widely ignored; a lot of their recommendations are very application and industry specific, and some of them seem now like they existed more to advertise new and shiny Windows Vista UX features (which Microsoft later denounced as cheesy and outdated when Windows 8 came out). Don't worry about the UX cops writing you tickets if you decide to ignore some of these guidelines. I still see tons of progress bars as meters.Killoran
C
11

It is possible, but not through ProgressBar. Nor does Win7 use a PB to draw those meters, there is no window handle associated with the bar. It must be using custom drawing. That's possible in WinForms as well with the VisualStyleRenderer class. One thing that doesn't help however is that the required visual style parts and states are not declared, not even in .NET 4.0.

This sample form reproduces the meter bar:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

namespace WindowsFormsApplication1 {
  public partial class Form1 : Form {
    public Form1() {
      InitializeComponent();
    }
    VisualStyleRenderer renderer = new VisualStyleRenderer(VisualStyleElement.ProgressBar.Bar.Normal);
    protected override void OnPaint(PaintEventArgs e) {
      renderer.SetParameters("PROGRESS", 11, 2);
      renderer.DrawBackground(e.Graphics, new Rectangle(10, 10, 200, 15));
      renderer.SetParameters("PROGRESS", 5, 4);
      renderer.DrawBackground(e.Graphics, new Rectangle(10, 10, 100, 15));
    }
  }
}

I got the part and state numbers from the vsstyle.h SDK header file.

Category answered 20/4, 2010 at 0:50 Comment(4)
To anyone interested, you can find vsstyle.h in %ProgramFiles%\Microsoft SDKs\Windows\vx.xx\Include where vx.xx is whatever version SDK installed (you might have several). en.wikipedia.org/wiki/Microsoft_Windows_SDKPerrault
Also should point out to anyone having trouble reproducing this: notice that this draws to a background. If you have panels or any other containers, you'll want the renderer to draw on THEIR paint events, not the form's. Otherwise, the panel overlaps and, as you should know by now, panels aren't actually transparent, so it will look like your bar didn't render.Perrault
When I try to run this, I get Given combination of Class, Part, and State is not defined by the current visual style. on the line renderer.SetParameters("PROGRESS", 11, 2);.Asymmetric
I marked this as the answer, though the second call to SetParameters and DrawBackground just draws a blue rectangle on Windows 8.Rearward

© 2022 - 2024 — McMap. All rights reserved.