Añadir porcentaje al progressBar

Iniciado por Meta, 27 Febrero 2016, 17:19 PM

0 Miembros y 1 Visitante están viendo este tema.

Meta

Hola:

Estoy haciendo una pequeña prueba. Recibo en el puerto serie / USB datos que recoge Visual C# de 0 a 1023 y lo muestro en un label.



Hasta ahí funciona bien.

Tengo dos label más. El segundo tiene que demostrar el porcentaje del 0 % a 100% según el dato obtenido del 0 a 1023.

En el otro label, el tercero debemostrar número con decimales del 0.00 a 5.00.

A pesar de encontrar la fórmula, no se implementarlo en C#.

El código es este:
Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO.Ports; // No olvidar.

namespace Arduino_In_Analogico_prueba_01
{
   public partial class Form1 : Form
   {
       // Utilizaremos un string como buffer de recepción.
       string Recibidos;
       int Porcentaje;

       public Form1()
       {
           InitializeComponent();

           if (!serialPort1.IsOpen)
           {
               try
               {
                   serialPort1.Open();
               }
               catch (System.Exception ex)
               {
                   MessageBox.Show(ex.ToString());
               }
           }

           serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
       }

       // Al recibir datos.
       private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
       {

           // Acumula los caracteres recibidos a nuestro 'buffer' (string).
           Recibidos = serialPort1.ReadLine();

           // Invocar o llamar al proceso de tramas.
           Invoke(new EventHandler(Actualizar));
       }


       // Como variables de clase

       private string[] separador = new string[] { ",", "\r", "\n", "/n" };
       private List<string> leodato1 = new List<string>();

       
       
       // Procesar los datos recibidos en el bufer y extraer tramas completas.
       private void Actualizar(object sender, EventArgs e)
       {
           // En el evento
           leodato1.Clear();
           leodato1.AddRange(Recibidos.Split(separador,StringSplitOptions.RemoveEmptyEntries));

           label_Lectura_Potenciometro.Text = leodato1[0].ToString();
           progressBar1.Value = Convert.ToInt32(leodato1[0].ToString());
           progressBar1.PerformStep();
       }
   }
}


Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#1

@Meta                                                        
                                                                 
Por favor, corrije el formato de tu código  





Cita de: Meta en 27 Febrero 2016, 17:19 PMA pesar de encontrar la fórmula, no se implementarlo en C#.

Hay un pequeño fallo de diseño en tu código, primero asignas/sumas el valor con la propiedad ProgressBar.Value y luego utilizas el método ProgressBar.PerformStep(), con esto estás avanzando dos veces el valor de la barra de progreso.

Para calcular los valores que representar en los labels, puedes hacerlo de la siguiente manera:

   

Vb.Net:
Código (vbnet) [Seleccionar]
Public NotInheritable Class Form1 : Inherits Form

   Private Sub Test() Handles MyBase.Shown

       Me.ProgressBar1.Minimum = 0
       Me.ProgressBar1.Maximum = 1023
       Me.ProgressBar1.Step = 1

       For x As Integer = 0 To 1023
           Threading.Thread.Sleep(10)
           UpdateProgress(x)
       Next

   End Sub

   Private Sub UpdateProgress(ByVal value As Integer)

       Dim percent100 As Double = ((value / 1023) * 100)
       Dim percent5 As Double = (5.0F / (100.0R / percent100))

       Me.ProgressBar1.PerformStep()

       Me.Label1.Text = Convert.ToString(value)
       Me.Label2.Text = String.Format("{0:0}%", percent100)
       Me.Label3.Text = String.Format("{0:0.00} de {1:0.00}", percent5, 5.0F)

       Me.Label1.Update()
       Me.Label2.Update()
       Me.Label3.Update()

   End Sub

End Class


