ListBox显示即时提示(Tips)

  Listbox内容太长时超出Listbox宽度的部分将无法显示,一种解决方法是让Listbox产生横向滚动条,滚动显示内容(见前面的《发掘ListBox的潜力(一):自动调整横向滚动条宽度 》),另一种方法是让Listbox以Tips的方法显示完整内容。本文要实现的是后一种方式。

  Tips其实是一个特殊的窗体,类名为:tooltips_class32(在Commctrl(D6)有定义),可使用CreateWindow函数创建;Windows定义了一组以TTM_开头的消息用来与之通信,比如设置显示内容使用TTM_SETTITLE、删除显示内容使用TTM_DELTOOL。下面是例子:

hWndTip := CreateWindow(TOOLTIPS_CLASS, 'kktListBoxToolTips',
    WS_POPUP or TTS_NOPREFIX or TTS_ALWAYSTIP, 0, 0, 0, 0, hWndTip, 0, HInstance, nil);
SendMessage(hWndTip, TTM_ADDTOOL, 0, Integer(@ti));
SendMessage(hWndTip, TTM_DELTOOL, 0, Integer(@ti));

Tips有两种显示时机:鼠标指向某ListItem时和鼠标点击某ListItem时,这里提供了一个选项供用户,默认为鼠标点击ListItem时显示,因此在type作如下声明:

TToolTipShowEvent = (tsMouseOver, tsClick);

并在控件published处声明ShowToolTipWhen属性:

property ShowToolTipWhen: TToolTipShowEvent read FShowToolTipWhen writeSetShowToolTipWhen default tsClick;

接下来处理WM_LBUTTONDOWN消息判断是否应该显示内容,及处理要显示的内容:

procedure TkktListBox.WMMouseLBDown(var Message: TMessage);
var
  
X, Y, i: integer;
begin
  inherited;
  if (FShowToolTipWhen = tsMouseOver) then Exit;
  X := LOWORD(Message.lParam);
  Y := HIWORD(Message.lParam);
  i := ItemAtPos(Point(X, Y), true); //ItemIndex
  if (i = -1) and (TipsIndex <> -1) then HideToolTip;
  if i<>-1 then ShowToolTip(X, Y, i);
end;

对WM_MOUSEMOVE的处理方式类似:

procedure TkktListBox.WMMouseMove(var Message: TMessage);
var
  X, Y, i: integer;
begin
  if (FShowToolTipWhen = tsClick) then Exit;
  X := LOWORD(Message.lParam);
  Y := HIWORD(Message.lParam);
  i := ItemAtPos(Point(X, Y), true);
  if (i = -1) and (TipsIndex <> -1) then HideToolTip;
  if i<>-1 then ShowToolTip(X, Y, i);
  inherited;
end;

Tips的消隐则在CM_MOUSELEAVE消息里处理:

procedure TkktListBox.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  HideToolTip;
end;

下面给出TkktListBox的完整代码:

unit kktListBox;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Commctrl; const
TTM_SETTITLE = (WM_USER + 32); type
TGetHintTextEvent = procedure(Index: integer; var HintText: string; Sender: TObject) of object;
TToolTipShowEvent = (tsMouseOver, tsClick); TkktListBox = class(TListBox)
private

hWndTip: THandle;
ti: TOOLINFO;
TipsIndex: integer;
FOnGetHintText: TGetHintTextEvent;
FHintTitle: String;
FShowToolTipWhen: TToolTipShowEvent;

    procedure SetHintText(Index: integer);
procedure SetHintTitle(const Value: String);
procedure SetShowToolTipWhen(const Value: TToolTipShowEvent); protected
property ScrollWidth stored False;
public

constructor Create(AOwner: TComponent); override;
procedure CreateWnd; override;
destructor Destroy; override; published
property HintTitle: String read FHintTitle write SetHintTitle;
property ShowToolTipWhen: TToolTipShowEvent read FShowToolTipWhen write SetShowToolTipWhen default tsClick;
property OnGetHintText: TGetHintTextEvent Read FOnGetHintText write FOnGetHintText; end; procedure Register; implementation { TkktListBox }

procedure TkktListBox.CMMouseLeave(var Message: TMessage);
begin
inherited;
HideToolTip;
end; constructor TkktListBox.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
TipsIndex := -1;
FShowToolTipWhen := tsClick;
end;

    //uId := Handle;

