【问题标题】:How to set tooltips on ListView Subitems in .Net如何在 .Net 中的 ListView 子项上设置工具提示
【发布时间】:2009-08-25 13:26:56
【问题描述】:

我正在尝试为我的列表视图控件中的一些子项设置工具提示文本。我无法显示工具提示。

大家有什么建议吗?

Private _timer As Timer
Private Sub Timer()
    If _timer Is Nothing Then
        _timer = New Timer
        _timer.Interval = 500
        AddHandler _timer.Tick, AddressOf TimerTick
        _timer.Start()
    End If
End Sub
Private Sub TimerTick(ByVal sender As Object, ByVal e As EventArgs)
    _timer.Enabled = False
End Sub

Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
    If Not _timer.Enabled Then
        Dim item = Me.HitTest(e.X, e.Y)
        If Not item Is Nothing AndAlso Not item.SubItem Is Nothing Then
            If item.SubItem.Text = "" Then
                Dim tip = New ToolTip
                Dim p = item.SubItem.Bounds
                tip.ToolTipTitle = "Status"
                tip.ShowAlways = True
                tip.Show("FOO", Me, e.X, e.Y, 1000)
                _timer.Enabled = True
            End If
        End If
    End If

    MyBase.OnMouseMove(e)
End Sub

【问题讨论】:

    标签: vb.net listview tooltip


    【解决方案1】:

    假设 .NET 2.0 或更高版本,您还可以将ListView.ShowItemToolTips 设置为true。如果您需要自定义给定项目的工具提示文本,请将 ListViewItem.ToolTipText 设置为您要显示的字符串。

    【讨论】:

      【解决方案2】:

      问题中的原始代码不起作用,因为它在OnMouseMove 内创建了一个New ToolTip。我猜ToolTip.Show 方法是异步的,因此函数在调用它后立即退出,破坏了临时的ToolTip。当Show 执行时,该对象不再存在。

      解决方案是通过以下方式创建一个持久的ToolTip 对象:

      1. 表单上的ToolTip 控件;或
      2. 一个私有的ToolTip类字段(配置在类的FinalizeDispose方法中);或
      3. 函数内的Static 对象。

      另外,不需要GetItemAt(),因为ListViewHitTestInfo 已经包含项目和子项目引用。
      改进Colin的答案,这是我的代码:

      Private Sub ListView_MouseMove(sender As Object, e As MouseEventArgs) _
      Handles MyList1.MouseMove
          Static prevMousePos As Point = New Point(-1, -1)
      
          Dim lv As ListView = TryCast(sender, ListView)
          If lv Is Nothing Then _
              Exit Sub
          If prevMousePos = MousePosition Then _
              Exit Sub  ' to avoid annoying flickering
      
          With lv.HitTest(lv.PointToClient(MousePosition))
              If .SubItem IsNot Nothing AndAlso Not String.IsNullOrEmpty(.SubItem.Text) Then
                  'AndAlso .Item.SubItems.IndexOf(.SubItem) = 1
                  '...when a specific Column is needed
      
                  Static t As ToolTip = toolTip1  ' using a form's control
                  'Static t As New ToolTip()      ' using a private variable
                  t.ShowAlways = True
                  t.UseFading = True
                  ' To display at exact mouse position:
                  t.Show(.SubItem.Tag, .Item.ListView, _
                         .Item.ListView.PointToClient(MousePosition), 2000)
                  ' To display beneath the list subitem:
                  t.Show(.SubItem.Tag, .Item.ListView, _
                         .SubItem.Bounds.Location + New Size(7, .SubItem.Bounds.Height + 1), 2000)
                  ' To display beneath mouse cursor, as Windows does:
                  ' (size is hardcoded in ugly manner because there is no easy way to find it)
                  t.Show(.SubItem.Tag, .Item.ListView, _
                         .Item.ListView.PointToClient(Cursor.Position + New Size(1, 20)), 2000)
              End If
              prevMousePos = MousePosition
          End With        
      End Sub
      

      我使代码尽可能通用,以便可以将函数分配给多个ListViews。

      【讨论】:

        【解决方案3】:

        您可以使用MouseMove 事件:

        private void listview1_MouseMove(object sender, MouseEventargs e)
        {
            ListViewItem item = listview1.GetItemAt(e.X, e.Y);
            ListViewHitTestInfo info = listview1.HitTest(e.X, e.Y);
            if((item != null) && (info.SubItem != null))
            {
                toolTip1.SetToolTip(listview1, info.SubItem.Text);
            }
            else
            {
                toolTip1.SetToolTip(listview1, "");
            }
        }
        

        【讨论】:

          【解决方案4】:

          ObjectListView(.NET WinForms ListView 的开源包装器)内置了对单元格工具提示的支持(而且,是的,它确实适用于 VB)。你监听一个CellToolTip 事件,你可以做这样的事情(这无疑是过度的):

          如果您不想使用 ObjectListView,则需要子类化 ListView,侦听 WM_NOTIFY 消息,然后在其中以类似于以下方式响应 TTN_GETDISPINFO 通知:

          case TTN_GETDISPINFO:
              ListViewHitTestInfo info = this.HitTest(this.PointToClient(Cursor.Position));
              if (info.Item != null && info.SubItem != null) {
                  // Call some method of your own to get the tooltip you want
                  String tip = this.GetCellToolTip(info.Item, info.SubItem); 
                  if (!String.IsNullOrEmpty(tip)) {
                      NativeMethods.TOOLTIPTEXT ttt = (NativeMethods.TOOLTIPTEXT)m.GetLParam(typeof(NativeMethods.TOOLTIPTEXT));
                      ttt.lpszText = tip;
                      if (this.RightToLeft == RightToLeft.Yes)
                          ttt.uFlags |= 4;
                      Marshal.StructureToPtr(ttt, m.LParam, false);
                      return; // do not do normal processing
                  }
              }
              break;
          

          显然,这是 C#,而不是 VB,但你明白了。

          【讨论】:

          • 感谢您的建议。我宁愿不使用控件,因为这是我需要为我的列表视图控件做的唯一事情。是否有关于如何“监听 WM_NOTIFY 消息”的教程或示例?谢谢
          • 只需下载 ObjectListView 的代码并查看 ObjectListView.cs 中的 WndProc()。
          • 我想我得到了它的工作,除了一行。 Dim ttt As TOOLTIPTEXT = DirectCast(m.GetLParam(GetType(NativeMethods.TOOLTIPTEXT)), NativeMethods.TOOLTIPTEXT) 我在 NaticeMethods 类中没有看到 TOOLTIPTEXT。
          【解决方案5】:

          如果您在“详细信息”模式下为 ListView 控件设置 ShowItemTooltips 并且不执行任何其他操作,则 ListView 控件将自动为超出其列宽的项和子项提供工具提示。即使 FullRowSelect 属性设置为 true,这也可以工作。如果为 ListViewItem 设置了 ToolTipText 并且 FullRowSelect 为 true,则工具提示将出现在整行;这就是不会为子项显示工具提示的情况。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-09-29
            • 1970-01-01
            • 2021-05-28
            • 2013-01-15
            • 1970-01-01
            相关资源
            最近更新 更多