【问题标题】:Change the color of a ToolStripProgressBar without disabling the XP Visual Styles?在不禁用 XP 视觉样式的情况下更改 ToolStripProgressBar 的颜色?
【发布时间】:2014-01-02 06:18:01
【问题描述】:

在 Winforms 中,我想在不禁用整个应用程序的 XP Visual Syles 的情况下更改 ToolStripProgressBar 的背景颜色,这可能吗?也许只为 StatusStrip 控件禁用 XP 视觉样式?

我知道 ToolStripProgressBar 不继承自 Control 类型,但 StatusStrip 确实(不是?),那么确定这一定是一个解决方案,或者可能继承 StatusStrip 来控制绘画事件或其他东西......我不知道该怎么做。

我尝试将我的StatusStrip 控件的RenderMode 属性设置为专业模式,但系统仍在为myToolStripProgressBar 选择背景色。

【问题讨论】:

  • 因为 VisualStyles 在应用程序级别 (Application.EnableVisualStyles) 启用,您可能不走运。 Forms 有一个 VisualStyles 命名空间,进度条继承自该命名空间,但该命名空间似乎更适合应用那些 VisualStyles。
  • 我敢肯定,如果没有你自己完成所有的绘画,这将无法完成。

标签: c# .net vb.net winforms progress-bar


【解决方案1】:

您可以自定义由名为 ToolStripProgressBarToolStripControlHost 托管的 ProgressBar 的外观。您可以通过ToolStripProgressBar 的属性ProgressBar 访问托管的ProgressBar。然后,您可以为该ProgressBar 添加Paint 事件处理程序。然而,只有在为ProgressBar 设置控件样式UserPaint 时才会触发此Paint 事件,这是设计的(当然与默认支持Paint 事件的其他普通控件不同)。所以你可以试试下面的代码。事实上,我尝试用非 XP 样式 ToolStripProgressBar 注释掉行 Application.EnableVisualStyles(); 以查看您真正想要的东西,看起来它太简单了,下面的代码应该可以满足您的需求:

//define some variables first, note that don't rely on the 
//ProgressBarRenderer.ChunkThickness and ProgressBarRenderer.ChunkSpaceThickness
//because they are actually small and using our own variables will allow us to change
//the chunk size easily.
int chunkThickness = 13;
int chunkSpace = 1;
Rectangle chunkRect = new Rectangle(0, 0, chunkThickness,
                          toolStripProgressBar1.ProgressBar.Height-4);
//The hosted ProgressBar's Paint event handler
private void progressBar_Paint(object sender, PaintEventArgs e){
  chunkRect.Location = Point.Empty;
  chunkRect.Offset(2, 2);                
  var percent = (float) toolStripProgressBar1.Value / toolStripProgressBar1.Maximum;
  var valueLength = percent * toolStripProgressBar1.ProgressBar.Width;
  var chunks = (int) (valueLength / (chunkThickness + chunkSpace) + 0.5f);
  for (int i = 0; i < chunks; i++) {
     //I use the green color for the chunk color, it's up to you.
     e.Graphics.FillRectangle(Brushes.Green, chunkRect);                    
     chunkRect.Offset(chunkThickness + chunkSpace, 0);
  }
  ControlPaint.DrawBorder3D(e.Graphics, toolStripProgressBar1.ProgressBar.ClientRectangle,
                           Border3DStyle.SunkenOuter);
}
//Now in your form constructor, just add this code to end up everything before
//trying running the code:
public Form1(){
   InitializeComponent();
   //do this to allow the Paint event to be fired and more ...
   typeof(Control).GetMethod("SetStyle", System.Reflection.BindingFlags.NonPublic |
                                         System.Reflection.BindingFlags.Instance)
                  .Invoke(toolStripProgressBar1.ProgressBar, 
                          new object[] {ControlStyles.UserPaint |
                                        ControlStyles.OptimizedDoubleBuffer, true });
   //hook up the progressBar_Paint event handler for the hosted ProgressBar
   toolStripProgressBar1.ProgressBar.Paint += progressBar_Paint;
}

这外观和感觉不正是你在等待的吗?:

更新:对于连续进度条,它比积木样式简单得多,请尝试以下更新progressBar_Paint

private void progressBar_Paint(object sender, PaintEventArgs e){
  var percent = (float) toolStripProgressBar1.Value / toolStripProgressBar1.Maximum;
  var valueLength = percent * toolStripProgressBar1.ProgressBar.Width;
  var chunkRect = new RectangleF(2,2,valueLength,
                                 toolStripProgressBar1.ProgressBar.Height-4);
  e.Graphics.FillRectangle(Brushes.Green, chunkRect);
  ControlPaint.DrawBorder3D(e.Graphics, toolStripProgressBar1.ProgressBar.ClientRectangle,
                           Border3DStyle.SunkenOuter);
}

