Problème d'affichage

Messages postés
47
Date d'inscription
mardi 21 novembre 2006
Statut
Membre
Dernière intervention
5 novembre 2016
- - Dernière réponse : vikingch
Messages postés
8
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
Afficher la suite 

3 réponses

Messages postés
1137
Date d'inscription
lundi 17 novembre 2003
Statut
Membre
Dernière intervention
23 janvier 2016
17
0
Merci
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...
Commenter la réponse de yann_lo_san
Messages postés
47
Date d'inscription
mardi 21 novembre 2006
Statut
Membre
Dernière intervention
5 novembre 2016
0
Merci
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..
Commenter la réponse de soussous78
Messages postés
47
Date d'inscription
mardi 21 novembre 2006
Statut
Membre
Dernière intervention
5 novembre 2016
0
Merci
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
        }
vikingch
Messages postés
8
Date d'inscription
jeudi 30 janvier 2014
Statut
Membre
Dernière intervention
20 mars 2014
-
Salut, avais tu trouvé une solution ?
Commenter la réponse de soussous78