Traducción online a C#:
Código (csharp) [Seleccionar]
public sealed class Form1 : Form
{
private void Test() {
this.ProgressBar1.Minimum = 0;
this.ProgressBar1.Maximum = 1023;
this.ProgressBar1.Step = 1;

for (int x = 0; x <= 1023; x++) {
Threading.Thread.Sleep(10);
UpdateProgress(x);
}
}

private void UpdateProgress(int value) {
double percent100 = ((value / 1023) * 100);
double percent5 = (5f / (100.0 / percent100));

this.ProgressBar1.PerformStep();

this.Label1.Text = Convert.ToString(value);
this.Label2.Text = string.Format("{0:0}%", percent100);
this.Label3.Text = string.Format("{0:0.00} de {1:0.00}", percent5, 5f);

this.Label1.Update();
this.Label2.Update();
this.Label3.Update();
}

public Form1() {
Shown += Test;
}
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Saludos!








Meta

Hola:

Quiero que se muestra así. Gracias. ;)



He estado haciendo pruebas, no funciona porque me olvidé que los datos recibidos desde el puerto serie que viene por cada 0.1 segundos o 100 milisengudos del 0 al 1023, se incluye un retorno de carro, por ejemplo, 823\n.

Por eso hay que usar estos códigos.
Código (csharp) [Seleccionar]
        // Como variables de clase
        private string[] Separador = new string[] { ",", "\r", "\n", "/n" };
        private List<string> Leodato1 = new List<string>();


Y dentro de Actualizar.
Código (csharp) [Seleccionar]
        // Procesar los datos recibidos en el bufer y extraer tramas completas.
        private void Actualizar(object sender, EventArgs e)
        {
            // En el evento
            Leodato1.Clear();
            Leodato1.AddRange(Recibidos.Split(Separador,StringSplitOptions.RemoveEmptyEntries));

            label_Lectura_Potenciometro.Text = Leodato1[0].ToString();
            progressBar1.Value = Convert.ToInt32(Leodato1[0].ToString());

       
    }

Recuerda, por cada muestra recibida del 0 al 1023, cualquier valor entregado tiene un retorno de carro \n. Me funciona tu código así tal como estás, no cuando me recibe en el puerto serie.
Solo me falta el voltaje y el porcentaje.

Preguntas opcionales.
Por cierto, me encantó visualmente lo que hiciste.


1) ¿Con qué compilador lo hiciste?

2) ¿Con Visual C# 2105 se puede cambiar el color del progressBar? (Nunca me ha salido, si de los label, ya que los progress siempre lo veo verde y quiero cambiarlo azul o naranja por decir algo).

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#3
Cita de: Meta en 28 Febrero 2016, 07:13 AMMe funciona tu código así tal como estás, no cuando me recibe en el puerto serie.

Es responsabilidad tuya adaptar el código que mostré (el cual, como tu has dicho, fuciona), a tu código con el arduino.

La lógica del código creo que es bastante clara, solo debes fijarte en como obtengo el porcentaje y el voltaje mediante las operaciones aritméticas de esas dos variables, y hacer exactamente lo mismo en tu código.




Cita de: Meta en 28 Febrero 2016, 07:13 AMpor cada muestra recibida del 0 al 1023, cualquier valor entregado tiene un retorno de carro \n.

