C# transparent image above 2 images - c#

I have make a playbar for my new MP3 player but I have a problem as shown in attachement
and this is my simple code :
public void setpercent(int percent)
{
pic1.Width = pic2.Width / 100 * percent;
pic3.Left = pic1.Width - ( pic3.Width /2);
}
I thought to use Graphics but I can't move it after.
and the method of ".Parent" doesn't work in this case.

In the Load() event of your Form, modify the Region() property of pic3 so that it becomes circular instead of rectangular. This can be done by construction a GraphicsPath and adding an Ellipse to it. If this doesn't line up properly with your image, then manually determine the correct bounding box for the ellipse and use that instead:
private void Form1_Load(object sender, EventArgs e)
{
System.Drawing.Drawing2D.GraphicsPath GP = new System.Drawing.Drawing2D.GraphicsPath();
GP.AddEllipse(pic3.ClientRectangle);
pic3.Region = new Region(GP);
}

Related

How do I keep previously painted objects from disappearing when a new one is creating in a Windows Form Application?

My problem is that within my Windows Form Application, I want to draw an Ellipse everytime the mouse is clicked within a specific picture box, and I want the previously drawn ellipses to remain present in the picture box.
In its current state, once the mouse is clicked, the previously drawn ellipse will be replaced with the new one drawn at the cursor's new location.
Ball.Paint draws an ellipse.
Here is the relevant code to the problem:
private Ball b;
private void pbField_Paint(object sender, PaintEventArgs e)
{
if (b != null)
b.Paint(e.Graphics);
}
private void pbField_MouseClick(object sender, MouseEventArgs e)
{
int width = 10;
b = new Ball(new Point(e.X - width / 2, e.Y - width / 2), width);
Refresh();
}
If there is any more needed code or information I am able to provide it.
You need some sort of data structure to store prior ellipses. One possible solution is below:
private List<Ball> balls = new List<Ball>(); // Style Note: Don't do this, initialize in the constructor. I know it's legal, but it can cause issues with some code analysis tools.
private void pbField_Paint(object sender, PaintEventArgs e)
{
if (b != null)
{
foreach(Ball b in balls)
{
b.Paint(e.Graphics);
}
}
}
private void pbField_MouseClick(object sender, MouseEventArgs e)
{
int width = 10;
b = new Ball(new Point(e.X - width / 2, e.Y - width / 2), width);
balls.Add(b);
Refresh();
}
If you want more than one ball to be painted, you need to keep track of a list of balls, rather than just b. Every time the control is refreshed, it is expected to redraw all its contents. That means that in pbField_Paint, you need to be ready to draw as many balls as have been added to the scene.

PictureBox Refresh causes layers above to flicker

I am trying to read data from ports and show that on a dial. the background is a PictureBox containing the image of a circular scale giving readings, and a Lineshape has been used to represent the dial. The PictureBox has been 'sent to back' to allow visibility of the Lineshape. I'm enclosing representative codes:
if i do this:
private void timer1_Tick(object sender, EventArgs e)
{
ang += 2.0 * Math.PI / 180.0;
lineShape1.X1 = Convert.ToInt32(lineShape1.X2 - r * Math.Sin(ang));
lineShape1.Y1 = Convert.ToInt32(lineShape1.Y2 - r * Math.Cos(ang));
}
then it leaves a trace on the PictureBox.
But if i use the Refresh function of the PictureBox, then the dial appears to flicker. i have tried with timer intervals of 10, 15, 20, 50 and 100, but the problem persists.
private void timer1_Tick(object sender, EventArgs e)
{
ang += 2.0 * Math.PI / 180.0;
lineShape1.X1 = Convert.ToInt32(lineShape1.X2 - r * Math.Sin(ang));
lineShape1.Y1 = Convert.ToInt32(lineShape1.Y2 - r * Math.Cos(ang));
pictureBox1.Refresh();
}
For the sake of the actual problem, it is not possible to increase the interval. What can i do to Show a smooth variation of the dial?
As #Hans Passant suggested, you should not be using a LineShape object. This is a example of code that implement his suggestion (quick, untested):
private void timer1_Tick(object sender, EventArgs e)
{
pictureBox1.Invalidate();
}
void pictureBox1_Paint(object sender, PaintEventArgs e)
{
ang += 2.0 * Math.PI / 180.0;
var X1 = Convert.ToInt32(X2 - r * Math.Sin(ang));
var Y1 = Convert.ToInt32(Y2 - r * Math.Cos(ang));
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.DrawLine(
new Pen(Color.Yellow, 1f),
new Point(X1, Y1),
new Point(X2, Y2 ));
}
Also, try to set this.DoubleBuffered = true; to avoid the flickering problem.
GDI+ is known to have this effect, in general. This is why WinForms has generally been replaced with WPF and XAML. I think, IIRC, PictureBox is especially prone to this problem. What you need to do is perform all of your "drawing" on the image in the PictureBox outsde of the PictureBox. Once all of your drawing is complete, update the PictureBox with the new image.
However, if you're drawing new images really quickly and subsequently updating the PictureBox, you're still likely to get flicker. PictureBox was just not designed for this use case. It's designed, more or less, to display a static image (or one that may change occassionally, but not at a high frequency).

