C# - Generic event handler to move pictureboxes created at runtime with mouse - c#

I'm a somewhat beginner to C# using Visual Studio 2019 and currently creating a game and am struggling to find a way to create a generic mousedown/mousemove event handler to move pictureboxes created at runtime through a class constructor with the mouse
I've figured out how to move them how I want but right now it only works when I click the form and not the picturebox itself, which is far from ideal. Is there a way to create a generic event handler that is able to determine which pictureBox is clicked and moves only that one? And how would I go about doing that? If it helps I've added the pictureBoxes to Form1's Controls in order to display them. The code is the class constructor of how the pictureBox is created at runtime using the line:
"new Piece(new Position(100, 100), 200, 300, form);"
public Piece(Position pos, int xSize, int ySize, Form form)
{
this.pos = pos;
this.xSize = xSize;
this.ySize = ySize;
pic = new PictureBox();
pic.BackColor = Color.LightBlue;
pic.Size = new System.Drawing.Size(xSize, ySize);
UpdateImgPos();
pic.Visible = true;
form.Controls.Add(pic);
Pieces.Add(this);
childPlatforms = new List<Platform>();
}

If i understand it right, then you can use the event of the picturebox. The Parameter sender is the Control, which fire the event.
PictureBox pictureBox = new PictureBox();
// add image, set start location, etc...
pictureBox.Size = new System.Drawing.Size(100, 50);
pictureBox.MouseDown += PictureBox_MouseDown;
this.Controls.Add(pictureBox);
// ...
private void PictureBox_MouseDown(object sender, MouseEventArgs e)
{
// cast object sender to PictureBox pictureBox
if (!(sender is PictureBox pictureBox)) return;
pictureBox.Location = CursorPosition;
}

Related

Background image of control bugged

