C# 在禁用的控件上显示工具提示

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1732140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 20:22:05  来源:igfitidea点击:

Displaying tooltip over a disabled control

c#winformstooltip

提问by DJ.

I'm trying to display a tooltip when mouse hovers over a disabled control. Since a disabled control does not handle any events, I have to do that in the parent form. I chose to do this by handling the MouseMoveevent in the parent form. Here's the code that does the job:

当鼠标悬停在禁用的控件上时,我试图显示工具提示。由于禁用的控件不处理任何事件,因此我必须在父窗体中执行此操作。我选择通过处理MouseMove父窗体中的事件来做到这一点。这是完成这项工作的代码:

    void Form1_MouseMove(object sender, MouseEventArgs e)
    {
        m_toolTips.SetToolTip(this, "testing tooltip on " + DateTime.Now.ToString());
        string tipText = this.m_toolTips.GetToolTip(this);
        if ((tipText != null) && (tipText.Length > 0))
        {
            Point clientLoc = this.PointToClient(Cursor.Position);
            Control child = this.GetChildAtPoint(clientLoc);
            if (child != null && child.Enabled == false)
            {
                m_toolTips.ToolTipTitle = "MouseHover On Disabled Control";
                m_toolTips.Show(tipText, this, 10000);
            }
            else
            {
                m_toolTips.ToolTipTitle = "MouseHover Triggerd";
                m_toolTips.Show(tipText, this, 3000);
            }
        }
    }

The code does handles the tooltip display for the disabled control. The problem is that when mouse hovers over a disabled control, the tooltip keeps closing and redisplay again. From the display time I added in the tooltip, when mouse is above the parent form, the MouseMoveevent gets called roughly every 3 seconds, so the tooltip gets updated every 3 seconds. But when mouse is over a disabled control, the tooltip refreshes every 1 second. Also, when tooltip refreshes above form, only the text gets updated with a brief flash. But when tooltip refreshes above a disabled control, the tooltip windows closes as if mouse is moving into a enabled control and the tooltip is supposed to be closed. but then the tooltip reappears right away.

该代码确实处理禁用控件的工具提示显示。问题是当鼠标悬停在禁用的控件上时,工具提示会不断关闭并再次重新显示。从我在工具提示中添加的显示时间来看,当鼠标位于父窗体上方时,该MouseMove事件大约每 3 秒调用一次,因此工具提示每 3 秒更新一次。但是当鼠标悬停在禁用的控件上时,工具提示每 1 秒刷新一次。此外,当工具提示在表单上方刷新时,只有文本会通过短暂的闪光更新。但是,当工具提示在禁用的控件上方刷新时,工具提示窗口将关闭,就像鼠标移动到启用的控件中一样,并且工具提示应该关闭。但随后工具提示会立即重新出现。

Can someone tell me why is this? Thanks.

有人能告诉我这是为什么吗?谢谢。

采纳答案by DJ.

The answer turned out to be a bit simpler, but needed to be applied at all times.

结果证明答案有点简单,但需要始终应用。

void OrderSummaryDetails_MouseMove(object sender, MouseEventArgs e)
{
      Control control = GetChildAtPoint(e.Location);
      if (control != null)
      {
          string toolTipString = mFormTips.GetToolTip(control);
          this.mFormTips.ShowAlways = true;
          // trigger the tooltip with no delay and some basic positioning just to give you an idea
          mFormTips.Show(toolTipString, control, control.Width / 2, control.Height / 2);
      }
}

回答by serge_gubenko

you can show the tooltip only once when mouse hits the disbled control and then hide it when mouse leaves it. Pls, take a look at the code below, it should be showing a tooltip message for all the disabled controls on the form

您只能在鼠标击中禁用的控件时显示一次工具提示,然后在鼠标离开时隐藏它。请看下面的代码,它应该显示表单上所有禁用控件的工具提示消息

private ToolTip     _toolTip = new ToolTip();
private Control     _currentToolTipControl = null; 

public Form1()
{
    InitializeComponent();

    _toolTip.SetToolTip(this.button1, "My button1");
    _toolTip.SetToolTip(this.button2, "My button2");
    _toolTip.SetToolTip(this.textBox1, "My text box");
}

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
    Control control = GetChildAtPoint(e.Location);
    if (control != null)
    {
        if (!control.Enabled && _currentToolTipControl == null)
        {
            string toolTipString = _toolTip.GetToolTip(control);
            // trigger the tooltip with no delay and some basic positioning just to give you an idea
            _toolTip.Show(toolTipString, control, control.Width/2, control.Height/2);
            _currentToolTipControl = control;
        }
    }
    else
    {
        if (_currentToolTipControl != null) _toolTip.Hide(_currentToolTipControl);
        _currentToolTipControl = null;
    }
}

