Click here to Skip to main content
15,887,867 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I have a large number of dynamically created rectangles to display on screen. Through trial and error I now draw only the rectangles that have changed to a bitmap and the bitmap in a OnPaint event, but i still get flickering. Any suggestions on where I might be going wrong.

I'm using VS 2015 .Net 4.5. I create a new Windows Forms project. Set with height and width of the form to 550 and add one button and name it bRunTask. I create an instance of PathAViewModel (class lib based on path find A star) 50 columns x 50 rows. Then subscribe to the OnUpdate event. OnUpdate passes an int that corresponds to any rectangle that state has changed. I get the state and redraw the rectangle with its new color and Invalidate about 30 times a sec. Then make a call to PathAViewmodel.RunTask in the button click event.

I'v included the relevant code below will attached two project files. One for this project and one for the class Lib.if requested.
C#
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 PathAStarlib;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;

namespace wfBitmapDisplay
{
    public partial class Form1 : Form
    {
        PathAViewModel MyView;
        

        Rectangle[] MyRecArry;
        Stopwatch MyWatch = new Stopwatch();

        Graphics gDisplay;
        Bitmap bitmap;
        Graphics gBitmap;
        Brush MyBrush;

        public Form1()
        {
            InitializeComponent();

            bitmap = new Bitmap(this.Width, this.Height, PixelFormat.Format32bppArgb);
            gBitmap = Graphics.FromImage(bitmap);
            gBitmap.CompositingMode = CompositingMode.SourceCopy;

            MyView = new PathAViewModel(50,50);
            MyView.OnUpdate += new PathAViewModel.UpdateDisplayHandler(RunOnUpdate);

            this.Paint += Form1_Paint;
            this.DoubleBuffered = true;
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

            InitMyComponents();

            gDisplay = this.CreateGraphics();

            gBitmap.DrawRectangles(Pens.Black, MyRecArry);
        }
        private void Form1_Paint(object sender, PaintEventArgs e)
        {
            gDisplay.DrawImage(bitmap, new Point(0, 0));
        }
        private void bRunTask_Click(object sender, EventArgs e)
        {
            MyView.RunTask();
        }
        private void RunOnUpdate(int x)
        {
            
            foreach (Node n in MyView.MyModel.lNodes.Where(u => u.Id == x))
            {
                switch (n.ToString())
                {
                    case "1":
                        MyBrush = Brushes.Aqua;
                        break;
                    case "2":
                        MyBrush = Brushes.Blue;
                        break;
                    case "3":
                        MyBrush = Brushes.Red;
                        break;
                    case "4":
                        MyBrush = Brushes.Green;
                        break;
                    case "5":
                        MyBrush = Brushes.Black;
                        break;
                    case "6":
                        MyBrush = Brushes.Yellow;
                        break;
                    default:
                        MyBrush = Brushes.White;
                        break;

                }
                gBitmap.FillRectangle(MyBrush, MyRecArry[n.Id - 1]);
            }
            if (MyWatch.ElapsedMilliseconds % 35 == 0)
                Invalidate();
        }
        
        private void InitMyComponents()
        {
            bRunTask.Top = this.Bottom - 60;
            bRunTask.Text = "Find Path";

            MyRecArry = new Rectangle[MyView.Columns * MyView.Rows];
            int x = 0;
            for (int r = 1; r <= MyView.Rows; r++)
            {
                for (int c = 1; c <= MyView.Columns; c++)
                {
                    MyRecArry[x].Width = ((bitmap.Width - 10) / MyView.Columns);
                    MyRecArry[x].Height = ((bitmap.Height - 50) / MyView.Rows);
                    MyRecArry[x].X = (c - 1) * MyRecArry[x].Width;
                    MyRecArry[x].Y = (r - 1) * MyRecArry[x].Height;
                    x++;
                }

            }

            foreach (Node n in MyView.MyModel.lNodes.Where(u => u.Id == MyView.MyModel.StartId))
                gBitmap.FillRectangle(Brushes.Green, MyRecArry[n.Id - 1]);
            foreach (Node n in MyView.MyModel.lNodes.Where(u => u.Id == MyView.MyModel.FinishId))
                gBitmap.FillRectangle(Brushes.Red, MyRecArry[n.Id - 1]);
            foreach (Node n in MyView.MyModel.lNodes.Where(u => u.IsPassable == false))
                gBitmap.FillRectangle(Brushes.Black, MyRecArry[n.Id - 1]);
        }

       
    }
}
Posted
Updated 4-Nov-15 6:58am
v4

Your paint handler looks strange to me.

C#
private void Form1_Paint(object sender, PaintEventArgs e)
{
    gDisplay.DrawImage(bitmap, new Point(0, 0));
}


Try this:

C#
private void Form1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawImage(bitmap, new Point(0, 0));
}
 
Share this answer
 
Comments
ryanba29 4-Nov-15 13:06pm    
Thank you. Solved my problem. I thought creating two graphics objects must have been wrong, but was unsure of how to fix. Ty
ryanba29 4-Nov-15 13:13pm    
Adding DoubleBuffering and removing the extra Graphics object does it.
 
Share this answer
 
v2
Comments
ryanba29 4-Nov-15 12:55pm    
I have tried both.
this.DoubleBuffered = true;
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
In the form constructor. I will add re update post. Ty

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900