Как изменить цвет индикатора выполнения в C # .NET 3.5? - PullRequest
83 голосов
/ 22 апреля 2009

Я хотел бы сделать две вещи на моем индикаторе прогресса.

  1. Измените зеленый цвет на красный.
  2. Снимите блоки и сделайте их одним цветом.

Любая информация об этих двух вещах, которые мне интересно узнать, как это сделать, будет чрезвычайно оценена!

Спасибо.

Ответы [ 22 ]

104 голосов
/ 18 марта 2012

ОК, мне потребовалось некоторое время, чтобы прочитать все ответы и ссылки. Вот что я получил от них:

Пример результатов

Принятый ответ отключает визуальные стили, он позволяет вам установить цвет на что угодно, но результат выглядит просто:

enter image description here

Используя следующий метод, вы можете получить что-то вроде этого:

enter image description here

Как сделать

Сначала включите это, если у вас нет: using System.Runtime.InteropServices;

Во-вторых, вы можете либо создать этот новый класс, либо поместить его код в существующий static неуниверсальный класс:

public static class ModifyProgressBarColor
{
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l);
    public static void SetState(this ProgressBar pBar, int state)
    {
        SendMessage(pBar.Handle, 1040, (IntPtr)state, IntPtr.Zero);
    }
}

Теперь, чтобы использовать его, просто позвоните:

ModifyProgressBarColor.SetState(progressBar1, 2);

Обратите внимание на второй параметр в SetState, 1 = нормальный (зеленый); 2 = ошибка (красная); 3 = предупреждение (желтый).

Надеюсь, это поможет!

73 голосов
/ 22 апреля 2009

Поскольку предыдущие ответы не работают с визуальными стилями. Возможно, вам потребуется создать собственный класс или расширить индикатор выполнения:

public class NewProgressBar : ProgressBar
{
    public NewProgressBar()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        Rectangle rec = e.ClipRectangle;

        rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
        if(ProgressBarRenderer.IsSupported)
           ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
        rec.Height = rec.Height - 4;
        e.Graphics.FillRectangle(Brushes.Red, 2, 2, rec.Width, rec.Height);
    }
}

РЕДАКТИРОВАТЬ: обновлен код, чтобы индикатор выполнения использовал визуальный стиль для фона

32 голосов
/ 20 сентября 2011

Это версия самого принятого кода без мерцания, которую вы можете найти в ответах на этот вопрос. Вся заслуга в постерах этих роковых ответов. Спасибо Дасти, Крис, Мэтт и Джош!

Как и запрос "Fueled" в одном из комментариев, мне также нужна была версия, которая вела себя немного более ... профессионально. Этот код поддерживает стили, как в предыдущем коде, но добавляет рендеринг закадрового изображения и буферизацию графики (и правильно удаляет графический объект).

Результат: все хорошо, без мерцания. :)

public class NewProgressBar : ProgressBar
{
    public NewProgressBar()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        // None... Helps control the flicker.
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        const int inset = 2; // A single inset value to control teh sizing of the inner rect.

        using (Image offscreenImage = new Bitmap(this.Width, this.Height))
        {
            using (Graphics offscreen = Graphics.FromImage(offscreenImage))
            {
                Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);

                if (ProgressBarRenderer.IsSupported)
                    ProgressBarRenderer.DrawHorizontalBar(offscreen, rect);

                rect.Inflate(new Size(-inset, -inset)); // Deflate inner rect.
                rect.Width = (int)(rect.Width * ((double)this.Value / this.Maximum));
                if (rect.Width == 0) rect.Width = 1; // Can't draw rec with width of 0.

                LinearGradientBrush brush = new LinearGradientBrush(rect, this.BackColor, this.ForeColor, LinearGradientMode.Vertical);
                offscreen.FillRectangle(brush, inset, inset, rect.Width, rect.Height);

                e.Graphics.DrawImage(offscreenImage, 0, 0);
                offscreenImage.Dispose();
            }
        }
    }
}
27 голосов
/ 22 апреля 2009

В конструкторе вам просто нужно установить для свойства ForeColor любой цвет, который вы захотите. В случае с красным для него есть предопределенный цвет.

