Search code examples
c#.netvb.netgdi+powerpacks

Help Repainting a Line


I am doing a custom control (inherited from VisualBasic.PowerPacks.LineShape), that should be painted like as standard one, but also having a Icon displayed near it.

So, I just overrided OnPaint like this:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
    base.OnPaint(e);
}

Now, everything is OK, but when my control moves, the icon still remains drawn on the ancient place.

Is there a way to paint it properly?

alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S5gXmp7xYiI/AAAAAAAADHI/pa1OhpKYSoM/Untitled-2.png Real project situation

CODE: The sample code for tests

alt text http://lh6.ggpht.com/_1TPOP7DzY1E/S5jSluxvtDI/AAAAAAAADHw/EUz0Tfet-rw/s800/Capture2.png

using Microsoft.VisualBasic.PowerPacks;
using System.Windows.Forms;
using System.Drawing;

namespace LineShapeTest
{
    /// 
    /// Test Form
    /// 
    public class Form1 : Form
    {        
        IconLineShape myLine = new IconLineShape();
        ShapeContainer shapeContainer1 = new ShapeContainer();
        Panel panel1 = new Panel();

        public Form1()
        {
            this.panel1.Dock = DockStyle.Fill;
            // load your back image here
            this.panel1.BackgroundImage = 
                global::WindowsApplication22.Properties.Resources._13820t;
            this.panel1.Controls.Add(shapeContainer1);

            this.myLine.StartPoint = new Point(20, 30);
            this.myLine.EndPoint = new Point(80, 120);
            this.myLine.Parent = this.shapeContainer1;

            MouseEventHandler panelMouseMove = 
                new MouseEventHandler(this.panel1_MouseMove);
            this.panel1.MouseMove += panelMouseMove;
            this.shapeContainer1.MouseMove += panelMouseMove;

            this.Controls.Add(panel1);
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                myLine.StartPoint = e.Location;
            }
        }
    }

    /// 
    /// Test LineShape
    /// 
    public class IconLineShape : LineShape
    {
        Icon myIcon = SystemIcons.Exclamation;

        protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
        {
            e.Graphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
            base.OnPaint(e);
        }
    }
}

Nota Bene, for the lineShape:

Parent = ShapeContainer
Parent.Parent = Panel

Update 1 TRACES

In this variant of OnPaint, we have traces:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    Graphics g = Parent.Parent.CreateGraphics();
    g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);            
    base.OnPaint(e);
}        

alt text http://lh4.ggpht.com/_1TPOP7DzY1E/S5j29lutQ0I/AAAAAAAADH4/4yEnZd_hPjA/s800/Capture3.png

Update 2 BLINKS

In this variant of OnPaint, we have a blinking image:

protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
    Parent.Parent.Invalidate(this.Region, true);
    Graphics g = Parent.Parent.CreateGraphics();
    g.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);            
    base.OnPaint(e);
}  

alt text http://lh5.ggpht.com/_1TPOP7DzY1E/S5j4Bam7hiI/AAAAAAAADIA/1hQWKyV8Fr0/s800/Capture4.png

Update 3: External Invalidation

This variant works well, but... from exterior of IconLineShape class:

private void panel1_MouseMove(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Left)
    {
        Region r = myLine.Region;
        myLine.StartPoint = e.Location;
        panel1.Invalidate(r);
    }
}


/// 
/// Test LineShape
/// 
public class IconLineShape : LineShape
{
    Icon myIcon = SystemIcons.Exclamation;
    Graphics parentGraphics;

    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    {
        parentGraphics.DrawIcon(myIcon, StartPoint.X, StartPoint.Y);
        base.OnPaint(e);
    }

    protected override void OnParentChanged(System.EventArgs e)
    {
        // Parent is a ShapeContainer
        // Parent.Parent is a Panel
        parentGraphics = Parent.Parent.CreateGraphics();
        base.OnParentChanged(e);
    }
}

Even this resolves the problem of the test example, I need this control to be done inside the control, because I can't force the external "clients" of this control do not forget to save the old region and invalidate the parent each time changing a location...


Solution

  • Finally, ended up to add a PictureBox instead of drawing the icon by myself.

    using Microsoft.VisualBasic.PowerPacks;
    using System.Windows.Forms;
    using System.Drawing;
    
    namespace LineShapeTest
    {
        /// 
        /// Test Form
        /// 
        public class Form1 : Form
        {
            IconLineShape myLine = new IconLineShape();
            ShapeContainer shapeContainer1 = new ShapeContainer();
            Panel panel1 = new Panel();
    
            public Form1()
            {
                this.panel1.Dock = DockStyle.Fill;
                // load your back image here
                //this.panel1.BackgroundImage =
                //global::WindowsApplication22.Properties.Resources._13820t;
                this.panel1.BackColor = Color.White;
                this.panel1.Controls.Add(shapeContainer1);
    
                this.myLine.StartPoint = new Point(20, 30);
                this.myLine.EndPoint = new Point(80, 120);
                this.myLine.Parent = this.shapeContainer1;
    
                MouseEventHandler panelMouseMove =
                    new MouseEventHandler(this.panel1_MouseMove);
                this.panel1.MouseMove += panelMouseMove;
                this.shapeContainer1.MouseMove += panelMouseMove;
    
                this.Controls.Add(panel1);
            }
    
            private void panel1_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    myLine.StartPoint = e.Location;
                }
            }
        }
    
        /// 
        /// Test LineShape
        /// 
        public class IconLineShape : LineShape
        {
            Icon myIcon = SystemIcons.Exclamation;
            PictureBox pictureBox = new PictureBox();
    
            public IconLineShape()
            {
                pictureBox.Image = Bitmap.FromHicon(myIcon.Handle);
                pictureBox.Size = myIcon.Size;
                pictureBox.Visible = true;
            }
    
            protected override void OnMove(System.EventArgs e)
            {
                base.OnMove(e);
                pictureBox.Location = this.StartPoint;
            }
    
            protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
            {
                base.OnPaint(e);
                pictureBox.Invalidate();
            }
    
            public override bool HitTest(int x, int y)
            {            
                return base.HitTest(x, y) |
                    pictureBox.RectangleToScreen(
                        pictureBox.DisplayRectangle).Contains(new Point(x, y));
            }
    
            protected override void OnParentChanged(System.EventArgs e)
            {
                // Parent is a ShapeContainer
                // Parent.Parent is a Panel
                pictureBox.Parent = Parent.Parent;
                base.OnParentChanged(e);
            }
        }
    }
    

    Thanks everybody for participating!