在这种情况下如何处理 ToolStripMenuItem?

如何解决在这种情况下如何处理 ToolStripMenuItem?

这是一个 CLR 项目(.NET Framework 4.5)。

我有一个 ContextMenuStrip,当在 ToolStripMenuItem 上按下鼠标右键时会显示它,因为 ToolStripMenuItem 没有 ContextMenuStrip 属性我必须设置右键单击MouseUp 事件中的事件如下所示:

private: System::Void itemToolStripMenuItem_MouseUp(System::Object^ sender,System::Windows::Forms::MouseEventArgs^ e) {
    if (e->Button == System::Windows::Forms::MouseButtons::Right) {
        this->contextMenuStrip1->Show(this->menuStrip1,this->menuStrip1->PointToClient(System::Drawing::Point(this->Cursor->Position.X,this->Cursor->Position.Y)));
    }
}

我希望 DropDown 在单击鼠标右键后保持打开状态,我知道有一个 AutoClose 属性可以设置为 false:

private: System::Void contextMenuStrip1_opening(System::Object^ sender,System::ComponentModel::CancelEventArgs^ e) {
    this->itemsToolStripMenuItem->DropDown->AutoClose = false;
}

问题是当将 AutoClose 设置为 false 时,它​​不会再关闭 DropDown。我找不到用于关闭 Leave 并将 DropDown 设置回 true 的 AutoClose 事件。

我还需要在单击鼠标右键后突出显示 DropDown 项。 这就是我想要实现的目标:

enter image description here

解决方法

menu.DropDown.Closing += ...; 事件用于防止在右键单击项目时关闭菜单。 IsSelected 属性在派生的 ToolStripMenuItem3 类中被覆盖,以保持选中状态。

public class MyForm : Form {

    MenuStrip menubar = new MenuStrip { Dock = DockStyle.Top };
    ToolStripMenuItem menu = new ToolStripMenuItem("Menu");
    ToolStripDropDown menuRemove = new ToolStripDropDown();
    ToolStripMenuItem miRemove = new ToolStripMenuItem("Remove");
    ToolStripItem miClickedItem = null;
    Object tag = new Object();

    public MyForm() : base() {
        var item1 = new ToolStripMenuItem3("Item1");
        var item2 = new ToolStripMenuItem3("Item2");
        var item3 = new ToolStripMenuItem3("Item3");
        menu.DropDownItems.AddRange(new [] { item1,item2,item3 });
        menubar.Items.Add(menu);
        this.MainMenuStrip = menubar;

        Controls.Add(menubar);

        menuRemove.Items.Add(miRemove);

        menu.DropDown.MouseClick += DropDown_MouseClick;
        menu.DropDown.Closing += DropDown_Closing;

        menuRemove.Closed += menuRemove_Closed;
        menuRemove.ItemClicked += menuRemove_ItemClicked;
    }

    private class ToolStripMenuItem3 : ToolStripMenuItem {

        public ToolStripMenuItem3(String text) : base(text) { }

        public override bool Selected {
            get {
                bool b = base.Selected;
                return b || this.Tag != null;
            }
        }
    }

    void menuRemove_Closed(object sender,ToolStripDropDownClosedEventArgs e) {
        if (miClickedItem != null) {
            miClickedItem.Tag = null;
            miClickedItem.Invalidate();
            miClickedItem = null;
            menu.DropDown.Refresh();
        }

        // There is a bug that prevents the DropDown from auto-closing.
        // The menu.DropDown.Closing event is no longer received.
        // Calling Visible = true fixes this problem.
        menu.DropDown.Visible = true;
        bool inside = menu.DropDown.Bounds.Contains(Cursor.Position);
        if (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked) { } // Remove clicked,keep menu open
        else if (e.CloseReason == ToolStripDropDownCloseReason.AppClicked) {
            if (!inside)
                menu.DropDown.Close(); // mouse was clicked outside of the menu bounds
        }
        else
            menu.DropDown.Close();
    }

    void menuRemove_ItemClicked(object sender,ToolStripItemClickedEventArgs e) {
        if (e.ClickedItem == miRemove) {
            menu.DropDown.Items.Remove(miClickedItem);
            miClickedItem = null;
            if (menu.DropDown.Items.Count == 0)
                menu.DropDown.Close(ToolStripDropDownCloseReason.CloseCalled);
        }
    }

    void DropDown_Closing(object sender,ToolStripDropDownClosingEventArgs e) {
        e.Cancel = (miClickedItem != null);
    }

    void DropDown_MouseClick(object sender,MouseEventArgs e) {
        var dropDown = (ToolStripDropDown) sender;
        if (e.Button == MouseButtons.Right) {
            Point p = e.Location;
            if (miClickedItem != null) {
                miClickedItem.Tag = null;
                miClickedItem.Invalidate();
            }

            miClickedItem = dropDown.GetItemAt(p);
            if (miClickedItem != null) {
                // miClickedItem is null if the mouse click is on the border of the menu
                miClickedItem.Tag = tag; // any non-null object
                menuRemove.Show(dropDown,p);
                miRemove.Select();
                dropDown.Invalidate();
            }
        }
    }

