Moving a picturebox without redrawing it? [duplicate] - c#

I need to knock out a quick animation in C#/Windows Forms for a Halloween display. Just some 2D shapes moving about on a solid background. Since this is just a quick one-off project I really don't want to install and learn an entire new set of tools for this. (DirectX dev kits, Silverlight, Flash, etc..) I also have to install this on multiple computers so anything beyond the basic .Net framework (2.0) would be a pain in the arse.
For tools I've got VS2k8, 25 years of development experience, a wheelbarrow, holocaust cloak, and about 2 days to knock this out. I haven't done animation since using assembler on my Atari 130XE (hooray for page flipping and player/missile graphics!)
Advice? Here's some of the things I'd like to know:
I can draw on any empty widget (like a panel) by fiddling with it's OnPaint handler, right? That's how I'd draw a custom widget. Is there a better technique than this?
Is there a page-flipping technique for this kind of thing in Windows Forms? I'm not looking for a high frame rate, just as little flicker/drawing as necessary.
Thanks.
Post Mortem Edit ... "a couple of coding days later"
Well, the project is done. The links below came in handy although a couple of them were 404. (I wish SO would allow more than one reply to be marked "correct"). The biggest problem I had to overcome was flickering, and a persistent bug when I tried to draw on the form directly.
Using the OnPaint event for the Form: bad idea. I never got that to work; lots of mysterious errors (stack overflows, or ArgumentNullExceptions). I wound up using a panel sized to fill the form and that worked fine.
Using the OnPaint method is slow anyway. Somewhere online I read that building the PaintEventArgs was slow, and they weren't kidding. Lots of flickering went away when I abandoned this. Skip the OnPaint/Invalidate() and just paint it yourself.
Setting all of the "double buffering" options on the form still left some flicker that had to be fixed. (And I found conflicting docs that said "set them on the control" and "set them on the form". Well controls don't have a .SetStyle() method.) I haven't tested without them, so they might be doing something (this is the form):
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
So the workhorse of the code wound up looking like (pf is the panel control):
void PaintPlayField()
{
Bitmap bufl = new Bitmap(pf.Width, pf.Height);
using (Graphics g = Graphics.FromImage(bufl))
{
g.FillRectangle(Brushes.Black, new Rectangle(0, 0, pf.Width, pf.Height));
DrawItems(g);
DrawMoreItems(g);
pf.CreateGraphics().DrawImageUnscaled(bufl, 0, 0);
}
}
And I just called PaintPlayField from the inside of my Timer loop. No flicker at all.

Set off a timer at your desired frame rate. At each timer firing twiddle the internal representation of the shapes on the screen (your model) per the animation motion you want to achieve, then call Invalidate(true). Inside the OnPaint just draw the model on the screen.
Oh yeah, and you probably want to turn Double Buffering on (this is like automatic page flipping).

2d Game Primer
Timer Based Animation
Both of these give good examples of animation. The code is fairly straightforward. i used these when I needed to do a quick animation for my son.

Related

High performance plot control in WPF

I am doing some work for which I need to develop a control, it should be a simple graph that shows several points and two edges.
My problem is that I need to show up to 16k points, with an update rate of 30 Hz. Has anyone done something similar?, and has any advice?.
For example whether to inherit from FrameworkElement or Control (ItemsControl in this case). If the control inherits from FrameworkElememt it may have a better performance drawing the points in the OnRender method but I would miss the Templating feature that comes from inheriting from Control.
Or does there exist another control that can do this out there?
Thanks in advance for your time.
I ended up using InteropBitmap, it is the fatest bitmap rendering class from WPF.
It allows you to map the image that you want to paint (in memory) and then reder it as a Image. This was perfect as i needed to plot points on the screen.
I got great performance (almost 50Hz for 20k points), i also use PLINQ to update the points in memory.
check this article for more details...
Try and read about ZoomableCanvas. I believe it can solve your problem. You can render all the points as small rectangles/ellipses inside the ZoomableCanvas.

C# - Are there (similar) .AddChild and .AddEventListeners in C# and can they be used on Graphics?

I'm new to C# but not to OOP.
I'd like to make a "canvas" panel on which a user can draw shapes by mouseClick-ing but also delete them (nothing fancy, fixed sizes and whatnot, plain old pen objects). Like I said, I want the user to be able to delete whatever objects he alt-clicks on.
I'm not sure how exactly could I go about doing this. If I were using Flash, I'd probably do something like:
my_circle_object = new disc-or-whatever-etc;
canvas.addChild(my_circle_object);
my_circle_object.AddEventListener(MouseClickEvent, function_to_remove_child);
Now, since compiled languages are the devil when it comes to simple front-end UI related stuff, I'm sure It'll take 20 times more code to write this in C#. But, is there anything similar to my example?
I've spent all afternoon reading on things like GraphicsContainers, SmoothingPaint, Graphics Persistence using bitmaps etc. but I never found a simple add event method..
Thank you
The objects that you draw using the shape methods on a Graphics object (e.g. DrawLine, DrawEllipse, DrawRect, etc.) do not represent conceptual objects as far as the graphics API is concerned. Calling those functions simply draws the item to the graphics surface as a bitmap. Once that's done, there's nothing there to attach an event to.
You'll need to create your own shape types and have them draw themselves to the graphics object. You'll have to attach to the appropriate mouse events on whatever control you're using (I'm assuming a Panel) and do your own collision detection.

Resizing window causes black strips

