rightT is a timer which is supposed to change the image of the object (which inherits from PictureBox)
when the code runs (after I turned on the timer) the image changes only once and never changes again
anyone knows why it happens?
rightT.Tick += (EventHandler)delegate
{
this.Location = new Point(this.Location.X + _movementSize,
this.Location.Y); // moves the character
this.Image = this.rightState++ % 2 == 0 ? Properties.Resources.MarioAnimation2 : Properties.Resources.MarioAnimation1; // changes the photo
this.Refresh();
};
I think Application.DoEvents(); is better suited for forcing the gui to update. you can place it anywhere you like and as much as you like.
Related
my code for my game had a paint system where is draws then redraws a car (or a box) every 50 ticks. i have really bad flickering when running the code (even when not moving) anything else you need i can grab :)
i have tried:
-Double buffering
-Putting everything into a panel and refreshing that
//My Paint Code
Bitmap greenCar = new
e.Graphics.FillRectangle(car.getDrawingbrushColor(),
car.getCarposition());
e.Graphics.DrawImage(greenCar,car2.getCarposition());
}
my timer code
scoreTimer.Tick += new EventHandler(Tick2);
scoreTimer.Interval = 100;
scoreTimer.Start();
DoubleBuffered = true;
My Refresh Code
{
this.Counter.Text = Scorecounter.ToString();
Scorecounter += 1;
panel1.Refresh();
}
i just dont want it to flicker, i is really holding me back.
I am trying to implement MiddleClickScrolling in ScrollViewer and it works well.
The problem is when moving the pointer the Storyboard will restart to update the speed but when we move the pointer a jitter is occurring. I have attached a gif but you may not notice this jitter in this gif.
Since this a big class, I can't put all the code here. You can see my full code on GitHub (Note: Please select SmoothScroll branch if you are cloning it). An easy way to reproduce this issue is to move the pointer Up and Down for a small distance rapidly.
This is my code for storyboard animation
_verticalDoubleAnimation = new DoubleAnimation()
{
EnableDependentAnimation = true,
Duration = new TimeSpan(0, 0, 1)
};
//Different function
var offsetX = _currentPosition.X - _startPosition.X;
var offsetY = _currentPosition.Y - _startPosition.Y;
SetCursorType(offsetX, offsetY);
if (CanScrollVertical())
{
if (Math.Abs(offsetY) > _threshold)
{
RunInUIThread(() =>
{
_verticalDoubleAnimation.From = _scrollViewer.VerticalOffset;
_verticalDoubleAnimation.To = _scrollViewer.VerticalOffset + (offsetY > 0 ? _scrollViewer.ScrollableHeight : -_scrollViewer.ScrollableHeight);
if ((_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor)) == double.NaN)
{
return;
}
_verticalDoubleAnimation.Duration = TimeSpan.FromSeconds(_scrollViewer.ScrollableHeight / (Math.Abs(offsetY) * _factor));
_verticalStoryboard.Begin();
});
}
else
{
RunInUIThread(() =>
{
_verticalStoryboard.Stop();
_sliderVertical.Value = _scrollViewer.VerticalOffset;
});
}
}
Instead of animating it, use a timer or a while loop to dynamically update the position using the ScrollViewer.ChangeView() method. Make sure the interval is less than 16.6ms for smooth 60fps motion. Also make sure to set the final parameter of ChangeView to false so that its built-in animation is disabled.
So in your first commit, change this:
timer = new Timer(ScrollAsync, null, 50, 50);
To this:
timer = new Timer(ScrollAsync, null, 0, 5);
The Timer does not give precision within 1ms or even 10ms to my undestanding. Overcompensating by updating it every 1-5ms should make up for that so it's probably fine and it's what I'm using in my custom scrolling control. A Stopwatch is very precise but is a massive CPU hog. Another option: It's a lot of extra work, but if you want precision timing and maximum performance with minimal battery usage, you can use Win2D's CanvasAnimatedControl which can be used to run code exactly once every 60th of a second.
When a specific condition is met I disable my picturebox and the image freeze's, whenever it runs again the gif starts all over again not from where it was stopped is there anyway to resume it ?
Stopping picturebox : http://prntscr.com/b6gg7a
"Resuming" picturebox : http://prntscr.com/b6gglb
I believe indeed this is a rather tedious/unlikely to perform with an animated gif.
What you could/should do IMO is the following:
Instead of making the background a gif, break it into multiple frames(pictures).
Set up a timer that triggers the background to change to the next image.
You can pause and resume that timer the same as you would enable and disable the picturebox.
Your background change function could look something like this:
int bgCount = 8; //Amount of frames your background uses
int bgCurrent = 0;
string[] bgImg = {
"bg1.png",
"bg2.png",
"bg3.png",
"bg4.png",
"bg5.png",
"bg6.png",
"bg7.png",
"bg8.png",
};
void changeBG()
{
if(bgCurrent > bgCount-1) //If not displaying the last background image go to the next one
{
bgCurrent++;
imgBox.image = bgImg[bgCurrent];
}else //If displaying the last background image -> Start with the first one
{
bgCurrent = 0;
imgBox.image = bgImg[bgCurrent];
}
}
}
And you just let the timer trigger this event. And you simply start and stop the timer.
Sidenote:
1* You might experiment with, instead of changing the source, just make 8 imageboxed and call/display them as they are needed.
This seems simple enough, and I have followed advice I have found on other posts here. If my picturebox grows to accommodate a large image, I want the form to grow a little more, so there's some whitespace under the photo (otherwise, it looks like the form cropped the photo).
if ((pictureBox1.Height + 25) >= this.Height)
{
this.Size = new Size(this.Width, (pictureBox1.Height + 35));
this.Refresh(); // tried with and without refresh
}
Unfortunately, nothing happens. When going step by step, I see that the Height of the form never changes. I've read here on stack overflow that setting minimum size or maximum size can cause this behaviour, but both are set to their defaults (0,0).
Suggestions?
Thank you
What you have seems to work for me. I would try putting a break in your code at the refresh and examining the values that you are getting and then stepping through the refresh and checking again. Check to make sure that you are getting the expected values for this.Height and pictureBox1.Height.
Here is the exact code that I used to test this:
this.Size = new Size(300, 300);
PictureBox pictureBox1 = new PictureBox();
pictureBox1.Size= new Size(700, 700);
this.Controls.Add(pictureBox1);
if ((pictureBox1.Height + 25) >= this.Height)
{
this.Size = new Size(this.Width, (pictureBox1.Height + 35));
this.Refresh(); // tried with and without refresh
}
Your going to have to post more of the code in order to get much help.
comrades) I've found some interesting behavior of Invalidate method in multithreaded applications. I hope you could help me with a problem...
I experience troubles while trying to invalidate different controls at one time: while they're identical, one succesfully repaints itself, but another - not.
Here is an example: I have a form (MysticForm) with two panels (SlowRenderPanel) on it. Each panel has a timer and with a period of 50ms Invalidate() method is called. In OnPaint method I draw number of current OnPaint call in the centre of panel. But notice that in OnPaint method System.Threading.Thread.Sleep(50) is called to simulate long time draw procedure.
So the problem is that the panel added first repaints itself much more often than another one.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1 {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MysticForm());
}
}
public class MysticForm : Form {
public SlowRenderPanel panel1;
public SlowRenderPanel panel2;
public MysticForm() {
// add 2 panels to the form
Controls.Add(new SlowRenderPanel() { Dock = DockStyle.Left, BackColor = Color.Red, Width = ClientRectangle.Width / 2 });
Controls.Add(new SlowRenderPanel() { Dock = DockStyle.Right, BackColor = Color.Blue, Width = ClientRectangle.Width / 2 });
}
}
public class SlowRenderPanel : Panel {
// synchronized timer
private System.Windows.Forms.Timer timerSafe = null;
// simple timer
private System.Threading.Timer timerUnsafe = null;
// OnPaint call counter
private int counter = 0;
// allows to use one of the above timers
bool useUnsafeTimer = true;
protected override void Dispose(bool disposing) {
// active timer disposal
(useUnsafeTimer ? timerUnsafe as IDisposable : timerSafe as IDisposable).Dispose();
base.Dispose(disposing);
}
public SlowRenderPanel() {
// anti-blink
DoubleBuffered = true;
// large font
Font = new Font(Font.FontFamily, 36);
if (useUnsafeTimer) {
// simple timer. starts in a second. calls Invalidate() with period = 50ms
timerUnsafe = new System.Threading.Timer(state => { Invalidate(); }, null, 1000, 50);
} else {
// safe timer. calls Invalidate() with period = 50ms
timerSafe = new System.Windows.Forms.Timer() { Interval = 50, Enabled = true };
timerSafe.Tick += (sender, e) => { Invalidate(); };
}
}
protected override void OnPaint(PaintEventArgs e) {
string text = counter++.ToString();
// simulate large bitmap drawing
System.Threading.Thread.Sleep(50);
SizeF size = e.Graphics.MeasureString(text, Font);
e.Graphics.DrawString(text, Font, Brushes.Black, new PointF(Width / 2f - size.Width / 2f, Height / 2f - size.Height / 2f));
base.OnPaint(e);
}
}
}
Debug info:
1) Each panel has a bool field useUnsafeTime (set to true by default) which allows using System.Windows.Forms.Timer (false) insted of System.Threading.Timer (true). In the first case (System.Windows.Forms.Timer) everything works fine. Removing System.Threading.Sleep call in OnPaint also makes execution fine.
2) Setting timer interval to 25ms or less prevents second panel repainting at all (while user doesn't resize the form).
3) Using System.Windows.Forms.Timer leads to speed increasement
4) Forcing control to enter synchronization context (Invoke) doesn't make sense. I mean that Invalidate(invalidateChildren = false) is "thread-safe" and could possibly have different behavior in diffenent contexts
5) Nothing interesting found in IL comparison of these two timers... They just use different WinAPI functions to set and remove timers (AddTimerNative, DeleteTimerNative for Threading.Timer; SetTimer, KillTimer for Windows.Forms.Timer), and Windows.Forms.Timer uses NativeWindow's WndProc method for rising Tick event
I use a similar code snippet in my application and unfortunately there is no way of using System.Windows.Forms.Timer) I use long-time multithreaded image rendering of two panels and Invalidate method is called after rendering is completed on each panel...
That would be great if someone could help me to understand what's different happening behind the scenes and how to solve the problem.
P.S. Interesting behavior isn't it?=)
Nice demonstration of what goes wrong when you use members of a control or form on a background thread. Winforms usually catches this but there's a bug in the Invalidate() method code. Change it like this:
timerUnsafe = new System.Threading.Timer(state => { Invalidate(true); }, null, 1000, 50);
to trip the exception.
The other panel is slower because lots of its Invalidate() calls are getting canceled by the paint event. Which is just slow enough to do so. Classic threading race. You cannot call Invalidate() from a worker thread, the synchronous timer is an obvious solution.
Invalidate() invalidates the client area or rectangle ( InvalidateRect() ) and "tells" Windows that next time Windows paints; refresh me, paint me. But it does not cause or invoke a paint message. To force a paint event, you must force windows to paint after an Invalidate call. This is not always needed, but sometimes it's what has to be done.
To force a paint you have to use the Update() function. "Causes the control to redraw the invalidated regions within its client area."
You have to use both in this case.
Edit: A common technique to avoid these kinds of problems is keep all your paint routines and anything related in a single (generally main) thread or timer. The logic can run elsewhere but where the actual paint calls are made should all be in one thread or timer.
This is done in games and 3D simulations.
HTH