I want do something like that:
I have form with pictures, when I click on ones, I want to display new window with this picture (it must be only picture, without some toolbox or border). Continuing I want to be able move this window (when I press button on mouse and move mouse, this window must move with my cursor, when I up button window won't move when I move mouse).
I do it like that:
make new window form, remove toolbar, border, add pictureBox, add method on mouseDown, mouseUp and mouseMove. Code for method:
private void FormZdjecie_MouseDown( object sender, MouseEventArgs e ) {
buttonUp = false;
previous = e.Location;
}
private void pictureBox1_MouseUp( object sender, MouseEventArgs e ) {
buttonUp = true;
}
private void pictureBox1_MouseMove( object sender, MouseEventArgs e ) {
if ( !buttonUp ) {
Point diff = new Point();
diff.X = e.X - previous.X;
diff.Y = e.Y - previous.Y;
this.Location = new Point( this.Location.X + diff.X, this.Location.Y + diff.Y );
previous = e.Location;
}
}
I work, but it very slow refresh. How do it to work like windows form (when I move normal windows form it look fine), but my method look badly ;p Any idea how to make it?
You need to use the WinAPI. See here.
Related
How do I drag borderless Form? I tried almost everything but most of the solutions are pretty confusing as I don't have decent experience in C#.
so i find this approach. feel free to delete if its duplicate but for me it looks the most simple.
in order to drag window we need some sort of loop that runs while we have mouse button pressed, im doing it with timer.
also we need variable that will store initial mouse press location.
using System.Timers;
using Timer = System.Timers.Timer;
public partial class Form1 : Form
{
private static Timer moveTimer;
private static Point pnt;
public Form1()
{
InitializeComponent();
moveTimer = new Timer();
moveTimer.Interval = 0.1;
moveTimer.Enabled = false;
moveTimer.Elapsed += moveTimerEvent;
moveTimer.AutoReset = true;
}
next we just add MouseDown and MouseUp Events to every control we want to be able to move window. usually i have this event on menustrip like most browsers do nowadays but you can use any control
private void AddHub_MouseDown(object sender, MouseEventArgs e)
{
pnt = new Point(e.Location.X+(sender as Control).Location.X, e.Location.Y + (sender as Control).Location.Y);
moveTimer.Enabled = true;
}
private void AddHub_MouseUp(object sender, MouseEventArgs e)
{
moveTimer.Enabled = false;
}
we are getting mouse location with respect to control with e.location and then controls location with respect to form with (sender as Control).Location
so mouse location with respect to form is mouse location with respect to control + controls location with respect to form
and finally we use timer event moveTimerEvent to actually drag a window
private void moveTimerEvent(Object source, ElapsedEventArgs e)
{
if (InvokeRequired)
{
Invoke(new MethodInvoker(delegate { Location = new Point(Cursor.Position.X - pnt.X, Cursor.Position.Y - pnt.Y); }));
}
}
we need to invoke a method as timer moveTimerEvent is running in another thread and cant directly affect Form1.
this is a pseudo code to calculate Form1 location from mouse location: Form1.location = Cursor.Position - pnt and this location is with respect to screen.
i'm are trying to mimic the behavior of web browsers in a WinForm application where you can drag and drop tabs in and out of the browser and create another instance of the it when you drop the tab somewhere with no existing tabs.
Currently the WinForm application only has one main TabControl and I was looking at the DoDragDrop() related events, but they seem to only work when you have two TabControls and move TabPages around those two.
Is there a way to make it work with only one TabControl? Meaning, If you Drop a TabPage out of the TabControl then it will create a new TabControl with the TabPage in it?
I can only think of using:
private void TabControl_DragLeave(object sender, EventArgs e)
{
Form newInstance = new Form();
TabControl newTabControl = new TabControl();
newInstance.Controls.Add(newTabControl);
newTabControl.TabPages.Add(sender as TabPage);
newInstance.Show();
}
but that is pretty crud and will create the new tab every time you leave the TabControl.
It seems you are looking for an event which raises at the end of drop, regardless of ending over your control or outside of the control.
You can rely on QueryContinueDrag and check if the action is Drop, then check the mouse position and for example if it's not inside your control, just create another window and add the selected tab into a tab control inside the new window.
private void tabControl1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
tabControl1.DoDragDrop(tabControl1.SelectedTab, DragDropEffects.All);
}
}
private void tabControl1_DragOver(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(TabPage)))
e.Effect = DragDropEffects.Move;
}
private void tabControl1_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (e.Action == DragAction.Drop)
{
var tabPage = tabControl1.SelectedTab;
if (!tabControl1.RectangleToScreen(tabControl1.Bounds).Contains(Cursor.Position))
{
var form = new Form();
form.Text = tabPage.Text;
var tabControl = new TabControl();
tabControl.TabPages.Add(tabPage);
tabControl.Dock = DockStyle.Fill;
form.Controls.Add(tabControl);
form.FormBorderStyle = FormBorderStyle.SizableToolWindow;
form.StartPosition = FormStartPosition.Manual;
form.Location = new Point(Cursor.Position.X - form.Width / 2,
Cursor.Position.Y - SystemInformation.CaptionHeight / 2);
form.Show();
e.Action = DragAction.Cancel;
//You can comment tabControl.TabPages.Add
//Then set e.Action = DragAction.Continue
//Then the DragDrop event will raise and add the tab there.
}
}
}
private void tabControl1_DragDrop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(TabPage)))
{
var tabPage = (TabPage)e.Data.GetData(typeof(TabPage));
tabControl1.TabPages.Remove(tabPage);
tabControl1.TabPages.Add(tabPage);
}
}
For more advanced scenarios and to enhance the code:
When start dragging, you can start dragging just if the mouse dragged at least for a specific points, for example 16 points. It's easy to calculate. Having p1 as mouse down point and p2 as mouse move point, and d as drag threshold. start dragging just in case (p1.X-p2.X)*(p1.X-p2.X) + (p1.Y-p2.Y)*(p1.Y-p2.Y) > d*d.
You can use GiveFeedback event to disable default cursor of the mouse and instead show a more suitable cursor while dragging, easily by e.UseDefaultCursors = false; and setting Cursor.Current = Cursors.SizeAll; for example.
You can encapsulate the logic and put it in a derived TabControl. Then in DragEnter and DragLeave events set a static property for tracking drop target. In case the drop-target has value, it means you are dropping on a derived tab control, otherwise it means you are dropping outside. Then drag and drop will be easily enabled for all your custom tab controls.
You can close the tool form, after a drag and drop, in case the form doesn't contain any other tab.
When adding the tab, you can insert it before/after the selected tab or the tab under cursor in target.
I have this menu (Android style), which is in a FlowLayoutPanel that organizes the elements (Bunifu Tile Buttons):
Well, I thought about implementing a drag function where you could reposition the elements in execution time by dragging them with the mouse as it is done in Android.
To do this, I used a FlowLayoutPanel to organize the elements and this code::
...
Interval = 100, Enabled = true;
private void Timer_0_Tick(object sender, EventArgs e)
{
var cursor = Cursor.Position;
if(bunifuTileButton1.DisplayRectangle.Contains(cursor))
{
if(Hector.Framework.Utils.Peripherals.Mouse.MouseButtonIsDown(Hector.MouseButton.Left))
{
bunifuTileButton1.Location = cursor;
}
}
}
But when I drag the elements, they simply return to their original position by releasing the mouse button.
So, my question is:
Is it possible to implement a function that in C # Winforms that reorganize the elements as Android does using a FlowLayoutPanel that automatically organizes the elements in execution time?
Firstly , you need to implement the functionality which will help you drag-and-drop your controls.But before that, you need to store the control's current position in some class-level variables.Consider the following code snippet :
int xloc;
int yloc;
///other codes in-between
private void btn1_Click()
{
xloc = this.btn1.Location.X;
yloc = this.btn1.Location.Y;
}
Now the drag-and-drop feature :
private Point setNewLocation;
private void btn1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
setNewLocation= e.Location;
}
}
private void btn1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
btn1.Left = e.X + btn1.Left - setNewLocation.X;
btn1.Top = e.Y + btn1.Top - setNewLocation.Y;
}
}
This will help you move the control...But what happens when you place a control over another one ? I mean you definitely don't want one control to overlap the other.Rather you may want to,when one control is placed over the other, the other control will change it's position to the previous position of the control that is overlapping it.So, on the MouseUP event of the currently dragged control , use this :
private void btn1_MouseUP()
{
foreach (Control other in FlowlayoutPanel1.Controls)
{
///change control type as required
if (!other.Equals(btn1) && other is Button && btn1.Bounds.IntersectsWith(other.Bounds))
{
other.Location = new Point(xloc, yloc)
}
}
I haven't debugged the code so if you encounter any bug, make sure to leave a comment :)
Whenever I move a Windows Form by some component (i.e. a Label) in the client area, I end up with a strange mouse offset in which the form does not stay visually underneath the cursor. It will still move according to my mouse location on the screen, but it dramatically shifts southeast of the cursor's position.
I've had to specify a negative offset of my own to counteract this offset; my code is as follows:
private void component_MouseDown(object sender, MouseEventArgs e)
{
if (sender is Label)
{
if (e.Button == MouseButtons.Left)
{
mouseLoc = new Point(-(e.X + OFFSET_X), -(e.Y + OFFSET_Y));
isMouseDown = true;
}
}
}
private void component_MouseMove(object sender, MouseEventArgs e)
{
if (isTitleLabelMouseDown)
{
Point p = Control.MousePosition;
p.Offset(mouseLoc);
Location = p;
}
}
private void component_MouseUp(object sender, MouseEventArgs e)
{
isMouseDown = false;
}
This offset does fix the problem, but what throws me for a loop is why the form's location offsets when I move it by its client area in the first place?
Thanks!
You seem to be translating client coordinates to screen coordinates. There is a better way...
https://msdn.microsoft.com/en-us/library/system.windows.forms.control.pointtoscreen%28v=vs.110%29.aspx
Edit: And of course there's a better way to do this whole thing. Basically, you want to intercept the click higher up the chain and tell Windows that the click is actually in the window title, which will cause Windows to do the dragging for you...
Winforms - WM_NCHITEST message for click on control
I have a winform on which i want to allow the user to move a control.
The control is (for now) a vertical line : label with border and a width of 1.
The context is not very important but i'll give it to you anyways. I have a background with some graphics and i'd like the user to be able to slide a guideline above the graphics. The graphics are made with the NPlots library. It looks something like this:
http://www.ibme.de/pictures/xtm-window-graphic-ramp-signals.png
If i can find out how the user can click and drag the label/line control around the screen, i can solve my guideline problem. Please help.
The code for this can get a bit complex, but essentially you will need to capture the MouseDown, MouseMove, and MouseUp events on your form. Something like this:
public void Form1_MouseDown(object sender, MouseEventArgs e)
{
if(e.Button != MouseButton.Left)
return;
// Might want to pad these values a bit if the line is only 1px,
// might be hard for the user to hit directly
if(e.Y == myControl.Top)
{
if(e.X >= myControl.Left && e.X <= myControl.Left + myControl.Width)
{
_capturingMoves = true;
return;
}
}
_capturingMoves = false;
}
public void Form1_MouseMove(object sender, MouseEventArgs e)
{
if(!_capturingMoves)
return;
// Calculate the delta's and move the line here
}
public void Form1_MouseUp(object sender, MouseEventArgs e)
{
if(_capturingMoves)
{
_capturingMoves = false;
// Do any final placement
}
}
In WinForms, you can handle the MouseDown, MouseMove and MouseUp events of a control. On MouseDown, set some bit or reference telling your form what control the mouse was clicked on, and capture the X and Y of the mouse from MouseEventArgs. On MouseMove, if a control is set, adjust its X and Y by the difference between your last captured X and Y and the current coordinates. On MouseUp, release the control.
I would set up an "edit mode" for this; when the user enters this mode, the current event handlers of your form's controls should be detached, and the movement handlers attached. If you want to persist or revert these changes (like you're making a custom form designer your client can use to customize window layouts), you'll also need to be able to take some sort of snapshot of the before and after layouts of the controls.
I wrote a component to do exactly that: move a control on a form (or move a borderless form on the screen). You can even use it from the designer, without writing any code.
http://www.thomaslevesque.com/2009/05/06/windows-forms-automatically-drag-and-drop-controls-dragmove/
Here's an extension method that you can use for any control. It uses Rx and is based on the A Brief Introduction to the Reactive Extensions for .NET, Rx post and sample by Wes Dyer.
public static class FormExtensions
{
public static void EnableDragging(this Control c)
{
// Long way, but strongly typed.
var downs =
from down in Observable.FromEvent<MouseEventHandler, MouseEventArgs>(
eh => new MouseEventHandler(eh),
eh => c.MouseDown += eh,
eh => c.MouseDown -= eh)
select new { down.EventArgs.X, down.EventArgs.Y };
// Short way.
var moves = from move in Observable.FromEvent<MouseEventArgs>(c, "MouseMove")
select new { move.EventArgs.X, move.EventArgs.Y };
var ups = Observable.FromEvent<MouseEventArgs>(c, "MouseUp");
var drags = from down in downs
from move in moves.TakeUntil(ups)
select new Point { X = move.X - down.X, Y = move.Y - down.Y };
drags.Subscribe(drag => c.SetBounds(c.Location.X + drag.X, c.Location.Y + drag.Y, 0, 0, BoundsSpecified.Location));
}
}
Usage:
Button button1 = new Button();
button1.EnableDragging();
Well in all honesty there is a simpler way where by you initialize a global boolean variable called whatever you like, in this case, isMouseClicked. On your control you wish to allow dragging you go to its mouse down event,
Make sure these event are your control events not your forms event.
if (e.button == MouseButtons.left)
//this is where you set the boolean to true
Then go to its mouse move event
if (isMouseClicked == true)
//You then set your location of your control. See below:
Button1.Location = new Point(MousePosition.X, MousePosition.Y);
On your mouse up make sure to set your isMouseClicked to false;