Is it possible to remove some lines in my graphic panel without erasing the rest?
PanelGraphics.Clear(Color.Black); erases all the graphics but I only want to remove one line, or a certain color.
Is this possible?
Is it possible to remove some lines in my graphic panel without erasing the rest?
Not really. The Graphics does not tell you anything about the actual context, it can be the screen, a printer, a bitmap, a metafile, the surface of a control or something similar. If you draw a Panel or a control you must always re-draw the whole content once it is invalidated. Otherwise, you will get a messy result. Just try to move your window partly out of the screen, the custom-drawn content will be "erased" unless you redraw it.
However, if you have a concrete image, such as a Bitmap, you can replace its colors; however, you must know the exact PixelFormat of the image. See my answer here if you are interested: https://stackoverflow.com/a/33562891/5114784
Related
I am trying to do the following:
Open a new form and draw few lines and arcs (this is working well).
When an event occurs a new coordinate (x1,y1) is calculated, and a
small circle should be drawn at that coordinate.
When the next event occurs, a small circle should be drawn at
(x2,y2), and the first circle should disappear, while keeping the
lines and arcs that were drawn at step 1.
How do I delete the first circle while keeping all the rest?
Thank you
Once a circle has been drawn, there is no way to delete it. So, you need to clear the entire canvas with the background color and redraw everything.
So, you need to:
Come up with a bunch of "shape" classes for representing each line and each ark and each circle. They will probably all derive from some common base "Shape" class which offers methods that are common to all shapes, for example, a method to draw the shape on a canvas.
Instantiate objects from these classes to represent the shapes that are supposed drawn on the screen, and keep these objects in a list throughout the lifetime of your application.
When the event occurs, you make any changes to your shapes, (in your case, remove a circle and add another circle, or, more likely, change the coordinates of an existing circle without removing it and re-inserting it in the list,) and then you need to invalidate the canvas control that you presumably use for painting, (search for "Invalidate" for documentation,) so as to cause the canvas to repaint itself.
You override the paint method of the canvas control so as to do your painting: first you clear the control to its background color, and then you iterate through your list of shapes, calling each shape to draw itself on the canvas.
Of course this will cause flicker; if that's unacceptable, then you will need to read up on how to implement "double buffering" (look it up) to eliminate the flicker.
Another approach for flicker elimination is to only erase and repaint the area that has changed. In your case, that would be the smallest rectangle that contains both the circle in its old location, and the circle in its new location. So, instead of invalidating the entire canvas, you invalidate only that rectangle. The problem with this approach is that other shapes that cross the invalidated area might appear to be redrawn somewhat inaccurately. This may be unacceptable, or it may be acceptable, you will not know unless you try it.
You can't in the way you're thinking of, because the graphics works like MSPaint (a 2d array of pixels and when it's drawn, it's drawn) not Adobe Photoshop (layers or objects that can be moved independently)
The easiest thing to do is implement photoshop-like functionality yourself and keep eg a List of everything you want to draw, draw from the list (the list includes a circle) then later, remove that circle from the list, add another one and redraw the whole canvas from the list
I know it seems wasteful, and you probably could get into the mechanics of saving the pixels you drew over when you draw the first circle and restore them to erase the circle, but it's far more complex than just ditching it all and starting over every time
I've been learning how to draw lines in winforms apps, and I'd like to be able to select something (rectangle, for example) that has already been drawn by left clicking it, and then be able to move it around to another location by dragging it with the mouse.
How can this be done? I don't see any methods for this so I think I will need to figure out if there is anything where I left-click on the form, and if there is, then somehow figure out the dimensions of it and redraw it appropriately. Is this correct? And how would I know where the reactangle starts, where it ends, how heigh it is, what color(s) it has, and what if it's overlapping another line, rectangle or another shape?
I've not been able to find much on the System.Drawing namespace for things like this, and what I have found so far is just basic "How to draw lines" type stuff.
Your drawing is a bitmap, not a vectorial image. Basically, it's just lots of pixels. Once your rectangle is drawn, it's just some pixels, but the rectangle itself (with coordinates and size) doesn't exist anymore.
What you can do is saving data for every shape (in a List for example). Then, when you click on your image to select something, you test every object in your list in reverse order until the mouse coordinates are within your shape. Then, if, for example, you want to delete the shape, you remove the shape from your list, then you clear your image and redraw every shape in your list.
Specifically: I need to capture as a bitmap a specific region of what a picturebox is actually displaying. The coordinates of the region are specified by the bounds of a control that I have overlayed on top of the picturebox (but that belongs to the picturebox). The control is hidden when I make the "snapshot" of the region.
I tried using normal screen capture methods (CopyFromScreen), but you can't really control the timing there. So it was capturing "interstitial" states, like transitions between photos in my picturebox. Frequently it was only capturing purely black images (the background color of the picture box).
So I tried just converting the image (picturebox.image property) being displayed to a bitmap. The problem there is that the picture box is rarely showing exactly the image. It's displaying some PORTION of the image, scaled and clipped as appropriate to it's sizemode (which is zoom). So the I can't just take my control coordinates and clip them from the image as a whole.
So I tried to estimate what portion of the image was being displayed, and correcting my rectangle based on that. Turns out that I was basically re-creating the "zoom" code of the picturebox to do this (using aspect ratio of the picturebox, the aspect ratio of the image, guessing at what level of scaling is currently happening to the image if it's larger or smaller than the picturebox, etc). It was not pretty.
So: now I need a method of just capturing only the bitmap currently being displayed in the client area of the picturebox, including the photo and any black "letterboxing" currently being displayed around it. Anybody got one?
Remember that I can't rely on using CopyFromScreen. It's not reliable enough for my purposes. I think I need a method of getting picturebox to TELL me the bits it is displaying.
This will copy and save the currently shown content of the PictureBox including a BackgroundImage (if there is one and if it shines through) and also all Controls that belong to the PictureBox, like Labels etc.. Also included are elements drawn in the Paint event. Things drawn outside the Paint event are non-persistent and will not be included.
using (Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width,
pictureBox1.ClientSize.Height))
{
pictureBox1.DrawToBitmap(bmp, pictureBox1.ClientRectangle);
bmp.Save(yourfilename, ImageFormat.Png);
}
Note: On my test Form the PicureBox is sitting inside an AutoScroll Panel pan_PBscroll. The PictureBox is displaying pixels 1:1 and is therefore, with a photograph loaded, much bigger than the Panel, the Form or even the Screen. So to clip to the actually visible parts I could not use the pictureBox1.ClientSize and pictureBox1.ClientRectangle but used the dimensions of that Panel. This may well apply to you, too.
I'm not sure about your timing issues. But since you mentioned CopyFromScreen here are a few differences:
CopyFromScreen makes a 1:1 copy of each screen pixel
This includes non-persistent drawings and excludes anything covered or hidden
Control.DrawToBitmap makes the Control draw itself onto a Bitmap, just as it draws itself during Paint
This excludes anything that doesn't belong to the Control but includes all members of its Controls collection
This also excludes non-persistent drawings but includes the full Size of the Control, whether it fits on the Form or Screen or not and whether it is hidden or covered or not.
For Controls with active Scrollbars only the visible parts are copied. To copy all you need to resize it temporarily. Then you can get a complete image of a listbox even if it has a thousand items..
Since you're using a PictureBox I would say to take a look PictureBox.Image where you can get the Bitmap object.
Hope it helps.
In my application the user can write from keyboard on an image. Is it possible to display the caret on the image (as in TextBox for example)?
You've got 3 separate issues:
1) Drawing Text at arbitrary locations.
See MSDN DrawString Method
2) Merging two separate images (the original and the text) into one.
As far as I know the image host controls, that you're likely using to show the image, provide a bitmap object property, so you need to be able to save that bitmap object to a file once you've done the DrawString.
3) Draw the caret symbol at arbitrary locations
You can do this with basic drawing commands to create your own caret, that's using Graphics with Pens and Paths.
Then the issue is to make it flash (which means drawing what's underneath your caret again, then your caret etc)
I think there's options on the Pen object that might achieve this for you.
I would tackle each in turn then put them together.
If you are referring to the Caret (the blinking indicator which shows the position when inputting text), you probably have to use P/Invoke. You should start here:
http://msdn.microsoft.com/en-us/library/windows/desktop/ff468799(v=vs.85).aspx
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.