Non-Clipped Overlapped Image - c#

I would like a transparent overlapped non-clipped image. I have one PictureBox overlapping another, as shown in this SO thread.
The solution, which makes sense, sets the parent of the top image to the bottom image. The top image is then set to have a transparent background. The technique works perfectly, just setting the parent of the top image to that of the bottom clips the top image to the area of the bottom image.
Top Image Parent Property NOT Set to the Bottom Image
Now, here is what happens if the top image parent property gets set to the bottom image.
I do not want the top image clipped.
I would volunteer the entire Visual Studio 2019 (VS2019) project, but not sure how to post it.
Here is the code:
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
//this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Left = (int)this.ChangeX.Value;
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.ImgTop.Top = (int)this.ChangeY.Value;
}
}
}
I put 2 NumericUpDown controls to better adjust the position of the finger pointer.
The call to method BringToFront() can be deleted, as does nothing, just above as mentioned in a couple of answers and used for testing.
UPDATE
I do NOT want to stretch the bottom image. I want to see the form background.
I also realize that the hand pointer is out of bounds of the bottom (parent) image. As such, the hand pointers gets clipped, cut off.
I want to the entirety of the top image to show, just the part of the top image, which overlaps the bottom image to be transparent.
Using what has got to be the world's best app, Paint.Net, here is what I want, also in a nice reusable code format.
My thought towards a solution is at the moment to make a programmatic copy of the hand pointer and overlay that using onto the form just clipping the left portion, which overlaps the bottom image. I think this idea might work, will post as answer if it works.

This answer can probably be optimized and made more reusable, but it works.
I created a copy of the top control. I then used this updated code, which includes a reusable method.
using System;
using System.Drawing;
using System.Windows.Forms;
namespace ImageOverlap
{
public partial class FrmMain : Form
{
public FrmMain()
{
InitializeComponent();
}
private void FrmMain_Load(object sender, EventArgs e)
{
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ChangeX.Value = 430;
this.ChangeY.Value = 15;
}
private void ChangeX_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation((int)this.ChangeX.Value, this.ImgTop.Top);
}
private void ChangeY_ValueChanged(object sender, EventArgs e)
{
this.SetOverlayImageLocation(this.ImgTop.Left, (int)this.ChangeY.Value);
}
private void SetOverlayImageLocation(int newX, int newY)
{
this.ImgTop.Left = newX;
this.ImgTop.Top = newY;
Point ptImageAtParent = new Point(this.ImgTop.Left + this.ImgBottom.Left, this.ImgTop.Top + this.ImgBottom.Top);
this.ImgTopCopy.Location = ptImageAtParent;
this.ImgTopCopy.SendToBack();
}
}
}
I am thinking that .Net probably has a nice method/property to get the point relative to the parent. I did that in a brute force method. I then set the copy to the back. The location of the copy is set relative to the parent. The trick is that the copy has the parent property set to the main control.
Here is the runtime visual that I got, no Paint.Net involved; looks identical, which is the objective.
The nice part is that the NumericUpDown controls work flawlessly moving the combined image, which to the user appears as one image.

You want the entire image render on bottom image, if yes it means your problem is calculation of top image position.
this.ImgTop.Parent = this.ImgBottom;
this.ImgTop.BackColor = Color.Transparent;
this.ImgTop.BringToFront();
this.ImgTop.Top = 0;
this.ImgTop.Left = ImgBottom.Width - ImgTop.Width;
I see your replay to Reza, sorry for misunderstood. you set the parent of top image to bottom image. the control can't do any more actions outside of parent area after this. if you want to do that you can dynamically split your image into to separate image controls, one of theme inside the bottom image and another outside and control position of both of theme or implement own control maybe by the help of polygons.

Related

Fix background crush C# winforms

