The SmoothProgressBar replaces the standard windows default progress indicator for custom GUI's and answers several drawbacks to not only the default progressbar, but many other Windows-default components such as lack of customization, even in development environments such as Microsoft's own Visual Studio.
I will only post the the key methods Set_Value and OnPaint as they are the critical sections anyway and provide all the examples needed to code the other simpler sections described in the Microsoft article above. I should note this code, though it will be compilable working C++, will nonetheless still be a bit pseudo codish. This is because I had to do some tweaks and fudges here and there to get some more finesse behavior. Part of this is due to the fact that I derived this progress bar directly from TProgressBar. I had to 'hide' some of its base properties and replace them with my own equivalent. I also had to play around a bit with the drawing of some boundary lines to get this to fit into the default TProgressBar border properly. You could most certainly do this deriving directly from the more generic TComponent as well (similar to the article above).
Set_Value(...):
Code:
/// <summary> /// Set_Value /// </summary> /// <param name="NewValue">The new value of the progressbar.</param> void __fastcall SmoothProgressBar::Set_Value(int NewValue) { int oldValue = value; // Make sure that the value does not stray outside the valid range. if (NewValue < minimum) { value = minimum; } else if (NewValue > maximum - 1) { value = maximum - 1; shrinkVertical = 3; lastLineFlag = true; } else { value = NewValue; } // Invalidate only the changed area. float percent; TRect newValueRect(this->ClientRect); TRect oldValueRect(this->ClientRect); newValueRect.Left = newValueRect.Left; // Use a new value to calculate the rectangle for progress. percent = (float)(value - minimum) / (float)(maximum - minimum); newValueRect.Right = newValueRect.Left + (int)((float)newValueRect.Width() * percent); newValueRect.Top = newValueRect.Top + shrinkVertical; newValueRect.Bottom = newValueRect.Bottom - shrinkVertical; oldValueRect.Left = oldValueRect.Left; // Use an old value to calculate the rectangle for progress. percent = (float)(oldValue - minimum) / (float)(maximum - minimum); oldValueRect.Right = oldValueRect.Left + 2 + (int)((float)oldValueRect.Width() * percent); oldValueRect.Top = oldValueRect.Top + shrinkVertical; oldValueRect.Bottom = oldValueRect.Bottom - shrinkVertical; TRect updateRect; // Find only the part of the screen that must be updated. if (newValueRect.Width() > oldValueRect.Width()) { updateRect.Left = oldValueRect.Width(); updateRect.IntersectRect(newValueRect, oldValueRect); } else { updateRect.Left = newValueRect.Width(); updateRect.IntersectRect(oldValueRect, newValueRect); } InvalidateRect(this->Handle, &updateRect, 1); SmoothProgressBar::OnPaint(this); }
OnPaint(...):
Code:
/// <summary> /// On Paint /// </summary> /// <param name="Sender">The sender of this event</param> void __fastcall SmoothProgressBar::OnPaint(TObject *Sender) { HDC dc; HPEN dcPen; dc = GetDC(this->Handle); this->Brush->Color = this->progressBar_Color; float percent = (float)(value - minimum) / (float)(maximum - minimum); TRect clientRect(this->ClientRect); FillRect(dc, &clientRect, this->Brush->Handle); dcPen = CreatePen(PS_SOLID, 1, this->progressBar_Color); SelectObject(dc, dcPen); SetBkColor(dc, this->progressBar_Color); if (lastLineFlag == true) // Global flag { MoveToEx(dc, clientRect.Right - 1, clientRect.Top + 1, NULL); LineTo(dc, clientRect.Right - 1, clientRect.Bottom - 1); MoveToEx(dc, clientRect.Right, clientRect.Top + 1, NULL); LineTo(dc, clientRect.Right, clientRect.Bottom - 1); } lastLineFlag = false; }
I hope this saves somebody some time in trudging through Google search results, questionably useful help files, and quite a bit of raw source code looking for similar examples to what I was trying to accomplish.
Just one more little blip. Since I derived this from TProgressBar (which is really just a shell around the Windows Progress bar), I did have to hide and lock-in the defaults of some of the base properties. I will give an example of hiding the Position property:
Code:
public: __property int Position = {read = position, default = 0}; // Hide the base
No comments:
Post a Comment