hope this helps, regards

希望这有帮助,问候

回答by Antonio Leite

Here is how I solved this problem

这是我解决这个问题的方法

I have an application that generates code automatically for a PIC32MX.

我有一个为 PIC32MX 自动生成代码的应用程序。

The application has 3 Tab Pages text = PWM, ADC and UART.

该应用程序有 3 个标签页文本 = PWM、ADC 和 UART。

On each Tab Page I have one Check Box text = RPA0

在每个标签页上,我有一个复选框文本 = RPA0

The intention is, when a peripheral uses RPA0, the other peripheral is prevented from using that pin, by disabling it on the other pages, and a tooltip text must pop up on the disabled check boxs saying (example "Used by PWM") what peripheral is using that pin.

目的是,当一个外设使用 RPA0 时,通过在其他页面上禁用它来防止另一个外设使用该引脚,并且必须在禁用的复选框上弹出工具提示文本,说明(例如“PWM 使用”)什么外围设备正在使用该引脚。

The problem is that the tooltip text won't pop up on a disabled check box.

问题是工具提示文本不会在禁用的复选框上弹出。

To solve the problem, I just removed the text of the check boxes and inserted labels with the text the check box should have.

为了解决这个问题,我只是删除了复选框的文本并插入了带有复选框应该具有的文本的标签。

When a check box is checked, the other check boxes are disabled and the label next to it takes a tool tip text.

选中某个复选框后,其他复选框将被禁用,并且旁边的标签带有工具提示文本。

As the label is enabled, the tooltip text pops up, even on a disabled check box.

启用标签后,即使在禁用的复选框上也会弹出工具提示文本。

Double the work, half the complexity.

工作翻倍,复杂性减半。

Here is the code and the designer for C# 2010

这是 C# 2010 的代码和设计器

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void cb_ADC_RPA0_CheckedChanged(object sender, EventArgs e)
        {
            /* Disable pin on other peripherals */
            cb_UART_RPA0.Enabled = !((CheckBox)sender).Checked;
            cb_PWM_RPA0.Enabled = !((CheckBox)sender).Checked;

            SetTootTip((CheckBox)sender, lbl_PWM_RPA0, lbl_UART_RPA0, "ADC");

        }



        private void cb_PWM_RPA0_CheckedChanged(object sender, EventArgs e)
        {
            /* Disable pin on other peripherals */
            cb_UART_RPA0.Enabled = !((CheckBox)sender).Checked;
            cb_ADC_RPA0.Enabled = !((CheckBox)sender).Checked;

            SetTootTip((CheckBox)sender, lbl_ADC_RPA0, lbl_UART_RPA0, "PWM");
        }

        private void cb_UART_RPA0_CheckedChanged(object sender, EventArgs e)
        {
            /* Disable pin on other peripherals */
            cb_ADC_RPA0.Enabled = !((CheckBox)sender).Checked;
            cb_PWM_RPA0.Enabled = !((CheckBox)sender).Checked;
            SetTootTip((CheckBox)sender, lbl_ADC_RPA0, lbl_PWM_RPA0, "UART");

        }

        void SetTootTip(CheckBox sender, Label lbl1, Label lbl2, string text)
        {
            /* Update tooltip on the other labels */
            if (sender.Checked)
            {
                toolTip1.SetToolTip(lbl1, "Used by " + text);
                toolTip1.SetToolTip(lbl2, "Used by " + text);
            }
            else
            {
                toolTip1.SetToolTip(lbl1, "");
                toolTip1.SetToolTip(lbl2, "");
            }
        }
    }
}


