web-dev-qa-db-fra.com

Comment changer la couleur de progressbar dans C # .NET 3.5?

J'aimerais faire deux choses sur ma barre de progression.

  1. Changez la couleur verte en rouge.
  2. Enlevez les blocs et faites en une couleur.

Toute information sur ces deux choses que je me demande comment accomplir sera appréciée avec gratitude!

Merci.

84
Ivan Prodanov

Puisque les réponses précédentes ne semblent pas fonctionner avec les styles visuels. Vous aurez probablement besoin de créer votre propre classe ou d'étendre la barre de progression:

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);
    }
}

EDIT: code mis à jour pour que la barre de progression utilise le style visuel pour l'arrière-plan

76
Crispy

OK, il m'a fallu un certain temps pour lire toutes les réponses et les liens. Voici ce que j'en ai tiré:

Exemple de résultats

La réponse acceptée désactive les styles visuels, elle vous permet de définir la couleur comme vous le souhaitez, mais le résultat est simple:

enter image description here

En utilisant la méthode suivante, vous pouvez obtenir quelque chose comme ceci à la place:

enter image description here

Comment

Commencez par inclure ceci si vous n’avez pas: using System.Runtime.InteropServices;

Deuxièmement, vous pouvez soit créer cette nouvelle classe, soit placer son code dans une classe static non générique existante:

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);
    }
}

Maintenant, pour l'utiliser, appelez simplement:

ModifyProgressBarColor.SetState(progressBar1, 2);

Notez le deuxième paramètre dans SetState, 1 = normal (vert); 2 = erreur (rouge); 3 = avertissement (jaune).

J'espère que ça aide!

110
user1032613

Ceci est une version sans scintillement du code le plus accepté que vous pouvez trouver comme réponse à cette question. Tout crédit aux affiches de ces réponses fatastiques. Merci Dusty, Chris, Matt et Josh!

Comme pour la demande de "Fueled" dans l'un des commentaires, j'avais également besoin d'une version qui se comportait un peu plus ... professionnellement. Ce code conserve les styles comme dans le code précédent, mais ajoute un rendu d'image hors écran et une mise en mémoire tampon graphique (et dispose correctement l'objet graphique).

Résultat: tout bon, et pas de scintillement. :)

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();
            }
        }
    }
}
33
William Daniel

Dans le concepteur, il vous suffit de définir la propriété ForeColor sur la couleur de votre choix. Dans le cas du rouge, il existe une couleur prédéfinie.

Pour le faire en code (C #), procédez comme suit:

pgs.ForeColor = Color.Red;

Edit : Ah oui, réglez également le style sur continu. En code, comme ceci:

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

Autre édition: Vous devrez également supprimer la ligne qui lit Application.EnableVisualStyles() de votre Program.cs (Ou similaire) ). Si vous ne pouvez pas faire cela parce que vous voulez que le reste de l'application ait des styles visuels, alors je vous suggère de peindre le contrôle vous-même ou de passer à WPF, car ce genre de choses est simple avec WPF. Vous pouvez trouver un tutoriel sur le propriétaire en dessinant une barre de progression sur codeplex

27
dustyburwell

En utilisant les réponses de Matt Blaine et Chris Persichetti, j'ai créé une barre de progression plus esthétique tout en permettant un choix de couleurs infini (j'ai fondamentalement changé une ligne dans la solution de Matt):

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);
        }
    }
}

Usage:

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

Résultats

You can use any gradient you like!

Télécharger

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

15
Josh M.

Modification de la réponse de dustyburwell. (Je n'ai pas assez de représentants pour l'éditer moi-même.) Comme pour sa réponse, cela fonctionne avec les "styles visuels" activés. Vous pouvez simplement définir la propriété ForeColor de la barre de progression dans la vue de conception de la fiche.

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);
    }
}
14
Matt Blaine

Je viens de mettre cela dans une classe statique.

  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);
  } 

J'espère que ça aide,

Marc

5
Marc

La barre de progression est généralement thématique ou respecte les préférences de couleur de l'utilisateur. Donc, pour changer la couleur, vous devez soit désactiver les styles visuels et définir ForeColor, soit dessiner le contrôle vous-même.

En ce qui concerne le style continu au lieu de blocs, vous pouvez définir la propriété Style:

pBar.Style = ProgressBarStyle.Continuous;
3
Joey

