Problème d'affichage

soussous78 Messages postés 47 Date d'inscription mardi 21 novembre 2006 Statut Membre Dernière intervention 5 novembre 2016 - 17 janv. 2013 à 12:59
vikingch Messages postés 7 Date d'inscription jeudi 30 janvier 2014 Statut Membre Dernière intervention 20 mars 2014 - 4 févr. 2014 à 10:39
Bonjour,
J'ai un petit soucis avec une classe que j'ai fait.
Cette (exactement ces) classe, permet d'afficher un bandeau avec un message qui défile. Or ce message me fait des freeze. Quelqu'un aurait une idée d'où cela pourrait venir, ou une meilleure idée pour ce faire?

tout d'abord j'ai une classe de thread pour créer l'image :
public class T_Texte
    {
        public event BMPEventHandler OnBitmapCreated;
        string texte;
        Color BackColor;
        Color ForeColor;
        Control Parent;
        Font f;
        public T_Texte(string texte, Color BackColor, Color ForeColor, Control Parent, Font f)
        {
            this.texte = texte;
            this.BackColor = BackColor;
            this.ForeColor = ForeColor;
            this.Parent = Parent;
            this.f = f;
        }
        public void Run()
        {
            #region calcul de la taille du texte
            Bitmap bmp = new Bitmap(10, 10);
             Graphics g = Graphics.FromImage(bmp);
            //on entre la taille du texte dans un SizeF
             SizeF S_texte= g.MeasureString(texte, f);
            g.Dispose();

            double longeurTotale = S_texte.Width + Parent.Width;//longeur du texte+ecran
            double nbPixSec = (double)Parent.Width/10;//nombre de pixel par seconde (10 seconde pour traverser l'ecran)
            int nbSec = 1+(int)(longeurTotale / nbPixSec);//nombre de seconde nécessaire pour traverser l'écran avec sa propre longeur
            #endregion
            DateTime dt_fin = DateTime.Now.AddSeconds(nbSec); //heure de la fin de défilement
            DateTime dt_now = DateTime.Now;//heure actuelle
            while (Statique.ProgramRun && dt_fin > dt_now) //Statique.ProgramRun est la porte de sortie du thread si on éteint le programme
            {
                // création du bitmap de sortie
                Bitmap b = new Bitmap(Parent.Width,Parent.Height);
                Graphics gr = Graphics.FromImage(b);
                //recherche du centre du panel
                float Top = Parent.Height / 2 - S_texte.Height / 2;
                //on calcule l'emplacement gauche de l'ecriture
                double milisecRest=(dt_fin-dt_now).TotalMilliseconds;
                double nbpix=milisecRest*nbPixSec/1000;
                float Left = (float)nbpix - S_texte.Width;
                // on dessine le fond et l'ecriture
                gr.FillRectangle(new SolidBrush(BackColor), new Rectangle(0, 0, Parent.Width, Parent.Height));
                gr.DrawString(texte, f, new SolidBrush(ForeColor), Left, Top);
                //
                gr.Dispose();
                
                OnBitmapCreated(this,new ImgClassEventArgs(b));
                //on réalloue dt_now
                dt_now = DateTime.Now;
            }
        }
    }


J'ai ensuite un control ou sera déssiné le bandeau:
public partial class Texte : UserControl
    {
        Bitmap bmp;
        public Texte()
        {
            InitializeComponent();
            //double buffer
            this.DoubleBuffered = true;
            this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.UserPaint | ControlStyles.OptimizedDoubleBuffer, true);
            UpdateStyles();
        }
        /// <summary>
        /// classe qui démarrera te thread
        /// </summary>
        public void run(string texte, Color BackColor, Color ForeColor, Font f)
        {
            T_Texte tt = new T_Texte(texte, BackColor, ForeColor, this, f);
            tt.OnBitmapCreated += new BMPEventHandler(ti_OnBitmapCreated);
            Thread t = new Thread(new ThreadStart(tt.Run));
            t.Start();
        }
        void ti_OnBitmapCreated(object sender, ImgClassEventArgs e)
        {
            bmp = e.bmp;
            this.Invalidate();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            if (bmp != null)
                e.Graphics.DrawImage(bmp, e.ClipRectangle);
        }
    }

et j'appelle ca simplement :
Affiches.Texte.Texte t= new Affiches.Texte.Texte();
            this.Controls.Add(t);
            t.Dock = DockStyle.Fill;
            Application.DoEvents();
            t.run("Test d'ecriture",Color.Black,Color.Blue,new Font("Arial",70));


Merci

3 réponses

yann_lo_san Messages postés 1137 Date d'inscription lundi 17 novembre 2003 Statut Membre Dernière intervention 23 janvier 2016 26
17 janv. 2013 à 13:48
Salut,

