Dynamically adding shapes to a panel - c#

Alright, i have been struggling with a specific issue. On a web page in C# i would like to build a diagram. It will consist of some rectangles (i want the rectangles to have extra functionality later, later it will have arrows and other images).
After quite some research i discovered that it is not possible to dynamically draw stuff from the c# code to the user web page.
All the things i can find tell me to make a bitmap and then save it to the outputstream or something, which i did. But it had a strange result, after clicking the button (it should build a rectangle and add it to the panel) :
http://imgur.com/ddfjgAZ
code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
//toegevoegd
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Drawing.Imaging;
using System.IO;
using System.Drawing.Text;
namespace Drawing.Usercontrols
{
public partial class WebUserControl1 : System.Web.UI.UserControl
{
Panel Panel1 = new Panel();
Panel Panel2 = new Panel();
View View1 = new View(); //how does this even work
Bitmap objBitmap = new Bitmap(400, 440);
protected void Page_Load(object sender, EventArgs e)
{
//adding a square... on a Panel...
Panel2.Width=500;
Panel2.Height = 500;
Panel2.BackColor = Color.BlueViolet;
this.Controls.Add(Panel2);
//Making a graphicsobject from the bitmap
Graphics objGraphics = Graphics.FromImage(objBitmap);
//objGraphics.Clear(Color.Blue);
Pen p = new Pen(Color.Yellow, 3);
Brush x = new SolidBrush(Color.BlueViolet);
//This piece will put up a sweet ellipse on the rectangle
Rectangle rect = new Rectangle(200, 100, 60, 20);
objGraphics.DrawEllipse(p, rect);
Panel1.Controls.Add(Panel2);
//This will add the bitmap to the page, but not really, everything on the page will dissapear and this dude will show up
//objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
//This will add an image from the internet to the panel, which works
//Panel2.Controls.Add(new System.Web.UI.WebControls.Image { ImageUrl = String.Format("http://ecx.images-amazon.com/images/I/518rMVxp3qL._SL75_SS50_.jpg") });
// textboxes adding
this.Controls.Add(Panel1);
Label FeedbackLabel = new Label();
TextBox Inputtextbox = new TextBox();
Button Submitbutton = new Button();
FeedbackLabel.ID = "lblFeedback";
FeedbackLabel.Text = "Hello world";
Submitbutton.ID = "btnSubmit";
Submitbutton.Text = "Submit";
Inputtextbox.ID = "txtInput";
Submitbutton.Click += SubmitButton_Click;
Panel1.Controls.Add(FeedbackLabel);
Panel1.Controls.Add(Submitbutton);
Panel1.Controls.Add(Inputtextbox);
}
protected void SubmitButton_Click(object sender, EventArgs e)
{
// this is the part where the black rectangle is drawn
objBitmap.Save(Response.OutputStream, ImageFormat.Jpeg);
}
}
}
So my final question is: Can i build rectangles with shapes in it and place them across a panel/layout
(later i want to use those rectangles as objects (adding onclick events to them, but i wont bother you with that just yet)
Thanks a lot in advance!

Related

C# Main Form BackColor moves in front of image

first of all, I'm new to C# Forms (and also new to StackOverflow). I want to have a small launcher window. I disabled the title bar, so the Main Form is supposed to just be there and hold the UI elements. I added a slightly smaller PictureBox that I want to be the "real" background so it will create a neat border between the main form and the background image. So far so good.
The issue is now that all UI elements that use transparent background and are placed on top of the PictureBox will now display the background of the main form instead of the PictureBox and it looks terrible.
I am confused. I tried sending the main form to back, I tried to add the PictureBox manually by code.. but it's all the same result. The PictureBox seems to be in front of the main form, but transparent UI elements will use the BackColor of the main form instead of the Background Image of the PictureBox that's there.
What am I missing? Any help appreciated. :)
I added a slightly smaller PictureBox that I want to be the "real" background so it will create a neat border between the main form and the background image.
That background PictureBox is causing this. The smaller picture boxes with the transparent back color need to be placed directly into a container with a background image and nothing in between. For example, you could remove the background picture box and override the Form's OnPaint method to draw the background image and leave some margins:
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class LauncherForm : Form
{
public LauncherForm() : base()
{
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Black;
Padding = new Padding(20);
ControlBox = false;
FormBorderStyle = FormBorderStyle.None;
}
private Image bgImage;
public new Image BackgroundImage
{
get => bgImage;
set { bgImage = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = new Rectangle(Padding.Left, Padding.Top,
Width - Padding.Left - Padding.Right,
Height - Padding.Top - Padding.Bottom);
g.Clear(BackColor);
if (BackgroundImage != null)
g.DrawImage(BackgroundImage, r);
g.DrawRectangle(Pens.DimGray, r);
}
}
Another option is to do the same but with a Panel control to host the other picture boxes:
Select your project.
Right click and select Add -> Class...
In the add dialog, rename the class to LauncherPanel.cs and hit the Add button.
Replace the class block only (keep the namespace) in the new class with the code below.
Save and rebuild.
Open the designer, check the top of the ToolBox window, you'll find the new control LauncherPanel under the components of your project.
Drop an instance into the designer.
Select the control and press F4 key to activate the Properties window. Set the Image property and optionally the BorderColor and BorderWidth properties.
Add the other picture boxes into the launcherPanel1 or whatever you name it.
using System;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
// Within the namespace of your project..
[DesignerCategory("")]
public class LauncherPanel : Panel
{
public LauncherPanel() : base()
{
DoubleBuffered = true;
ResizeRedraw = true;
BackColor = Color.Black;
}
private Image bgImage;
public Image Image
{
get => bgImage;
set { bgImage = value; Invalidate(); }
}
private Color borderColor = Color.DimGray;
[DefaultValue(typeof(Color), "DimGray")]
public Color BorderColor
{
get => borderColor;
set { borderColor = value; Invalidate(); }
}
private int borderWidth = 1;
[DefaultValue(1)]
public int BorderWidth
{
get => borderWidth;
set { borderWidth = value; Invalidate(); }
}
protected override void OnPaint(PaintEventArgs e)
{
var g = e.Graphics;
var r = ClientRectangle;
r.Width--;
r.Height--;
g.Clear(BackColor);
if (Image != null)
g.DrawImage(Image, r);
using (var pn = new Pen(borderColor, borderWidth))
g.DrawRectangle(pn, r);
}
}
Choosing the Panel option, you will get something like this at design time:
And like this at runtime:
Make sure you have transparent PNG images for the picture boxes in the Panel.

New form is not reporting its size as I expect

Continue from the overlay window's incorrect size problem.
So here is the minimum system:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.Size = new Size(1920, 1080);
MessageBox.Show("x:" + this.Size.Width + " y:" + this.Size.Height);
}
}
}
It says my window size is 1438x818 (even though it does appear to fill the desktop area of the screen)....
Did some new research
The problem starts to occur when my size is set larger than 14xx by 83x
Any size larger than that will be restricted to 14xx by 83x
if I say
this.size = new Size (500,500);
then it is okay...
[Final edit]
Well. I think I found the problem.
https://social.msdn.microsoft.com/Forums/vstudio/en-US/60e3b413-7746-46d4-8351-0c7f4e38378f/does-form-size-has-any-limitation-like-maximum-width-or-maximum-height?forum=netfxbcl
The form size does have a hidden limit and it seems that fixing it is out of my ability as an indie developer. I cannot find where is a hidden limitation is..
What I need to do is map the logic coordinate of anything in my form to a new world coordinate based on 1436/1920 scale ratio. Problem bypassed.
If you want to set size as 1920x1080 you can try this.
this.MinimumSize = new Size(1920, 1080);
this.MaximumSize = new Size(1920, 1080);
The size of the form must be lesser than or equal to current screen size.
Besides you can change the ClientSize of the form by
this.ClientSize = new System.Drawing.Size(1920, 1080);