【讨论】:

  • @ElektroStudios 它比实现块样式的进度条要简单得多,请参阅我的代码更新。
  • 在看到你的更新之前,我已经解决了调整块空间值的问题,这就是我删除评论的原因,抱歉给你更多的工作,这是我的错,因为没有注意到这些变量,谢谢你的时间
【解决方案2】:

我只想分享我基于@King King C# 答案的vbnet 方法。

我尝试修改它以供通用使用,但代码仍然有点硬编码。

''' <summary>
''' The Backcolor to fill the ToolStrip ProgressBar.
''' </summary>
Private ProgressBar_BackColor As Brush = New SolidBrush(Color.FromArgb(120, 147, 73))

''' <summary>
''' The ForeColor to fill the ToolStrip ProgressBar.
''' </summary>
Private ProgressBar_ForeColor As Brush = New SolidBrush(Color.Black)

''' <summary>
''' Draws a border effect inside the bounds of the ProgressBar.
''' </summary>
Private ProgressBar_Border As Single = 0

''' <summary>
''' Indicates the StringFormat of the ProgressBar Text.
''' </summary>
Private ProgressBar_Text_Format As StringFormat =
    New StringFormat With {.Alignment = Drawing.StringAlignment.Center,
                           .Trimming = StringTrimming.EllipsisCharacter}


Public Sub New()

    ' Necessary call to the designer.
    InitializeComponent()

    ' Set the Style of the ToolStripProgesssBar (For be able to fill the progressbar with a custom color).
    GetType(Control).GetMethod("SetStyle", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance).
                     Invoke(ToolStripProgressBar1.ProgressBar,
                            New Object() {ControlStyles.UserPaint Or ControlStyles.OptimizedDoubleBuffer, True})

End Sub

' ProgressBarStatus [Paint]
Private Sub ProgressBarStatus_Paint(sender As Object, e As PaintEventArgs) _
Handles ToolStripProgressBar1.Paint

    ' Fill the progressbar
    Select Case sender.style

        Case ProgressBarStyle.Continuous

            ' The ProgressBar Rectangle.
            Dim ProgressBarRect As RectangleF =
                New RectangleF(ProgressBar_Border / 2, ProgressBar_Border / 2,
                               CSng(sender.Value / sender.Maximum) * CSng(sender.ProgressBar.Width - ProgressBar_Border),
                               sender.ProgressBar.Height - ProgressBar_Border)

            e.Graphics.FillRectangle(ProgressBar_BackColor, ProgressBarRect)

        Case ProgressBarStyle.Blocks

            ' The Width of each block.
            Dim BlockWidth As Integer = 10

            ' The space between each block.
            Dim BlockSpace As Integer = 1

            ' The ProgressBar Rectangle.
            Dim ProgressBarRect As Rectangle =
                New Rectangle(0, 0, BlockWidth, sender.ProgressBar.Height - 4)

            ' Calculate the block count.
            Dim PercentDone As Single = CSng(sender.ProgressBar.Value / sender.ProgressBar.Maximum)
            Dim valueLength As Single = PercentDone * CSng(sender.ProgressBar.Width)
            Dim BlockCount As Integer = CInt(valueLength / (BlockWidth + BlockSpace) + 0.5F)

            ProgressBarRect.Offset(2, 2)

            For i As Integer = 0 To BlockCount - 1
                e.Graphics.FillRectangle(ProgressBar_BackColor, ProgressBarRect)
                ProgressBarRect.Offset(BlockWidth + BlockSpace, 0)
            Next

            ControlPaint.DrawBorder3D(e.Graphics, sender.ProgressBar.ClientRectangle, Border3DStyle.SunkenOuter)

    End Select

    ' Draw the Text
    Dim TextBounds As Rectangle = sender.ProgressBar.Bounds
    TextBounds.Inflate(0, 4) ' Correct the Text position.

    Using fnt As New Font(CType(sender.ProgressBar.Font.FontFamily, FontFamily),
                          CSng(sender.ProgressBar.Font.SizeInPoints) + 1,
                          FontStyle.Bold)

        e.Graphics.DrawString(sender.ProgressBar.Value, fnt, ProgressBar_ForeColor, TextBounds, ProgressBar_Text_Format)

    End Using

End Sub

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-20
    相关资源
    最近更新 更多