c'est pas plutôt sur le formulaire parent qu'on devrait activer le Dbl Buffer ?

Sinon, beaucoup d'allocation dans la boucle du Thread (while), Bitmap, Graphics ect...
Ne pourrais tu pas référencer des membres de la classe une seule fois ??!!
et faire le Dispose lors de l'arret du thread.

1 seul new Bitmap
1 seul CreateGraphics
les 2 float et les 2 doubles déclarés hors de la pile aussi
1 seul ImgClassEventArgs en rajoutant un setter bitmap à la place d'appeler le constructeur

cela allègerait pas mal la boucle et le GC

bye...
0
soussous78 Messages postés 47 Date d'inscription mardi 21 novembre 2006 Statut Membre Dernière intervention 5 novembre 2016
17 janv. 2013 à 15:31
Merci d'avoir regardé,
- J'avais essayé avec un seul bitmap mais j'avais un soucis de clignotement.
Je pense a cause du fait que le bitmap était construit dans un thread et que le onpaint est dans un autre, et le fait de ne pas recréer l'image, le onpaint doit parfois dessiner lorsque je met la couleur du fond.

- Les float et double sont dans la boucle car le formulaire initial peut être agrandit.

- pour le ImgClassEventArgs, je ne vois pas ce qu'est un setter Bmp.

Pour le Buffer, il est bien a la bonne place, c'est moi qui ai mal choisi mon nom de variable. Je ne dessine pas sur le parent mais bien sur le controle..
0
soussous78 Messages postés 47 Date d'inscription mardi 21 novembre 2006 Statut Membre Dernière intervention 5 novembre 2016
12 févr. 2013 à 21:21
Bonjour,
J'ai tenté d'une autre manière :
J'ai fait appeler entrer le control dans le constructeur et tente d'afficher directement dans le control a partir du thread.
Du coup je crée un bitmap au début du thread (imgGardee ) et un graphics pour dessiner dedans.
Dès le début, je crée le graphics correspondant au control.
Et au moment de l'affichage, je colle l'imgGardee dabs le graphics du control.
Donc le GC ne s'occupe ni des bitmap ni des graphics.
Mon problème de saccade est toujours d'actualité. Je suis vraiment a cours d'idée. Si un oeil neuf me trouve où le code pêche ou si quelqu'un trouve un code permettant de faire défiler un texte dans un bandeau sans saccade. Je suis preneur.

public void Run()
        {
            Bitmap imgGardee = new Bitmap(s.Width, s.Height);
            Graphics gr = Graphics.FromImage(imgGardee);
            Graphics grSend = c.CreateGraphics();

           double nbpixelSec = s.Width / 10;
            double TotalWidth = s.Width + gr.MeasureString(texte, font).Width;
            double duree = (TotalWidth)/nbpixelSec;
            
            DateTime dtnow = DateTime.Now;
            DateTime dtfin = DateTime.Now.AddSeconds(duree);
            DateTime dtdebut = dtnow;

            #region Boucle
            while (dtfin > dtnow)
            {
                
                #region en cas de resize
                if (s != c.Size)
                {
                    s = c.Size;
                    imgGardee = new Bitmap(s.Width, s.Height);
                    gr = Graphics.FromImage(imgGardee);
                    grSend = c.CreateGraphics();
                    TotalWidth = s.Width + gr.MeasureString(texte, font).Width;
                }
                #endregion
                double ratio = (dtfin-dtnow).TotalMilliseconds/(dtfin - dtdebut).TotalMilliseconds;
                double left = TotalWidth * ratio - (int)gr.MeasureString(texte, font).Width;
                StringFormat sf = new StringFormat();
                sf.Alignment = StringAlignment.Center;
                sf.LineAlignment = StringAlignment.Center;
                gr.FillRectangle(new SolidBrush(Color.Black),new Rectangle(new Point(0,0),s));
                gr.DrawString(texte, font, new SolidBrush(Color.White), new Rectangle((int)left, 0, 1+(int)gr.MeasureString(texte,font).Width, (int)s.Height), sf);
                grSend.DrawImage(imgGardee, new Rectangle(0, 0, s.Width, s.Height));
                dtnow = DateTime.Now;
                Thread.Sleep(10);
            }
            gr.Dispose();
            grSend.Dispose();
            gr.Dispose();
            c.Fini = true;
            #endregion
        }
0
vikingch Messages postés 7 Date d'inscription jeudi 30 janvier 2014 Statut Membre Dernière intervention 20 mars 2014
4 févr. 2014 à 10:39
Salut, avais tu trouvé une solution ?
0
Rejoignez-nous