How to render an image on the screen C#

I have been trying to create a test program that just displays a bitmap image on the screen for a while now. Ideally, the image would be translucent (have an alpha channel) and "click throughable." However, I have not found any way to do this.
The application that I have for this is a keyboard indicators app that runs in the background and displays a popup image onscreen for a couple seconds whenever a modifier like num lock or caps lock is pressed.
What I have found is an MSDN example for how to render an image on the screen, but I haven't been able to make this work properly in a Windows Forms app. In the Form1.cs of a blank WFA app, I have:
using System.Drawing;
using System.Windows.Forms;
namespace KeyboardIndicators
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
PictureBox pictureBox1 = new PictureBox();
pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.Form1_Paint);
}
private void Form1_Paint(object sender, System.Windows.Forms.PaintEventArgs pe)
{
Bitmap myBitmap = new Bitmap("Profile Image.jpg");
Graphics g = pe.Graphics;
g.DrawImage(myBitmap, 100, 100);
}
}
}
I am probably missing a lot here, but I am not having much luck debugging it in Visual Studio.
I have yet to find a site online that fully describes how to do something like what I would like to do. I have seen this kind of thing done before in other apps, so I know it can be done somehow.
I found the answer to my question thanks to the initial answer by #Habeeb on this question, which inspired me to research that method. By looking at this Q/A, I realized I didn't need to create a helper function to do this. To #Idle_Mind's point also, I set the WS_EX_TRANSPARENT flag to transparent.
This is the code I ended up with in my Form1.cs file: (I ended up changing the test image to cube.png, a .png image with an alpha channel)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace KeyboardIndicators {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
PictureBox pictureBox = new PictureBox();
Image myBitmap = Image.FromFile("cube.png");
Size bitmapSize = new Size(myBitmap.Width, myBitmap.Height);
this.Size = bitmapSize;
pictureBox.ClientSize = bitmapSize;
pictureBox.Image = myBitmap;
pictureBox.Dock = DockStyle.Fill;
this.Controls.Add(pictureBox);
this.FormBorderStyle = FormBorderStyle.None;
}
protected override CreateParams CreateParams {
get {
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
}
}
When run, the following is shown onscreen:
This works for me, as it is overlayed on all apps I need, is semi-transparent and is click-throughable.
From your code, I do not see the Bitmap image is set to the PictureBox.
Please try the below code:
pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage ;
MyImage = new Bitmap(fileToDisplay);
pictureBox1.ClientSize = new Size(xSize, ySize);
pictureBox1.Image = (Image) MyImage ;
If you want to add PictureBox via code, see below:
private void Form1_Load(object sender, EventArgs e)
{
var picture = new PictureBox
{
Name = "pictureBox1",
Size = new Size(xSize, ySize),
Location = new Point(100, 100),
Image = Image.FromFile("hello.jpg"),
};
this.Controls.Add(picture);
}
The first piece of code shows how to update image, but a different approach.