I work on MDIParent with background image after i move a child from in it the background image crush like this
how can i solve this issue in C# winforms??
The MDIClient Control is the object used, in Multiple-Document Interface, as the Container for all child Forms.
This Control has a BackGroundImage property. You can set an Image object using this property, instead of using the [MDIParent].BackGroundImage. This would actually solve the Image tearing problem.
But, you can't set a specific Layout property. See the Docs about the MDIClient BackgroundImageLayout:
This property is not relevant to this class.
You can set this property, but it's ignored: the default ImageLayout.Tile is used instead.
A different Layout can be set, assigning the Image object to the MDIParent BackGroundImage and specifying a BackGroundImageLayout. This will change the Layout, but it will also cause the tearing effect you are reporting.
A possible solution is to draw the Image object on the MDIClient surface, using it's Paint() event as usual.
This will solve the tearing effect. Not the flickering; this can be noticed when you resize the MDIParent Form (well, MDI applications are not resized that often, maybe maximized and normalized).
Some flickering can be seen when the background Image is not covered by a child Form.
A small adjustment to the Image specs is required: setting its DPI resolution = to the MDIParent reported device context DPI, otherwise the Image size will not match the default size (it's affected by the DPI resolution).
See this post for a description:
Image is not drawn at the correct spot.
An example:
(Here, I assume the background Image is loaded from the Project resources)
public partial class MDIParent : Form
{
private MdiClient mdiBackground = null;
private Bitmap BackGroundImage = null;
public MDIParent()
{
InitializeComponent();
//Specify an existing Resources' Image
BackGroundImage = new Bitmap(Properties.Resources.[Some Res Image] as Bitmap);
BackGroundImage.SetResolution(this.DeviceDpi, this.DeviceDpi);
}
private void Form1_Load(object sender, EventArgs e)
{
mdiBackground = this.Controls.OfType<MdiClient>().First();
mdiBackground.Paint += (s, evt) => {
evt.Graphics.DrawImage(BackGroundImage,
(mdiBackground.Width - BackGroundImage.Width) / 2.0F,
(mdiBackground.Height - BackGroundImage.Height) / 2.0F);
};
//Show some child Forms on start-up
}
private void Form1_Resize(object sender, EventArgs e)
{
if (this.mdiBackground != null) mdiBackground.Invalidate();
}
private void MDIParent_FormClosed(object sender, FormClosedEventArgs e)
{
if (BackGroundImage != null) BackGroundImage.Dispose();
}
}

Center C# form on secondary screen

Quick question, hopefully an easy fix.
I am kinda new to C# and am trying to center a second form, on the secondary screen when it opens. So far I can get it to open on the second screen no problem but it sits in the top left and I cant get it to center. I am aware of the fact that the Location = Screen.AllScreens[1].WorkingArea.Location; will put it in the top left part of said working area. I was wondering if there is a way to (essentially) change the .Location to something else that will center regardless of actual screen size? This will be going onto multiple different systems with varying screen sizes.
Here is the code that I have so far.
On the first form.
public partial class FrmPrompt : Form
{
public FrmPrompt()
{
InitializeComponent();
}
private void ButNo_Click(object sender, EventArgs e)
{
frmConfirm confirm = new frmConfirm();
Screen[] screens = Screen.AllScreens;
lblConfirmMsg.Text = "Please Wait For Customer To Confirm...";
butContinue.Hide();
confirm.Show();
}
}
On the second form:
public partial class frmConfirm : Form
{
public frmConfirm()
{
InitializeComponent();
Location = Screen.AllScreens[1].WorkingArea.Location;
}
private void pictureBox1_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
Thanks!
CenterScreen will locate Form on current screen, so if your FrmPrompt on second screen, when you clicking ButNo - this will work. But I think this is not you asking for.
More then that, CenterScreen will overwrite any location setting of your from Location that was setted before Show method invocation. So I suggests to override OnShown method of frmConfirm
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
var area = Screen.AllScreens[1].WorkingArea;
var location = area.Location;
location.Offset((area.Width - Width) / 2, (area.Height - Height) / 2);
Location = location;
}
try this on the first form, no need to set anything in the 2nd form.
//put it after this line: frmConfirm confirm = new frmConfirm();
confirm.StartPosition = FormStartPosition.CenterScreen;

C#, BindingNavigator, SplitButton, Ugly dot remaining

Draw a toolstrip on an empty form. Add a SplitButton on this toolstrip. Will be working as a login in button later on.
On this SplitButton I want to remove the dropdown in the start position. The only thing you can do is to login. Once you have logged in, the dropdown is populated with items like "Change Password", "Update Profile" and so on.
I have tried put the property:
loginButton.DropDownButtonWidth = 0;
this almost removes the drop down, it is gone, but its a very ugly dot on the right, which seems like to be one pixel left from the drop down corner. See images below:
I have tried a lot of other properties to remove the drop down, but no progress. And I cant find anything similar when I google.
I got excellent help fix another problem with the tool strip a few days back, the tool strip had a drawing problem too in its default state. but is removed if you do override a method, see this post:
Toolstrip drawing problem
Does anyone know how I can remove the ugly dot, or remove the drop down some other way?
Full source, one line essentially with the SplitButton named loginButton:
using System;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
loginButton.DropDownButtonWidth = 0;
}
}
}
You can use your own renderer to try to achieve that:
private class NoArrowRenderer : ToolStripProfessionalRenderer {
protected override void OnRenderArrow(ToolStripArrowRenderEventArgs e) {
if (e.Item.GetType() != typeof(ToolStripSplitButton)) {
base.OnRenderArrow(e);
}
}
}
Then apply it to your ToolStrip:
toolStrip1.Renderer = new NoArrowRenderer();