    protected override void Dispose(bool disposing) {
        base.Dispose(disposing);
        if (disposing) {
            if (menuRemove != null) {
                menuRemove.Dispose();
                menuRemove = null;
            }
        }
    }
}

ToolStripMenuItem with built-in close button

ToolStripMenuItemX 类:

public class MyForm2 : Form {

    MenuStrip menubar = new MenuStrip { Dock = DockStyle.Top };
    ToolStripMenuItem menu = new ToolStripMenuItem("Menu");

    public MyForm2() : base() {
        var item1 = new ToolStripMenuItemX("Item1");
        var item2 = new ToolStripMenuItemX("Item2");
        var item3 = new ToolStripMenuItemX("Item3");
        menu.DropDownItems.AddRange(new [] { item1,item3 });
        menubar.Items.Add(menu);
        this.MainMenuStrip = menubar;

        Controls.Add(menubar);
    }
}

public class ToolStripMenuItemX : ToolStripMenuItem {

    DrawItemState closeState = DrawItemState.None;
    bool isHit = false;
    bool cancelClose = false;
    Point ptMouse = Point.Empty;
    ToolStripDropDown menuCurrent;
    bool dispose = false;

    public ToolStripMenuItemX(String text) : base(text) {
    }

    protected override void OnParentChanged(ToolStrip oldParent,ToolStrip newParent) {
        base.OnParentChanged(oldParent,newParent);
        if (newParent is ToolStripDropDown) {
            var menu = (ToolStripDropDown) newParent;
            menu.Closing += menu_Closing;
            menuCurrent = menu;
        }
    }

    void menu_Closing(object sender,ToolStripDropDownClosingEventArgs e) {
        if (cancelClose || isHit)
            e.Cancel = true;

        if (dispose) {
            // after the MouseUp event,this menu_Closing is called immediately after,one last time
            // unhook the event and dispose this item
            menuCurrent.Closing -= menu_Closing;
            menuCurrent = null;
            Dispose();
        }
    }

    protected override void OnMouseMove(MouseEventArgs mea) {
        ptMouse = mea.Location;
        var r = GetCloseRectangle();
        closeState = (ptMouse.X >= r.X ? DrawItemState.HotLight : DrawItemState.Selected);
        if (!isHit && mea.Button == MouseButtons.Left) {
            // originally the user clicked the item,but then moved the mouse over the X button
            // in this case,don't close the 
            cancelClose = (ptMouse.X >= r.X);
        }
        base.OnMouseMove(mea);
        Invalidate();
    }

    protected override void OnMouseLeave(EventArgs e) {
        base.OnMouseLeave(e);
        closeState = DrawItemState.None;
        cancelClose = false;
        isHit = false;
        Invalidate();
    }

    protected override void OnMouseDown(MouseEventArgs e) { 
        var r = GetCloseRectangle();
        isHit = r.Contains(e.Location);
        cancelClose = isHit;
        base.OnMouseDown(e);
        Invalidate();
    }

    protected override void OnMouseUp(MouseEventArgs e) {
        base.OnMouseUp(e);
        cancelClose = false;

        // OnMouseUp is called after the 'Closing' event is processed,so setting canceClose has no effect here
        var r = GetCloseRectangle();
        if (isHit) {
            if (r.Contains(e.Location)) {
                // remove the menu item,keep the drop down menu open
                menuCurrent.Items.Remove(this);
                menuCurrent.Invalidate();
                dispose = true; // flags this item for disposal
            }
        }
    }

    public override bool Selected {
        get {
            Rectangle r = GetCloseRectangle();
            return (ptMouse.X >= r.X ? false : base.Selected);
        }
    }

    private Rectangle GetCloseRectangle() {
        var r = this.ContentRectangle;
        int h = r.Height;
        return new Rectangle(r.Right - h,r.Y,h,h);
    }

    protected override void OnPaint(PaintEventArgs e) {
        base.OnPaint(e);
        var g = e.Graphics;
        if (closeState == DrawItemState.HotLight || closeState == DrawItemState.Selected) { 
            var r = GetCloseRectangle();

            if (closeState == DrawItemState.HotLight) {
                var renderer = (ToolStripProfessionalRenderer) this.DropDown.Renderer;
                var ct = renderer.ColorTable;
                Color c1 = (isHit ? ct.ButtonPressedHighlight : ct.ButtonSelectedHighlight);
                Color c2 = (isHit ? ct.ButtonPressedBorder : ct.ButtonSelectedBorder);

                using (var b = new SolidBrush(c1))
                    g.FillRectangle(b,r);

                using (var p = new Pen(c2))
                    g.DrawRectangle(p,r);
            }

            using (var sf = StringFormat.GenericDefault) {
                sf.Alignment = StringAlignment.Center;
                sf.LineAlignment = StringAlignment.Center;
                g.DrawString("x",this.Font,SystemBrushes.ActiveCaptionText,r,sf);
            }
        }
    }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?