Can someone help about create a winform animation like in Win7 Calculator when you hover mouse over button, currently i use bunch of image then looping it in backgroundworker, but i think its wrong, this is my code:
this occur when mouse enter,
private void bgTurnOn_DoWork(object sender, DoWorkEventArgs e)
{
Label labelSender = (Label)e.Argument;
int ii = labelSender.ImageIndex;
for (int i = ii + 4; i <= 11; i++)
{
if (labelSender.AllowDrop)
{
labelSender.ImageIndex = i;
Thread.Sleep(40);
}
}
}
and this when mouse leave
private void bgTurnOff_DoWork(object sender, DoWorkEventArgs e)
{
Label labelSender = (Label)e.Argument;
int ii = labelSender.ImageIndex;
for (int i = ii; i >= 0; i--)
{
if (!labelSender.AllowDrop)
{
labelSender.ImageIndex = i;
Thread.Sleep(80);
}
}
}
note: I just use AllowDrop so I do not bother to declare new variable, i have 42 button, so i think i need more efficient solution.
It seems that you want a glow effect, so you can use the next idea:
Make an OpacityPictureBox : PictureBox which supports opacity (in levels of 1-100 or double 0-1). See this for more information.
Add two public const int values of MaxOpacity and MinOpacity to the OpacityPictureBox class, for easy and safe range checks from the outside. The values might be 0, 100 or 0, 1, or something else, depending on your implementation of opacity.
Make an AnimatedPictureBox : UserControl which holds 1 PictureBox named pbNormal and 1 OpacityPictureBox named opbHover, both Dock = DockStyle.Fill, and one timer named timer. Make sure that pbNormal is below opbHover.
Have three public properties:
Normal of type Image which delegates into pbNormal.Image
Hover of type Image which delegates into opbHover.Image
AnimationInterval of type int which delgates into timer.Interval
In the constructor of the AnimatedPictureBox, after calling InitializeComponents, do opbHover.Opacity = 0;. You can also do this.Cursor = Cursors.Hand; if you want the cursor to change into a hand when hovering over it.
Have a private members: _animationDirection of type int, which will be -1 or 1.
Have a private method that starts an animation in a given direction:
Code:
private void Animate(int animationDirection)
{
this._animationDirection = animationDirection;
this.timer.Start();
}
Override OnMouseEnter and OnMouseLeave:
Code:
protected override void OnMouseEnter(EventArgs e)
{
this.Animate(1);
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
this.Animate(-1);
base.OnMouseEnter(e);
}
Listen to timer.Tick event and with this:
Code:
private void timer_Tick(object sender, EventArgs e)
{
var hoverOpacity = this.opbHover.Opacity + this._animationDirection;
if (hoverOpacity < OpacityPictureBox.MinOpacity ||
hoverOpacity > OpacityPictureBox.MaxOpacity)
{
this.timer.Stop();
return;
}
this.opbHover.Opacity = hoverOpacity;
}
Related
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 create a subclass datagridview to override the mousewheel event to catch mouse scroll then send key UP or DOWN. i create a datatable to be bind as datasource for mydatagridview by button click
private void button1_Click(object sender, EventArgs e)
{
DataTable myDataTable = new DataTable();
int NUM_ROWS = 150;
int NUM_COLS_TO_CREATE = 10;
for (int i = 0; i < NUM_COLS_TO_CREATE; i++)
{
myDataTable.Columns.Add("x" + i, typeof(string));
}
for (int i = 0; i < NUM_ROWS; i++)
{
var theRow = myDataTable.NewRow();
for (int j = 0; j < NUM_COLS_TO_CREATE; j++)
{
theRow[j] = "whatever";
}
//add the row *after* populating it
myDataTable.Rows.Add(theRow);
}
MyDataGridView1.DataSource = myDataTable;
}
the code that override the mousewheel event as this
public partial class MyDataGridView : DataGridView
{
protected override void OnMouseWheel(MouseEventArgs e)
{
if (e.Delta < 0)
SendKeys.Send("{DOWN}");
else
SendKeys.Send("{UP}");
}
}
Its working fine if we use mouse wheel to scroll each item in a SLOW way, but if you scroll too FAST using the mouse wheel, somewhat the datagridview becomes lagging.
As example from row 1 to 5, it will jump the row from 1 to 3,then 3 to 5 something like that, here come another weird issue. i use "Navicat" a lot in my daily basis..
so if i open both my application and Navicat. the mouse wheel scrolling now become very smooth on my application even if i scroll too fast. but then if i close Navicat then scrolling become lagging again. what was causing this? i am very sorry if i cant explained it well, all i want is just want to makes the scrolling each item smooth. Any suggestion?
as #Bozhidar mentioned that i should better handling the MouseWheel event instead or overriding it. so i've come up with the solution just in case anyone need it too.
in Form_Load add
MyDataGridView1.MouseWheel += new MouseEventHandler(MyDataGridView1_MouseWheel);
then place this anywhere inside your class
private void MyDataGridView1_MouseWheel(object sender, MouseEventArgs e)
{
HandledMouseEventArgs hme = (HandledMouseEventArgs)e;
hme.Handled = true;
int rowIndex = MyDataGridView1.CurrentCell.RowIndex;
int cellIndex = MyDataGridView1.CurrentCell.ColumnIndex;
MyDataGridView1.CurrentCell = MyDataGridView1.Rows[e.Delta < 0 ? Math.Min(rowIndex + 1, MyDataGridView1.RowCount - 1) : Math.Max(rowIndex - 1, 0)].Cells[cellIndex];
}
The SendKeys method is not as reliable when it comes to precise timing - see the official documentation. Try setting the "SendKeys" app setting to "SendInput" in order to force the new behavior.
But you'd be better off handling the MouseWheel event instead of overriding it. You need to hook it by hand - not sure why it isn't present into the Property Window. Given your DataGridView is named dgv:
private void Form1_Load(object sender, EventArgs e)
{
dgv.MouseWheel += Dgv_MouseWheel;
}
Next, have you considered FirstDisplayedScrollingRowIndex? Just set it as appropriate in the event, and set the Handled flag, like this:
private void dgv_MouseWheel(object sender, MouseEventArgs e)
{
dgv.FirstDisplayedScrollingRowIndex += 3;
var he = (HandledMouseEventArgs);
he.Handled = true;
}
Here's an approach that preserves the default scrolling behavior of scrolling the viewport, but not changing the row selection.
It also performs much faster than the built-in mouse wheel handler when millions of rows are being handled in a virtual grid:
private void Form1_Load(object sender, EventArgs e)
{
DataGridView1.MouseWheel += DataGridView1_MouseWheel;
}
private void DataGridView1_MouseWheel(object sender, MouseEventArgs e)
{
var hme = e as HandledMouseEventArgs;
hme.Handled = true;
int displayedRowIndex = DataGridView1.FirstDisplayedScrollingRowIndex;
// each "detente" scroll appears to create a delta of 120
// dividing delta by 120 to get the number of rows scrolled
// taking the negative of the delta so that it can be added to the displayedRowIndex intuitively as negative is down, positive is up
var rowDelta = -(e.Delta / 120);
var newDisplayedRowIndex = e.Delta < 0 ? Math.Min(displayedRowIndex + rowDelta, DataGridView1.RowCount - 1) : Math.Max(displayedRowIndex + rowDelta, 0);
DataGridView1.FirstDisplayedScrollingRowIndex = newDisplayedRowIndex;
}
Some quick context: in this project we're using a Visual C# Windows Form project to recreate Minesweeper.
I am using an array of Cells (which inherit from Control.Button).
As extra credit, I want the user to be able to flag a cell like you can in the class version of the game. However, I can't get right-clicking to work.
When trying to find a solution, I read that you need to typecast the EventArg as a MouseEventArg, but that didn't solve my problem as right-clicking doesn't even trigger my click event.
Here's some paraphrased code:
namespace Project_5___Minesweeper_GUI
{
public partial class Form1 : Form
{
public class Cell : Button { /*Custom Cell-Stuff Goes Here*/ }
Cell[,] board = new Cell[AXIS_LENGTH, AXIS_LENGTH]; //Axis Length is just the dimensions of the board (I use 10x10).
private void Form1_Load(object sender, EventArgs e)
{
for (int i = 0; i < AXIS_LENGTH; i++)
{
for (int j = 0; j < AXIS_LENGTH; j++)
{
board[i, j] = new Cell();
//Set position and size
board[i, j].MouseClick += button_arrayClick; //button_arrayClick() is never called by a right-click. Code for it is below. I suspect this line of code has to do with right-clicks not class button_arrayClick().
groupBox1.Controls.Add(board[i, j]); //I'm containing the array of Cells inside of a groupbox.
}
}
}
private void button_arrayClick(object sender, EventArgs e) //Is prepared for handling a right-click, but never receives them.
{
Cell temp = (Cell)sender;
MouseEventArgs me = (MouseEventArgs)e;
if (me.Button == MouseButtons.Left)
{
//Stuff that happens on left-click
} else {
//Stuff that happens on right-click
}
}
}
}
This is where I grabbed the type-casting the event arguments from.
MouseClick does not handle right clicks for buttons. You can use MouseDown.
board[i, j].MouseDown += button_arrayClick;
Use the _MouseDown event instead.
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
//stuff that happen on right-click
}
else if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
//stuff that happen on left click
}
}
listen for MouseDown event
private void button1_MouseDown(object sender, MouseEventArgs e)
Ok so please keep answers very direct and i must say i am very new to C#, i don't know a lot of stuff. Without further adieu my problem.
I am trying to move a picture box horizontally across the screen on a timer.The timer must go infinitely. I have tried all i currently know in C# and searched around quite a lot but nothing answered my exact question which is what i need because of my lesser knowledge of C#. For the last two weeks i worked on graphics mostly and the rest of that was trying to get this to work, So i have no code in my game. This is because for anything to work i need this part to be working. My game is 2D topdown. Any and all help is appreciated.
Thank you for taking the time to read.
Edit
No more answers needed, Thank you Odrai for the answer, it helped me a lot.
Use pictureBox.Location = new Point(x, y) or set pictureBox.Left/Top/Right. You can define x and y as variabels and initialize them with a default value. Increment x on timer tick.
Sample 1:
public partial class Form1 : Form
{
private Random _random
public Form1()
{
InitializeComponent();
_random = new Random();
}
private void timer1_Tick(object sender, EventArgs e)
{
int x = _random.Next(0, 500);
int y = _random.Next(0, 500);
pictureBox1.Top += y;
pictureBox1.Left += x;
}
}
Sample 2:
private void timer1_Tick(object sender, EventArgs e)
{
this.SuspendLayout();
pictureBox.Location = new Point(picust.Location.X + 10, picust.Location.Y);
this.ResumeLayout();
}
Add two buttons with title LEFT and RIGHT to a form and write the following code.
It might give you an idea, how to do simple moving animations.
public partial class Form1 : Form
{
int difference = 0;
Timer timer = new Timer();
public Form1()
{
InitializeComponent();
timer.Interval = 15;
timer.Tick += timer_Tick;
timer.Start();
}
void timer_Tick(object sender, EventArgs e)
{
pictureBox1.Left += difference;
}
private void btnLeft_Click(object sender, EventArgs e)
{
difference = -2;
}
private void btnRight_Click(object sender, EventArgs e)
{
difference = 2;
}
}
Try This Code it will work :
private void timer1_Tick(object sender, EventArgs e)
{
int width = this.Width; // get the width of Form.
if(pictureBox1.Location.X > width - pictureBox1.Width) //to check condition if pic box is touch the boundroy of form width
{
pictureBox1.Location = new Point(1, pictureBox1.Location.Y); // pic box is set to the new point. here 1 is indicate of X coordinate.
}
else
{
pictureBox1.Location = new Point(pictureBox1.Location.X + 100, pictureBox1.Location.Y); // to move picture box from x coordinate by 100 Point.
}
}
//Try This //
picturebox1.Location = 0,0;
I have a windows form application with a PictureBox control containing an image. I want to move the PictureBox control to the right in a slow movement. Here is my code:
Point currentPoint = pictureBox_Logo.Location;
for (int i = 0; i < 25; i++)
{
pictureBox_Logo.Location = new Point(pictureBox_Logo.Location.X + 1, pictureBox_Logo.Location.Y);
Thread.Sleep(30);
}
The problem here is that when the code executes instead of seeing the picture move, I see a white picture move and the moving stops until the picture appears.
What am I missing and what can I do about it?
Code:
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();
}
}
original thread is here Move images in C#
Try to use pictureBox_Logo.Refresh() after Thread.Sleep(30);
Or look for standard Timer control.
My code is good written, but what I did wrong was putting the code in an event:
private void Form1_Shown(object sender, EventArgs e);
But when I put my code in a button it works without any problems.