How to do two different graphics plotting in parallel using C#

I am developing the GUI in C# using picturebox, button, and check box.I need to plot two different plots in parallel using one text file on an image. The image first reads in a picture box. The rest of the program has to be executed in the following way:
Reads text file contains the data points which have to be plotted.
After clicking the button the program execution started with the plotting of the First graphic (rectangular dot), however when the check box is checked the second graphic (continuous dots--path plot) plotting started in parallel with the first graphic.
when the check box is unchecked the second graphic stopped plotting and disappears.(As Both of the graphics style using the same text file).
I need help what to do in this case, should I create the separate thread for check box for this parallel plotting??
please help me where I am mistaken? And pardon my horrible English
From my point of view, the easiest way would be to reload the image into the picture box again and then redraw the first graphics object on it. So, the second one 'disappears'.
An additional thread makes no sense, because drawing must occur on the UI thread only (Windows general rule for GDI+, WinForms, WPF).
Such basic drawing as in your example is very fast.
Edit:
namespace PictureBoxDrawing
{
public partial class Form1 : Form
{
private Bitmap _bmpImage;
public Form1()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_bmpImage = new Bitmap(#"C:\Image.jpg");
InitializePictureBox(_bmpImage);
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
DrawPictureBox(pictureBox1, 10, 10, checkBox1.Checked);
}
private void button1_Click(object sender, EventArgs e)
{
DrawPictureBox(pictureBox1, 10, 10, checkBox1.Checked);
}
private void button2_Click(object sender, EventArgs e)
{
InitializePictureBox(_bmpImage);
}
private void DrawPictureBox(PictureBox pb, int x, int y, bool drawBlue)
{
using (Graphics g = pb.CreateGraphics())
{
g.FillRectangle(Brushes.Red, x,y, 9,9);
if(drawBlue)
g.FillRectangle(Brushes.Blue, x, y, 7, 7);
}
}
private void InitializePictureBox(Bitmap bmp)
{
pictureBox1.Image = bmp;
}
}
}
From your example, here is my simplified suggestion. Load and cache the bitmap in a field for later use. I have added a second button2, which can be used to reload the image into the picture box to demonstrate the behaviour. Because the red rectangle is greater than the blue (9 > 7), it overwrites it when redrawing. So it is not necessary to reload the bitmap, if the position is constant. If the position changes, call InitializePictureBox prior to the DrawPictureBox call.

How do I resize a dynamically created text box by dragging with mouse like in paint programs?

