I posted a similar but less specific question a couple hours ago, but the circumstances have changed. I'm working on a program that transforms graphics, presenting them in a panel in the upper left of the form. It was painting fine earlier, but now isn't and I can't undo, load old version, etc. Previously, the app was unresponsive even to events in the menus, as well as painting. I started a new project and got it up and running, the menus work and I brought over the buttons and stuff. But it still won't paint the axes and gridlines in the panel. I put breakpoints in both the main forms's paint handler and the splitContainer2_Panel1_Paint handler that should be doing the work, but the code here isn't even being executed. I have a timer that's active and invalidating the whole form every 100 ms, so why would the paint event handler not be called? Help?
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;
using System.IO;
namespace TransformerA
{
public partial class Transformer : Form
{
/* Initialize parameters */
private bool drawAxes = true;
private bool drawGrid = true;
private List<ObjectSettings> dispObjects = new List<ObjectSettings>();
/* Initialize form */
public Transformer()
{
InitializeComponent();
}
private void Transformer_Load(object sender, EventArgs e)
{
// Populate available objects listbox
string currentDir = Directory.GetCurrentDirectory();
string[] fileEntries = Directory.GetFiles(currentDir + #"\Objects");
foreach (string s in fileEntries) {
int start = s.LastIndexOf(#"\");
int end = s.LastIndexOf(#".");
availObjectsListBox.Items.Add(s.Substring(start + 1, end - start - 1));
} // end foreach
}
/* Paint graphics */
// Paint main form
private void Transformer_Paint(object sender, PaintEventArgs e)
{
splitContainer2_Panel1_Paint(sender, e);
}
// Paint graphics panel
private void splitContainer2_Panel1_Paint(object sender, PaintEventArgs e)
{
Rectangle r = splitContainer2.Panel1.ClientRectangle;
//Graphics g = splitContainer2.Panel1.CreateGraphics();
Graphics g = e.Graphics;
Pen axisPen = new Pen(Color.Gray, 2.0f);
Pen gridPen = new Pen(Color.Gray, 1.0f);
g.Clear(Color.Blue);
if (drawAxes) {
g.DrawLine(axisPen, r.Left + 0.5f * r.Width, r.Top, r.Left + 0.5f * r.Width, r.Bottom);
g.DrawLine(axisPen, r.Left, r.Top + 0.5f * r.Height, r.Right, r.Top + 0.5f * r.Height);
}
if (drawGrid) {
// Vertical lines
int xVal = 0;
int xCenter = r.Width / 2;
g.DrawLine(gridPen, xCenter, r.Top, xCenter, r.Bottom);
for (int i = 0; i < 10; i++) {
xVal += r.Width / 20;
g.DrawLine(gridPen, xCenter + xVal, r.Top, xCenter + xVal, r.Bottom);
g.DrawLine(gridPen, xCenter - xVal, r.Top, xCenter - xVal, r.Bottom);
}
// Horizontal lines
int yVal = 0;
int yCenter = r.Height / 2;
g.DrawLine(gridPen, r.Left, yCenter, r.Right, yCenter);
for (int i = 0; i < 10; i++) {
yVal += r.Height / 20;
g.DrawLine(gridPen, r.Left, yCenter + yVal, r.Right, yCenter + yVal);
g.DrawLine(gridPen, r.Left, yCenter - yVal, r.Right, yCenter - yVal);
}
}
// foreach object in displayed objects
// keep list of displayed objects and their settings (make struct)
g.Dispose();
axisPen.Dispose();
gridPen.Dispose();
}
/* File menu */
private void saveImageToolStripMenuItem_Click(object sender, EventArgs e)
{
}
private void exitToolStripMenuItem_Click(object sender, EventArgs e)
{
Close();
}
/* Options menu */
private void axesOnoffToolStripMenuItem_Click(object sender, EventArgs e)
{
if (drawAxes == true)
drawAxes = false;
else
drawAxes = true;
}
private void gridOnoffToolStripMenuItem_Click(object sender, EventArgs e)
{
if (drawGrid == true)
drawGrid = false;
else
drawGrid = true;
}
/* Help menu */
private void helpToolStripMenuItem_Click(object sender, EventArgs e)
{
AboutBox dlg = new AboutBox();
dlg.ShowDialog();
}
/* Other */
private void timer1_Tick(object sender, EventArgs e)
{
Invalidate();
}
}
}
Whoops, fixed it, I needed to add the event handler from the designer... i just pasted in the handler code from my old unworking version, so it didn't add the needed code to the designer code. Still can't figure out why it stopped working before but at least it's running now.
Related
I create a code give that allow me to resize a circle and move it
first mouse click give me the center for the circle.
the circle radius will change with the cursor movement (closer to the center smaller radius farther from the center bigger radius).
click second time the radius will not be changed and the circle will be finalized.
This is an image similar to what I want to do:
http://lh6.ggpht.com/_wQH6U92SY04/S_6lAJI7E-I/AAAAAAAAKwE/i-Jkq-nI5Ss/GoogleMapCircle%5B11%5D.gif?imgmax=800
The problems are :
the center is not exactly where I click the mouse first time.
the cursor should be exactly at the circle border when I move it.
the biggest problem is after clicking second time the circle is move farther from the center .
PLEASE HELP
using System;
using System.Drawing;
using System.Windows.Forms;
namespace project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
rectangleObj.X = e.X;
rectangleObj.Y = e.Y;
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X;
rectangleObj.Y = clickPrev.Y;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
}
}
I figured it out
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace Project
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
Bitmap background;
Graphics scG;
Rectangle rectangleObj;
Rectangle center;
int clikno = 0;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(this.Width, this.Height);//, this.Width,this.Height);
rectangleObj = new Rectangle(10, 10, 100, 100);
center = new Rectangle(10, 10, 3, 3);
scG = Graphics.FromImage(background);
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
if (clickPrev == Point.Empty) return;
Refresh();
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 3);
scG.Clear(SystemColors.Control);
scG.DrawEllipse(myPen, rectangleObj);
// scG.DrawRectangle(myPen, rectangleObj);
scG.DrawEllipse(myPen, center);
return background;
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
int radius = Convert.ToInt32(oradius);
if (clikno == 1)
{
rectangleObj.Height = radius;
rectangleObj.Width = radius;
rectangleObj.X = clickPrev.X- rectangleObj.Height /2;// +radius;
rectangleObj.Y = clickPrev.Y - rectangleObj.Width / 2;// +radius;
center.X = clickPrev.X - center.Height / 2;// +radius;
center.Y = clickPrev.Y - center.Width / 2;// +radius;
Refresh();
}
if (clikno == 2)
clikno = 0;
Refresh();
}
string myString = 5.ToString();
}
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Code running slow.. the code generates multiple circles have a center can be specified by first click then change the radius by moving the pointer to desired circle size then click to finish drawing the circle.. and repeat to draw another circle..I solved the problem by very simple step see the comments down
public partial class Form1 : Form
{
public class Seat
{
private string _SeatKey;
private Rectangle _SeatRectangle;
public Seat(string seatKey, Rectangle seatRectangle)
{
_SeatKey = seatKey;
_SeatRectangle = seatRectangle;
}
public string SeatKey
{
get { return _SeatKey; }
}
public Rectangle SeatRectangle
{
get { return _SeatRectangle; }
set { _SeatRectangle = value; }
}
}
List<Seat> _Seats = new List<Seat>();
List<Seat> _center = new List<Seat>();
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
for (int i = 0; i < 30; i = i + 1)
{
string mystring = "regctangle" + i.ToString();
_Seats.Add(new Seat(mystring, new Rectangle(50, 50, 50, 50)));
}
for (int i = 0; i < 30; i = i + 1)
{
string mystring = "center" + i.ToString();
_center.Add(new Seat(mystring, new Rectangle(50 , 50 , 3, 3)));
}
}
Bitmap background;
Graphics scG;
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
int clikno = 1;
int xpos;
int ypos;
int clicknew = 0;
int radius=0;
int recH;
int recW;
int xcen;
int ycen;
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
clikno = clikno + 1;
clicknew = clicknew + 1;
}
private void Form1_Load(object sender, EventArgs e)
{
background = new Bitmap(Width, Height);
scG = Graphics.FromImage(background);
}
protected override void OnPaint(PaintEventArgs pe)
{
pe.Graphics.DrawImage(Draw(), 0, 0);
}
public Bitmap Draw()
{
Graphics scG = Graphics.FromImage(background);
Pen myPen = new Pen(System.Drawing.Color.Red, 1/2);
Pen mPen = new Pen(System.Drawing.Color.Black, 3);
scG.Clear(SystemColors.Control);
_Seats[clikno].SeatRectangle = new Rectangle(xpos, ypos, recH, recW);
_center[clikno].SeatRectangle = new Rectangle(xcen, ycen, 3, 3);
for (int i = 0; i < clikno+1; i = i + 1)
{
scG.DrawEllipse(myPen, _Seats[i].SeatRectangle);
scG.DrawEllipse(mPen, _center[i].SeatRectangle);
}
Refresh();//This what cause the code running slow
return background;
}
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
AutoSize = true;
clickCurrent = this.PointToClient(Cursor.Position);
clickPrev = clickCurrent;
if (clickPrev == Point.Empty) return;
Refresh();
clickCurrent = Point.Empty;
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - e.X, 2)) + (Math.Pow(clickPrev.Y - e.Y, 2)));
radius = Convert.ToInt32(oradius);
if (clicknew == 1)
{
recH = radius;
recW = radius;
xpos = clickPrev.X - recW / 2;
ypos = clickPrev.Y - recH / 2;
xcen = clickPrev.X - 3 / 2;
ycen = clickPrev.Y - 3 / 2;
Refresh();
}
if (clicknew == 2)
clicknew = 0;
Refresh();
}
}
The part that is so slow is your MouseMove.
Usually one checks for the left mousebutton to be pressed:
private void yourDrawingControl_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button.HasFlag(MouseButtons.Left) )
{
// draw stuff
}
}
If that is not a condition that applies you should check for having moved for at least more than one pixel:
Point oldLocation = Point.Empty;
private void yourDrawingControl_MouseMove(object sender, MouseEventArgs e)
{
int minStep = 3;
if ( (Math.Abs(oldLocation.X - e.X) + Math.Abs(oldLocation.Y - e.Y) > minStep) )
{
// draw stuff
}
oldLocation = e.Location;
}
Also: While the graphics is being built up, do not draw into a Bitmap which you then draw with DrawImage in your Paint event. Instead in the Paint event draw directly onto the surfce of the control from a List<yourDrawingshapeClass> !
Drawing hundreds of Rectangles is extremely fast compared to drawing even one of your Bitmaps..
Also: It looks as if you are drawing onto the Form? Better draw onto a dedicated control with just the right size; the natural choice is a PictureBox, which is made for this and is double-buffered out-of-the-box. Instead your enforce the form to refresh all it controls..
Finally: Even if you refuse to change your convoluted code to something well-proven, at least make it not call Refresh in the MouseMove unconditionally (in the last line), even if nothing at all has changed!
I need to move a point along a rectangle path at the command of a button. I want it to start at the upper right corner of the rectangle path, but I am not sure how to get it to go all the way around the path and stop at the original point. The screen refreshes at the speed provided by the user in an input box. Thank you in advance!
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 System.Timers;
namespace Assignment_2
{
public partial class Form1 : Form
{
private const int formwidth = 1280;
private const int formheight = 720;
private const int ball_a_radius = 10;
private const int horizontaladjustment = 8;
private const double ball_a_distance_moved_per_refresh = 1.6;
private double ball_a_real_coord_x = 515;
private double ball_a_real_coord_y = 40;
private int ball_a_int_coord_x;
private int ball_a_int_coord_y;
private const double graphicrefreshrate = 30.0;
private static System.Timers.Timer graphic_area_refresh_clock = new System.Timers.Timer();
private static System.Timers.Timer ball_a_control_clock = new System.Timers.Timer();
private bool ball_a_clock_active = false;
public double speed = 0;
public Form1()
{
InitializeComponent();
ball_a_int_coord_x = (int)(ball_a_real_coord_x);
ball_a_int_coord_y = (int)(ball_a_real_coord_y);
System.Console.WriteLine("Initial coordinates: ball_a_int_coord_x = {0}. ball_a_int_coord_y = {1}.",
ball_a_int_coord_x, ball_a_int_coord_y);
graphic_area_refresh_clock.Enabled = false;
graphic_area_refresh_clock.Elapsed += new ElapsedEventHandler(Updatedisplay);
ball_a_control_clock.Enabled = false;
ball_a_control_clock.Elapsed += new ElapsedEventHandler(Updateballa);
Startgraphicclock(graphicrefreshrate);
Startballaclock(speed);
}
public class NumericTextBox : TextBox
{
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void panel2_Paint(object sender, PaintEventArgs e)
{
}
private void panel2_Paint_1(object sender, PaintEventArgs e)
{
//Create pen
Pen blackPen = new Pen(Color.Black, 1);
//Create rectangle
Rectangle rect = new Rectangle(125, 50, 400, 400);
//Draw rectangle to screen
e.Graphics.DrawRectangle(blackPen, rect);
Graphics graph = e.Graphics;
graph.FillEllipse(Brushes.Green, ball_a_int_coord_x, ball_a_int_coord_y, 2 * ball_a_radius, 2 * ball_a_radius);
base.OnPaint(e);
}
public void button7_Click(object sender, EventArgs e)
{
speed = Convert.ToInt32(textBox3.Text);
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
}
protected void Startgraphicclock(double refreshrate)
{
double elapsedtimebetweentics;
if (refreshrate < 1.0) refreshrate = 1.0;
elapsedtimebetweentics = 1000.0 / refreshrate;
graphic_area_refresh_clock.Interval = (int)System.Math.Round(elapsedtimebetweentics);
graphic_area_refresh_clock.Enabled = true;
}
protected void Startballaclock(double updaterate)
{
double elapsedtimebetweenballmoves;
if (updaterate < 1.0) updaterate = 1.0;
elapsedtimebetweenballmoves = 1000.0 / updaterate;
ball_a_control_clock.Interval = (int)System.Math.Round(elapsedtimebetweenballmoves);
ball_a_control_clock.Enabled = true;
ball_a_clock_active = true;
}
protected void Updatedisplay(System.Object sender, ElapsedEventArgs evt)
{
Invalidate();
if (!(ball_a_clock_active))
{
graphic_area_refresh_clock.Enabled = false;
System.Console.WriteLine("The graphical area is no longer refreshing. You may close the window.");
}
}
protected void Updateballa(System.Object sender, ElapsedEventArgs evt)
{
ball_a_real_coord_x = ball_a_real_coord_x - 5;
ball_a_real_coord_y = ball_a_real_coord_y - 5;
ball_a_int_coord_x = (int)System.Math.Round(ball_a_real_coord_x);
ball_a_int_coord_y = (int)System.Math.Round(ball_a_real_coord_y);
if (ball_a_int_coord_x >= formwidth || ball_a_int_coord_y + 2 * ball_a_radius <= 0 || ball_a_int_coord_y >= formheight)
{
ball_a_clock_active = false;
ball_a_control_clock.Enabled = false;
System.Console.WriteLine("The clock controlling ball a has stopped.");
}
}
private void button4_Click(object sender, EventArgs e)
{
ball_a_control_clock.Enabled = true;
}
}
}
I have a more straightforward way to move a circle. Your code is too long for me to read. See if you like this!
If I were you, I would use a PictureBox. I first create an image of a circle, and then put that image in the PictureBox. Then you can just use a timer to change the position of the PictureBox.
You should set the Interval of the timer to 33 ms, which is roughly 30 fps. This is how you would programme the timer:
Keep a counter to indicate how many pixels the circle has moved. Let's say you want it to move in a 100px x 50px rectangular path.
For every 33ms,
If the counter is less than 100,
increase the X position and the counter by 1,
if the counter is between 101 and 150,
increase the Y position and the counter by 1,
if the counter is between 151 and 250,
decrease the X position by 1 and increment the counter
if the counter is between 251 and 300,
decrease the Y position by 1 and increment the counter
if the counter is greater than 300,
stop the timer
I really don't like drawing stuff on the screen with the OnPaint event. I mean, you are moving a ball! People think of this as changing the x and y positions of a ball, not as deleting the ball at the previous position and drawing it in the new position. Changing the position of the picture box just makes LOTS more sense, don't you think so?
I'm trying to create a simple Windows Forms graphics app that basically will draw a circle every time the user clicks and it expands, while slowly fading away.
When I tried to use the Paint() Event for my graphics functionality, nothing happened, so I created a separate function called "Render" that is called in my main update Timer.
The app worked but the graphics flickered. After some researched I realized that I had to enable Double Buffering so that it would render to a buffer and then the buffer would be rendered to the screen.
The flickering still didn't stop!
Is this because double buffering only works for Paint() events and if so how do I get the Paint() event to work or am I not enabling Double Buffering right?
Here's my code:
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;
namespace Widget
{
public class Circle
{
public float X;
public float Y;
public float Radius;
public int Alpha;
public Circle(float X, float Y, float Radius, int Alpha)
{
this.X = X;
this.Y = Y;
this.Radius = Radius;
this.Alpha = Alpha;
}
}
public partial class Form1 : Form
{
public static readonly int ScreenX = Screen.PrimaryScreen.Bounds.Width;
public static readonly int ScreenY = Screen.PrimaryScreen.Bounds.Height;
public int WindowWidth = 500, WindowHeight = 500;
public Graphics G;
private Pen Pen;
private Timer timer = new Timer();
private List<Circle> Circles;
public Form1()
{
this.Text = "Widget - Sam Brandt";
this.Size = new Size(WindowWidth, WindowHeight);
this.StartPosition = FormStartPosition.Manual;
this.Location = new Point(ScreenX - WindowWidth - 100, 0);
this.FormBorderStyle = FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Icon = new Icon("C:\\Users\\Admin\\Desktop\\Code Repositories\\Visual Studios\\Widget\\Widget\\Properties\\WidgetIcon.ico");
Pen = new Pen(Color.Black, 1);
G = CreateGraphics();
//this.Paint += new PaintEventHandler(OnPaint);
ConstructMouse();
FormWithTimer();
DoubleBuffered = true;
Circles = new List<Circle>();
}
public void ConstructMouse()
{
this.MouseUp += new MouseEventHandler(OnMouseUp);
this.MouseMove += new MouseEventHandler(OnMouseMove);
this.MouseDown += new MouseEventHandler(OnMouseDown);
}
public void FormWithTimer()
{
timer.Tick += new EventHandler(timer_Tick);
timer.Interval = (10);
timer.Enabled = true;
timer.Start();
}
protected void OnMouseUp(object sender, MouseEventArgs e)
{
}
protected void OnMouseMove(object sender, MouseEventArgs e)
{
}
public void OnMouseDown(object sender, MouseEventArgs e)
{
Circles.Add(new Circle(e.Location.X, e.Location.Y, 0, 255));
}
/*public void OnPaint(object sender, PaintEventArgs e)
{
e.Graphics.Clear(Color.White);
for (int i = 0; i < Circles.Count; i++)
{
Circle C = Circles[i];
e.Graphics.DrawEllipse(new Pen(Color.FromArgb(C.Alpha, 0, 0, 0), 1), C.X - C.Radius, C.Y - C.Radius, 2 * C.Radius, 2 * C.Radius);
}
}*/
private void Tick()
{
for (int i = 0; i < Circles.Count; i++)
{
Circle C = Circles[i];
C.Radius++;
C.Alpha -= 3;
if (C.Alpha == 0)
{
Circles.RemoveAt(i);
}
}
}
public void Render()
{
G.Clear(Color.White);
for (int i = 0; i < Circles.Count; i++)
{
Circle C = Circles[i];
G.DrawEllipse(new Pen(Color.FromArgb(C.Alpha, 0, 0, 0), 1), C.X - C.Radius, C.Y - C.Radius, 2 * C.Radius, 2 * C.Radius);
}
}
public void timer_Tick(object sender, EventArgs e)
{
Render();
Tick();
}
}
}
Short answer - keep DoubleBuffered = true and use Paint event.
When I tried to use a PaintEvent for my graphics functionality, nothing happened
When you do some modifications and want to reflect them, use Control.Invalidate method, which according to the documentation
Invalidates the entire surface of the control and causes the control to be redrawn.
In your case, something like this
void timer_Tick(object sender, EventArgs e)
{
Tick();
Invalidate();
}
More observations here but probably will be the answer.
Why Timer?
Use the Paint event, it is called when the GDI+ determines it needs to, you are constantly painting with your code as-is.
Your code makes it look like you are not using double buffering.
I'd do all your drawing to a separate Graphics object, and then copy that to your main Graphics object on the timer tick event only if there's been a change. You may need to keep track of that with a boolean member. This means your background drawing will have to be triggered by some other event.
If your picture is actually changing every 10 milliseconds, I'd slow down the timer a bit and set it to 50 milliseconds.
Try this (in VB):
Dim aProp = GetType(Control).GetProperty("DoubleBuffered", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)
aProp.SetValue(Me, True, Nothing)
Also had problems with double buffering, and usual setting property DoubleBuffered to true do not work. I have found this solution somewhere on web
This is the code:
private void hsMagnfier_OnMouseDown(object sender)
{
int x = mLastCursorPosition.X;
int y = mLastCursorPosition.Y;
MagnifierForm magnifier = new MagnifierForm(mConfiguration, System.Windows.Forms.Cursor.Position);//mLastCursorPosition);
magnifier.Show();
}
This code above is in a Form which I can drag over the screen.
Then when I click on an icon it's doing the magnifier.Show(); and the magnifier form is shown up where the mouse current position is.
But if I click on it again so now the position of the new form the magnifier is in my Form1 center. And not where the mouse current position as in the first time.
This is the MagnifierForm code maybe first time it's in the current mouse position but in the next time/s it's in the center of Form1 ?
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;
using System.IO;
using System.Drawing.Imaging;
namespace ScreenVideoRecorder
{
public partial class MagnifierForm : Form
{
public MagnifierForm(Configuration configuration, Point startPoint)
{
InitializeComponent();
//--- My Init ---
mConfiguration = configuration;
FormBorderStyle = FormBorderStyle.None;
ShowInTaskbar = mConfiguration.ShowInTaskbar;
TopMost = mConfiguration.TopMostWindow;
Width = mConfiguration.MagnifierWidth;
Height = mConfiguration.MagnifierHeight;
// Make the window (the form) circular
GraphicsPath gp = new GraphicsPath();
gp.AddEllipse(ClientRectangle);
Region = new Region(gp);
mImageMagnifier = Properties.Resources.magnifierGlass;
mTimer = new Timer();
mTimer.Enabled = true;
mTimer.Interval = 20;
mTimer.Tick += new EventHandler(HandleTimer);
mScreenImage = new Bitmap(Screen.PrimaryScreen.Bounds.Width,
Screen.PrimaryScreen.Bounds.Height);
mStartPoint = startPoint;
mTargetPoint = startPoint;
if (mConfiguration.ShowInTaskbar)
ShowInTaskbar = true;
else
ShowInTaskbar = false;
}
protected override void OnShown(EventArgs e)
{
RepositionAndShow();
}
private delegate void RepositionAndShowDelegate();
private void RepositionAndShow()
{
if (InvokeRequired)
{
Invoke(new RepositionAndShowDelegate(RepositionAndShow));
}
else
{
// Capture the screen image now!
Graphics g = Graphics.FromImage(mScreenImage);
g.CopyFromScreen(0, 0, 0, 0, new Size(mScreenImage.Width, mScreenImage.Height));
g.Dispose();
if (mConfiguration.HideMouseCursor)
Cursor.Hide();
else
Cursor = Cursors.Cross;
Capture = true;
if (mConfiguration.RememberLastPoint)
{
mCurrentPoint = mLastMagnifierPosition;
Cursor.Position = mLastMagnifierPosition;
Left = (int)mCurrentPoint.X - Width / 2;
Top = (int)mCurrentPoint.Y - Height / 2;
}
else
{
mCurrentPoint = Cursor.Position;
}
Show();
}
}
void HandleTimer(object sender, EventArgs e)
{
float dx = mConfiguration.SpeedFactor * (mTargetPoint.X - mCurrentPoint.X);
float dy = mConfiguration.SpeedFactor * (mTargetPoint.Y - mCurrentPoint.Y);
if (mFirstTime)
{
mFirstTime = false;
mCurrentPoint.X = mTargetPoint.X;
mCurrentPoint.Y = mTargetPoint.Y;
Left = (int)mCurrentPoint.X - Width / 2;
Top = (int)mCurrentPoint.Y - Height / 2;
return;
}
mCurrentPoint.X += dx;
mCurrentPoint.Y += dy;
if (Math.Abs(dx) < 1 && Math.Abs(dy) < 1)
{
mTimer.Enabled = false;
}
else
{
// Update location
Left = (int)mCurrentPoint.X - Width / 2;
Top = (int)mCurrentPoint.Y - Height / 2;
mLastMagnifierPosition = new Point((int)mCurrentPoint.X, (int)mCurrentPoint.Y);
}
Refresh();
}
protected override void OnMouseDown(MouseEventArgs e)
{
mOffset = new Point(Width / 2 - e.X, Height / 2 - e.Y);
mCurrentPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
mTargetPoint = mCurrentPoint;
mTimer.Enabled = true;
}
protected override void OnMouseUp(MouseEventArgs e)
{
if (mConfiguration.CloseOnMouseUp)
{
Close();
mScreenImage.Dispose();
}
Cursor.Show();
Cursor.Position = mStartPoint;
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mTargetPoint = PointToScreen(new Point(e.X + mOffset.X, e.Y + mOffset.Y));
mTimer.Enabled = true;
}
}
protected override void OnPaintBackground(PaintEventArgs e)
{
if (mConfiguration.DoubleBuffered)
{
// Do not paint background (required for double buffering)!
}
else
{
base.OnPaintBackground(e);
}
}
protected override void OnPaint(PaintEventArgs e)
{
if (mBufferImage == null)
{
mBufferImage = new Bitmap(Width, Height);
}
Graphics bufferGrf = Graphics.FromImage(mBufferImage);
Graphics g;
if (mConfiguration.DoubleBuffered)
{
g = bufferGrf;
}
else
{
g = e.Graphics;
}
if (mScreenImage != null)
{
Rectangle dest = new Rectangle(0, 0, Width, Height);
int w = (int)(Width / mConfiguration.ZoomFactor);
int h = (int)(Height / mConfiguration.ZoomFactor);
int x = Left - w / 2 + Width / 2;
int y = Top - h / 2 + Height / 2;
g.DrawImage(
mScreenImage,
dest,
x, y,
w, h,
GraphicsUnit.Pixel);
}
if (mImageMagnifier != null)
{
g.DrawImage(mImageMagnifier, 0, 0, Width, Height);
}
if (mConfiguration.DoubleBuffered)
{
e.Graphics.DrawImage(mBufferImage, 0, 0, Width, Height);
}
}
//--- Data Members ---
#region Data Members
private Timer mTimer;
private Configuration mConfiguration;
private Image mImageMagnifier;
private Image mBufferImage = null;
private Image mScreenImage = null;
private Point mStartPoint;
private PointF mTargetPoint;
private PointF mCurrentPoint;
private Point mOffset;
private bool mFirstTime = true;
private static Point mLastMagnifierPosition = Cursor.Position;
#endregion
}
}
The first time the new Form the magnifier is shown up where my mouse cursour is.
The next time i click on it's showing the magnifier form in the center of Form1 and not where the mouse cursour is.
Why is that ? When i clikc on the icon again it's still doing the
System.Windows.Forms.Cursor.Position
Again. Strange.
Consider you have two forms - Master and Child
If you are calling Child from Master on MouseUp event(for example), write the code in MouseUp event of Master form
ChildForm obj=new ChildForm();
obj.pntLocation = new Point(Cursor.Position.X, Cursor.Position.Y);
obj.ShowDialog();
Declare a variable inside the Child for location
public Point pntLocation;
Now set location inside the Form_Load of Child
this.Location = pntLocation;
Ok found that the part that doing it is here in the Magnifier form:
mConfiguration.RememberLastPoint = false;
if (mConfiguration.RememberLastPoint)
{
mCurrentPoint = mLastMagnifierPosition;
Cursor.Position = mLastMagnifierPosition;
Left = (int)mCurrentPoint.X - Width / 2;
Top = (int)mCurrentPoint.Y - Height / 2;
}
else
{
mCurrentPoint = Cursor.Position;
}
So I added for now the line: mConfiguration.RememberLastPoint = false; which did the job for now.