hinst := hInstance;
lpszText := nil;
//LPSTR_TEXTCALLBACK;
//CALLBACK将导致回调次数太多
Rect.Left := 0;
Rect.Top := 0;
Rect.Bottom := 0;
Rect.Right := 0;
end;
sendMessage(hWndTip, WM_SETFONT, Self.Font.Handle, Integer(LongBool(False)));
SendMessage(hWndTip, TTM_ADDTOOL, 0, Integer(@ti));
SendMessage(hWndTip, TTM_SETTITLE, 0, Integer(Pchar(FHintTitle)));
end; destructor TkktListBox.Destroy;
begin
if hWndTip<>0 then SendMessage(hWndTip, WM_CLOSE, 0, 0);
inherited;
end; procedure TkktListBox.HideToolTip;
begin
TipsIndex := -1;
SendMessage(hWndTip, TTM_TRACKACTIVATE, 0, 0);
end; procedure TkktListBox.ShowToolTip(X, Y, Index: integer);
var
APoint: TPoint;
ARect: TRect;
begin
if (FShowToolTipWhen = tsClick) and (Index = TipsIndex) then Exit; if FShowToolTipWhen = tsMouseOver then begin
APoint := Point(X+20, Y+20);
end else begin //FShowToolTipWhen = tsClick
ARect := ItemRect(Index);
APoint := ARect.TopLeft;
end;
APoint := Self.ClientToScreen(APoint); SendMessage(hWndTip, TTM_TRACKPOSITION, 0, MAKELPARAM(APoint.X, APoint.Y));
if Index = TipsIndex then Exit;
SetHintText(Index);
SendMessage(hWndTip, TTM_TRACKACTIVATE, 1, integer(@ti));
TipsIndex := Index;
end; procedure TkktListBox.WMMouseLBDown(var Message: TMessage);
var
X, Y, i: integer;
begin
inherited;
if (csDesigning in ComponentState) or (FShowToolTipWhen = tsMouseOver) then Exit;
X := LOWORD(Message.lParam);
Y := HIWORD(Message.lParam);
i := ItemAtPos(Point(X, Y), true); //ItemIndex
if (i = -1) and (TipsIndex <> -1) then HideToolTip;
if i<>-1 then ShowToolTip(X, Y, i);
end; procedure TkktListBox.WMMouseMove(var Message: TMessage);
var
X, Y, i: integer;
begin
if (csDesigning in ComponentState) or (FShowToolTipWhen = tsClick) then Exit;
X := LOWORD(Message.lParam);
Y := HIWORD(Message.lParam);
i := ItemAtPos(Point(X, Y), true);
if (i = -1) and (TipsIndex <> -1) then HideToolTip;
if i<>-1 then ShowToolTip(X, Y, i);
inherited;
end; procedure TkktListBox.SetHintTitle(const Value: String);
begin
if FHintTitle = Value then Exit;
FHintTitle := Value;
SendMessage(hWndTip, TTM_SETTITLE, 0, Integer(Pchar(FHintTitle)));
end; procedure TkktListBox.SetHintText(Index: integer);
var
HintText: string;
begin
if Index<0 then Exit;
SendMessage(hWndTip, TTM_DELTOOL, 0, Integer(@ti));
HideToolTip;
HintText := Items[Index];
if Assigned(FOnGetHintText) then FOnGetHintText(Index, HintText, Self);
ti.lpszText := @HintText[1];
SendMessage(hWndTip, TTM_ADDTOOL, 0, Integer(@ti));
end; procedure TkktListBox.SetShowToolTipWhen(const Value: TToolTipShowEvent);
begin
if FShowToolTipWhen <> Value then begin
FShowToolTipWhen := Value;
HideToolTip;
end;
end; procedure Register;
begin
RegisterComponents('Kacarton', [TkktListBox]);
end; end.

http://blog.csdn.net/nhconch/article/details/520164

