【问题标题】:Displaying tooltip over a disabled control在禁用的控件上显示工具提示
【发布时间】:2009-11-13 21:48:36
【问题描述】:

当鼠标悬停在禁用的控件上时,我正在尝试显示工具提示。由于禁用的控件不处理任何事件,因此我必须在父窗体中执行此操作。我选择通过处理父表单中的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);
            }
        }
    }

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

谁能告诉我这是为什么?谢谢。

【问题讨论】:

    标签: c# winforms tooltip


    【解决方案1】:

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

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

    希望这会有所帮助,问候

    【讨论】:

    • 这似乎几乎可以工作。一些控件运行正常,而其他控件仍在闪烁。
    • 对我来说比 DJ 回答效果更好。我添加了一个 control.Visible 检查,所以我没有在不可见控件上弹出工具提示。我还将隐藏块移动到显示块之前并检查了 if(_currentToolTipControl != null && _currentToolTipControl != control) { ...Hide(); _currentToolTipControl = null; }(没有这个,快速移动到另一个禁用的控件将无法更新工具提示)。
    【解决方案2】:

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

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

    【讨论】:

    • 大家好 好的解决方案。请允许我改进代码,因为即使鼠标在其他地方,工具提示也会保留在屏幕上。 ... if (CurrentControl != null) { ... toolTips.Show(...);旧控制 = 当前控制; // 记住这个控件 } else if (OldControl != null) // 隐藏显示的工具提示 { toolTips.Hide(OldControl);旧控制 = 空; }
    【解决方案3】:

    如果是 TextBox 控件,将其设置为只读即可解决问题。

    【讨论】:

      【解决方案4】:

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

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

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

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

      这里是提示.. :)

      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
      }
      

      【讨论】:

        【解决方案5】:

        由于没有人指出这一点,这适用于任何暴露 ToolTipService 的控件:

        ToolTipService.ShowOnDisabled="True"

        如本例所示:

        <Button Content="OK"
                ToolTipService.ShowOnDisabled="True" />
        

        【讨论】:

        • 我可能遗漏了一些东西,但这似乎是 WPF 而不是 OP 指定的 Winforms。
        • @Dave 你是对的......现在。我只查看标记为 w/C# 和 WPF 的问题,因此我必须假设在我回答问题时,它的标记不正确。
        【解决方案6】:
        /*
        Inspired by the suggestions above in this post, i wrapped it up as an extended ToolTip control specially works for disabled control. 
        
                        // Reference example
                        var td = new ToolTipOnDisabledControl();
                        this.checkEdit3.Enabled = false;
                        td.SetTooltip(this.checkEdit3, "tooltip for disabled 3333333333333");
        */    
        
        using System;
        using System.Windows.Forms;
        
        namespace TestApp1
        {
            public class ToolTipOnDisabledControl
            {
                #region Fields and Properties
        
                private Control enabledParentControl;
        
                private bool isShown;
        
                public Control TargetControl { get; private set; }
        
                public string TooltipText { get; private set; }
                public ToolTip ToolTip { get; }
                #endregion
        
                #region Public Methods
                public ToolTipOnDisabledControl()
                {
                    this.ToolTip = new ToolTip();
                }
        
                public void SetToolTip(Control targetControl, string tooltipText = null)
                {
                    this.TargetControl = targetControl;
                    if (string.IsNullOrEmpty(tooltipText))
                    {
                        this.TooltipText = this.ToolTip.GetToolTip(targetControl);
                    }
                    else
                    {
                        this.TooltipText = tooltipText;
                    }
        
                    if (targetControl.Enabled)
                    {
                        this.enabledParentControl = null;
                        this.isShown = false;
                        this.ToolTip.SetToolTip(this.TargetControl, this.TooltipText);
                        return;
                    }
        
                    this.enabledParentControl = targetControl.Parent;
                    while (!this.enabledParentControl.Enabled && this.enabledParentControl.Parent != null)
                    {
                        this.enabledParentControl = this.enabledParentControl.Parent;
                    }
        
                    if (!this.enabledParentControl.Enabled)
                    {
                        throw new Exception("Failed to set tool tip because failed to find an enabled parent control.");
                    }
        
                    this.enabledParentControl.MouseMove += this.EnabledParentControl_MouseMove;
                    this.TargetControl.EnabledChanged += this.TargetControl_EnabledChanged;
                }
        
                public void Reset()
                {
                    if (this.TargetControl != null)
                    {
                        this.ToolTip.Hide(this.TargetControl);
                        this.TargetControl.EnabledChanged -= this.TargetControl_EnabledChanged;
                        this.TargetControl = null;
                    }
        
                    if (this.enabledParentControl != null)
                    {
                        this.enabledParentControl.MouseMove -= this.EnabledParentControl_MouseMove;
                        this.enabledParentControl = null;
                    }
        
                    this.isShown = false;
                }
                #endregion
        
                #region Private Methods
                private void EnabledParentControl_MouseMove(object sender, MouseEventArgs e)
                {
                    if (e.Location.X >= this.TargetControl.Left &&
                        e.Location.X <= this.TargetControl.Right &&
                        e.Location.Y >= this.TargetControl.Top &&
                        e.Location.Y <= this.TargetControl.Bottom)
                    {
                        if (!this.isShown)
                        {
                            this.ToolTip.Show(this.TooltipText, this.TargetControl, this.TargetControl.Width / 2, this.TargetControl.Height / 2, this.ToolTip.AutoPopDelay);
                            this.isShown = true;
                        }
                    }
                    else
                    {
                        this.ToolTip.Hide(this.TargetControl);
                        this.isShown = false;
                    }
                }
        
                private void TargetControl_EnabledChanged(object sender, EventArgs e)
                {
                    if (TargetControl.Enabled)
                    {
                        TargetControl.EnabledChanged -= TargetControl_EnabledChanged;
                        enabledParentControl.MouseMove -= EnabledParentControl_MouseMove;
                    }
                }
                #endregion
            }
        }
        

        【讨论】:

        • 虽然只允许代码回答,但不鼓励使用。考虑在代码旁边添加一些解释。
        • 对我来说更好的解决方案。谢谢!
        • EnabledParentControl_MouseMove... else -> else if(this.isShown)
        【解决方案7】:

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

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

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

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

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

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

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

        当一个复选框被选中时,其他复选框被禁用并且它旁边的标签带有一个工具提示文本。

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

        工作加倍,复杂性减半。

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

        【讨论】:

          【解决方案8】:

          我创建了一个只包含一个按钮的新用户控件。

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-07-31
            • 1970-01-01
            • 2011-02-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多