Te sugiero no utilizar indexers de Arrays con la función String.Split(), puedes reemplazar esa engorrosa metodología por el método String.TrimEnd() para eliminar los caracteres indeseados del final del string (los cuales puedes encontrar en la class Microsoft.VisualBasic.ControlChars (y antes de que lo preguntes, si, se puede y es recomendable usar esa Class desde C#, aunque tambien puedes usar los caracteres que representan esas constantes y ya está).




Cita de: Meta en 28 Febrero 2016, 07:13 AMPor cierto, me encantó visualmente lo que hiciste.

Visualmente hablando es un simple Form por defecto sin ningún tipo de personalización, simplemente el fondo del form sale de ese color por que Windows administra la colorización de las aplicaciones según la colorización del theme visual de Windows, a esto se le llama estilos visuales de la aplicación (o Visual Styles ), a menos que uses colores arbitraros para tu app claro está, como por ejemplo ese label tuyo que pusiste de amarillo.




Cita de: Meta en 28 Febrero 2016, 07:13 AM1) ¿Con qué compilador lo hiciste?

Toda aplicación de Visual Studio se compila con el compilador de .Net Framework, msbuild.exe (que internamente llama a vbc.exe para Vb.Net, o csc.exe para C#. )

¿Qué estas intentando preguntar exactamente?.




Cita de: Meta en 28 Febrero 2016, 07:13 AM¿Con Visual C# 2105 se puede cambiar el color del progressBar? (Nunca me ha salido, si de los label, ya que los progress siempre lo veo verde y quiero cambiarlo azul o naranja por decir algo).

Si, solo debes heredar la Class ProgressBar, activar el modo de dibujado de usuario, y bibujar el rectángulo, pero ten en cuenta que puede requerir mucho más esfuerzo que eso, dependiendo de tus necesidades, ya que al personalizar, se pierden los efectos o estilos visuales del control, sobre todo esos destellos luminosos que Windows pone sobre la barra de progeso que son tan chulos.
De todas formas alguien experto en GDI+ podría simular los destellos (yo no llego a tanto), hay barras de progeso muy avanzadas en CodeProject.

Vb.Net:
Código (vbnet) [Seleccionar]
Public Class CustomProgressBar : Inherits ProgressBar

   Public Sub New()
       MyBase.BackColor = Color.LimeGreen ' ProgressBar.DefaultBackColor
       Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)
       Me.SetStyle(ControlStyles.SupportsTransparentBackColor, False)
       Me.SetStyle(ControlStyles.UserPaint, True)
   End Sub

   Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

       Dim rc As Rectangle = e.ClipRectangle

       rc.Width = (((rc.Width * MyBase.Value) \ MyBase.Maximum) - 4)
       rc.Height = (rc.Height - 4)

       If (ProgressBarRenderer.IsSupported) Then
           ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle)
       End If

       Using br As New SolidBrush(MyBase.BackColor)
           e.Graphics.FillRectangle(br, 2, 2, rc.Width, rc.Height)
       End Using

   End Sub

End Class


Traducción online a C#:
Código (csharp) [Seleccionar]
public class ElektroProgressBar : ProgressBar {

public ElektroProgressBar() {
base.BackColor = Color.LimeGreen;
// ProgressBar.DefaultBackColor
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.SupportsTransparentBackColor, false);
this.SetStyle(ControlStyles.UserPaint, true);
}


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

rc.Width = (((rc.Width * base.Value) / base.Maximum) - 4);
rc.Height = (rc.Height - 4);

if ((ProgressBarRenderer.IsSupported)) {
ProgressBarRenderer.DrawHorizontalBar(e.Graphics, e.ClipRectangle);
}

using (SolidBrush br = new SolidBrush(base.BackColor)) {
e.Graphics.FillRectangle(br, 2, 2, rc.Width, rc.Height);
}
}
}

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Si quieres conservar los efectos visuales del control, puedes recurrir a la API de Windows para especificar el estado de la barra de progeso (normal, pausado, error, indeterminado), cada estado está ligado a un color por defecto en tu tema visual de Windows, esto quiere decir que los colores que puedes usar son muy limitados y que además dependen del tema visual del usuario (no recuerdo los colores del tema Aero, pero creo que eran verde, amarillo, rojo y verde otra vez), lo puedes hacer de manera muy sencilla con la librería de Microsoft WindowsAPICodePack, no recuerdo exactamente con que funciones de la API de Windows se hacia.

EDITO: Acabo de recordar (o mejor dicho, encontrar) como se hacia con la WinAPI, con la función SendMessage:

Código (csharp) [Seleccionar]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr w, IntPtr l);

SendMessage(MyProgressBar.Handle, 1040, (IntPtr)(del 1 al 4 son los diferentes estados), IntPtr.Zero);


Saludos








Meta

Hola:

Gracias por la info, el tema de los colores del progressBar lo haré para el final. ;)