namespace WindowsFormsApplication1
{
    partial class Form1
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new System.ComponentModel.Container();
            this.tabControl1 = new System.Windows.Forms.TabControl();
            this.tpPWM = new System.Windows.Forms.TabPage();
            this.tpUART = new System.Windows.Forms.TabPage();
            this.tpADC = new System.Windows.Forms.TabPage();
            this.cb_PWM_RPA0 = new System.Windows.Forms.CheckBox();
            this.cb_ADC_RPA0 = new System.Windows.Forms.CheckBox();
            this.lbl_PWM_RPA0 = new System.Windows.Forms.Label();
            this.lbl_ADC_RPA0 = new System.Windows.Forms.Label();
            this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
            this.lbl_UART_RPA0 = new System.Windows.Forms.Label();
            this.cb_UART_RPA0 = new System.Windows.Forms.CheckBox();
            this.tabControl1.SuspendLayout();
            this.tpPWM.SuspendLayout();
            this.tpUART.SuspendLayout();
            this.tpADC.SuspendLayout();
            this.SuspendLayout();
            // 
            // tabControl1
            // 
            this.tabControl1.Controls.Add(this.tpPWM);
            this.tabControl1.Controls.Add(this.tpUART);
            this.tabControl1.Controls.Add(this.tpADC);
            this.tabControl1.Location = new System.Drawing.Point(12, 12);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new System.Drawing.Size(629, 296);
            this.tabControl1.TabIndex = 0;
            // 
            // tpPWM
            // 
            this.tpPWM.Controls.Add(this.lbl_PWM_RPA0);
            this.tpPWM.Controls.Add(this.cb_PWM_RPA0);
            this.tpPWM.Location = new System.Drawing.Point(4, 22);
            this.tpPWM.Name = "tpPWM";
            this.tpPWM.Padding = new System.Windows.Forms.Padding(3);
            this.tpPWM.Size = new System.Drawing.Size(621, 270);
            this.tpPWM.TabIndex = 0;
            this.tpPWM.Text = "PWM";
            this.tpPWM.UseVisualStyleBackColor = true;
            // 
            // tpUART
            // 
            this.tpUART.Controls.Add(this.cb_UART_RPA0);
            this.tpUART.Controls.Add(this.lbl_UART_RPA0);
            this.tpUART.Location = new System.Drawing.Point(4, 22);
            this.tpUART.Name = "tpUART";
            this.tpUART.Padding = new System.Windows.Forms.Padding(3);
            this.tpUART.Size = new System.Drawing.Size(621, 270);
            this.tpUART.TabIndex = 1;
            this.tpUART.Text = "UART";
            this.tpUART.UseVisualStyleBackColor = true;
            // 
            // tpADC
            // 
            this.tpADC.Controls.Add(this.lbl_ADC_RPA0);
            this.tpADC.Controls.Add(this.cb_ADC_RPA0);
            this.tpADC.Location = new System.Drawing.Point(4, 22);
            this.tpADC.Name = "tpADC";
            this.tpADC.Padding = new System.Windows.Forms.Padding(3);
            this.tpADC.Size = new System.Drawing.Size(621, 270);
            this.tpADC.TabIndex = 2;
            this.tpADC.Text = "ADC";
            this.tpADC.UseVisualStyleBackColor = true;
            // 
            // cb_PWM_RPA0
            // 
            this.cb_PWM_RPA0.AutoSize = true;
            this.cb_PWM_RPA0.Location = new System.Drawing.Point(17, 65);
            this.cb_PWM_RPA0.Name = "cb_PWM_RPA0";
            this.cb_PWM_RPA0.Size = new System.Drawing.Size(15, 14);
            this.cb_PWM_RPA0.TabIndex = 0;
            this.cb_PWM_RPA0.UseVisualStyleBackColor = true;
            this.cb_PWM_RPA0.CheckedChanged += new System.EventHandler(this.cb_PWM_RPA0_CheckedChanged);
            // 
            // cb_ADC_RPA0
            // 
            this.cb_ADC_RPA0.AutoSize = true;
            this.cb_ADC_RPA0.Location = new System.Drawing.Point(17, 65);
            this.cb_ADC_RPA0.Name = "cb_ADC_RPA0";
            this.cb_ADC_RPA0.Size = new System.Drawing.Size(15, 14);
            this.cb_ADC_RPA0.TabIndex = 1;
            this.cb_ADC_RPA0.UseVisualStyleBackColor = true;
            this.cb_ADC_RPA0.CheckedChanged += new System.EventHandler(this.cb_ADC_RPA0_CheckedChanged);
            // 
            // lbl_PWM_RPA0
            // 
            this.lbl_PWM_RPA0.AutoSize = true;
            this.lbl_PWM_RPA0.Location = new System.Drawing.Point(38, 65);
            this.lbl_PWM_RPA0.Name = "lbl_PWM_RPA0";
            this.lbl_PWM_RPA0.Size = new System.Drawing.Size(35, 13);
            this.lbl_PWM_RPA0.TabIndex = 1;
            this.lbl_PWM_RPA0.Text = "RPA0";
            // 
            // lbl_ADC_RPA0
            // 
            this.lbl_ADC_RPA0.AutoSize = true;
            this.lbl_ADC_RPA0.Location = new System.Drawing.Point(38, 66);
            this.lbl_ADC_RPA0.Name = "lbl_ADC_RPA0";
            this.lbl_ADC_RPA0.Size = new System.Drawing.Size(35, 13);
            this.lbl_ADC_RPA0.TabIndex = 2;
            this.lbl_ADC_RPA0.Text = "RPA0";
            // 
            // lbl_UART_RPA0
            // 
            this.lbl_UART_RPA0.AutoSize = true;
            this.lbl_UART_RPA0.Location = new System.Drawing.Point(37, 65);
            this.lbl_UART_RPA0.Name = "lbl_UART_RPA0";
            this.lbl_UART_RPA0.Size = new System.Drawing.Size(35, 13);
            this.lbl_UART_RPA0.TabIndex = 4;
            this.lbl_UART_RPA0.Text = "RPA0";
            // 
            // cb_UART_RPA0
            // 
            this.cb_UART_RPA0.AutoSize = true;
            this.cb_UART_RPA0.Location = new System.Drawing.Point(16, 65);
            this.cb_UART_RPA0.Name = "cb_UART_RPA0";
            this.cb_UART_RPA0.Size = new System.Drawing.Size(15, 14);
            this.cb_UART_RPA0.TabIndex = 5;
            this.cb_UART_RPA0.UseVisualStyleBackColor = true;
            this.cb_UART_RPA0.CheckedChanged += new System.EventHandler(this.cb_UART_RPA0_CheckedChanged);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(758, 429);
            this.Controls.Add(this.tabControl1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.tabControl1.ResumeLayout(false);
            this.tpPWM.ResumeLayout(false);
            this.tpPWM.PerformLayout();
            this.tpUART.ResumeLayout(false);
            this.tpUART.PerformLayout();
            this.tpADC.ResumeLayout(false);
            this.tpADC.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.TabControl tabControl1;
        private System.Windows.Forms.TabPage tpPWM;
        private System.Windows.Forms.Label lbl_PWM_RPA0;
        private System.Windows.Forms.CheckBox cb_PWM_RPA0;
        private System.Windows.Forms.TabPage tpUART;
        private System.Windows.Forms.TabPage tpADC;
        private System.Windows.Forms.Label lbl_ADC_RPA0;
        private System.Windows.Forms.CheckBox cb_ADC_RPA0;
        private System.Windows.Forms.ToolTip toolTip1;
        private System.Windows.Forms.CheckBox cb_UART_RPA0;
        private System.Windows.Forms.Label lbl_UART_RPA0;
    }
}