Чтобы сделать это в коде (C #), сделайте это:

pgs.ForeColor = Color.Red;

Редактировать : О да, также установите стиль на непрерывный. В коде вот так:

pgs.Style = System.Windows.Forms.ProgressBarStyle.Continuous;

Другое редактирование: Вам также необходимо удалить строку, которая читает Application.EnableVisualStyles() из вашего Program.cs (или аналогичного). Если вы не можете сделать это, потому что хотите, чтобы у остальной части приложения были визуальные стили, тогда я бы предложил нарисовать элемент управления самостоятельно или перейти к WPF, поскольку с WPF такого рода вещи просты. Вы можете найти руководство по рисованию индикатора выполнения на codeplex

15 голосов
/ 11 апреля 2011

Используя ответы Мэтта Блейна и Криса Персикетти, я создал индикатор выполнения, который выглядит немного лучше, но допускает бесконечный выбор цвета (в основном я изменил одну строку в решении Мэтта):

ProgressBarEx:

using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;

namespace QuantumConcepts.Common.Forms.UI.Controls
{
    public class ProgressBarEx : ProgressBar
    {
        public ProgressBarEx()
        {
            this.SetStyle(ControlStyles.UserPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            LinearGradientBrush brush = null;
            Rectangle rec = new Rectangle(0, 0, this.Width, this.Height);
            double scaleFactor = (((double)Value - (double)Minimum) / ((double)Maximum - (double)Minimum));

            if (ProgressBarRenderer.IsSupported)
                ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rec);

            rec.Width = (int)((rec.Width * scaleFactor) - 4);
            rec.Height -= 4;
            brush = new LinearGradientBrush(rec, this.ForeColor, this.BackColor, LinearGradientMode.Vertical);
            e.Graphics.FillRectangle(brush, 2, 2, rec.Width, rec.Height);
        }
    }
}

Использование:

progressBar.ForeColor = Color.FromArgb(255, 0, 0);
progressBar.BackColor = Color.FromArgb(150, 0, 0);

Результаты

You can use any gradient you like!

Скачать

https://skydrive.live.com/?cid=0EDE5D21BDC5F270&id=EDE5D21BDC5F270%21160&sc=documents#

14 голосов
/ 23 марта 2010

Модификация к ответу Дустибурвелла. (Мне не хватает представителя, чтобы редактировать его самостоятельно.) Как и его ответ, он работает с включенными «Визуальными стилями». Вы можете просто установить свойство ForeColor для индикатора выполнения в любом представлении дизайна формы.

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

public class ProgressBarEx : ProgressBar
{
    private SolidBrush brush = null;

    public ProgressBarEx()
    {
        this.SetStyle(ControlStyles.UserPaint, true);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        if (brush == null || brush.Color != this.ForeColor)
            brush = new SolidBrush(this.ForeColor);

        Rectangle rec = new Rectangle(0, 0, this.Width, this.Height);
        if (ProgressBarRenderer.IsSupported)
            ProgressBarRenderer.DrawHorizontalBar(e.Graphics, rec);
        rec.Width = (int)(rec.Width * ((double)Value / Maximum)) - 4;
        rec.Height = rec.Height - 4;
        e.Graphics.FillRectangle(brush, 2, 2, rec.Width, rec.Height);
    }
}
5 голосов
/ 31 мая 2010

Я просто поместил это в статический класс.

  const int WM_USER = 0x400;
  const int PBM_SETSTATE = WM_USER + 16;
  const int PBM_GETSTATE = WM_USER + 17;

  [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
  static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

  public enum ProgressBarStateEnum : int
  {
   Normal = 1,
   Error = 2,
   Paused = 3,
  }

  public static ProgressBarStateEnum GetState(this ProgressBar pBar)
  {
   return (ProgressBarStateEnum)(int)SendMessage(pBar.Handle, PBM_GETSTATE, IntPtr.Zero, IntPtr.Zero);
  }

  public static void SetState(this ProgressBar pBar, ProgressBarStateEnum state)
  {
   SendMessage(pBar.Handle, PBM_SETSTATE, (IntPtr)state, IntPtr.Zero);
  } 

Надеюсь, это поможет,

Марк

3 голосов
/ 22 апреля 2009

Обычно индикатор выполнения либо тематический, либо соответствует цветовым настройкам пользователя. Поэтому для изменения цвета вам нужно либо отключить визуальные стили и установить ForeColor, либо нарисовать элемент управления самостоятельно.

Что касается непрерывного стиля, то вместо блоков вы можете установить свойство Style:

pBar.Style = ProgressBarStyle.Continuous;
2 голосов
/ 21 мая 2015

Изменение Color и Value (мгновенное изменение)

Положите using System.Runtime.InteropServices; вверху ...

Позвонить с ColorBar.SetState(progressBar1, ColorBar.Color.Yellow, myValue);

Я заметил, что если вы измените значение бара (насколько оно велико), то оно не изменится, если его цвет будет отличаться от зеленого по умолчанию. Я взял код user1032613 и добавил параметр Value.

public static class ColorBar
{
    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l);
    public enum Color { None, Green, Red, Yellow }

    public static void SetState(this ProgressBar pBar, Color newColor, int newValue)
    {
        if (pBar.Value == pBar.Minimum)  // If it has not been painted yet, paint the whole thing using defualt color...
        {                                // Max move is instant and this keeps the initial move from going out slowly 
            pBar.Value = pBar.Maximum;   // in wrong color on first painting
            SendMessage(pBar.Handle, 1040, (IntPtr)(int)Color.Green, IntPtr.Zero);
        }
        pBar.Value = newValue;
        SendMessage(pBar.Handle, 1040, (IntPtr)(int)Color.Green, IntPtr.Zero);     // run it out to the correct spot in default
        SendMessage(pBar.Handle, 1040, (IntPtr)(int)newColor, IntPtr.Zero);        // now turn it the correct color
    }

}
2 голосов
/ 27 октября 2014

Все эти методы не работают для меня, но этот метод позволяет вам изменить его на цветную строку.

Обратите внимание, что я нашел этот код где-то еще в StackOverflow и немного его изменил. С тех пор я забыл, где я нашел этот код, и я не могу связать его из-за этого, извините за это.

Но в любом случае, я надеюсь, что этот код поможет кому-то, он действительно помог мне.

private void ProgressBar_MouseDown(object sender, MouseButtonEventArgs e)
    {
        var converter = new System.Windows.Media.BrushConverter();
        var brush = (Brush)converter.ConvertFromString("#FFB6D301");
        ProgressBar.Foreground = brush;
    }

Если используется имя «ProgressBar», замените его собственным именем индикатора выполнения. Вы также можете вызвать это событие с другими аргументами, просто убедитесь, что оно где-то внутри скобок.

...