Re[9]: Область рисования (C#)
От: Ael США  
Дата: 04.06.04 04:32
Оценка:
Здравствуйте, thespian, Вы писали:

T>Здравствуйте, Ael, Вы писали:


Ael>>А какая задача, почему надо рисовать именно на битмапе, и какой код мерцает?


T>Я просто пробовал рисовать анимацию на C# .Net, при анимировании 20 эллипсов — началось мерцание. Я решил разрисововать это в памяти, а потом всё выводить на экран — не помогло. Каким образом это всё можно сгладить?



Посмотрите вот такой пример:

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.ComponentModel;

    public class Form1 : System.Windows.Forms.Form
    {
        private Bitmap _hBitmap;
        private volatile Boolean _bFinish;
       const Int32 iNumber=30;
                     public Form1()
        {
            Int32 _iWidth=this.Width/iNumber;
            Int32 _iHeight=this.Height/iNumber;
        
             _hBitmap=new Bitmap(_iWidth,_iHeight);
            using(Graphics gr=Graphics.FromImage(_hBitmap))
            {
                
                    using (SolidBrush sBrush=new SolidBrush(Color.Green))
                    {
                        gr.Clear(Color.FromArgb(0,255,255,255));
                        gr.FillEllipse(sBrush,0,0,_iWidth,_iHeight);
                    }
                }            
            Thread t=new Thread(new ThreadStart(this.Animation));
            t.IsBackground=true;
            t.Start();
            this.Closing+=new CancelEventHandler(Form1_Closing);
        }
       
        private void Animation()
        {
            Thread.Sleep(100);
            Random rand=new Random(DateTime.Now.Millisecond);
            Int32 cX=0,cY=0;
            while (!_bFinish)
            {
                using (Graphics g=this.CreateGraphics())
                 {
                    using (Brush brushErase=new SolidBrush(this.BackColor))
                           {
                        for(cX=0;cX<this.Width;cX+=iNumber)
                            for (cY=0;cY<this.Height&&!_bFinish;cY+=iNumber)
                            {
                                if(rand.Next()%2==0)
                                    g.DrawImage(this._hBitmap,cX,cY,iNumber,iNumber);
                                else
                                    g.FillRectangle(brushErase,cX,cY,iNumber,iNumber);
                        
                                    }
                                        Thread.Sleep(100);
                            }
                    }
            }
        }


        
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        private void Form1_Closing(object sender, CancelEventArgs e)
        {
            this._bFinish=true;
        }
    }

Хотя по правилам нужно рисовать только в OnPaint. Можно переписать пример, чтобы он использовал делегат и вызывал OnPaint для выполнения в основном потоке. Это будет медленнее (появится мерцание), так что мне нравится больше
пример выше.
using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;

public delegate void PaintCallback(Rectangle rectClip);
    public class Form1 : System.Windows.Forms.Form
    {
        private Bitmap _hBitmap;
        private volatile Boolean _bDraw,_bFinish;
        const Int32 iNumber=30;
        private PaintCallback _pc;
        public Form1()
        {
            Int32 _iWidth=this.Width/iNumber;
            Int32 _iHeight=this.Height/iNumber;
        
            _hBitmap=new Bitmap(_iWidth,_iHeight);
            using(Graphics gr=Graphics.FromImage(_hBitmap))
            {
                
                using (SolidBrush sBrush=new SolidBrush(Color.Green))
                {
                    gr.Clear(Color.FromArgb(0,255,255,255));
                    gr.FillEllipse(sBrush,0,0,_iWidth,_iHeight);
                }
            }            
            this._pc=new PaintCallback(this.InvalidateUpdate);
            Thread t=new Thread(new ThreadStart(this.Animation));
            t.IsBackground=true;
            t.Start();
            this.Closing+=new CancelEventHandler(Form1_Closing);
        }
       
        private void InvalidateUpdate(Rectangle rectClip)
        {
            if(!this._bFinish)
            {
                this.Invalidate(rectClip);
                this.Update();
                _bDraw=false;    
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            if (_bDraw)
                e.Graphics.DrawImage(_hBitmap,e.ClipRectangle);
            base.OnPaint (e);
        }

        private void Animation()
        {
            Thread.Sleep(100);
            Random rand=new Random(DateTime.Now.Millisecond);
            Int32 cX=0,cY=0;
            while (!_bFinish)
            {
                using (Graphics g=this.CreateGraphics())
                {
                    using (Brush brushErase=new SolidBrush(this.BackColor))
                    {
                        for(cX=0;cX<this.Width;cX+=iNumber)
                            for (cY=0;cY<this.Height&&!_bFinish;cY+=iNumber)
                            {
                                if(rand.Next()%2==0)
                                    this._bDraw=true;
                                    this.BeginInvoke(this._pc,new Object[]{new Rectangle(cX,cY,iNumber,iNumber)});
                                                    
                            }
                        Thread.Sleep(100);
                    }
                }
            }
        }


        
        [STAThread]
        static void Main() 
        {
            Application.Run(new Form1());
        }

        private void Form1_Closing(object sender, CancelEventArgs e)
        {
            this._bFinish=true;
        }
    }

Кстати, если в битмапе обычный кружок, или там кружок и линии, то быстрее будет не рисовать это в битмап, а потом выводить битмап, а рисовать фигуры заново.С битмапом выигрываешь, если в битмапе — картинка.

T>П.С.: вопрос по примеру, почему компилятор на GraphicsPath выдаёт ошибку? Что надо прописать в using?

using System.Drawing.Drawing2D;
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.