Je vous suggère de jeter également un coup d'oeil à cet article sur CodeProject: Progress-O-Doom . C'est bien!

2
Drake

Changer Color et Value (changement instantané)

Mettez using System.Runtime.InteropServices; En haut ...

Appel avec ColorBar.SetState(progressBar1, ColorBar.Color.Yellow, myValue);

J'ai remarqué que si vous modifiez la valeur de la barre (sa taille), elle ne changera pas si elle est d'une couleur autre que le vert par défaut. J'ai pris le code de user1032613 et ajouté une option de valeur.

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
Sparfy

essayez d'utiliser messsage PBM_SETBARCOLOR, qui devrait faire l'affaire avec SendMessage

Voir http://www.vbforums.com/showthread.php?t=248721 pour un exemple.

2
Aleksandar

[~ # ~] éditer [~ # ~]

Par le son des choses que vous utilisez XP Theme qui a la barre de progression basée sur un bloc vert. Essayez d’inverser votre style d’UI vers Windows Classic et testez à nouveau, mais vous devrez peut-être implémenter votre organiser un événement OnPaint pour qu’il fasse ce que vous voulez dans tous les styles d’interface utilisateur

Ou comme quelqu'un l'a fait remarquer, désactivez les VisualStyles pour votre application.

Original

Pour autant que je sache, le rendu de la barre de progression se déroule en ligne avec le style de thème Windows que vous avez choisi (Win2K, XP, Vista).

Vous pouvez changer la couleur en définissant la propriété

ProgressBar.ForeColor

Je ne suis pas sûr que vous puissiez faire beaucoup plus cependant ...

fait des recherches sur Google

Voici un article de MS KB sur la création d’une barre de progression "Lisse"

http://support.Microsoft.com/kb/323116

2
Eoin Campbell

Toutes ces méthodes ne fonctionnent pas pour moi mais cette méthode vous permet de la changer en chaîne de couleur.

Veuillez noter que j'ai trouvé ce code ailleurs sur StackOverflow et que je l'ai un peu modifié. Depuis, j'ai oublié où j'ai trouvé ce code et je ne peux pas le lier à cause de ça, désolé pour ça.

Mais de toute façon, j'espère que ce code aide quelqu'un, il m'a vraiment aidé.

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

Lorsque le nom "ProgressBar" est utilisé, remplacez-le par votre propre nom de barre de progression. Vous pouvez également déclencher cet événement avec d'autres arguments en vous assurant simplement qu'il est entre crochets.

2
EpicNinjaCheese

Cliquez simplement sur votre projet dans Visual Basic Solution Explorer (où se trouvent vos fichiers vb) et sélectionnez Propriétés dans le menu. Dans la fenêtre qui apparaît, désactivez l'option "Activer XP Styles Visuels") "et maintenant, lorsque vous définissez la prévisualisation, cela devrait fonctionner maintenant.

1
Randy

Juste au cas où quelqu'un chercherait une autre option… vous pouvez étendre un panneau, l'utiliser comme arrière-plan (blanc ou autre), ajouter un autre panneau à l'intérieur pour le premier plan (la barre de défilement). Ensuite, vous avez le contrôle total en changeant la couleur, etc.

1
Eduardo

La barre de progression colorée VB.Net qui respecte la réponse aux styles visuels WXP est ...

J'ai commencé avec la réponse de 'user1032613' le 17/03/12. Notez que ceci est maintenant un module, pas une classe. De là, j'ai converti le code, mais il en fallait plus. En particulier, le code converti montrait une fonction DirectCast pour convertir le nombre entier "state" en un type IntPtr qui ne fonctionnait pas.

Imports System.Runtime.InteropServices

Public Module ModifyProgressBarColor

    Private Declare Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Long) As Long

    <DllImport("user32.dll", CharSet:=CharSet.Auto, SetLastError:=False)> _
    Private Function SendMessage(hWnd As IntPtr, Msg As UInteger, w As IntPtr, l As IntPtr) As IntPtr
    End Function

    <System.Runtime.CompilerServices.Extension()> _
    Public Sub SetState(pBar As ProgressBar, state As Integer)

        '-- Convert state as integer to type IntPtr
        Dim s As IntPtr
        Dim y As Integer = state
        s = IntPtr.op_Explicit(y)

        '-- Modify bar color
        SendMessage(pBar.Handle, 1040, s, IntPtr.Zero)

    End Sub