Hice este código de ejemplo en modo consola para hacer pruebas.



Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Porcentaje_Barra_Consola_CS
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Title = "Estilo progressBar C#";

            int Variar_este_valor = 0; // De 0 a 1023.
            double Resultado_Porcentaje = 0;
            double Resultado_Voltios = 0;

            Console.WriteLine("Introduce el valor entre 0 al 1023.");
            Variar_este_valor = Convert.ToInt32(Console.ReadLine());

            Resultado_Porcentaje = Variar_este_valor * (100.00 / 1023.00);
            Resultado_Voltios = Variar_este_valor * (5.00 / 1023.00);
            Console.WriteLine("{0} % y {1} Voltios.", Resultado_Porcentaje, Resultado_Voltios);
            Console.ReadLine();
        }

    }
}


Me faltan cosas, que los decimales se vean solo dos dígitos y que funcione.

REpitiendo el código que ya mejoraré como dijiste arriba.
Código (csharp) [Seleccionar]
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using System.IO.Ports; // No olvidar.

namespace Arduino_In_Analogico_prueba_01
{
    public partial class Form1 : Form
    {
        // Utilizaremos un string como buffer de recepción.
        string Recibidos;

        public Form1()
        {
            InitializeComponent();

            if (!serialPort1.IsOpen)
            {
                try
                {
                    serialPort1.Open();
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }

            serialPort1.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
        }

        // Al recibir datos.
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            // Acumula los caracteres recibidos a nuestro 'buffer' (string).
            Recibidos = serialPort1.ReadLine();

            // Invocar o llamar al proceso de tramas.
            Invoke(new EventHandler(Actualizar));
        }


        // Como variables de clase
        private string[] Separador = new string[] { ",", "\r", "\n", "/n" };
        private List<string> Leo_Dato1 = new List<string>();

        // Procesar los datos recibidos en el bufer y extraer tramas completas.
        private void Actualizar(object sender, EventArgs e)
        {
            double Porcentaje = 0;
            double Voltio = 0;

            // En el evento
            Leo_Dato1.Clear();
            Leo_Dato1.AddRange(Recibidos.Split(Separador, StringSplitOptions.RemoveEmptyEntries));

            label_Lectura_Potenciometro.Text = Leo_Dato1[0].ToString();
            progressBar1.Value = Convert.ToInt32(Leo_Dato1[0].ToString());

            Porcentaje = Leo_Dato1[0] * (100.00 / 1023.00); // Error aquí
            Voltio = Leo_Dato1[0] * (5.00 / 1023.00); // y aquí.

            label_Portentaje.Text = Porcentaje.ToString();
            label_Voltio.Text = Voltio.ToString();

        }
    }
}


Nos centramos donde da error.
Código (csharp) [Seleccionar]
            Porcentaje = Leo_Dato1[0] * (100.00 / 1023.00); // Error aquí
            Voltio = Leo_Dato1[0] * (5.00 / 1023.00); // y aquí.


Los dos errores dice esto:
CitarGravedad   Código   Descripción   Proyecto   Archivo   Línea
Error   CS0019   El operador '*' no se puede aplicar a operandos del tipo 'string' y 'double'   Arduino_In_Analogico_prueba_01   C:\Users\Usuario\Documents\Visual Studio 2015\Projects\Arduino_In_Analogico_prueba_01\Arduino_In_Analogico_prueba_01\Form1.cs   75

Saludos.
Tutoriales Electrónica y PIC: http://electronica-pic.blogspot.com/

Eleкtro

#5
Cita de: Meta en  1 Marzo 2016, 06:40 AMLos dos errores dice esto:
Citar
Error   CS0019   El operador '*' no se puede aplicar a operandos del tipo 'string' y 'double'

Resulta algo imperdonable que a estas alturas no entiendas a que se debe el error (o no sepas como solucionarlo).

Ponerte la solución en bandeja sería realmente facil, prefiero que leas los siguientes artículos para que aprendas por ti mismo a desenvolverte con (algunos de) los problemas más básicos:


Saludos!