This question already has answers here:
C# Drag-and-Drop: Show the dragged item while dragging
(5 answers)
Closed 8 years ago.
I am dragging a picturebox that has a background image in it onto another picturebox, and when it is dropped i will call a method that draws the image to the drop location. When it drags, it just shows the small square icon indicating that it can be dropped. How do i display the image in the picturebox being dragged?
You can add 2 PictureBoxes which have the same Location, BackgroundImage, BackgroundImageLayout, Size. 1 PictureBox is for dragging, 1 PictureBox is fixed (in Size and Location during runtime). Everything is very simple. Here is the demo code for you:
public partial class Form1 : Form {
public Form1(){
InitializeComponent();
draggingPic.Location = pictureBox2.Location;
draggingPic.Size = pictureBox2.Size;
draggingPic.Parent = this;
draggingPic.BackgroundImage = pictureBox2.BackgroundImage;
draggingPic.BackgroundImageLayout = pictureBox2.BackgroundImageLayout;
draggingPic.BorderStyle = pictureBox2.BorderStyle;
draggingPic.BringToFront();//This is important, your draggingPic should be on Top
//MouseDown event handler for draggingPic
draggingPic.MouseDown += (s, e) => {
downPoint = e.Location;
};
//MouseMove event handler for draggingPic
draggingPic.MouseMove += (s, e) => {
if(e.Button == MouseButtons.Left){
draggingPic.Left += e.X - downPoint.X;
draggingPic.Top += e.Y - downPoint.Y;
}
};
//MouseUp event handler for draggingPic
draggingPic.MouseUp += (s, e) => {
g.DrawImage(draggingPic.BackgroundImage, new Rectangle(pictureBox1.PointToClient(draggingPic.PointToScreen(Point.Empty)), draggingPic.Size));
draggingPic.Location = pictureBox2.Location;
};
//Initialize bm
//your pictureBox1 should have fixed Size during runtime
//Otherwise we have to recreate bm in a SizeChanged event handler
bm = new Bitmap(pictureBox1.Width, pictureBox1.Height);
pictureBox1.Image = bm;
g = Graphics.FromImage(bm);
}
Bitmap bm;
Graphics g;
Point downPoint;
PictureBox draggingPic = new PictureBox();
}
Initial look:
When dragging:
After some drag-drops:
Related
I have a floating borderless form that contains two buttons. When the user moves the mouse over the form, the FormBorderStyle changes to SizableToolWindow and then returns after a set time using a timer. When this happens the form shifts to accommodate the title bar and Form edge. I am able to compensate for this however when it happens you get a flicker of the form being shifted before being placed back into place.
Is there any way I can stop the window refreshing until after I have already shifted it back into place?
Here's my shifting code:
if (this.FormBorderStyle != FormBorderStyle.None)
{
// Suspend layout of Form
this.SuspendLayout();
// Suspend layout of button controls
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
this.FormBorderStyle = FormBorderStyle.None;
this.Left += this.change.Width;
this.Top += this.change.Height;
// Resume layout of buttons and Form
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
}
I ended up doing as Hans Passant suggested and creating a duplicate of my ClientRectangle area which is displayed on an already transparent full screen overlay.
My MouseLeave Event just starts the Timer.
This is the Code in my MouseEnter Event:
private void FloatingButtons_MouseEnter(object sender, EventArgs e)
{
if (this.FormBorderStyle != FormBorderStyle.SizableToolWindow)
{
if (this.Tag is Bitmap)
{
Owner.overlay.CreateGraphics().DrawImage(
(Bitmap)this.Tag,
new Rectangle(
Point.Add(this.Location, this.change),
this.ClientRectangle.Size),
new Rectangle(this.Location, this.ClientRectangle.Size),
GraphicsUnit.Pixel
);
}
this.Hide();
this.SuspendLayout();
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
if (this.change.Height == 0)
{
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
Rectangle scrPosition = RectangleToScreen(this.ClientRectangle);
this.change.Width = (scrPosition.Left - this.Left);
this.change.Height = (scrPosition.Top - this.Top);
}
this.Left -= this.change.Width;
this.Top -= this.change.Height;
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
this.Show();
if (this.Tag != null && this.Tag is Bitmap)
{
((Bitmap)this.Tag).Dispose();
this.Tag = null;
Overlay.performUpdate = true;
}
}
}
This is the code in my Timer_Tick Event:
if (this.FormBorderStyle != FormBorderStyle.None)
{
// Create a bitmap the size of my Form
Bitmap bmp = new Bitmap(this.Bounds.Width, this.Bounds.Height);
// Copy the form to the newly created Bitmap
this.DrawToBitmap(bmp, new Rectangle(Point.Empty, this.Bounds.Size));
// Create a rectangle of the Location and Size of the ClientArea
Rectangle rect = new Rectangle((Point)this.change, this.ClientRectangle.Size);
// The Owner Form contains a class that already performs overlays on the screen
Owner.overlay.CreateGraphics().DrawImage(
bmp,
new Rectangle(
Point.Add(this.Location, this.change),
this.ClientRectangle.Size),
rect,
GraphicsUnit.Pixel
);
// Store the Bitmap in the Tag for Disposal after being used
this.Tag = bmp;
// Now I can hide my Form and perform necessary changes
this.Hide();
this.SuspendLayout();
this.cbBlankDisplay.SuspendLayout();
this.btnPurgeMessages.SuspendLayout();
this.FormBorderStyle = FormBorderStyle.None;
this.Left += this.change.Width;
this.Top += this.change.Height;
this.btnPurgeMessages.ResumeLayout();
this.cbBlankDisplay.ResumeLayout();
this.ResumeLayout();
this.Show();
}
I was thinking of implementing a bitmap into a picturebox (or the otherway round), such that I could have the option to:
1.drag and drop the item (Control function with mousebuttons)
2.rotate the item (bitmap function).
This is what I have currently:
Bitmap bmp = new Bitmap(#"my source");
PictureBox item = new System.Windows.Forms.PictureBox();
I create the picturebox on the click of a button:
private void button2_Click(object sender, EventArgs e)
{
item.BackColor = Color.Blue;
item.Location = new Point(400, 200);
item.MouseDown += new MouseEventHandler(textbox_MouseDown);
item.MouseMove += new MouseEventHandler(textbox_MouseMove);
item.MouseUp += new MouseEventHandler(textbox_MouseUp);
item.MouseWheel += new MouseEventHandler(textbox_MouseWheel);
item.Image = bmp;
item.SizeMode = PictureBoxSizeMode.StretchImage;
this.Controls.Add(item);
item.BringToFront();
}
and in the textbox_MouseMove void, I try to use the middle button to signal the rotation of the image
void textbox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle )
{
if (activeControl == null || activeControl != sender)
{
return;
}
this.Paint += new PaintEventHandler(objectrotation_Paint);
Invalidate();
}
}
where the PaintEvent is responsible for the rotation of the image
private void objectrotation_Paint(object sender, PaintEventArgs d)
{
int dpi = 96;
bmp.SetResolution(dpi, dpi);
if (bmp != null)
{
float bw2 = bmp.Width / 2f;
float bh2 = bmp.Height / 2f;
d.Graphics.TranslateTransform(bw2, bh2);
d.Graphics.RotateTransform(angle);
d.Graphics.TranslateTransform(-bw2, -bh2);
d.Graphics.DrawImage(bmp,0,0);
d.Graphics.ResetTransform();
}
}
This however would create two sets of images, i.e. when I press button 2 I get one image, when I move my mouse with middle button down I get the second image (rotating).Refering to some of the questions on here, people recommend using
item.Image = bmp;
but it simply copies the from picturebox to the bitmap while they have seperate controls. While the picturebox class could not perform rotations without implementing a Bitmap, the Bitmap class does not have the option to perform actions like OnMouseMove etc.
Is there any way to combine my bitmap and the picturebox such that I could achieve my two goals?
I am using a panel to display a image in windows forms
I am drawing image in the panel in Panel_Paint event as follows:
Graphics g = panel1.CreateGraphics();
Image im = new Bitmap(#"../../Data/#3_Page2.PNG");
g.DrawImage(im,new Point(10,10));
Now, the image is drawn as i expected, with some part of the bottom of the image not displaying as its height is greater than forms height.
I have added the VScrollBar now. How do i make that panel to view the rest of the image with the help of VScrollBar.
You can use PictureBox with SizeMode set to AutoSize and AutoScroll property of Panel. That way the panel should add scrollbars if they are needed.
PictureBox pictureBox = new System.Windows.Forms.PictureBox();
pictureBox.Image = new Bitmap(#"../../Data/#3_Page2.PNG");
pictureBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize;
panel.AutoScroll = true;
panel.Controls.Add(this.pictureBox);
This solution works, however if your image is large enough, there is a little flicker when you scroll (however it's acceptable). First you have to add a VScrollBar right on the right of your panel and a HScrollBar right under the bottom of your panel. This demo requires you have a VScrollBar named vScrollBar1 and HScrollBar named hScrollBar1, a Button named buttonOpenImage to allow user to open some image, a Panel named panel1 used as the main area to draw the image:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
//To prevent/eliminate flicker, do this
typeof(Panel).GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.NonPublic).SetValue(panel1, true, null);
//------------------------
UpdateScrollbarsState();
}
int imgWidth, imgHeight;
Image image;
Point leftTop = Point.Empty;
int lastV, lastH;
private void OpenImage(){
OpenFileDialog openFile = new OpenFileDialog();
openFile.FileOk += (s, e) => {
try {
image = Image.FromFile(openFile.FileName);
//calculate the physical size of the image based on the resolution and its logical size.
//We have to do this because the DrawImage is based on the physical size (not logical).
imgWidth = (int)(image.Width * 96f / image.HorizontalResolution + 0.5);
imgHeight = (int)(image.Height * 96f / image.VerticalResolution + 0.5);
lastV = lastH = 0;
UpdateScrollbarsState();
vScrollBar1.Value = 0;
hScrollBar1.Value = 0;
panel1.Invalidate();
}
catch {
image = null;
MessageBox.Show("Image file is invalid or corrupted!");
}
};
openFile.ShowDialog();
}
private void UpdateScrollbarsState() {
//We have to update all the info about Minimum and Maximum
vScrollBar1.Minimum = 0;
hScrollBar1.Minimum = 0;
vScrollBar1.Maximum = Math.Max(imgHeight-panel1.Height,0);
hScrollBar1.Maximum = Math.Max(imgWidth-panel1.Width,0);
vScrollBar1.Visible = vScrollBar1.Maximum > 0;
hScrollBar1.Visible = hScrollBar1.Maximum > 0;
if (vScrollBar1.Maximum == 0) {
leftTop.Y = 0;
lastV = 0;
}
if (hScrollBar1.Maximum == 0) {
leftTop.X = 0;
lastH = 0;
}
}
private void panel1_Paint(object sender, PaintEventArgs e) {
if (image == null) return;
e.Graphics.DrawImage(image, leftTop);
}
//The ValueChanged event handler of your vScrollBar1
private void vScrollBar1_ValueChanged(object sender, EventArgs e) {
if (!vScrollBar1.Visible) return;
leftTop.Offset(0, -vScrollBar1.Value + lastV);
lastV = vScrollBar1.Value;
panel1.Invalidate();
}
//The ValueChanged event handler of your hScrollBar1
private void hScrollBar1_ValueChanged(object sender, EventArgs e) {
if (!hScrollBar1.Visible) return;
leftTop.Offset(lastH - hScrollBar1.Value, 0);
lastH = hScrollBar1.Value;
panel1.Invalidate();
}
//handler for SizeChanged event of the panel. However if resizing
//the form causes the panel's size changing, you should attach this
//handler for form.
private void panel1_SizeChanged(object sender, EventArgs e) {
UpdateScrollbarsState();
}
//handler for the Click event of a button (click to open an image)
private void buttonOpenImage_Click(object sender, EventArgs e) {
OpenImage();
}
}
The question I have here is sort of a 2 parter.
I have a picturebox that is positioned inside of a panel. When I open an image, the picturebox is resized to the size of the image, while the panel stays the same size. The panel just has scrollbars to see the whole image.
There are 2 things going wrong with this.
When I resize the picturebox, for some reason I can only draw in the previous portion of the picturebox. Ex. The imagebox starts out by default as 200x200. I open an image that is 500x400. And I can only still draw in the 200x200 portion of the image.
The second issue that I am having is that when I do draw in that selective portion of the picturebox, when I scroll to where my painting is out of view, and come back, the image that i painted gone. I know there is some sort of picturebox.invalidate() that I need. I am just not sure how to use it.
Here is my code to get a good grasp on what I'm doing.
public Form1()
{
InitializeComponent();
DrawArea = new Bitmap(pictureBox1.Size.Width, pictureBox1.Size.Height );
pictureBox1.Image = DrawArea;
objGraphics = this.pictureBox1.CreateGraphics();
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
drawImage(e);
}
public void drawImage(MouseEventArgs e)
{
Rectangle rDraw = new Rectangle();
if (e.Button == MouseButtons.Left)
{
rDraw.X = e.X;
rDraw.Y = e.Y;
rDraw.Width = 3;
rDraw.Height = 3;
objGraphics.DrawEllipse(System.Drawing.Pens.Black, rDraw);
}
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{
try
{
OpenFileDialog open = new OpenFileDialog();
open.Filter = "Image Files(*.jpg; *.bmp)|*.jpg; *.bmp";
if (open.ShowDialog() == DialogResult.OK)
{
Bitmap bit = new Bitmap(open.FileName);
pictureBox1.Size = bit.Size;
DrawArea = bit;
pictureBox1.Image = bit;
}
}
catch (Exception)
{
throw new ApplicationException("Failed loading image");
}
}
Thanks Alot!
You need to draw in the picturebox's Paint event.
You should (almost) never draw on CreateGraphics().
class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox {SizeMode = PictureBoxSizeMode.CenterImage};
pb.SizeMode = PictureBoxSizeMode.StretchImage;
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.Width = image.Width;
this.Height = image.Height;
this.Text = "Original image";
this.Paint += new PaintEventHandler(Drawer);
}
public virtual void Drawer(object source, PaintEventArgs e)
{
Graphics g = pb.CreateGraphics();
g.DrawImage(image,0,0);
}
I call this create object OriginalImage in other form on button click, but image is not draw? Where is problem?
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var oi = new OriginalImage();
oi.Show();
}
}
You're creating a PictureBox and adding it to your controls, but you never actually use it (you're drawing the image manually in the Paint event). Why? This control is likely obscuring the drawing area of the form, as any controls go on top of whatever you draw in the Paint event.
In addition, you're getting the Graphics object by calling CreateGraphics on the PictureBox rather than the Form itself. This is wrong, as the PictureBox's Paint event will fire after this code, erasing whatever you draw.
I would recommend changing your OriginalForm code to the following:
class OriginalImage: Form
{
private Image image;
private PictureBox pb;
public OriginalImage()
{
pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.StretchImage;
pb.Dock = DockStyle.Fill; // this will make the PictureBox occupy the
// whole form
Controls.Add(pb);
image = Image.FromFile(#"Image/original.jpg");
this.ClientSize = new Size(image.Width, image.Height); // this allows you to
// size the form while
// accounting for the
// border
this.Text = "Original image";
pb.Image = image; // use this instead of drawing it yourself.
}
}