I'm trying to get the tabpage that was clicked by right button of mouse,in another words the tabpage that opened the contextmenustrip.
There's a toolstripmenuitem called Close which I used to close the tab that was clicked on.
I used this code :
public partial class USBrowser : Form
{
private Point lastpoint;
}
private void closeTabToolStripMenuItem_Click(object sender, EventArgs e)
{
for (int i = 0; i < browserTabControl.TabCount; i++)
{
Rectangle rec = browserTabControl.GetTabRect(i);
if (rec.Contains(this.PointToClient(lastpoint)))
closeTab(i);//this function closes the tab at specific index
}
}
protected override void OnMouseClick(MouseEventArgs e)
{
base.OnMouseClick(e);
if (e.Button == MouseButtons.Right)
lastpoint = Cursor.Position;
}
I also added(when adding the tabpage) :
browserTabControl.TabPages.Insert(browserTabControl.TabCount - 1,WebPage);
browserTabControl.SelectTab(WebPage);
browserTabControl.SelectedTab.MouseClick += SelectedTab_MouseClick;
void SelectedTab_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
lastpoint = Cursor.Position;
}
The problem is that the lastpoint is always (0,0) !!
Why ?
Any other suggested idea is welcomed
thanx in advance
None of these event handlers will actually run. Not the form's OnMouseClick() method since you are not actually right-clicking the form. And not the tab page's MouseClick event handler since you gave the TabControl a context menu. So lastpoint being empty is the expected outcome.
It is not clear how you want this context menu to work. If you use it by right-clicking the tab page then it is simple, just destroy the selected page:
private void closeToolStripMenuItem_Click(object sender, EventArgs e) {
tabControl1.SelectedTab.Dispose();
}
If you activate it by right-clicking a tab, one that isn't selected, then it gets more complicated. You have to memorize which tab was clicked on, do so by using the context menu's Opening event:
private TabPage RightClickedTab;
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e) {
RightClickedTab = tabControl1.SelectedTab;
var pos = tabControl1.PointToClient(Cursor.Position);
for (int tab = 0; tab < tabControl1.TabCount; ++tab) {
if (tabControl1.GetTabRect(tab).Contains(pos)) {
RightClickedTab = tabControl1.TabPages[tab];
break;
}
}
}
private void closeToolStripMenuItem_Click(object sender, EventArgs e) {
if (RightClickedTab != null) RightClickedTab.Dispose();
}
Related
Im trying to open a new form when a label is double clicked. Im able to drag and drop the label .Im trying to open a new form on double click of label now.
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
this.DoDragDrop(control.Name, DragDropEffects.Move);
}
private void control_DoubleClick(object sender, EventArgs e)
{
frm = new Frm();
frm.ShowDialog();
frm.Dispose();
}
EDIT 1:
I have tried both possible answers below, and they have not worked for me?
A more cleaner way is (note I changed Frm to Form1):
private void control_DoubleClick(object sender, EventArgs e)
{
using (Form1 frm = new Form1())
{
frm.ShowDialog();
}
}
You can't add DragDrop on MouseDown and then DoubleClick. That won't work.
I don't think there's an easy way to get around that, but once a control is being dragged, it won't respond to double click messages.
I've made some quick tests, and there's a "hacky" way. It'll make your dragging look weird (since it'll start after some time, instead of immediately after you press the mouse button), but here it goes:
private bool _willDrag = false;
private bool control_MouseUp(object sender, MouseEventArgs e)
{
// disable dragging if we release the mouse button
_willDrag = false;
}
private bool control_DoubleClick(object sender, EventArgs e)
{
// disable dragging also if we double-click
_willDrag = false;
// .. the rest of your doubleclick event ...
}
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
if (control == null)
return;
_willDrag = true;
var t = new System.Threading.Timer(s =>
{
var callingControl = s as Control;
if (callingControl == null)
return;
// if we released the mouse button or double-clicked, don't drag
if(!_willDrag)
return;
_willDrag = false;
Action x = () => DoDragDrop(callingControl.Name, DragDropEffects.Move);
if (control.InvokeRequired)
control.Invoke(x);
else
x();
}, control, SystemInformation.DoubleClickTime, Timeout.Infinite);
}
In the form.Designer right click on your label then properties, in the properties window click in events (the thunder icon), in the double_Click event dropdown select the event handler (control_DoubleClick) this method must have two parameters an object and a eventArgs
This is tricky as the DoDragDrop will eat up any further mouse events, and MSDN posting a rather stupid example doesn't help much.
Solution: Do not start the D&D in the MouseDown if you want to still receive click or double click events but use the MouseMove instead:
Replace this
private void control_MouseDown(object sender, MouseEventArgs e)
{
var control = sender as Control;
this.DoDragDrop(control.Name, DragDropEffects.Move);
}
by this:
private void control_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
DoDragDrop((sender as Control), DragDropEffects.Move);
}
Don't forget to hook up the new event!
This function only recognizes mouse's Left button. How can I make this program recognize mouse's right button in order to click this button with mouse's right button?.
private void button2_Click(object sender, EventArgs e)
{
MouseEventArgs me = (MouseEventArgs)e;
if (buttonwasclicked==false)
{
DrawLinesOnBitmap(button2.BackgroundImage);
button2.BackgroundImage= ToGrayscale(button2.BackgroundImage);
buttonwasclicked = true;
}
else {
button2.BackgroundImageLayout = ImageLayout.Stretch;
button2.BackgroundImage = Image.FromFile("C:\\Users\\rati\\Desktop\\ks.png");
buttonwasclicked = false;
}
if (me.Button == MouseButtons.Left)
{
mysum += md;
if (buttonwasclicked == true) md *= -1; else md *= -1;
label1.Text = mysum.ToString();
}
if (me.Button == MouseButtons.Right) {
enemysum += ed;
if (buttonwasclicked == true) ed *= -1; else ed *= -1;
label2.Text = enemysum.ToString();
}
}
Use the "MouseClick" event rather than the "Click" event, "Click" doesn't recognise right clicks of the mouse.
If you're using Visual Studio, simply go to the designer, click the button, go to properties and click the lightning icon. Then you find "MouseClick" and double click this.
You need to use the MouseDown and MouseUp actions together in order to interpret a click.
Your actions list should look similar to this:
Then interpret the actions as follows:
int prevMouseX;
int prevMouseY;
private void mouseDown(object sender, MouseEventArgs e)
{
prevMouseX = e.X;
prevMouseY = e.Y;
}
private void mouseUp(object sender, MouseEventArgs e)
{
if (prevMouseX == e.X && prevMouseY == e.Y)
mouseClick(sender, e);
}
private void mouseClick(object sender, MouseEventArgs e)
{
//Do Stuff
}
That should work for you!
My code interprets a click as when the mouse goes down and up in the same position.
Try this if you want to do something on Button's right click event.
=> Create one context menu and do not create any option in it.(Drag & Drop ContextMenuStrip from Toolbox)
=> Assign that context menu to that button from Button's ContextMenuStrip property in Properties panel.
Write following code on Context Menu's Opening Event
private void contextMenuStrip1_Opening(object sender, CancelEventArgs e)
{
MessageBox.Show("hii");
e.Cancel=true;
}
You should use MouseDown event. It has MouseEventArgs parameter which contains Button property. So you can check wich button was down.
I would like to extended DataGridView to add a second ContextMenu which to select what columns are visible in the gird. The new ContextMenu will be displayed on right click of a column's header.
I am having difficulty get the correct horizontal position to show the context menu. How can I correct this?
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.ColumnHeaderMouseClick += new System.Windows.Forms.DataGridViewCellMouseEventHandler(ColumnHeaderMouseClick);
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
}
Here is a very simple way to make context menu appear where you right-click it.
Handle the event ColumnHeaderMouseClick
private void grid_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
contextMenuHeader.Show(Cursor.Position);
}
contextMenuHeader is a ContextMenuStrip that can be defined in the Designer view or at runtime.
To get the coordinate of the mouse cursor you could do this.
ContextMenu.Show(this, myDataGridView.PointToClient(Cursor.Position));
Have you tried using the Show overload that accepts a control and a position?
For example:
contextMenuStrip.Show(dataGrid, e.Location);
Edit: Full example
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid, e.Location);
}
}
}
}
e.Location does not show the popup menu at the correct coordinates, instead just use the MousePosition property as follows:
ContextMenuStrip.Show(MousePosition)
or, explicitely
ContextMenuStrip.Show(Control.MousePosition)
The position returned is relative to the cell. So we have to add that offset.
private void grdView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
var pos = ((DataGridView)sender).GetCellDisplayRectangle(e.ColumnIndex,
e.RowIndex, false).Location;
pos.X += e.X;
pos.Y += e.Y;
contextMenuStrip.Show((DataGridView)sender,pos);
}
}
Finally this worked for me.
ContextMenu.Show(myDataGridView, myDataGridView.PointToClient(Cursor.Position));
Calling Show twice will get you the exact location of the cursor. This answer is for those whom are unable to get the result with all above answers.
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(dataGrid, e.Location));
contextMenuStrip.Show(Cursor.Position);
}
}
Where I was going wrong was that DataGridViewCellMouseEventArgs returns the location/x,y of where the mouse clicked within the column header. Instead I need to use HitTest in the grid's MouseDown event for a hit on the column headers and then convert the position of the hit from the gird co-ordinates to the screen co-ordinates.
public partial class Form1 : Form
{
DataGridView dataGrid;
ContextMenuStrip contextMenuStrip;
public Form1()
{
InitializeComponent();
dataGrid = new DataGridView();
Controls.Add(dataGrid);
dataGrid.Dock = System.Windows.Forms.DockStyle.Fill;
//dataGrid.ColumnHeaderMouseClick += ColumnHeaderMouseClick;
dataGrid.MouseDown += MouseDown;
dataGrid.DataSource = new Dictionary<string, string>().ToList();
contextMenuStrip = new ContextMenuStrip();
contextMenuStrip.Items.Add("foo");
contextMenuStrip.Items.Add("bar");
}
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(PointToScreen(e.Location));
}
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
if (dataGrid.HitTest(e.X, e.Y).Type == DataGridViewHitTestType.ColumnHeader)
{
contextMenuStrip.Show(dataGrid.PointToScreen(e.Location));
}
}
}
}
You were nearly right. You just need to the apply the PointToScreen method to the calling control:
private void ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
contextMenuStrip.Show(((DataGridView)sender).PointToScreen(e.Location));
}
}
I think this is the most elegant solution, because it uses only the ColumnHeaderMouseClick arguments and not Cursor.Position.
I have a contextmenustrip that contains some option, I have almost implemented everything, i just want to check which items i have selected in options_MouseClick
private void ConsoleRichTextBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
options.Show();
Point currentPoint;
currentPoint = new Point(e.X, e.Y);
options.Show(ConsoleRichTextBox, currentPoint);
}
}
private void options_MouseClick(object sender, MouseEventArgs e)
{
//if options selected = clear
ConsoleRichTextBox.Clear();
}
You should just handle the Click event of each of the menu items. There's no need to handle the MouseClick event of a contextmenustrip. Also you can add multiple handlers to the same method and differentiate with the sender parameter as this will refer to the exact menu item that was clicked.
ToolStripMenuItem tsmi = new ToolStripMenuItem();
tsmi.Click += tsmi_Click;
and:
public void tsmi_Click(object sender, EventArgs e)
{
if (sender == tsmi)
{
// Do stuff
}
}
Is there any easy (5 lines of code) way to do this?
The shortest code to delete the tab the middle mouse button was clicked on is by using LINQ.
Make sure the event is wired up
this.tabControl1.MouseClick += tabControl1_MouseClick;
And for the handler itself
private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
var tabControl = sender as TabControl;
var tabs = tabControl.TabPages;
if (e.Button == MouseButtons.Middle)
{
tabs.Remove(tabs.Cast<TabPage>()
.Where((t, i) => tabControl.GetTabRect(i).Contains(e.Location))
.First());
}
}
And if you are striving for least amount of lines, here it is in one line
tabControl1.MouseClick += delegate(object sender, MouseEventArgs e) { var tabControl = sender as TabControl; var tabs = tabControl.TabPages; if (e.Button == MouseButtons.Middle) { tabs.Remove(tabs.Cast<TabPage>().Where((t, i) => tabControl.GetTabRect(i).Contains(e.Location)).First()); } };
Solution without LINQ not so compact and beautiful, but also actual:
private void TabControlMainMouseDown(object sender, MouseEventArgs e)
{
var tabControl = sender as TabControl;
TabPage tabPageCurrent = null;
if (e.Button == MouseButtons.Middle)
{
for (var i = 0; i < tabControl.TabCount; i++)
{
if (!tabControl.GetTabRect(i).Contains(e.Location))
continue;
tabPageCurrent = tabControl.TabPages[i];
break;
}
if (tabPageCurrent != null)
tabControl.TabPages.Remove(tabPageCurrent);
}
}
Don't have enough points to post a comment to the provided solutions but they all suffer from the same flaw: The controls within the removed tab are not released.
Regards
You could do this:
private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle)
{
// choose tabpage to delete like below
tabControl1.TabPages.Remove(tabControl1.TabPages[0]);
}
}
Basically you are just catching a mouse click on tab control and only deleting a page if the middle button was clicked.