To briefly explain:
I have a win form written in C# that contains a panel.
The panel contains a shape container, through that I have programmatically added some oval and line shape controls from VisualBasic.PowerPacks to the panel.
The reason of using such shapes was I needed to perform some operations on their MouseHover and MouseClick events.
I have also drawn some graphics like strings and ellipse on the panel using Graphics in Paint(object sender, PaintEventArgs e) method of the panel.
The application has zoom in and zoom out buttons and whenever user clicks on them the size of shapes and graphics are supposed to be changed based on the scale.
To redraw graphics after scaling, I needed to clear the old ones before drawing new graphics in the new scale, otherwise they remained on the panel. So, I used Clear(Color color) method of the graphic to do so.
Now, the problem I have is upon using Clear(Color color), everything including shape controls gets disappeared. By my perception, I do not expect shapes to be disappeared because they should be treated as controls, unless I am missing something here. How can I avoid this issue? Any advice would be appreciated.
Solved the problem by invalidating "shape.Invalidate()" shape controls.
Related
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.
I am creating a simple app to display multiple images one below the other.
In WPF, I used Number of canvas equivalent to number of images and added those canvas to the main canvas.
And using Image control in each canvas, i uploaded the images with me and it is looking good.
Now, I Am trying to do the same in Windows forms.
I tried Panel (as the main canvas in WPF) and draw images over it by using Panel_Paint event. it is fine. But I need to add something(as I added multiple canvas in WPF), but did not get strike any thing.
I planned for few panels, but all them need Panel_Paint to draw images over it.That is some what difficult to maintain... any other ideas?
You can create your own custom control and override OnPaint method. There you will be able to draw whatever you like in Canvas like mode. Create element specify its coordinates, draw it with Graphics object. And for overlaying use linear drawing order, items drawn later will be top most.
If you want to create a Paint-like canvas, where you can draw simple graphics and images, you could use an instance of Graphics, like the following:
// myPictureBox is the control where your graphics will be drawn
Graphics myCanvas = myPictureBox.CreateGraphics();
If you want to display a group of images, like .jpg are displayed in the files explorer, you could use a ListView.
I have problem with showing a diagram which is too big to see on one panel.
I have to scrollbars which should change the point of view on the diagram, but when i want to scroll the picture, the shapes are moving on the different position, everything getting crushed.
it looks like this here link
when i show it,and like this here link when i try to look on the bottom of the graph
it looks like application drawing the shapes every time when i scroll the panel, and when i go on the bottom of picture the point on the top left corner still is (0,0) not (0,500)
I have algorithm, which giving value of location on the panel and nr id of object to the array, then i have the loop which drawing it, getting info from dictionary about the object and his position from array.
How this problem can be solved ?
Thx for any advice's
Edited
I dont want to draw it again i want to draw one big graph, something like this(link in the comment), but i know that user can make for example 50 objects(shapes) and that kind of big graph cant be seen on the small panel so we have to have a chance to scroll and see the bottom of grapf, left side or this side which he want.
I'll try to give more details about application.
When you lunch it, you see the control panel(form1), where you adding events/functions/xor/or every of this option have their own shape on the graph.
So user adds for example event with text, pressing the button add which creates the object and adding it to the collection. He can adds events/functions,xor/or as many as he wants.
Ok, when he adds everything what he wanted, and now he would like to see graph so he pressing the button "generate the diagram", now the application is showing the next windwow with panel and scrollbars. You can see the window in links.
In the second form after this line
private void panel1_Paint(object sender, PaintEventArgs e){
I have algorithm which is putting the coordinate values to table, then forech loop is taking from dictionary ( collection):
text which should be shown on diagram in the middle of shape,
value which determine a type of shape on the panel.
from arrays loop taking the coordinate values.
This how its work, I can also put a code in here when its needed.
The standard mistake is forgetting to offset your drawing by the scroll position. Use the panel's AutoScrollPosition property, like this:
void panel1_Paint(object sender, PaintEventArgs e) {
e.Graphics.TranslateTransform(panel1.AutoScrollPosition.X, panel1.AutoScrollPosition.Y);
e.Graphics.DrawLine(Pens.Black, 0, 0, 300, 2000);
}
The Panel control is in general pretty cranky about painting, it was designed to be a container control. You typically also want it double-buffered and to force a repaint when it is being resized. Setting the DoubleBuffered and ResizeRedraw properties requires deriving your own control from Panel.
It looks like application drawing the shapes every time when i scroll the panel
Why don't you erase the drawing area and draw the shapes again?
Maybe you can post a code snippet?
I have used grahics in a panel. At start of the program I draw some points in the panel and after that I want to draw lines connecting those points. Problem is when I press tab button the graphics created disappear (but this happens once in the program). Next problem is I want to clear the panel I used following code to clear panel:
Panel1.Invalidate();
But this only clears the lines but not those points that were initially created. Does anyone has a simple solution because I don't want to recreate the panel.
Technical Detail: to draw initial points in panel, paint event of panel1 is used:
Graphics gfx = e.CreateGraphics()
For lines, there is a seprate function that is called on button click and in that I used:
Graphics gfx = Panel1.CreateGraphics();
Another button that is used to clear panel has following code:
Panel1.invalidate();
but it only clears the line graphics, not those initial points.
I was making a mistake by creating initial points in the paint event of panel1. So everytime i call
Panel1.Invalidate();
it recalls that paint event and those points are redrawn and not cleared.
Do you save the points in some sort of collection and draw them in the Paint event?
Then you should empty the collection and then call the Invalidate
The panel is redrawn inside the paint event. It means that you have to draw everything inside this method, instead of accessing the graphics context directly.
This explains why everything you draw when you use Graphics gfx = Panel1.CreateGraphics(); is lost every time the control is redrawn, since during the paint event, you are only drawing the initial points, nothing more.
Hai all,
I am dynamically creating button at runtime in a c#.net Windows Application, I want to draw a border for the dynamically created button how can i do it, i tried this
private void DrawBorder(Button bt)
{
Graphics g = bt.CreateGraphics();
ControlPaint.DrawBorder(g, bt.DisplayRectangle, Color.FromArgb(229, 227, 227), ButtonBorderStyle.Solid);
g.Dispose();
}
but it is not showing any error but i can't see any border
Please Help
If you want a button that draws differently, you should probably create a new class inheriting from Button, and in it you would override OnPaint and/or OnPaintBackground and implement your drawing logics, such as drawing a border.
The reason your current solution is not working probably depends on when you are calling your DrawBorder method. If your drawing code is not executed as part of handling an OnPaint event, then the graphics you draw will be drawn-over in the next paint.
But anyway, instead of drawing the border yourself, can't you set the Border proerpty on the Button object?