I have a form, which sets these styles in constructor:
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
And I draw some rectangles in Paint event. There are no controls on the form. Hovewer, when I resize the form, there are black strips at right and bottom of the form. Is there any way to get rid of them? I've tried everything, listening for WM_ERASEBKGND in WndProc, manually drawing the form on WM_PAINT, implementing custom double buffer, etc. Is there anything else I could try?
I've found this:
https://connect.microsoft.com/VisualStudio/feedback/details/522441/custom-resizing-of-system-windows-window-flickers
and it looks like it is a bug in DWM, but I just hope I can do some workaround.
Please note that I must use double buffering, since I want to draw pretty intense graphic presentation in the Paint event. I develop in C# .NET 2.0, Win7.
Status Update 1
I've managed to get rid of most of the black stripes by implementing the resize functionality by myself. Hovewer there are still some minor glitches. Is there any way to do resize and paint operation at once? Here is a pseudo-code of what I need to do:
IntPtr hDC;
var size = new Size(250, 200);
IntPtr handle = API.PaintAndResizeBegin(this.Handle /* Form.Handle */,
size.Width, size.Height, out hDC);
using (var g = Graphics.FromHdc(hDC)) {
this.backBuffer.Render(g, size);
}
API.PaintAndResizeCommit(handle);
Is there any way to implement the above code?
The second solution could be to back-buffer whole form, including non-client area. But how to do that? I don't want to paint the non-client area by myself, as I want to keep the nice aero effect on Vista/7. Any help will be deeply appreciated.
Status Update 2
It looks like this problem is unsolvable, since it is omnipresent on Windows, in every application. We can just hope that MS will take some inspiration in Mac OS X and will provide appropriate APIs in new Windows.
I've found the function which can paint and resize window at the same time - UpdateLayeredWindow.
So now it should be possible to create resizable windows, which do not have any strips while being resized. However, you need to paint the window content yourself, so it is a little inconvenient. But I think that using WPF and UpdateLayeredWindow, there shouldn't be any problem.
Update
Found problems. :-) When using UpdateLayeredWindow, you must paint the window's border yourself. So, if you want standard window painted using UpdateLayeredWindow with nice glass effect in win7, you are screwed.
On Microsft Connect is even a thread about this problem, where Microsoft says it is a bug by design, and if it ever gets fixed, then probably in Win8 or some newer system. So there isn't much we could do about this.
I found that it is best not to do any custom rendering directly on the Form surface. Instead, put a docked PictureBox on the form, create Bitmap object that will be displayed in the PictureBox, draw everything onto that using the System.Drawing.Graphics.FromImage(Image) method.
I used that method with a game loop to make a simple shooter game (Crimsonland-style) and got pretty good performance (with anti-aliased lines), above 100 FPS.

C# .net framework- border on only one side of the form

I am an inexperienced programmer , completely new to programming for windows .
I am writing a little program that I always wanted . Its being written using C# using .net framework. atleast thats what I think I am doing. All the talk about framework and .nets , windows forms , and win32 api has all got me really confused.. :(
anyways I have simple Form object.
Form f = new Form() ;
f.Text = "" ;
f.ControlBox =false ;
Now How to remove the all the borders on the form except one sides? As in, the side borders should go , but the top border should stay
FormBorderStyle doesn't have anything for this
Also how do you people solve such problems yourself , without asking ? look at others code ? read a a book ? any particular website ?
I have googled , but it didn't turn up nothing.
Gidday,
This is impossible, unfortunately - you can remove the whole border, though, and then draw your own on the form and use OnMouseDown, OnMouseUp and OnMouseMove to do your own dragging...
To solve such a problem myself, I would look at various different ways of verbally representing the problem (eg. "borderless form", "custom borders on winform", etc) and spend a bit of time Googling for it. As my boss wisely says, productivity isn't always about how much code you cut, it's also about what you can learn.
EDIT: As the popular expression goes, "Google knows all" - chances are that, if you spend a bit of time googling and you still can't find anything, then it probably hasn't been solved, or it's very very rare. Another way would be to invest in a few good books, e.g. Windows Forms programming (or even just Windows programming - it's incredibly useful to know about the underlying mechanics of Windows, and things like that are what help turn you into a great developer. A great programmer is good at coding, but a great developer is good at actually building useful software. :)
I assume you've tried FormBorderStyle.FixedSingle? This would display a form with a border at the top only.
Anyway, if that isn't the case you can set the forms Region.
Something like...
public static void HideBorders(Form form)
{
Rectangle newRegion = form.Bounds;
Rectangle formArea = form.Bounds;
Rectangle clientArea = form.RectangleToScreen(form.ClientRectangle);
formArea.Offset(form.Location);
newRegion.Offset(clientArea.X - formArea.X, 0);
newRegion.Width = clientArea.Width;
newRegion.Height = (clientArea.Y - formArea.Y) + clientArea.Height;
form.Region = new Region(newRegion);
}
As for how do you know what to do? All of the things you mentioned, help files, web forums, books. The main thing is practice, practice, practice. The more you do something the better you should become.
I don't think it's actually possible to do exactly what you describe, since the .NET Framework is just going to delegate the drawing of your Form's border and title bar to Windows itself, which doesn't have any option for what you describe AFAIK.
Instead, what I would do is use FormBorderStyle.None and then draw any window decorations (title bar, borders) you want manually.
A Google search for "borderless form C#" turns up these sites as the top three hits:
BorderLess Window (java2s.com)
Transparent borderless forms in C# (c-sharpcorner.com)
Draggable Form: Drag a Borderless Form by Clicking Anywhere on the Form (codeproject.com)

Simultaneous updates across two display contexts in openGL

I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).

Categories