回答by Rakesh

I tried many but ended up using this simple trick which I think it is more effective.

我尝试了很多,但最终使用了这个简单的技巧,我认为它更有效。

Create a subclass(CustomControl with just base control in it) which extends UserControl

创建一个扩展 UserControl 的子类(CustomControl,其中只有基本控件)

then instead of setting "Enabled" property to false create a Method which disables just basecontrol in it instead of whole CustomControl.

然后,而不是将“启用”属性设置为 false,而是创建一个方法,该方法仅禁用其中的 basecontrol 而不是整个 CustomControl。

Set the tool tip on CustomControl still will be able to fire eventhandlers setting the basecontrol disabled. This works wherever CustomControl is in use rather than coding on every form you use with.

在 CustomControl 上设置工具提示仍然可以触发事件处理程序,将 basecontrol 设置为禁用。这适用于任何使用 CustomControl 的地方,而不是在您使用的每个表单上编码。

Here is the hint.. :)

这是提示.. :)

public partial class MyTextBox : UserControl
{
   ...
   ...
   ...


   public void DisableMyTextBox()
    {
        this.txt.Enabled = false;  //txt is the name of Winform-Textbox from my designer
        this.Enabled = true;
    }

    public void EnableMyTextBox()
    {
        this.txt.Enabled = true;
        this.Enabled = true;
    }

    //set the tooltip from properties tab in designer or wherever
}

回答by MeJ

I created a new UserControl which only contains a button.

我创建了一个新的 UserControl,它只包含一个按钮。

public partial class TooltipButton : UserControl
{
    public TooltipButton()
    {
        InitializeComponent();
    }

    public new bool Enabled
    {
        get { return button.Enabled; }
        set { button.Enabled = value; }
    }

    [Category("Appearance")]
    [Description("The text displayed by the button.")]
    [EditorBrowsable(EditorBrowsableState.Always)]
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    [Bindable(true)]
    public override string Text
    {
        get { return button.Text; }
        set { button.Text = value; }
    }

    [Category("Action")]
    [Description("Occurs when the button is clicked.")]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
    public new event EventHandler Click;

    private void button_Click(object sender, EventArgs e)
    {
        // Bubble event up to parent
        Click?.Invoke(this, e);
    }
}

回答by Sanjay Sharma

In case of TextBox control, making it as readonly solved the issue.

在 TextBox 控件的情况下,将其设置为只读解决了该问题。