Lag when using graphics.drawline in winforms/C#

Beginner coder here getting into C#.. I'm making a program that involves drawing. Basically whenever I'm moving my mouse to draw, the actual line on the image appears delayed - and it's more.. straight, than it's supposed to be. It used to work fine, but at some point I guess something went wrong - can't remember what I did at the time so it's hard to retrace.. I tried to replicate just the drawing part of the program in a new solution, and it seems to work fine..
I'd post the .exe file so you can see what I mean but I'm not sure if we're allowed to post executables around here.
Edit: I've confirmed that the code works fine, look at the answer by sa_ddam213 for an example of the code. It seems as though it works fine in other peoples computers, so I'm completely confused.
Yo are creating a new Graphic and Pen object with every mouse move event, this will be a lot slower than creating these variables once in the Mouse_Down event.
Something like this may be a bit faster.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
b = new Bitmap(this.Width, this.Height);
}
private Graphics _graphics;
private Pen _pen;
private int pX = 0;
private int pY = 0;
private bool paint = false;
private Bitmap b;
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
pX = e.X;
pY = e.Y;
_graphics = Graphics.FromImage(b);
_pen= new Pen(Color.Black, 3);
paint = true;
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (paint)
{
_graphics.DrawLine(_pen, pX, pY, e.X, e.Y);
pictureBox1.BackgroundImage = b;
pictureBox1.Refresh();
pX = e.X;
pY = e.Y;
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
paint = false;
_graphics.Dispose();
_pen.Dispose();
}
}
Instead of pictureBox1.Invalidate(), try using pictureBox1.Refresh()
You might also need to move it AFTER the pictureBox1.BackgroundImage = b
Also, in your MouseDown, you need to set this.Capture = true, and in your MouseUp you should set this.Capture = false. If you don't do that and you release the mouse button while your mouse cursor is over a different application, your's will never receive the MouseUp message.
May be It's a problem with your VGA . Check with another PC and let us know

How to do Free hand Image Cropping in C# window application?

How to do Free hand Image Cropping in C# window application??
Okay, you provided very small amount of information, but I'll assume that you are using winforms. There are some tasks dealing with freehand-technique such as:
Drawing
Drag-n-dropping
Cropping
Selecting
They all are very similar. Let's assume that you have a PictureBox and want to crop an image inside it.
// Current selection
private Rectangle _cropRectangle;
// Starting point
private Point _cropStart;
// Dragging flag
private bool _isDragging;
private void pBox_MouseDown(object sender, MouseEventArgs e)
{
_cropRectangle = new Rectangle(e.X, e.Y, 0, 0);
_isDragging = true;
}
private void pBox_MouseUp(object sender, MouseEventArgs e)
{
_isDragging = false;
}
private void pBox_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDragging)
return;
_cropRectangle = new Rectangle(Math.Min(_cropStart.X, e.X),
Math.Min(_cropStart.Y, e.Y),
Math.Abs(e.X - _cropStart.X),
Math.Abs(e.Y - _cropStart.Y));
pBox.Invalidate();
}
private void pBox_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawRectangle(Pens.Red, _cropRectangle);
}
What happens: I make use of three mouse events (MouseDown, MouseUp, MoseMove) and the Paint event. Basically, whenever you want to do anything from the above list, you'll have handle these four events.
I tried to keep the code short and self-explanatory. There are four event handlers working with three instance fields. The fields are used to store the current state of dragging process.
Feel free to customize the code, especially the pBox_Paint handler. Mine just draws a thin red rectangle around selected area. You might want to do something more elaborate here.
Whenever you're done with your rectangle, you can call the Crop method:
private Image Crop()
{
Bitmap croppedImage = new Bitmap(_cropRectangle.Width, _cropRectangle.Height);
using (Graphics g = Graphics.FromImage(croppedImage))
{
g.DrawImage(pBox.Image, 0, 0, _cropRectangle, GraphicsUnit.Pixel);
}
return croppedImage;
}
It creates a new Bitmap and put the selected portion of source image into it. The returned Image object might be used in any manner you like.
EDIT: trying to simplify the code I made some mistakes earlier, fixed now.
You can use Graphics.DrawImage to draw a cropped image onto the graphics object from a bitmap.
Rectangle cropRect = new Rectangle(...);
Bitmap src = Image.FromFile(fileName) as Bitmap;
Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
using(Graphics g = Graphics.FromImage(target))
{
g.DrawImage(src, cropRect,
new Rectangle(0, 0, target.Width, target.Height),
GraphicsUnit.Pixel);
}
You can also refer the full code for this....
Refer this *Link*

A PictureBox Problem

