C# how drag borderless window with menuStrip? - c#

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.

Related

Handle DragDrop outside of control - DragEnd event?

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.

How to check whether the cursor position is outside of chart control in the windows form?

I am displaying tooltip in the MS chart. When moving from chart control to other controls or form free space , tooltip is not getting hided.
How to check whether the cursor position is outside of chart control in the windows form?
I tried below code, it did not work for me.
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!chart.ClientRectangle.Contains(chart.PointToClient(new Point(e.X,e.Y))))
{
if (ToolTip != null)
ToolTip.Hide(chart);
}
}
I put trace and checked, If I move to form free space from chart control, the event is firing, only when moving to other control from chart, Form1_MouseMove is not getting called.
How to resolve my problem?
Try handling MouseEnter and MouseLeave events on your target control (the chart in your case, the button in mine).
using System.Drawing;
using System.Windows.Forms;
namespace WindowsFormsApp
{
public partial class Form1 : Form
{
private const string mouseIsOver = "Mouse is over";
private const string mouseIsOutside = "Mouse is outside";
public Form1()
{
InitializeComponent();
var button = new Button { Text = mouseIsOutside, AutoSize = true, Location = new Point(10, 10) };
button.MouseEnter += (sender, e) => button.Text = mouseIsOver;
button.MouseLeave += (sender, e) => button.Text = mouseIsOutside;
this.Controls.Add(button);
}
}
}

Mouse up event doesn't get triggered

I have the following problem: I have a panel which has a specific color, say red.
When the user presses his mouse, the color of this panel gets stored in a variable. Then the user moves, his mouse still pressed, over to another panel. When he releases the mouse there, this panel should get the background color of the first that had been stored in the variable. My code looks something like this:
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
I need to identify the sender first because there are many possible panels that can trigger this event. The first MouseDown method works totally fine, the color is stored nicely in the variable. The secon one however doesn't even get triggered when the user does what I described above. When the ser clicks on the second panel, it works (there is an MouseUp part in a click aswell I guess).
What's wrong here? Why is the event not triggered when the user holds the mouse key down before?
(This answer assumes you are using Windows Forms.)
It could be that you need to capture the mouse by setting this.Capture = true in the MouseDown of the source control. (See Control.Capture)
If you did that, the source window would get the MouseUp event, and it would be the source window that had to determine the destination window under the mouse coords. You can do that using Control.GetChildAtPoint() (see this answer on Stack Overflow).
Use Windows Forms Drag and Drop Support Instead! <- Click for more info
I'm going to suggest you bite the bullet and use the .Net Drag and Drop methods to do this. It requires some reading up, but it will be much better to use it.
You start a drag in response to a MouseDown event by calling Control.DoDragDrop().
Then you need to handle the Control.DragDrop event in the drop target control.
There's a few more things you might need to do to set it up; see the Control.DoDragDrop() documentation for an example.
(For WPF drag and drop support, see here.)
when your mouse enter the target control , mouse down triggerd ang get target BackColor! you need add an boolean flag to your code :
public Color currentColor;
bool flag=false;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
if(flag==false)
{
flag=true
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
}
//assume mouse up for panles
private void AttempsColorChanger(object sender, MouseEventArgs e)
{
if(flag==true)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
flag=flase;
}
}
and also you need change your flag in mouseMove( if )
As I mentioned in my comment Mouse Events are captured by the originating control, You would probably be better off using the DragDrop functionality built into Windows Forms. Something like this should work for you. I assigned common event handlers, so they can be assigned to all of your panels and just work.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void panel_MouseDown(object sender, MouseEventArgs e)
{
((Control)sender).DoDragDrop(((Control)sender).BackColor,DragDropEffects.All);
}
private void panel_DragDrop(object sender, DragEventArgs e)
{
((Control)sender).BackColor = (Color)e.Data.GetData(BackColor.GetType());
}
private void panel_DragEnter(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Copy;
}
}
I know it's an old question but I had the same issue and none of the above answers worked for me. In my case I had to handle the MouseMove event in the target control and check for the mouse to be released. I did set 'BringToFront' on my target panel just in case that helped at all.
public Color currentColor;
private void ColorPickMouseDown(object sender, MouseEventArgs e)
{
Panel pnlSender = (Panel)sender;
currentColor = pnlSender.BackColor;
}
private void panelTarget_MouseMove(object sender, MouseEventArgs e)
{
//the mouse button is released
if (SortMouseLocation == Point.Empty)
{
Panel pnl = (Panel)sender;
pnl.BackColor = currentColor;
}
}

MouseHover and MouseLeave Events controlling

I was building a simple form with one simple effect- opacity reduced when mouse is not over the form, and form becomes opaque when mouse is over it. I am currently encountering couple of difficulties:-
Firstly, I did this-
this.MouseHover += new EventHandler(Form1_MouseHover);
this.MouseLeave += new EventHandler(Form1_MouseLeave);
But I had 1 richtextbox in form too, and as mouse went over it, the form lost opacity again. I had to add this too:-
richTextBox1.MouseHover+=new EventHandler(Form1_MouseHover);
richTextBox1.MouseLeave+=new EventHandler(Form1_MouseLeave);
wondering if there was any better way,because there is still some gap between richtextbox and form boundaries, and form is losing opacity when mouse cursor goes there.
If the mouse is NOT over the form (suppose initially), the form is less opaque. Now, I want form to become opaque as soon as mouse goes over it, but it only happens when mouse movement over form stops completely. If I keep moving mouse over the form, it does not become opaque. Is this a problem with the way events are stored in message queue and all that or will I be able to do something, because I have seen applications with the effect I am trying to implement.
The MouseEnter/Leave events are too unreliable to do this. Best thing to do is just use a Timer that checks if the mouse is still inside the window. Drop a Timer on the form and make the code look like this:
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
this.Opacity = 0.99;
timer1.Interval = 200;
timer1.Enabled = true;
timer1.Tick += timer1_Tick;
}
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
timer1_Tick(this, e);
}
private void timer1_Tick(object sender, EventArgs e) {
this.Opacity = this.Bounds.Contains(this.PointToClient(Cursor.Position)) ? 0.99 : 0.20;
}
}
Btw: avoid increasing the Opacity to 1.0, that forces the native window to be recreated and that can have a lot of side-effects. Using 0.99 is best.
I might be wrong, but why would you use MouseHover event? MouseHover detects when the mouse stop moving on the form and is usually used to show Tooltips.
The event you are looking for is MouseEnter which is the opposite of MouseLeave and detects when the mouse enters the client rect of a window.
In the Leave event, just check if the cursor position is in the window client rect to know if it did actually leave the form or if it is just on top of child control.
Ofc if you use a region, you'll have to adapt the code.
private void Form1_MouseEnter(object sender, EventArgs e)
{
this.Opacity = 1;
}
private void Form1_MouseLeave(object sender, EventArgs e)
{
if (!this.ClientRectangle.Contains(this.PointToClient(Cursor.Position)))
{
this.Opacity = 0.5;
}
}
Add a timer control then use below in timer's tick event. Above answers won't work if you have custom/user controls in your form. So have to use ClientRectangle
this.Opacity = this.ClientRectangle.Contains(this.PointToClient(Cursor.Position)) ? 0.99 : 0.20;
private void Form1_MouseEnter(object sender, EventArgs e)
{
this.Opacity = 1.0;
}
private void Form1_MouseLeave(object sender, EventArgs e)
{
this.Opacity = 0.8;
}

method for move window

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.

Categories

Resources