End Module

Et encore une fois, appelez ceci dans le code using avec cette ligne:

Call ModifyProgressBarColor.SetState(prb, 2)

BTW - j'ai essayé d'autres couleurs - 0, 4, 5 - ils ont tous juste affiché vert.

0
DanW52

Je pense que la solution la plus simple est une solution rapide, mais vous pouvez supprimer, commenter Application.EnableVisualStyles () de Program.cs ou nommer la partie contenant la fonction Main. Après cela, vous pouvez modifier librement la couleur de la barre de progression par progressBar.ForeColor = Color.TheColorYouDesire;

static void Main()
        {
            //Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
         }
0
Mladen Tasevski

Bien: Quote: Habituellement, la barre de progression est thématique ou respecte les préférences de couleur de l'utilisateur. Donc, pour changer la couleur, vous devez soit désactiver les styles visuels et définir ForeColor, soit dessiner le contrôle vous-même.

En ce qui concerne le style continu au lieu de blocs, vous pouvez définir la propriété Style:

pBar.Style = ProgressBarStyle.Continuous;

ProgressBarStyle.Continuous versus Blocks est inutile avec VistualStyles activé ...

Les blocs ne fonctionneront que lorsque les styles visuels sont désactivés ... ce qui en fait un point discutable (en ce qui concerne la couleur de progression personnalisée). Lorsque les styles visuels sont désactivés ... la barre de progression doit être colorée en fonction de la couleur de garde.

J'ai utilisé une combinaison de la réponse de William Daniel (avec les styles visuels activés, afin que le ForeColor ne soit pas simplement plat) - et la réponse de Barry (au texte personnalisé sur la barre de progression) de: Comment puis-je mettre du texte ProgressBar?

0
NeoH4x0r

Barre verticale UP for Down de couleur rouge:

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



public class VerticalProgressBar : ProgressBar
{


    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.Style |= 0x04;
            return cp;

        }
    }
    private SolidBrush brush = null;

    public VerticalProgressBar()
    {
        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.DrawVerticalBar(e.Graphics, rec);
        rec.Height = (int)(rec.Height * ((double)Value / Maximum)) - 4;
        rec.Width = rec.Width - 4;
        e.Graphics.FillRectangle(brush, 2, 2, rec.Width, rec.Height);

    } 
}
0
Mandrova

Je connais son chemin trop vieux pour qu'on y réponde maintenant .. mais quand même, un petit Tweak à @ Daniel pour résoudre le problème de ne pas afficher la barre de progression à valeur nulle. Dessinez simplement la progression uniquement si la largeur du rectangle intérieur est différente de zéro.

Merci à tous les contributeurs.

        public class ProgressBarEx : ProgressBar
        {
            public ProgressBarEx()
            {
                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)
                        {
                            LinearGradientBrush brush = new LinearGradientBrush(rect, this.ForeColor, this.BackColor, LinearGradientMode.Vertical);
                            offscreen.FillRectangle(brush, inset, inset, rect.Width, rect.Height);
                            e.Graphics.DrawImage(offscreenImage, 0, 0);
                            offscreenImage.Dispose();
                        }
                    }
                }
            }
        }
0
Divins Mathew

J'ai trouvé que cela peut être fait en traçant un rectangle à l'intérieur de la barre de progression et en définissant sa largeur en fonction de la valeur actuelle de la progression. J'ai également ajouté un support pour les progrès de droite à gauche. De cette façon, vous n’avez pas besoin d’utiliser l’image, et comme Rectnalge.Inflate n’est pas appelé, le rectangle dessiné est plus petit.

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

    protected override void OnPaintBackground(PaintEventArgs pevent) { }

    protected override void OnPaint(PaintEventArgs e)
    {
        double scaleFactor = (((double)Value - (double)Minimum) / ((double)Maximum - (double)Minimum));
        int currentWidth = (int)((double)Width * scaleFactor);
        Rectangle rect;
        if (this.RightToLeftLayout)
        {
            int currentX = Width - currentWidth;
            rect = new Rectangle(currentX, 0, this.Width, this.Height);
        }
        else
            rect = new Rectangle(0, 0, currentWidth, this.Height);

        if (rect.Width != 0)
        {
            SolidBrush sBrush = new SolidBrush(ForeColor);
            e.Graphics.FillRectangle(sBrush, rect);
        }
    }
}
0
ZOK