I've done a mini test program to prototype a way to drag and drop an image (at the right)(using a button as a support) to a panel (left part)(The current panel background letter are only for test purpose) and to move it inside the panel perimeter.
The image on the moving control is manually drawn during the Paint event :
void bouton_Paint( object sender, PaintEventArgs e )
{
Button but = sender as Button;
Bitmap img = new Bitmap(WindowsFormsApplication1.Properties.Resources.triaxe);
img.MakeTransparent(Color.White);
e.Graphics.DrawImage(img, 0, 0, but.Width, but.Height);
}
As you can see below, during the moving process, the background of the moved control is frezzed. So it is not very pretty
Is it to make the progress smoother ?
Thank you.
This is the code to move my triaxe on the form :
void bouton_MouseUp( object sender, MouseEventArgs e )
{
Button button = sender as Button;
button.Tag = false;
button.BackColor = Color.Transparent;
}
void bouton_MouseMove( object sender, MouseEventArgs e )
{
Button button = sender as Button;
if (button.Tag != null && (bool)button.Tag == true)
{
button.Left += e.X - MouseDownLocation.X;
button.Top += e.Y - MouseDownLocation.Y;
}
}
private Point MouseDownLocation;
void bouton_MouseDown( object sender, MouseEventArgs e )
{
Button button = sender as Button;
MouseDownLocation = e.Location;
button.Tag = true;
button.BackColor = SystemColors.Control;
}
Let's assume you do not want to draw the graphics alone but do want a Control with transparency move on top of another Control.
You have to solve two problems:
Winforms doesn't support transparency well; you have two options:
Either let the system fake it for you
Or do the faking yourself.
For the first it is enough to have a control with a transparent backcolor and an Image or BackgroundImage (depending on the control type) with transparency and then nest the moving control in the background control.
For a simplistic test you can add if (button.Parent != panel1) button.Parent = panel1; to your mousedown code. This will look jumpy but should display transparency correctly. (Don't forget to make the Backcolor transparent; in your code your make it SystemColors.Control.
To fake it yourself you would do exactly what the system does:
You get the target suface in a bitmaps (with DrawToBitmap) and then combine the area the mover currently covers with the image; here getting that area is key.
Then you can set that image as backgroundimage or draw it onto the mover.
The other problem is with the moving code. Here the issue is that when you move the mouse the MouseMove event is triggered and you can move the control. But by moving it the mouse will have moved relativly to the new location and the event will be triggered again leading to flicker an jumpiness!
To avoid this you can test the numbers or use a flag or unregister the move event before setting the location and re-register afterwards.
Also setting the location in one go instead of the two coordinates is a good idea..: button.Location = new Point(button.Left + e.X - MouseDownLocation.X, button.Top + e.Y - MouseDownLocation.Y);
Imo you should still consider drawing just the graphics on On panel.MouseMove and panel.Paint. On panel.MouseUp you can still add a Button to the panel.Controls right there. Both issues are avoided and you are free to add the functionality you want as well..

C# - Drawing in a panel with "Paint"

I've been working on a project for class where I need to display on screen polygons (drawed in a Panel), but I've been reading arround here that I should work with Paint event, tho I can't make it work (started learning C# a little ago).
private void drawView()
{
//"playerView" is the panel I'm working on
Graphics gr = playerView.CreateGraphics();
Pen pen = new Pen(Color.White, 1);
//Left Wall 1
Point lw1a = new Point(18, 7);
Point lw1b = new Point(99, 61);
Point lw1c = new Point(99, 259);
Point lw1d = new Point(18, 313);
Point[] lw1 = { lw1a, lw1b, lw1c, lw1d };
gr.DrawPolygon(pen, lw1);
}
I was doing something like this to draw it on screen, it would be possible to do this with a Paint method? (it is called method, or event? I'm really lost here).
Thanks!
I think you are referring to the Control.Paint event from windows forms.
Basically, you would attach a listener to the Paint event of a windows forms element, like this :
//this should happen only once! put it in another handler, attached to the load event of your form, or find a different solution
//as long as you make sure that playerView is instantiated before trying to attach the handler,
//and that you only attach it once.
playerView.Paint += new System.Windows.Forms.PaintEventHandler(this.playerView_Paint);
private void playerView_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
{
// Create a local version of the graphics object for the playerView.
Graphics g = e.Graphics;
//you can now draw using g
//Left Wall 1
Point lw1a = new Point(18, 7);
Point lw1b = new Point(99, 61);
Point lw1c = new Point(99, 259);
Point lw1d = new Point(18, 313);
Point[] lw1 = { lw1a, lw1b, lw1c, lw1d };
//we need to dispose this pen when we're done with it.
//a handy way to do that is with a "using" clause
using(Pen pen = new Pen(Color.White, 1))
{
g.DrawPolygon(pen, lw1);
}
}

Activating mousedown on dynamically created object

I'm working on a project where I want to "drag" data from a listview to a panel. The goal is that people can select the information on the listview and then position a panel with that information on it on a sort of flowchart on another panel.
Pretty much all of the code is already working but there's one thing which I'm still struggeling with. When I perform a Mouse Down on the listview, a panel is being generated with a few labels on it to be able to drag. The code below is a simplified version for readability.
private void createPlayerPanel()
{
var coordinates = this.PointToClient(Cursor.Position);
// CREATE THE PANEL
Panel panPlayer = new Panel();
// SETUP THE PANEL
panPlayer.Name = "panPlayer1";
panPlayer.Width = 200;
panPlayer.Height = 50;
panPlayer.BackColor = Color.Gainsboro;
panPlayer.Click += new EventHandler(this.panClick);
panPlayer.MouseDown += new MouseEventHandler(panMouseDown);
// ADD THE PANEL TO THE FORM
this.Controls.Add(panPlayer);
// BRING THE PANEL TO THE FRONT OF THE FORM
panPlayer.BringToFront();
panPlayer.Location = new Point(coordinates.X - 14, coordinates.Y - 12);
}
public bool Dragging = false;
Point location;
Panel panSelected;
private void panMouseDown(object sender, MouseEventArgs e)
{
panSelected = (Panel)sender;
Dragging = true;
location = e.Location;
}
However with the same Mouse Down I would like to drag the panel to the flowchart. So in one smooth movement, click on the information in the listview and drag it to the second panel.
When I generate the panel, I also include a Mouse Down mouseeventhandler but which is not active yet when I perform the mousedown. So when I release the mouse and then hold down the mouse again, it works fine and I can drag the panel to it's new position. But I would like to do it in one action. So MOUSE DOWN > GENERATE PANEL > ACTIVATE MOUSE EVENT > DRAG PANEL
Is there a way I can activate the mousedown-event of the panel when I've finished creating it?

How to use BringToFront(); properly?

So I've been working on a little game project called economy, and I've ran into a little problem. What I want is to draw a stick man on the screen when someone hires a new employee, I do this by creating a new picture box, and assigning the stick man image to it. However because I needed to do this over and over again (so that they could have unlimited employees) I had it create a new object each time.
To remove the stick men, when someone fired them, I added a new picture box over the old stick men that is just white, so it looks as if they disappear. However for some reason BringToFront(); does not appear to work with it, and so I can't get the white picture to be drawn over the stick men.
If someone could tell me why it is not working, or a way to reference the original stickmen pictureboxe's to change their image, that would be fantastic.
public void Hire_Worker_Click(object sender, EventArgs e)
{
workers++;
money -= 10000;
PictureBox WPB = new PictureBox();
//Set location and size of new picturebox
WPB.Image = Economy.Properties.Resources.Worker;
WPB.Width = 68;
WPB.Height = 118;
WPB.Location = new Point(workerx,400);
workerx += 68;
Controls.Add(WPB);
}
public void Fire_Worker_Click(object sender, EventArgs e)
{
if (workers > 1)
{
clickfire++;
workers--;
money -= 100;
if (clickfire == 1)
{
workerx -= 68;
}
PictureBox WWPB = new PictureBox();
//Set location and size of picturebox
WWPB.BringToFront();
WWPB.Image = Economy.Properties.Resources.whiteworker;
WWPB.Width = 68;
WWPB.Height = 118;
WWPB.Location = new Point(workerx, 375);
workerx -= 68;
Controls.Add(WWPB);
}
}
BringToFront only works when the control is already in the parent, so move that line:
Controls.Add(WWPB);
WWPB.BringToFront();

Is there a way to move adjust a pushpin position manualy on windows phone 8 using bing maps?

I am working on a windows phone 8.0 application wich uses bing maps. I wnat to add a push pin with my current location. So far soo good. What I do not manage to do is to move that pin. More precisely, I want to tap that pin and to mo move it otherwhere on the map.
I tried with events like ManipulationStarted, ManipulationDelta, ManipulationCompleted and other resources on the web, but no results yet.
My C# code:
public partial class MainPage : PhoneApplicationPage
{
Pushpin pin = new Pushpin();
// Constructor
public MainPage()
{
InitializeComponent();
GetCurrentPosition();
}
async void GetCurrentPosition()
{
Geolocator geolocator = new Geolocator();
geolocator.DesiredAccuracyInMeters = 50;
Geoposition geoposition = await geolocator.GetGeopositionAsync();
Grid MyGrid = new Grid();
MyGrid.RowDefinitions.Add(new RowDefinition());
MyGrid.RowDefinitions.Add(new RowDefinition());
MyGrid.Background = new SolidColorBrush(Colors.Transparent);
pin.Content = "I'm a pin";
pin.Foreground = new SolidColorBrush(Colors.Purple);
pin.ManipulationDelta += pin_ManipulationDelta;
pin.ManipulationStarted += pin_ManipulationStarted;
pin.ManipulationCompleted += pin_ManipulationCompleted;
MyGrid.Children.Add(pin);
//Creating a MapOverlay and adding the Grid to it.
MapOverlay MyOverlay = new MapOverlay();
MyOverlay.Content = MyGrid;
MyOverlay.GeoCoordinate = new GeoCoordinate(geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude);
MyOverlay.PositionOrigin = new Point(0, 0.5);
MyMap.Center = new System.Device.Location.GeoCoordinate(geoposition.Coordinate.Latitude, geoposition.Coordinate.Longitude);
MyMap.ZoomLevel = 16;
MyMap.CartographicMode = Microsoft.Phone.Maps.Controls.MapCartographicMode.Road;
MapLayer MyLayer = new MapLayer();
MyLayer.Add(MyOverlay);
MyMap.Layers.Add(MyLayer);
translateTransform = new TranslateTransform();
}
void pin_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
{
//MessageBox.Show("started");
}
void pin_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
MessageBox.Show("moving");
//how do a get the coordonites while I'm moving the pin?
}
void pin_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
MessageBox.Show("completed");
}
}
Aby ideas how to make the pin draggeble? If I set pin.AllowDrop=true it throws NotImplementedException.
Thank you in advance!
Just thinking a little differently...
The solution I used for NZ Topo Map was to overlay a cross-hair over the map so the user could position the pin precisely by dragging the map instead of dragging a pin. I would then use an app bar with a tick and a cross for "create pin" and "cancel".
Just an alternative UI idea for you to mull over that might be easier to implement and maybe easier for the user.
You have to set the move events on the mouse events on the map. This will let you be able to track where the user has moved to. Essentially you would add a mouse down event to the pushpin which would set a flag to capture to allow dragging the pin. Then you would use the mouse move event on the map to reposition the pushpin and the mouse up event on the map to turn the dragging flag off. You will also likely want to display panning of the map. Try capturing the center value when the mouse down event fires, then set the center of the map to this value constantly on the mouse move event when the drag flag it turned on.

Categories