At the moment my code takes about 10% of my CPUs power. How can I make it more efficient and less flickerish?
Code:
private void timer1_Tick(object sender, EventArgs e)
{
DrawLocal();
Thread.Sleep(17);
pictureBox1.Invalidate();
}
private void DrawLocal()
{
int localReadX = ReadAddress("hl2", "client.dll+0xBFFF00 364 0");
int localReadY = ReadAddress("hl2", "client.dll+0xBFFF00 368 0");
byte[] bytesOflocalX = BitConverter.GetBytes(localReadX);//converts to float
byte[] bytesOflocalY = BitConverter.GetBytes(localReadY);//converts to float
float localX = BitConverter.ToSingle(bytesOflocalX, 0)/10;//converts to float
float localY = BitConverter.ToSingle(bytesOflocalY, 0)/10;//converts to float
Graphics localP = pictureBox1.CreateGraphics();
localP.FillRectangle(new SolidBrush(Color.Red), localX, localY, 5, 5);
Graphics localName = pictureBox1.CreateGraphics();
localName.DrawString(" local", new Font("Arial", 7), new SolidBrush(Color.Red), localX, localY);
}
The comments above, demonstrated below:
private Font f = new Font("Arial", 7);
public Form1()
{
InitializeComponent();
pictureBox1.Paint += pictureBox1_Paint;
}
private void timer1_Tick(object sender, EventArgs e)
{
pictureBox1.Invalidate();
}
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
int localReadX = ReadAddress("hl2", "client.dll+0xBFFF00 364 0");
int localReadY = ReadAddress("hl2", "client.dll+0xBFFF00 368 0");
byte[] bytesOflocalX = BitConverter.GetBytes(localReadX);//converts to float
byte[] bytesOflocalY = BitConverter.GetBytes(localReadY);//converts to float
float localX = BitConverter.ToSingle(bytesOflocalX, 0) / 10;//converts to float
float localY = BitConverter.ToSingle(bytesOflocalY, 0) / 10;//converts to float
e.Graphics.FillRectangle(Brushes.Red, localX, localY, 5, 5);
e.Graphics.DrawString(" local", f, Brushes.Red, localX, localY);
}
Related
I draw a figures on a windows form, not on picturebox. And I would like to save view of my windows form to special folder on desktop. I dont know if better will be make a screenshot or i should try to save it as an image (bitmap) in my folder.
Generally I tried both options but it doesnt work :(
I put here one of my attempt ...
public void Form1_Paint(object sender, PaintEventArgs e)
{
int x1, y1, x2, y2;
Random losowa1 = new Random();
x1 = losowa1.Next(0, 200);
y1 = losowa1.Next(120, 300);
x2 = losowa1.Next(300, 480);
y2 = losowa1.Next(120,300);
e.Graphics.FillRectangle(Brushes.Black, x1, y1, 100, 100);
e.Graphics.FillEllipse(Brushes.Black, x2, y2, 100, 100);
Bitmap bitmap = new Bitmap(this.Width, this.Height);
DrawToBitmap(bitmap, new Rectangle(0, 0, bitmap.Width, bitmap.Height));
bitmap.Save("#C:\\Desktop", ImageFormat.Jpeg);
// MessageBox.Show("saved");
System.Threading.Thread.Sleep(1000);
this.Close();
}
and
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i < 3; i++)
{
Form1 OknoStart = new Form1();
OknoStart.ShowDialog();
}
try this
int i;
public Form1(int i)
{
InitializeComponent();
this.i = i;
}
private void Form1_Load(object sender, EventArgs e)
{
using (Bitmap bmp = new Bitmap(this.Width, this.Height))
{
this.DrawToBitmap(bmp, new Rectangle(Point.Empty, bmp.Size));
bmp.Save(#"C:\Users\User\Desktop\sample" + i+".png", ImageFormat.Png);
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
int x1, y1, x2, y2;
Random losowa1 = new Random();
x1 = losowa1.Next(0, 200);
Random losowa2 = new Random();
y1 = losowa2.Next(0, 480);
Random losowa3 = new Random();
x2 = losowa1.Next(300, 500);
Random losowa4 = new Random();
y2 = losowa2.Next(0, 480);
e.Graphics.FillRectangle(Brushes.Black, x1, y1, 100, 100);
e.Graphics.FillEllipse(Brushes.Black, x2, y2, 100, 100);
System.Threading.Thread.Sleep(2000);
this.Close();
}
private void button1_Click(object sender, EventArgs e)
{
for (int i=0;i<3;i++) {
Form1 form1 = new Form1(i);
form1.ShowDialog();
}
}
I am using visual studio c# windows form, I need help to draw a circle using the Mouse click.. first click will give me the center of the circle equal to the cursor position and the second click will give me a point on the border of the circle equal to the second position of the cursor, the distance between the to points will give me the radius..now I have radius and point ..I can draw a circle ..The code doesn't work because I only can get one position of the cursor no matter how many times I click the mouse
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
int lastX = Cursor.Position.X;//the first click x cursor position
int lastY = Cursor.Position.Y;//the first click y cursor position,
//is there any way to reuse the Cursor.Position for different point ??
int x = Cursor.Position.X;//the second click x cursor position
int y = Cursor.Position.Y;//the second click y cursor position
Graphics g;
double oradius=Math.Sqrt(((lastX-x)^2) +((lastY-y)^2));
//double newy = Math.Sqrt(lastY);
// int newxv = Convert.ToInt32(newx);
int radius= Convert.ToInt32(oradius);
g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, x, y,radius,radius);
}
private void DrawCircle(PaintEventArgs e, int x, int y, int width, int height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
e.Graphics.DrawEllipse(pen, x - width / 2, y - height / 2, width, height);
}
}
You need to store the first click as well before you start doing the calculations. One way to do this is to create a class that simply throws an event every second time you pass it x and y coordinates like this:
public class CircleDrawer
{
private int _firstX;
private int _firstY;
private int _secondX;
private int _secondY;
private bool _isSecondClick;
private event EventHandler OnSecondClick;
public void RegisterClick(int x, int y)
{
if(_isSecondClick)
{
_secondX = x;
_secondY = y;
if(OnSecondClick != null)
OnSecondClick(this, null);
}
else
{
_firstX = x;
_firstY = y;
_isSecondClick = true;
}
}
}
You can then in your code simply call your methods:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
int lastX = Cursor.Position.X;//the first click x cursor position
int lastY = Cursor.Position.Y;//the first click y cursor position,
_circleDrawer.RegisterClick(lastX, lastY);
}
And in your constuctor:
public MyForm()
{
_circleDrawer = new CircleDrawer();
_circleDrawer.OnSecondClick += DrawCircle();
}
public void DrawCircle()
{
// Your drawing code
}
Your lastX and lastY are local variables, and you initialize them in the beginning of the MouseDown event handler. They should be class level variables and should be populated at the end of the MouseDown event handler.
Also, you should test if they already have a value, and only if they have value then draw the circle and then clear them (so that the next circle will have it's own center).
Here is an improvement of your code. Note I've used the using keyword with the graphics object and with the pen - get used to use it every time you are using an instance of anything that's implementing the IDisposable interface.
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (_lastPosition != Point.Empty)
{
var currentPosition = Cursor.Position;
var oradius = Math.Sqrt(((_lastPosition.X - currentPosition.X) ^ 2) + ((_lastPosition.Y - currentPosition.Y) ^ 2));
var radius = Convert.ToInt32(oradius);
using (var g = this.CreateGraphics())
{
var arg = new PaintEventArgs(g, new Rectangle());
DrawCircle(arg, currentPosition, radius, radius);
}
_lastPosition = Point.Empty;
}
else
{
_lastPosition = Cursor.Position;
}
}
private void DrawCircle(PaintEventArgs e, Point position, int width, int height)
{
using (var pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3))
{
e.Graphics.DrawEllipse(pen, position.X - width / 2, position.Y - height / 2, width, height);
}
}
Note: This code can be improved even further.
There are many things fundamentally wrong with this code, here is a complete, working example.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private Point clickCurrent = Point.Empty;
private Point clickPrev = Point.Empty;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
clickPrev = clickCurrent;
clickCurrent = this.PointToClient(Cursor.Position);
if (clickPrev == Point.Empty) return;
Graphics g;
double oradius = Math.Sqrt((Math.Pow(clickPrev.X - clickCurrent.X, 2)) + (Math.Pow(clickPrev.Y - clickCurrent.Y, 2)));
int radius = Convert.ToInt32(oradius);
g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, clickPrev.X, clickPrev.Y, radius * 2, radius * 2);
clickCurrent = Point.Empty;
}
private void DrawCircle(PaintEventArgs e, int x, int y, int width, int height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
e.Graphics.DrawEllipse(pen, x - width / 2, y - height / 2, width, height);
}
}
private int _firstX;
private int _firstY;
private int _secondX;
private int _secondY;
private bool _isSecondClick;
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
if (_isSecondClick)
{
_secondX = Cursor.Position.X;
_secondY = Cursor.Position.Y;
var radious1 = Math.Pow(_firstX - _secondX, 2);
var radious2 = Math.Pow(_firstY - _secondY, 2);
var radious = Math.Sqrt(radious1 + radious2);
Graphics g = this.CreateGraphics();
Rectangle rectangle = new Rectangle();
PaintEventArgs arg = new PaintEventArgs(g, rectangle);
DrawCircle(arg, _secondX, _secondY, radious, radious);
}
else
{
_firstX = Cursor.Position.X;
_firstY = Cursor.Position.Y;
_isSecondClick = true;
}
}
private void DrawCircle(PaintEventArgs arg, int x, int y, double width, double height)
{
System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
var xL = Convert.ToInt32(x - width / 2);
var yL = Convert.ToInt32(y - height / 2);
var hL = Convert.ToInt32(height);
var wL = Convert.ToInt32(width);
arg.Graphics.DrawEllipse(pen, xL, yL, wL, hL);
}
Please help me with this problem :(
This is what i'm trying to do:
Because QuickFont use different coordinate system with my ortho so i have to calculate coordinate for my text and it's ok.
The problem is when i resized the form, the text's coordiantes become wrong.
Here is my code:
public static void DrawOxy(float lO, float rO, float tO, float bO, int controlW, int controlH)
{
GL.Color3(Color.Blue);
GL.Begin(BeginMode.Lines);
GL.Vertex2(lO, 0);
GL.Vertex2(rO, 0);
GL.Vertex2(0, tO);
GL.Vertex2(0, bO);
for (float i = lO; i < rO; i+=2)
{
GL.Vertex2(i, 0.5);
GL.Vertex2(i, -0.5);
}
for (float j = bO; j < tO; j+=2)
{
GL.Vertex2(0.2, j);
GL.Vertex2(-0.2, j);
}
GL.End();
QFont font = new QFont(new Font(FontFamily.GenericSansSerif, 15));
GL.PushAttrib(AttribMask.ColorBufferBit);
font.Options.Colour = Color.Red;
QFont.Begin();
float horStep = ((float)controlW / rO);
font.Print(horStep.ToString(), new Vector2(0, 0));
float beginX = 0;
for (float i = lO; i < rO; i += 2)
{
font.Print(i.ToString(), new Vector2(beginX, (((float)controlH / 2))));
beginX += horStep;
}
QFont.End();
GL.PopAttrib();
}
private void SetupViewport()
{
int w = glControl1.Width;
int h = glControl1.Height;
int left = -(w / 2);
int right = w / 2;
int top = h / 2;
int bottom = -(h / 2);
GL.MatrixMode(MatrixMode.Projection);
GL.LoadIdentity();
GL.Ortho(leftOr, rightOr, bottomOr, topOr, -1, 1); // Bottom-left corner pixel has coordinate (0, 0)
GL.Viewport(0, 0, w, h); // Use all of the glControl painting area
}
private void glControl1_Load(object sender, EventArgs e)
{
loaded = true;
GL.ClearColor(Color.White);
SetupViewport();
}
private void glControl1_Paint(object sender, PaintEventArgs e)
{
if (!loaded) // Play nice
return;
GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
GL.LineWidth(2);
DrawingObjects.DrawOxy(leftOr, rightOr, topOr, bottomOr, glControl1.Width, glControl1.Height);
glControl1.SwapBuffers();
}
private void glControl1_Resize(object sender, EventArgs e)
{
if (!loaded)
{
return;
}
SetupViewport();
}
Sorry about my english :)
You need to recreate the projection matrix. Based on your code above, this should do it:
protected override void OnResize(EventArgs e)
{
base.OnResize(e);
SetupViewport();
}
I have a card that has10cm height and 15cm width. I am trying to print a string on the following coordinates: 1,5cm from top to bottom and 3,5cm from the left to right. Until now i tried to use the bellow code that i found on msdn but with no luck. The code that i am using is :
System.IO.StreamReader fileToPrint;
System.Drawing.Font printFont;
private void printButton_Click(object sender, EventArgs e)
{
string printPath = System.Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
fileToPrint = new System.IO.StreamReader(printPath + #"\myFile.txt");
printFont = new System.Drawing.Font("Arial", 10);
printDocument1.Print();
fileToPrint.Close();
}
private void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
{
float yPos = 0f;
int count = 0;
float leftMargin = e.MarginBounds.Left;
float topMargin = e.MarginBounds.Top;
string line = null;
float linesPerPage = e.MarginBounds.Height/printFont.GetHeight(e.Graphics);
while (count < linesPerPage)
{
line = fileToPrint.ReadLine();
if (line == null)
{
break;
}
yPos = topMargin + count * printFont.GetHeight(e.Graphics);
e.Graphics.DrawString(line, printFont, Brushes.Black, leftMargin, yPos, new StringFormat());
count++;
}
if (line != null)
{
e.HasMorePages = true;
}
}
I need to implement a simple animation of a ball moving in uniform circular motion. I've tried several formulas and the following version seems the best so far.However, there are still 2 issues and I really can't figure out what's wrong.
First, a couple of seconds right after the program starts, the ball moves erratically. I think that the values for theta (the angle in radians) are not computed correctly, but I don't know why.
Secondly, the movement becomes more uniform after a while, but it seems to decrease over time.
The value for 'speed' indicates the number of seconds it takes to do a full revolution.
What I want is an uniform, correct circular movement (according to the value of speed) and without the jerkiness in the beginning.
My code so far:
public partial class ServerForm : Form
{
Stopwatch watch;
//Angular velocity
float angularVelocity;
//Angle
float theta = 20;
//Speed - time to complete a full revolution, in seconds
private float speed = 3;
//Circle center
private int centerX = 250;
private int centerY = 200;
//Circle radius
private float R = 120;
//Current position
private LocationData currentLocation;
public ServerForm()
{
InitializeComponent();
}
public void UpdateUI()
{
currentLocation.CoordX = (float)(centerX + Math.Cos(theta) * R);
currentLocation.CoordY = (float)(centerY + Math.Sin(theta) * R);
currentLocation.Speed = speed;
try
{
this.Invoke(new Action(() => { this.Invalidate(); }));
}
catch (Exception ex)
{
watch.Stop();
Application.Exit();
}
theta += (float)((angularVelocity * 1000 / watch.ElapsedMilliseconds));
//Console.Out.WriteLine("elapsed miliseconds: " + watch.ElapsedMilliseconds + " theta = " + theta);
}
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
Brush color = new SolidBrush(Color.BlueViolet);
g.FillEllipse(color, currentLocation.CoordX, currentLocation.CoordY, 30, 30);
//Draw circle & center
g.DrawEllipse(new Pen(color), centerX, centerY, 5, 5);
float x = centerX - R;
float y = centerY - R;
float width = 2 * R;
float height = 2 * R;
g.DrawEllipse(new Pen(color), x, y, width, height);
base.OnPaint(e);
}
private void button1_Click(object sender, EventArgs e)
{
if (!String.IsNullOrEmpty(textSpeed.Text))
{
ResetValues(float.Parse(textSpeed.Text));
}
}
private void ResetValues(float newSpeed)
{
speed = newSpeed;
angularVelocity = (float)(2 * Math.PI / speed); // radians / sec
//Start at the top
currentLocation.CoordX = centerX;
currentLocation.CoordY = centerY - R;
theta = 90;
watch.Restart();
}
private void ServerForm_Load(object sender, EventArgs e)
{
watch = new Stopwatch();
timer1.Enabled = true;
timer1.Interval = 100;
timer1.Tick += timer1_Tick;
currentLocation = new LocationData();
ResetValues(speed);
}
void timer1_Tick(object sender, EventArgs e)
{
UpdateUI();
}
}
LocationData is just a class holding the coordinates & current speed.
Are the units for time & angular velocity (and the transformations to use miliseconds) correct?
I changed BackgroundWorker to Timer, but I still get that erratic motion and the movement slows down after a while.
Try using a System.Windows.Forms.Timer instead of a BackgroundWorker. I believe you'll get more consistent results. This is definitely not a good case for using a BackgroundWorker.
Here's a more-or-less complete solution. Note that I'm scaling the swing radius and the ball radius by the size of the Form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
SetStyle(ControlStyles.Opaque, true);
SetStyle(ControlStyles.ResizeRedraw, true);
SetStyle(ControlStyles.DoubleBuffer, true);
SetStyle(ControlStyles.UserPaint, true);
}
private void Form1_Load(object sender, System.EventArgs e)
{
_stopwatch.Start();
}
private void Timer1_Tick(object sender, System.EventArgs e)
{
Invalidate();
}
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(BackColor);
const float rotationTime = 2000f;
var elapsedTime = (float) _stopwatch.ElapsedMilliseconds;
var swingRadius = Math.Min(ClientSize.Width, ClientSize.Height) / 4f;
var theta = Math.PI * 2f * elapsedTime / rotationTime;
var ballRadius = Math.Min(ClientSize.Width, ClientSize.Height) / 10f;
var ballCenterX = (float) ((ClientSize.Width / 2f) + (swingRadius * Math.Cos(theta)));
var ballCenterY = (float) ((ClientSize.Height / 2f) + (swingRadius * Math.Sin(theta)));
var ballLeft = ballCenterX - ballRadius;
var ballTop = ballCenterY - ballRadius;
var ballWidth = ballRadius * 2f;
var ballHeight = ballRadius * 2f;
e.Graphics.FillEllipse(Brushes.Red, ballLeft, ballTop, ballWidth, ballHeight);
e.Graphics.DrawEllipse(Pens.Black, ballLeft, ballTop, ballWidth, ballHeight);
}
private readonly Stopwatch _stopwatch = new Stopwatch();
}