none
drawing cross hair +C#

    Question

  •      i'm trying to draw crosshairs that follow the mouse around the screen. The following code works. but not quite, it draws a new crosshair for every mouse move, but doesn't remove the old one, so i end up with a screen full of vertical and horizontal lines.

    how do i remove the last lines drawn on every mouse move?

    public void MyMouseMove( Object sender, MouseEventArgs e )
    {

    Pen blackPen = new Pen(Color.FromArgb(128,0,0,255), 1); // Pen blackPen = new Pen(Color.FromArgb(0,0,0,255), 1);
       Graphics g = SelectionRectangle.ActiveForm.CreateGraphics();
    // Create coordinates of points that define line.
    float formLeft = this.Left;
    float formTop = this.Top ;
    float formRight = this.Right ;
    float formBottom = this.Bottom ;
    mouseX = e.X ;
    mouseY = e.Y ;
    // Draw line to screen.
    g.DrawLine(blackPen,0,mouseY,mouseX,mouseY );
    g.DrawLine(blackPen, mouseX, 0, mouseX,mouseY);
    g.DrawLine(blackPen, formRight, mouseY, mouseX, mouseY);
    g.DrawLine(blackPen, mouseX, formBottom,mouseX, mouseY);

    algates
    Tuesday, November 24, 2009 4:10 AM

Answers

  • I'd love to write that code for you, but I'm a little short on time today, so here's the easiest thing I could come up with in the meantime  (#3 from my list):

    public partial class Form1 : Form
    {
    	public Form1()
    	{
    		InitializeComponent();
    	}
    
    	int lastX = 0;
    	int lastY = 0;
    	private void Form1_MouseMove( object sender, MouseEventArgs e )
    	{
    		Region r = new Region();
    		r.Union(new Rectangle(0, lastY, this.Width, 1) );
    		r.Union(new Rectangle(lastX, 0, 1, this.Height) );
    		this.Invalidate( r );
    		this.Update();
    		Graphics g = Graphics.FromHwnd( this.Handle );
    		g.DrawLine( Pens.Black, 0, e.Y, this.Width, e.Y );
    		g.DrawLine( Pens.Black, e.X, 0, e.X, this.Height );
    		lastX = e.X;
    		lastY = e.Y;
    	}
    
    	private void Form1_MouseLeave( object sender, EventArgs e )
    	{
    		this.Invalidate();
    	}
    }
    
    Sorry if you really had your heart set on #4 and #5.  But basically, instead of Invalidate and Update, you restore the old area, then save the new area before drawing.  I suspect what I wrote above will be good enough for you, though.  Depends on how nasty your Paint handler is, I suppose.
    • Marked as answer by algates Saturday, November 28, 2009 6:18 AM
    Wednesday, November 25, 2009 4:52 PM

All replies

  • Hi,

    You can call g.Clear(SelectionRange.ActiveForm.BackColor) just after the line you create graphics object.
    Tuesday, November 24, 2009 5:10 AM
  • Dear Tamer Oz,
                   Fine.Ya i did it. but it clears all my graphics which i drawn in SelectionRange.ActiveForm.So i redrawn once again..Is there is any solution to delete only cross hair or not to erase other graphics by using g.Clear(SelectionRange.ActiveForm.BackColor) . so that it will be more advantage for me to not using redraw everying once again.



    Regards,
    ALGATES. :)


    algates
    Tuesday, November 24, 2009 7:37 AM
  • Hi

    as an alternate you can call SelectionRange.ActiveForm.Refresh() at the first line of mousemove event.

    Tuesday, November 24, 2009 5:07 PM
  • Why dont you want to use the cross hairs cursor?

    Ciaran
    Tuesday, November 24, 2009 5:45 PM
  • You should always be able to paint the entire contents of the window from scratch if needed.  Just wanted to make sure you know that.  So I suspect performance is the issue with redrawing everything, right?
    Well, a few approaches come to mind:
    1. Draw the whole thing every time.  Start painting with a clear, then draw the contents of the window, followed by the crosshairs.  You can double-buffer the window to prevent flicker.  Simplest code, though.  Least amount of work.
    2. XOR drawing.  Invert the pixels in the column or row rather than paint over them.  Then to remove the lines, invert them again.  Problems:  crosshairs invisible against grey background because inverse of grey is still grey.
    3. Partial invalidation.  Instead of redrawing everything, just invalidate the area covered by the old crosshairs, and the new crosshairs.  This will speed up drawing a bit because other parts of the window won't need writes to video memory. (Drawing operations are clipped by the valid region.)  But otherwise, it's very similar to #1, but just with clipping.
    4. Save background beneath new crosshairs, then draw the crosshairs.  Then to remove them, draw the saved background image. and repeat for new crosshairs.  Could be the fastest technique, actually.
    5. Layered drawing.  Use a transparent window above your content and let windows blend the background for you.  Essentially, you will either get a paint message for the bottom window, or it will handle saving and restoring pixels for you.
    6. A crosshair cursor.  Doesn't have the full width and height of the window, so this depends on your requirements.  Way simpler, though!

    Good luck!
    Tuesday, November 24, 2009 5:57 PM

  • Just make a transparent form that looks like a cursor.
    Allow the mouse to drag it around.  Hide and Show it as needed.

    Mark the best replies as answers. "Fooling computers since 1971."
    • Proposed as answer by Matthew Watson Thursday, December 03, 2009 9:38 AM
    Tuesday, November 24, 2009 7:00 PM
  • Dear Wyck,
            I have tried 5 method but i am having some difficulties. Can you please explain 4 and 5 method with some sample code.

    Thanks
    Wednesday, November 25, 2009 7:02 AM
  • I'd love to write that code for you, but I'm a little short on time today, so here's the easiest thing I could come up with in the meantime  (#3 from my list):

    public partial class Form1 : Form
    {
    	public Form1()
    	{
    		InitializeComponent();
    	}
    
    	int lastX = 0;
    	int lastY = 0;
    	private void Form1_MouseMove( object sender, MouseEventArgs e )
    	{
    		Region r = new Region();
    		r.Union(new Rectangle(0, lastY, this.Width, 1) );
    		r.Union(new Rectangle(lastX, 0, 1, this.Height) );
    		this.Invalidate( r );
    		this.Update();
    		Graphics g = Graphics.FromHwnd( this.Handle );
    		g.DrawLine( Pens.Black, 0, e.Y, this.Width, e.Y );
    		g.DrawLine( Pens.Black, e.X, 0, e.X, this.Height );
    		lastX = e.X;
    		lastY = e.Y;
    	}
    
    	private void Form1_MouseLeave( object sender, EventArgs e )
    	{
    		this.Invalidate();
    	}
    }
    
    Sorry if you really had your heart set on #4 and #5.  But basically, instead of Invalidate and Update, you restore the old area, then save the new area before drawing.  I suspect what I wrote above will be good enough for you, though.  Depends on how nasty your Paint handler is, I suppose.
    • Marked as answer by algates Saturday, November 28, 2009 6:18 AM
    Wednesday, November 25, 2009 4:52 PM
  • I uploaded a transparent window example to filedropper:  http://www.filedropper.com/transparencytest   Ignore the missing SETUP project, I excluded it.

    Drag and drop any semi-transparent .png file onto the exe to display it.  Use Alt-F4 to exit, or close the app from the task-bar.

    This is overkill unless the rendered crosshairs are going to be something fancier than just lines.  (e.g. something with an alpha channel - i.e. semi-transparency)
    • Proposed as answer by Benita Blas Monday, November 30, 2009 7:00 AM
    Wednesday, November 25, 2009 6:08 PM
  • hi Wyck..
           thank you very much ...its working nice..can i know how to  restore the old area, then save the new area before drawing.




    Regards,
    ALGATES.

    algates
    Saturday, November 28, 2009 6:20 AM
  •   The above code is calling invalide ..so it calling onpaint....is there is way to draw without calling form onpaint.


    Regards,
    ALGATES
    algates
    Thursday, December 03, 2009 8:31 AM
  • I'd like to ask you a quick question before answering that.

    Why don't you want to call paint to draw your window?
    Thursday, December 03, 2009 4:49 PM
  • Dear WycK,
              In the paint event I have traversed and draw more elements and also i have drawn grid dots

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    namespace GridTest
    {
       
    public partial class Form1 : Form
       
    {
           
    Graphics g;
           
    const int gridsize = 20;

           
    public Form1()
           
    {
               
    InitializeComponent();
                g
    = splitContainer1.Panel2.CreateGraphics();
                splitContainer1
    .Panel2.Invalidate();
           
    }

           
    private void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
           
    {
               
    Drawgrid();          
           
    }

           
    private void Drawgrid()
           
    {
               
    for (int x = 0; x < splitContainer1.Panel2.ClientSize.Width; x += gridsize)
               
    {
                   
    for (int y = 0; y < splitContainer1.Panel2.ClientSize.Height; y += gridsize)
                   
    { g.DrawLine(Pens.Black, new Point(x, y), new Point(x + 1, y)); }
               
    }
           
    }
    int lastX = 0;
    int lastY = 0;
           
    private void splitContainer1_Panel2_MouseMove(object sender, MouseEventArgs e)
           
    {
              Region r = new Region();
               r.Union(new Rectangle(0, lastY, this.Width, 1) );
              r.Union(new Rectangle(lastX, 0, 1, this.Height) );
              this.Invalidate( r );          // This is calling paint event so  DrawGrid() is calling every mouse move.it makes my application to slow.
              this.Update();
              Graphics g = Graphics.FromHwnd( this.Handle );
              g.DrawLine( Pens.Black, 0, e.Y, this.Width, e.Y );
              g.DrawLine( Pens.Black, e.X, 0, e.X, this.Height );
              lastX = e.X;
              lastY = e.Y;

              }

           
    private Point RoundToNearest(int nearestRoundValue, Point currentPoint)
           
    {
               
    Point newPoint = new Point();
               
    int lastDigit;

                lastDigit
    = currentPoint.X % nearestRoundValue;

               
    if (lastDigit >= (nearestRoundValue/2))
               
    { newPoint.X = currentPoint.X - lastDigit + nearestRoundValue; }
               
    else
               
    { newPoint.X = currentPoint.X - lastDigit; }

                lastDigit
    = currentPoint.Y % nearestRoundValue;
               
    if (lastDigit >= (nearestRoundValue / 2))
               
    { newPoint.Y = currentPoint.Y - lastDigit + nearestRoundValue; }
               
    else
               
    { newPoint.Y = currentPoint.Y - lastDigit; }

               
    return newPoint;
           
    }
       
    }


    algates
    Saturday, December 05, 2009 5:02 AM
  •       I have the same problem with the update makes the screen not clear enough, so I do like this:

            private void picturebox1_MouseMove(object sender, MouseEventArgs e)
            {
                Point ptCurrent = new Point(e.X, e.Y);

                    // If we have drawn previously, draw again in
                    // that spot to remove the lines.
                    if (ptLast.X != -1)
                    {
                        DrawCrossHair(ptOriginal, ptLast);
                    }
                    // Update last point.
                    ptLast = ptCurrent;
                    // Draw new lines.
                    DrawCrossHair(ptCurrent);
            }

            private void DrawCrossHair(Point pp)
            {
                Point p3 = new Point();
                Point p4 = new Point();

                p3.X = 0; p3.Y = pp.Y;
                p4.X = picturebox1.Width; p4.Y = p1.Y;
                p3 = picturebox1.PointToScreen(p3);
                p4 = picturebox1.PointToScreen(p4);
                ControlPaint.DrawReversibleLine(p3, p4, Color.Gray);

                p3.X = pp.X; p3.Y = 0;
                p4.X = pp.X; p4.Y = pic_CurveFit.Height;
                p3 = picturebox1.PointToScreen(p3);
                p4 = picturebox1.PointToScreen(p4);
                ControlPaint.DrawReversibleLine(p3, p4, Color.Gray);
            }

    Monday, June 14, 2010 8:59 AM
  •  

    Hi Rudedog2

     

    I need to solve the same problem (Draw a full screen crosshairs in C#). I have tried the solutions suggested but there are a bit slow. The crosshairs follow the cursor with a time lag. I would like to try your suggested solution, but I would appreciate a little more detail. Could you possibly give a more complete example to follow.

     

    Thanks for your help.

    Saturday, February 26, 2011 5:29 PM
  • Please.  Start a new thread of your own and post your drawing code.  It sounds like you have a minor problem with your drawing routines.
    Mark the best replies as answers. "Fooling computers since 1971."

    http://rudedog2.spaces.live.com/default.aspx

    Saturday, February 26, 2011 6:16 PM
  • Dear All,

    I am quite interesting this post since I am doing the same thing described in here.

    In my case, I would like to use long cross hair like cross cursot from start and end of width and height.

    Could it be possible to have a look complete working sample for a while?

    Thanks and best regards


    KYAW KYAW OO

    Wednesday, February 08, 2012 4:16 AM
  • Here's the new thread started by Steven1m.

    http://social.msdn.microsoft.com/Forums/en/csharpgeneral/thread/ee843aba-f2cc-4d4a-bd67-dd2fa7df5b0c

    There is code for a transparent form that looks like crosshairs.  There is code for a form that instantiates the crosshairs form and uses it.

    Rudy   =8^D


    Mark the best replies as answers. "Fooling computers since 1971."

    http://thesharpercoder.blogspot.com/

    Wednesday, February 08, 2012 10:41 PM