how to take snapshot from rendered HTML in WPF

Is there any way to take a snapshot of rendered html, i.e from webBrowser control and make an image object of the output?
is it possible by code besides using webbrowser, bcoz i think it needs to be visible on screen before the source is render as output.
i have html string which contains some picture text and table. of height of almost 700px, could be less or more on other scenario.
please guide me on this.
Use a RenderTargetBitmap instance. This allows you to render a control without displaying it on screen. Be careful to give it a width and height ;)
http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.rendertargetbitmap%28v=vs.110%29.aspx
Sample from MSDN
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Globalization;
namespace SDKSample
{
public partial class RenderTargetBitmapExample : Page
{
public RenderTargetBitmapExample()
{
Image myImage = new Image();
FormattedText text = new FormattedText("ABC",
new CultureInfo("en-us"),
FlowDirection.LeftToRight,
new Typeface(this.FontFamily, FontStyles.Normal, FontWeights.Normal, new FontStretch()),
this.FontSize,
this.Foreground);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
drawingContext.DrawText(text, new Point(2, 2));
drawingContext.Close();
RenderTargetBitmap bmp = new RenderTargetBitmap(180, 180, 120, 96, PixelFormats.Pbgra32);
bmp.Render(drawingVisual);
myImage.Source = bmp;
// Add Image to the UI
StackPanel myStackPanel = new StackPanel();
myStackPanel.Children.Add(myImage);
this.Content = myStackPanel;
}
}
}

How do I draw a circle and line in the picturebox?

How do I draw a circle and line in the picturebox?
or:
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(
new Pen(Color.Red,2f),
new Point(0,0),
new Point(pictureBox1.Size.Width, pictureBox1.Size.Height ));
e.Graphics.DrawEllipse(
new Pen(Color.Red, 2f),
0,0, pictureBox1.Size.Width, pictureBox1.Size.Height );
}
Handle the paint event of the picture box and do your custom drawing there.
The best way is to NOT draw a circle and line in a picturebox! It is not designed for that purpose.
From Bob Powell's GDI+ blog:
The root of this problem is that the fundamental rules of windows
programming have been broken. And as a consequence of the picture box
is blamed for something that's really not its fault. To help explain
why, the four points below outline what's gone wrong in this case.
The PictureBox control is for displaying images. It is not a handy placeholder for a graphics surface.
Windows is an event driven system in which each event must be serviced in the correct context and events destined to handle button click or mouse move events must not be used to do drawing on screen or other weird stuff.
The PictureBox refreshes itself by drawing the System.Drawing.Image based object stored in it's Image property. If there is no image, it will show the background colour.
Stealing and drawing upon the Graphics object of any control is not good practice, should be strongly discouraged and breaks the rules of handling events in the right place at the right time. Basically if you do this it will cause you pain. When you bang your head against a wall it causes you pain. that is a sign that you should stop doing it. It's the same for the PictureBox.CreateGraphics call.
The right way to do it.
Following the rules of the event driven system is easy but requires a
little forethought. So, if you want to draw some little bit of
graphics and have it remain there when a window moves in front of it
and away again or when you minimize and restore, you have to service
the Paint event of whatever object it is that you wish to paint on.
The PictureBox carries baggage around with it that is unnecessary for
this kind of application. If you just want to draw something in one
place, draw it on the form by responding to the Form.Paint event. If
you want a handy placeholder for a graphic that works within a set
bounds, use a Panel control and service it's Paint event. If you want
to duplicate a graphic over and over for your corporate image, create
a control and do the drawing in the OnPaint override.
Source: https://web.archive.org/web/20120330003635/http://bobpowell.net/picturebox.htm (the original site is defunct).
the picturebox is a control and has an image as source - so you have to draw on the image and hand the image to the control to show it
MyImage = new Bitmap(fileToDisplay);
pictureBox1.ClientSize = new Size(xSize, ySize);
pictureBox1.Image = MyImage;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Asssignment
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Graphics g = this.CreateGraphics();
Pen p = new Pen(Color.Blue);
int radius = 200;
int x =Width/2;
int y =Height/2;
int first_point1 = (int)(Math.Cos(0) * radius + x);
int first_point2 = (int)(Math.Sin(0) * radius + y);
Point p1= new Point(first_point1,first_point2);
for(int i=1;i<500; i++)
{
int dx = (int)(Math.Cos(i)*radius+x );
int dy = (int)(Math.Sin(i)*radius+y );
Point p2 = new Point(dx, dy);
g.DrawLine(p, p1, p2);
p1 = p2;
}
}
}
}

Categories