Displaying tooltip over a disabled control

2020-02-01 03:36发布

问题:

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 MouseMove event in the parent form. Here's the code that does the job:

    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 MouseMove event 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.

Can someone tell me why is this? Thanks.

回答1:

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



回答2:

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);
      }
}


回答3:

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

then instead of setting "Enabled" property to false create a Method which disables just basecontrol in it instead of whole 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.

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
}


回答4:

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



回答5:

Here is how I solved this problem

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

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

On each Tab Page I have one Check Box text = 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.

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

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;
    }
}


回答6:

I created a new UserControl which only contains a button.

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);
    }
}