发掘ListBox的潜力(三):显示即时提示(Tips)的更多相关文章

  1. 发掘ListBox的潜力(一):自动调整横向滚动条宽度

    <自绘ListBox的两种效果>一文帖出之后,从反馈信息来看,大家对这种小技巧还是很认同.接下来我将继续围绕ListBox写一系列的文章,进一步发掘ListBox的潜力,其中包括:自动调整 ...

  2. 发掘ListBox的潜力(二):鼠标拖放插入点提示

    鼠标拖放插入点提示 鼠标拖放是Windows常见的操作,比如拷贝文件就可用拖放方式进行.在我们编写的应用程序中,有时为了方便用户操作需要支持鼠标拖放.对于大部分的VCL控件只要鼠标将DragMode设 ...

  3. [Domino]从嵌入另一个数据库嵌入的Embedded View无法正常显示,提示unable to lauch

    发现问题 1. 项目中需要在一个数据库中插入另一个数据库的Embedded View,使用起来十分费劲,在选择数据库的下拉菜单中经常会找不到目标数据库: 2. 在做日文版的时候,从workbench导 ...

  4. 实现password框中显示文字提示的方式

    其实实际上实现中并不能让password中显示文字提示,但是我们在工作中有这样的需求,当没输入东西的时候,框内有提示输入密码,但是当输入东西的时候又显示的是*号,那么是如何实现的呢?其实原理很简单,就 ...

  5. Android三种消息提示

    Android消息提示有三种方式: 1  使用Toast显示消息提示框 Toast类用于在屏幕中显示一个提示信息框,该消息提示框没有任何控制按钮,并且不会获得焦点,经过一定时间后自动消失.通常用于显示 ...

  6. Android Studio移动鼠标显示悬浮提示的设置方法

    欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...

  7. PowerShell 显示气球提示框 1

    #加载 Winform 程序集,使用Out-Null抑制输出 [system.Reflection.Assembly]::LoadWithPartialName('System.Windows.For ...

  8. 使用ElasticSearch服务从MySQL同步数据实现搜索即时提示与全文搜索功能

    最近用了几天时间为公司项目集成了全文搜索引擎,项目初步目标是用于搜索框的即时提示.数据需要从MySQL中同步过来,因为数据不小,因此需要考虑初次同步后进行持续的增量同步.这里用到的开源服务就是Elas ...

  9. 解决在Pycharm中无法显示代码提示的问题

    #coding: utf-8from cx_Oracle.CURSOR import *import cx_Oracle conn= cx_Oracle.connect('XX', 'XX', '12 ...

随机推荐

  1. Oracle AWR 报告详解

    转自:http://blog.csdn.net/laoshangxyc/article/details/8615187 持续更新中... Oracle awr报告详解 DB Name DB Id In ...

  2. Javascript 运动基础 01

    JS运动基础  运动基础   让Div运动起来 速度——物体运动的快慢 运动中的Bug 不会停止 速度取某些值会无法停止 到达位置后再点击还会运动 重复点击速度加快   匀速运动 速度不变 <s ...

  3. 树莓派变成一个Web服务器: nginx + php + sqlite

    将树莓派变成一个Web服务器,通过访问网页,就可以控制树莓派,比如:查看摄像头\开灯等等. 一想到Linux Web服务器,我们首先想到的是,Apache + MySql + Php. 树莓派可以安装 ...

  4. USACO Party Lamps 【Binary code solvution】【规律】

    写这道题目的时候遇到了一个令人诧异的问题,就是平台上跑来的结果和我本机跑起来的结果不一样. 后来Debug了之后才发现是我数组开小了,只开到100 的数组竟然都去访问他170位的地址肯定要跪成翔啊.. ...

  5. 引用 U-boot给kernel传参数和kernel读取参数—struct tag

    引用 清风徐徐 的 U-boot给kernel传参数和kernel读取参数—struct tag U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux ...

  6. Android常用动画alpha和rotate同时使用

    Android的动画可以是一种动画,也可以多种动画作用于一张图片上,如RotaeAnimation和AlphaAnimation同时放到一个配置文件中 alpha1.xml <?xml vers ...

  7. 《编程之美》学习笔记——指挥CPU占用率

    问题: 写一个程序.让用户来决定Windows任务管理器(Task Manager)的CPU占用率(单核). 有下面几种情况: 1.CPU占用率固定在50%,为一条直线 2.CPU的占用率为一条直线, ...

  8. Axis2(7):将Spring的装配JavaBean发布成WebService

    在现今的Web应用中经常使用Spring框架来装载JavaBean.如果要想将某些在Spring中装配的JavaBean发布成WebService,使用Axis2的Spring感知功能是非常容易做到的 ...

  9. linux 单网卡绑定两个ip

    一.ubuntu系统: #vi /etc/network/interfaces  OR  $ sudo vi /etc/network/interfaces Modify as follows: au ...

  10. 基于Qt的FreeType字体轮廓解析

    一.本文目的 以前的文档中.详细的介绍了FreeType开源字体引擎库的基础知识.基本用法.但并未详细的阐明在TurboCG中.是如何解析出一个文字的轮廓的,本文集中阐述.怎么样使用FreeType开 ...