I have created a text box, inside a PictureBox, on mouse click at run time. Now I want to resize it using mouse drag. Is there some simple way to do this ?
Here is the code I have so far:
public partial class Form1 : Form
{
public static TextBox PTB; //declaring text box to be created
public static bool textOption; //stores the state of button , i.e whether or not text box button is clicked before or not
public Form1()
{
InitializeComponent();
this.pictureBox1.Click += new System.EventHandler(this.pictureBox1_Click);
}
private void pictureBox1_Click(object sender, EventArgs e)
{
if (textOption == true)//if user selected option to draw text box
{
MouseEventArgs eM = (MouseEventArgs)e; //create an instance of mouse event
PTB = new TextBox();//dynamically creating text box
PTB.Location = new System.Drawing.Point(eM.X, eM.Y);//settign position of textbox where mouse was clicked
PTB.Name = "textBox1";
PTB.Size = new System.Drawing.Size(100, 20);//size of text box
this.pictureBox1.Controls.Add(PTB);//adding the textbox to the picture box
}
}
Update
I'm sorry I have totally misread your question.
The reason is probably that you seem to be under the impression that Paint programs have TextBoxes sitting on their canvas. They don't. They draw text the same way as they draw lines or circles etc..
Also: Resizing the TextBox will not change the Font size, in case that's is what you want.
Finally: A TextBox will never be transparent, it will always sit on the PictureBox and look, well, like a TextBox. Not like anything in a Paint programm..
But: If you actually do want to resize the TextBox here are a few hints:
You need some way to show the user they are on the right spot by changing the cursor to the right icon
You need to store the mouse down point (attention: it will be inside the TextBox!) and keep track of the increments in the MouseMove. As long as the Button is down all rported e.Location will still be in the TextBox coordinates.
Use the increments (not the absolute values) to increase the size of the TextBox.
It is really hard to get the resizing right on the top and left sides. (Because it will involve moving at the same time), so better don't try!
Do include moving, which is easy and will suffice for all you need.
No, this is a good deal harder than increasing font size. 200-300 lines of code, the last time I did it..
But you may find another somewhat simpler answer; look for "Resize Control with Mouse winforms c#" on Google..
I leave the old answer in place, even if it not what you were looking for..
Old answer about changing font size while placing text:
It is not very hard but you need to get it right; it is basically the same as drawing a Rectangle
with a live preview. You need these things: four events, a Point or two, a Size and a font variable..
The events are:
MouseDown
MouseMove
MouseUp
Paint
You need to store a point for the placement (in the MouseDown event) and a size you update in the MouseMove.
From that size you can calculate the maximum Font size you can fit in the Rectangle.
On MouseUp you finalize things.
In the Paint event you draw string at the down Point with the current Font size.
In the MouseMove you call Invalidate on the PictureBox to trigger the Paint event.
in the MouseMouve you should check the Button to be the left one.
For extra good UI you can also check the keyboard for space and use it to move the DownPoint..
The Click event is rather useless, btw..
Here is a minimal code example to get you started:
Point mDown = Point.Empty;
float fSize = 12f;
private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
using (Font font = new Font("Consolas", fSize))
e.Graphics.DrawString("Hello World", font, Brushes.Black, mDown);
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
mDown = e.Location;
pictureBox1.Invalidate();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
fSize = Math.Abs(e.Y - mDown.Y) / 2f + 1;
pictureBox1.Invalidate();
}
I left out the MouseUp. Here you would store the final state (font, location..) of the drawn string somewhere or persist it by drawing into a Bitmap etc..
I also didn't do a full Rectangle calculation but determined the font size by simply scaling the y-movement down a little.. You could improve with a little pythagoras ;-)
The ability to resize a window is innate behavior, provided by the default window procedure built into Windows. All you have to do is give the control a resizable border. Everything else is for free, you'll get the correct cursor and dragging a corner or edge resizes the control.
using System;
using System.Windows.Forms;
class ResizeableTextBox : TextBox {
protected override CreateParams CreateParams {
get {
var cp = base.CreateParams;
cp.Style |= 0x840000; // Turn on WS_BORDER + WS_THICKFRAME
return cp;
}
}
}
This sample will create the TextBox on the MouseDown event and start resizing, the final size of the TextBox will be where the mouse button is released on the MouseUp event. It will let you create multiple textboxes as well.
I realize this might not be exactly what you want but it might be a start.
private int _textBoxCounter;
private TextBox _textBoxCurrentResizing;
public Form1()
{
InitializeComponent();
pictureBox1.MouseDown += PictureBox1OnMouseDown;
pictureBox1.MouseUp += PictureBox1OnMouseUp;
pictureBox1.MouseMove += PictureBox1OnMouseMove;
}
public Point RelativeMousePosition { get { return PointToClient(MousePosition); } }
private void PictureBox1OnMouseMove(object sender, MouseEventArgs mouseEventArgs)
{
ResizeTextBox();
}
private void PictureBox1OnMouseUp(object sender, MouseEventArgs mouseEventArgs)
{
EndResizeTextBox();
}
private void PictureBox1OnMouseDown(object sender, MouseEventArgs mouseEventArgs)
{
var tb = CreateTextBox();
StartResizeTextBox(tb);
}
private TextBox CreateTextBox()
{
var tb = new TextBox
{
Location = RelativeMousePosition,
Size = new Size(100, 20),
Multiline = true,
Name = "textBox" + _textBoxCounter++,
};
pictureBox1.Controls.Add(tb);
return tb;
}
private void StartResizeTextBox(TextBox tb)
{
_textBoxCurrentResizing = tb;
}
private void ResizeTextBox()
{
if (_textBoxCurrentResizing == null) return;
var width = Math.Abs(_textBoxCurrentResizing.Left - RelativeMousePosition.X);
var height = Math.Abs(_textBoxCurrentResizing.Top - RelativeMousePosition.Y);
_textBoxCurrentResizing.Size = new Size(width, height);
}
private void EndResizeTextBox()
{
_textBoxCurrentResizing = null;
}

Categories

Resources