My question is very simple.
My Label1 should move continuously from left to right.
(Start from the left part of the form and go to the right part of the form. When it reaches the right part of the Form, go to the left and so on.) I have 2 timers(one for right and one for left)
I have the following code, it starts at the left and goes to the right, but when it reaches the right of the Form, it doesn't return.
Can anyone help me?
enum Position
{
Left,Right
}
System.Windows.Forms.Timer timerfirst = new System.Windows.Forms.Timer();
private int _x;
private int _y;
private Position _objPosition;
public Form1()
{
InitializeComponent();
if (label1.Location == new Point(0,180))
{
_objPosition = Position.Right;
}
if (label1.Location == new Point(690,0))
{
_objPosition = Position.Left;
}
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
Label1.SetBounds(_x, _y, 0, 180);
}
private void tmrMoving_Tick(object sender, EventArgs e)
{
tmrMoving.Start();
if (_objPosition == Position.Right && _x < 710)
{
_x +=10;
}
if(_x == 710)
{
tmrMoving.Stop();
}
Invalidate();
}
private void tmrMoving2_Tick(object sender, EventArgs e)
{
tmrMoving2.Start();
if (_objPosition == Position.Right && _x > 690)
{
_x -= 10;
}
if(_x == 1)
{
tmrMoving2.Stop();
}
Invalidate();
}
Thanks.
I think you've overcomplicated things. Let's just have one timer, a step number of pixels that we sometimes flip negative, and some time later flip back to positive. We can move the label by repeatedly setting its Left:
public partial class Form1 : Form
{
private int _step = 10;
public Form1()
{
InitializeComponent();
}
private void timer1_Tick(object sender, EventArgs e)
{
if (label1.Right > this.Width) _step = -10;
if (label1.Left < 0) _step = 10;
label1.Left += _step;
}
}
You might want to fine tune it, but the basic motion is there
Related
I have written a program that is supposed to connect 10 points generated by mouseclicks, with lines.
I am the following problems:
it draws all lines from the top left corner.
I can think of the solution being something along the lines of setting the first point as the first mouseclick, but i do not know how to do this.
code:
public partial class Form1 : Form
{
Point[] punten = new Point[10];
private int kliks = 0;
private int lijst = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
kliks = kliks + 1;
lijst = kliks;
punten[lijst] = e.Location;
if (lijst < 9)
{
punten[lijst] = e.Location;
}
else
{
Pen pen = new Pen(Color.Blue);
Graphics papier = this.CreateGraphics();
papier.DrawLines(pen, punten);
}
}
}
}
The problem for you is using a fixed-size array. Each entry defaults to a point (0,0) and so the Drawlines() method draws the 10 elements, even the ones not set by mouseclicks. This results in the final few points begin at the origin (0,0). In addition, there is a buggy implementation of which clicks to keep and how many have happened in using kliks and lijst for the same thing.
This being C#, it is better to learn how to separate your data model that keeps track of your mouselicks and your display codes that draws the lines.
PointHistory.cs
Consider the following class that uses an array of Point to keep track of the mouseclicks. The class is initialized with the maximum number of points to keep (here 10 for example). There are methods for adding a point AddPoint(point) and to remove the oldest point with RemoveFirstPoint(). The number of points defined is viewed with the .Count property.
Finally, the GetPoints() method, returns a copy of the array with only the elements that have been defined. This method is used in the code that draws the lines.
using System;
using System.Linq;
public class PointHistory
{
private readonly Point[] points;
private readonly int maxPoints;
private int count;
public PointHistory(int pointCapacity)
{
count = 0;
maxPoints = pointCapacity;
points = new Point[pointCapacity];
}
public Point[] GetPoints() { return points.Take(count).ToArray(); }
public int Count { get => count; }
public int Capacity { get => maxPoints; }
public void AddPoint(Point point)
{
if (count < maxPoints)
{
points[count++] = point;
}
}
public void RemoveFirstPoint()
{
if (count > 0)
{
for (int i = 0; i < count - 1; i++)
{
points[i] = points[i + 1];
}
count--;
}
}
}
Form1.cs
Another issue is your drawing, which needs to happen in Paint event handler. Use your MouseClick event to modify the list of points, and the Paint event to do the drawing.
public partial class Form1 : Form
{
readonly PointHistory history;
public Form1()
{
InitializeComponent();
history = new PointHistory(10);
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.MouseClick += Form1_MouseClick;
this.Paint += Form1_Paint;
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
history.AddPoint(e.Location);
}
else if (e.Button == MouseButtons.Right)
{
history.RemoveFirstPoint();
history.AddPoint(e.Location);
}
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
if (history.Count >= 2)
{
e.Graphics.DrawLines(Pens.Blue, history.GetPoints());
}
foreach (var point in history.GetPoints())
{
e.Graphics.FillEllipse(Brushes.Blue, point.X - 2, point.Y - 2, 4, 4);
}
}
}
I have added some extra code to add little dots at the mouse clicks for a better visual effect.
Left button clicks try to add points to the history of mouseclicks, up to the limit set in the constructor for PointHistory. The right mousebutton cicks removes the oldest point first before adding the new point.
Based on the comments, I want to present a version below that does not define a separate class for the logic, and everything is done internally withing the Form1 class. Also no advanced libraries such as Linq are used
public partial class Form1 : Form
{
private readonly Point[] points;
private int count;
public Form1()
{
InitializeComponent();
points = new Point[10];
count = 0;
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
this.Paint += Form1_Paint;
this.MouseClick += Form1_MouseClick;
}
public Point[] GetPoints()
{
Point[] results = new Point[count];
for (int i = 0; i < count; i++)
{
results[i] = points[i];
}
return results;
// Alternative to the loop above
//
//Array.Copy(points, results, count);
//return results;
}
public void AddPoint(Point point)
{
if (count < points.Length)
{
points[count++] = point;
}
}
public void RemoveFirstPoint()
{
if (count > 0)
{
for (int i = 0; i < count - 1; i++)
{
points[i] = points[i + 1];
}
count--;
}
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
AddPoint(e.Location);
}
else if (e.Button == MouseButtons.Right)
{
RemoveFirstPoint();
AddPoint(e.Location);
}
this.Invalidate();
}
private void Form1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
Point[] mouseClicks = GetPoints();
if (count >= 2)
{
e.Graphics.DrawLines(Pens.Blue, mouseClicks);
}
foreach (var point in mouseClicks)
{
e.Graphics.FillEllipse(Brushes.Blue, point.X - 2, point.Y - 2, 4, 4);
}
}
}
The main method to look at is GetPoints() which returns an array of points that have been defined by mouse clicks and ignores any points that have not been defined yet.
There is an alternate implementation commented with uses Array.Copy() instead of a loop which would make for a better imlpementation.
Purpose of this code was to move a title(label) first rightwards until it hits the 600th pixel on the X axis and then leftwards until it hits the 27th pixel on the X axis of the form by using 2 timer tools and the Point class. One timer for going right and the other timer for going left. They should've work by swithing on and off consecutively after one another, however it does not work.
The label is stuck at 600th X location and does not move back to where it was.
The timer interval is 100 so it moves with a decent speed that allows us to see it moving.
namespace AlanCevreHesabiUygulamasi
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
if (label11Point.X == 27)
{
timer2.Stop();
timer1.Start();
}
if (label11Point.X == 599)
{
timer1.Stop();
timer2.Start();
}
}
Point label11Point = new Point(27, 32);
private void timer1_Tick(object sender, EventArgs e)
{
while (label11Point.X <= 600)
{
label12.Text = label11Point.X.ToString();
label11Point.X += 1;
label11.Location = label11Point;
break;
}
}
private void timer2_Tick(object sender, EventArgs e)
{
while (label11Point.X >= 27)
{
label12.Text = label11Point.X.ToString();
label11Point.X -= 1;
label11.Location = label11Point;
break;
}
}
}
}
Label is stuck at 600th pixel of the form, does not move back. How to make it work?
I'm surprised you see movement resulting from a while loop in a timer tick handler. Why have a timer if your are going to do it that way.
In this solution, I have a timer, and the movements happen during a timer tick. I also have three possible directions, Right, Left and Stopped (in case you want to have a start/stop button).
In the Windows Forms designer, I dropped both a label and a timer on the form. I left their properties alone except for the timer's Interval property (that I set to 10 (ms))
Then I added an enum and an instance of the enum as a field to the Form class:
public partial class Form1 : Form
{
private enum Direction { MoveRight, MoveLeft, Stopped }
Direction _direction;
public Form1()
{
InitializeComponent();
}
}
I double-clicked the Caption area of the form in the designer to create a form Load handler, and added a call to start the timer:
private void Form1_Load(object sender, EventArgs e)
{
timer1.Start();
}
Finally, I double-clicked the timer to get a timer Tick handler and added some code:
private void timer1_Tick(object sender, EventArgs e)
{
var curLocation = label1.Location;
if (_direction == Direction.MoveRight && curLocation.X > 600)
{
_direction = Direction.MoveLeft;
}
else if (_direction == Direction.MoveLeft && curLocation.X < 27)
{
_direction = Direction.MoveRight;
}
int offset = _direction switch
{
Direction.MoveRight => 1,
Direction.MoveLeft => -1,
_ => 0,
};
curLocation.X += offset;
label1.Location = curLocation;
}
The _direction field determines if the label is moving to the right or the left.
How can you write the code without a timer?"
You asked "How can you write the code without a timer?" I'm still flabbergasted that your label moves as the result of a while loop in an event handler - something must have changed from my good-old understanding of Win32 processing.
Anyways, I cheat and await a call to Task.Delay instead of using a timer. Take my existing code and do the following:
Add two buttons to your form (One labeled Start (named StartBtn) and the other labeled Stop (named StopBtn).
Add another Direction-typed field to the class: Direction _previousDirection;
Comment out the call to timer1.Start(); in the Form1_Load handler
Comment out all the code in the timer1_Tick method (at this point, you could remove the timer from the form if you want)
Select both buttons (Start and Stop) and press <Enter>. This will bring up click handlers for both buttons.
Change the StopBtn button's handler to look like:
New Stop Button code:
private void StopBtn_Click(object sender, EventArgs e)
{
_previousDirection = _direction;
_direction = Direction.Stopped;
}
Change the StartBtn's handler to look like the following. Note that nearly everything in the while loop (except the call to Task.Delay) is the same as the previous timer tick handler code. Also note that I made the handler async void to allow for the await keyword to do it's magic.
Start Button code:
private async void StartBtn_Click(object sender, EventArgs e)
{
_direction = _previousDirection;
while (_direction != Direction.Stopped)
{
var curLocation = label1.Location;
if (_direction == Direction.MoveRight && curLocation.X > 600)
{
_direction = Direction.MoveLeft;
}
else if (_direction == Direction.MoveLeft && curLocation.X < 27)
{
_direction = Direction.MoveRight;
}
int offset = _direction switch
{
Direction.MoveRight => 1,
Direction.MoveLeft => -1,
_ => 0,
};
curLocation.X += offset;
label1.Location = curLocation;
await Task.Delay(10);
}
}
I solved it, I don't know why but in my opening post the Form1() function only makes one of the if() conditions work. However, putting the if() statements into the timers solved the problem. Now, the title goes back and forth in the specified x axis intervals.
namespace AlanCevreHesabiUygulamasi
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
timer1.Start();
}
Point label11Point = new Point(27, 32);
private void timer1_Tick(object sender, EventArgs e)
{
while (label11Point.X >= 27)
{
label12.Text = label11Point.X.ToString();
label11Point.X += 1;
label11.Location = label11Point;
break;
}
if (label11Point.X == 600)
{
timer2.Start();
timer1.Stop();
}
}
private void timer2_Tick(object sender, EventArgs e)
{
while (label11Point.X <= 600)
{
label12.Text = label11Point.X.ToString();
label11Point.X -= 1;
label11.Location = label11Point;
break;
}
if (label11Point.X == 27)
{
timer1.Start();
timer2.Stop();
}
}
I want to make an AI using PictureBox that can roam randomly without messing its movements like for example:
PictureBox must execute the movement to go Right, if the Timer runs out it the next movement is going Down, like just how random it would roam.
I'd thought I might figured it out to Hard code it. However might took long, also once the Timer Stops, it won't Restart again. idk why.
Here's a Picture of my Game so you would have some ideas about it.
Here's the code also
private void Game_Load(object sender, EventArgs e)
{
E_Right.Start();
if(Upcount == 0)
{
E_Right.Start();
}
}
private void E_Right_Tick(object sender, EventArgs e)
{
if(Rightcount > 0)
{
EnemyTank.Left += 5;
EnemyTank.BackgroundImage = Properties.Resources.EnemyTank_RIGHT_v_2;
Rightcount = Rightcount - 1;
}
if (Rightcount == 0)
{
E_Right.Stop();
E_Down.Start();
}
}
private void E_Up_Tick(object sender, EventArgs e)
{
if (Upcount > 0)
{
EnemyTank.Top -= 5;
EnemyTank.BackgroundImage = Properties.Resources.EnemyTank_TOP_v_1;
Upcount = Upcount - 1;
}
if (Upcount == 0)
{
E_Up.Stop();
E_Right.Start();
}
}
private void E_Down_Tick(object sender, EventArgs e)
{
if (Downcount > 0)
{
EnemyTank.Top += 5;
EnemyTank.BackgroundImage = Properties.Resources.EnemyTank_DOWN_v_1;
Downcount = Downcount - 1;
}
if (Downcount == 0)
{
E_Down.Stop();
E_Left.Start();
}
}
private void E_Left_Tick(object sender, EventArgs e)
{
if (Leftcount > 0)
{
EnemyTank.Left -= 5;
EnemyTank.BackgroundImage = Properties.Resources.EnemyTank_LEFT_v_1;
Leftcount = Leftcount - 1;
}
if (Leftcount == 0)
{
E_Left.Stop();
E_Up.Start();
}
}
Well just assume that the PictureBox is in Location(0,0). If you see a PictureBox an image of a Tank nevermind that. That goes for the MainTank of the user will be using.
You could do it with just one timer:
int moveTo = 0; // Move while this is not 0
int speed = 3;
Random rand = new Random();
// Keep track of whether the tank is moving up/down or left/right
enum MoveOrientation { Vertical, Horizontal };
MoveOrientation orientation = MoveOrientation.Vertical;
void ChooseNextPosition()
{
// Negative numbers move left or down
// Positive move right or up
do {
moveTo = rand.Next(-5, 5);
} while (moveTo == 0); // Avoid 0
}
private void Game_Load(object sender, EventArgs e) {
ChooseNextPosition();
timer1.Start();
}
private void timer1Tick(object sender, EventArgs e) {
if (orientation == MoveOrientation.Horizontal)
{
EnemyTank.Left += moveTo * speed;
}
else
{
EnemyTank.Top += moveTo * speed;
}
moveTo -= moveTo < 0 ? -1 : 1;
if (moveTo == 0)
{
// Switch orientation.
// If currently moving horizontal, next move is vertical
// And vice versa
orientation = orientation == MoveOrientation.Horizontal ? MoveOrientation.Vertical : MoveOrientation.Horizontal;
// Get new target
ChooseNextPosition();
}
}
So here is the basic code:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
protected Random random;
public Form1()
{
InitializeComponent();
random = new Random();
}
private void Form1_Load(object sender, EventArgs e)
{ }
private void button1_Click(object sender, EventArgs e)
{
bool button1Clicked = true;
if (button1Clicked == true) { ITIpanel.Visible = true; }
}
private void ITIpanel_Paint(object sender, PaintEventArgs e)
{
ITItimer.Enabled = true;
}
private void ITItimer_Tick(object sender, EventArgs e)
{
double rand = random.NextDouble();
if (rand < .50d) { bluestimPanel.Visible = true; }
else if (rand > .5d) { redstimPanel.Visible = true; }
ITItimer.Enabled = false;
}
private void bluestimPanel_Paint(object sender, PaintEventArgs e)
{
Trialtimer.Enabled = true;
}
private void redstimPanel_Paint(object sender, PaintEventArgs e)
{
Trialtimer.Enabled = true;
}
private void Trialtimer_Tick(object sender, EventArgs e)
{
bluestimPanel.Visible = false;
redstimPanel.Visible = false;
Trialtimer.Enabled = false;
ITIpanel.Visible = true;
}
}
}
As you can see, the program itself is fairly straight forward. At the tick of the ITItimer the red or blue panels occurs at random. I want to modify this such that if the ITItimer ticks a total of 10 times, the red and blue panels will both have occurred 5 times each.
I have been researching this for a week or so and have yet to find a solution. Any ideas on how I could best accomplish this?
I actually got the following to work:
double rand = random.NextDouble();
if (rand < .50d && blue < 5) { bluestimPanel.Visible = true; }
else if (blue == 5) { redstimPanel.Visible = true; }
if (rand > .5d && red < 5) { redstimPanel.Visible = true; }
else if (red == 5) { bluestimPanel.Visible = true; }
if (red >= 5 && blue >= 5) { panel1.Visible = true; }
It isn't exactly the prettiest thing in the world. But it gets the job done.
Random numbers using most normal library routines are a low-quality source of pseudorandomness. If this is for a randomized scientific study, this will be a flaw in your protocol design.
The approach that I would recommend would be to consider this a method of randomly arranging a session of at least N trials, where there are X trial types.
The below is pseudocode for illustration of the concept.
Let MinimumTrials be N MOD X + X
Let SessionList be a List<Trial>
For Each TrialType
add X instances of that trial type to SessionList
Shuffle(SessionList)
Then your session engine can call the individual Trials as it walks through the SessionList to have an even distribution of possible trial orders. Note that Shuffle is an operation which requires a certain degree of finesse to get right, searching on SO is a good starting point for that.
I want to load an small image into a WinForms pictureBox control and then animate it moving to the other side of the form.
I've loaded image and used a timer to move the image, but when I run it the application just shows the final position of the pictureBox and its image.
How I can show image smoothly transition to the final location?
Here is my code so far:
public partial class Form1 : Form
{
private int counter = 0;
void timer_Tick(object sender, EventArgs e)
{
counter++;
if (counter == 1)
{
pictureBox1.Show();
timer1.Stop();
counter = 0;
}
}
public Form1()
{
InitializeComponent();
timer1.Interval = 10;
timer1.Tick += new EventHandler(timer_Tick);
}
private void button1_Click(object sender, EventArgs e)
{
while(i<=100){
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
pictureBox1.Location = new Point(x+25, y);
timer1.Start();
}
}
}
Does this work? Sorry, I can't test it where I am right now (on netbook without VS).
public partial class Form1 : Form
{
void timer_Tick(object sender, EventArgs e)
{
int x = pictureBox1.Location.X;
int y = pictureBox1.Location.Y;
pictureBox1.Location = new Point(x+25, y);
if (x > this.Width)
timer1.Stop();
}
public Form1()
{
InitializeComponent();
timer1.Interval = 10;
timer1.Tick += new EventHandler(timer_Tick);
}
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Show();
timer1.Start();
}
}