How can I prevent GDI+ from re-drawing everything on paint? - c#

I want to change the colour of certain parts of a control which is using GDI+ to draw itself, like when certain objects are hovered/clicked, for example.
How can I re-draw only the necessary parts? It seems bad to re-draw thousands of pixels when I only need to make a change to a few of them.
To be specific, I have drawn anywhere from 1 to 128 rectangles, and I will need to re-draw anywhere from 1 to 128 rectangles in various events. I don't want to re-draw 128 rectangles in order to make a change to only 1-127.
I have read that it is a bad idea to use drawing code in places which are not the on paint event. But, is it possible to do this when relying on the paint event?

You can use one of the Control.Invalidate methods to specify the region you want to redraw.
Then in the Paint event hander you can check the invalidated region with the e.ClipRectangle property.

Related

What's the best way to paint in Unity?

I'm making a little game, you're given a canvas and have to completely fill it up by painting everything. The problem is that I don't know how to let the user draw on an object in the UI.
I researched 2DTextures and their setPixel() method, but that seems limiting, because making an 800x600 2DTexture would mean you'd have to paint 480000 pixels, and that's too much. If I make the 2DTexture smaller, 150x100 for example, it would be to small. I'd basically need to make the pixels "bigger", each one being a 4x4 of the real pixels.
Another thing I thought of is making a grid in the UI (150x100) and make the single cells change color then touched. Is this viable? How would I go about doing it?
Last thing, I need to check when the canvas is finished, so I need a way to check the color of every pixel (or cell,in case of the grid), would iterating every pixel with getPixel() be fast enough?

Line gets drawn only after Control moves over it

I have a set of custom controls and a list of geometric objects that I need to draw on the same handle.
I override the OnPaint procedure, put the base.OnPaint(e) in the first line and commence with the drawing of the geometric objects (via e.Graphics.DrawLine etc.).
Those are in a locked list and decay after a while.
Also the customized controls can move around the window.
Now this is almost working as intended except for this fun fact:
The geometric shapes appear only after a control is moved along/above their layouts.
I was able to reproduce this in a small environment: PASTEBIN
I tried flushing the graphics object; save/restore; changing Clip.
Nothing seemed to work.
I am guessing that regions only get invalidated and repainted once a control is present. But how can I force them to be drawn anyways?
Control.Invalidate will tell the framework that the control needs to be redrawn. It does this automatically to redraw controls after, for example, the mouse has obscured part of it, but it will only redraw a the small section that the mouse covered (hence why you end up with a "(re)painting with the mouse" effect. Also moving a window will force it to redraw, as does covering it with another window and then moving that window away again.
But if you are doing a bunch of custom painting, you need to let it know that the control needs to be redrawn by calling Invalidate yourself.

How do you draw a Control?

How do you draw a control?
I'm not talking about UserControl/Custom Control (or am I?), but I am talking about using GDI to draw my own custom shape, and give it properties and events, like myNotSoStraightThickLine.Clicked, or myNotSoStraightThickLine.Color, etc.
How do you make things that you've drawn with GDI+ clickable, selectable, movable, with events and properties that other controls inherit, as well as making it Disposable whenever needed?
You'll have to draw each thing that you want, and capture mouse move events and mouse click events to determine whether you have clicked a part of each element. Which will get tricky if you are dealing with diagonals and ellipses, you may have to determine a full list of possible x + y coordinates (on a per pixel basis) for each of your elements possible positions on creation and compare those on the mouse move/click events.
And as for recording colours, you could get the properties of the PictureBox content at the location of your move/click event, or perhaps it would be better to same some objects with a mirror of the properties of the controls that you are drawing, that way you could actually create your objects and then take their properties for drawing them, which could be simpler.

OnPaint events order

I developed some components with their own OnPaint-override where I draw them.
I now added a status panel which is designed to overlap topmost with part of my form. I use a alpha-blended color to gray out the underlying controls and display a text on it.
Unfortunately some of my underlying custom controls paint themselves after the status bar and so draw themselves above the status bar. Debugging I found out that first the status bar on paint event was called, later the paint event of the underlying controls.
How can I make sure the proper order is used to paint?
When underlying components draw themselves the components infront of them should always be automatically invalidate so they redraw themselves but that is not happing. I also called SendToFront on the statusbar but that did not helper neither. So I am also asking what is the proper mechanism to maintain the order and how do the core components handle that.
Edit: I also run in this problem: With every run of my OnPaint-event my overlay gets more and more opaque because it draws with alpha=128--red again and again on itself.
To eliminate external factors (like variations between XP, Vista, Win7), you could:
blend the "status panel" graphics onto each control in their OnPaint handlers, so you don't need to mess about with a semi-transparent status window to achieve the desired display.
use one opaque control (essentially the status panel) and render the final image you want into it by compositing the graphics from the individual controls, which would elimimnate any uncertainty over how the rendering process will operate. This would mean that you'd have to add custom click handling, but that's usually a fairly trivial addition - one easy way around this is to put the main "display control" behind a set of invisible controls (the buttons) so that all the click handling can work as normal, but the painting is delegated to a single control.

Creating Overlay Control in winforms

I am using c# winforms to show an Image. The displaying of the image is done using a user control. Now I want to provide the user to draw lines, put other small images, write text etc over the image on an overlay control. How can I provide this functionality? If I use another user control to show the overlay control with transparent back, will that work?? any other solution will be welcome.
You might try approaching this with a canvas (Panel) that handles painting the image as the background and all the annotations/markup afterwards. This will make the foreground appear to be transparent. I expect you'll want to set Control.DoubleBuffer for performance.
You might experiment with setting the style ControlStyles.AllPaintingInWmPaint. Also, try overriding Control.OnPaintBackground and do nothing, and override Control.OnPaint and do all your painting inside there.
If performance is still unacceptable, pay close attention to the PaintEventArgs.ClipRect property. This is the only area you need to paint. The trick is figuring out which of your annotations/overlays intersect with this rectangle and painting them in the correct order.
Either this canvas or a higher level control will need to track mouse movement so you know where to draw the lines, paste images, etc.

Categories

Resources