I have a problem:
I have 3 picture boxes with 3 different images as in Image
what can i set to pictureBox3 so both images look same.....
EDITED:
I want to move pictureBox3 on pictureBox2,
So there is no Option to merge them to single image
Make sure the image in pictureBox3 is transparent. Set the BackColor to transparent. In code, set the Parent property of the pictureBox3 to be pictureBox2. Adjust the Location coordinates of pictureBox3 since they will be relative to the coordinates of pictureBox2 once you've changed the Parent.
private void Form1_Load(object sender, EventArgs e)
{
pictureBox3.Parent = pictureBox2;
pictureBox3.Location =
new Point(
pictureBox3.Location.X
- pictureBox2.Location.X,
pictureBox3.Location.Y
- pictureBox2.Location.Y);
}
In designer you will not see the transparency, but at runtime you will.
Update
In the image, the left side shows the designer view, the right side is the runtime version.
Another update
I really don't understand how it would be possible that this doesn't work for you. I suppose there must be something we are doing different. I'll describe the exact steps to take to create a working sample. If you follow the exact same steps, I wonder if we'll get the same results or not. Next steps describe what to do and use two images I found on the net.
Using Visual Studio 2008, create a New Project using template Windows Forms Application. Make sure the project is targeted at the .NET Framework 3.5.
Set the Size of the Form to 457;483.
Drag a PictureBox control onto the form. Set its Location to 0;0 and its Size to 449;449.
Click the ellipsis besides its Image property, click the Import... button and import the image at http://a.dryicons.com/files/graphics_previews/retro_blue_background.jpg (just type the URL in the File name text box and click Open). Then click OK to use the image.
Drag another PictureBox onto the form, set its Location to 0;0 and its Size to 256;256. Also set its BackColor property to Transparent.
Using the same method as described above, import image http://www.axdn.com/redist/axiw_i.png which is a transparent image.
Now place the following code in the form's OnLoad event handler:
private void Form1_Load(object sender, EventArgs e)
{
pictureBox2.Parent = pictureBox1;
}
That's it! If I run this program I get a transparent image on top of another image.
I'll add another example that according to the updated requirement allows for moving image3.
To get it working, put an image with transparency in Resources\transp.png
This uses the same image for all three images, but you can simply replace transparentImg for image1 and image2 to suitable images.
Once the demo is started the middle image can be dragged-dropped around the form.
public partial class Form1 : Form
{
private readonly Image transparentImg; // The transparent image
private bool isMoving = false; // true while dragging the image
private Point movingPicturePosition = new Point(80, 20); // the position of the moving image
private Point offset; // mouse position inside the moving image while dragging
public Form1()
{
InitializeComponent();
//
// pictureBox1
//
this.pictureBox1.Location = new System.Drawing.Point(0, 0);
this.pictureBox1.Name = "pictureBox1";
this.pictureBox1.Size = new System.Drawing.Size(231, 235);
this.pictureBox1.TabIndex = 0;
this.pictureBox1.TabStop = false;
this.pictureBox1.Paint += new System.Windows.Forms.PaintEventHandler(this.pictureBox1_Paint);
this.pictureBox1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseDown);
this.pictureBox1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseMove);
this.pictureBox1.MouseUp += new System.Windows.Forms.MouseEventHandler(this.pictureBox1_MouseUp);
this.Controls.Add(this.pictureBox1);
transparentImg = Image.FromFile("..\\..\\Resources\\transp.png");
}
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
var g = e.Graphics;
g.DrawImageUnscaled(transparentImg, new Point(20, 20)); // image1
g.DrawImageUnscaled(transparentImg, new Point(140, 20)); // image2
g.DrawImageUnscaled(transparentImg, movingPicturePosition); // image3
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
var r = new Rectangle(movingPicturePosition, transparentImg.Size);
if (r.Contains(e.Location))
{
isMoving = true;
offset = new Point(movingPicturePosition.X - e.X, movingPicturePosition.Y - e.Y);
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (isMoving)
{
movingPicturePosition = e.Location;
movingPicturePosition.Offset(offset);
pictureBox1.Invalidate();
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
isMoving = false;
}
}
This code will do the trick:
using (Graphics g = Graphics.FromImage(pictureBox1.Image))
{
g.DrawImage(pictureBox2.Image,
(int)((pictureBox1.Image.Width - pictureBox2.Image.Width) / 2),
(int)((pictureBox1.Image.Height - pictureBox2.Image.Height) / 2));
g.Save();
pictureBox1.Refresh();
}
It will draw the image from pictureBox2 on the existing image of pictureBox1.
For starters, set the BackColor property of PictureBox3 to Transparent. This should work in almost all cases.
You should also use an image with a transparent background instead of white so you do not have the white borders around your purple circle. (Recommended image format: PNG)
Update
Following the replies I got, it appears setting the BackColor to Transparent doesn't work. In that case, it's best you handle the Paint event of the PictureBox and do the painting of the new image yourself as Albin suggested.
You might do some hack by overriding OnPaint and stuff, example here.
But I'd recommend to merge the pictures in pictureBox2 and 3 into a single image before displaying them in a single pictureBox.

Categories

Resources