如何摆脱TListBox垂直滚动限制? [英] How to get rid of TListBox vertical scroll limit?

查看:174
本文介绍了如何摆脱TListBox垂直滚动限制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已使用<$ c执行日志查看器$ c> TListBox 在虚拟模式

I've implement a log viewer using a TListBox in virtual mode.

它工作正常(对于我写的所有代码),显示内容为预期(我甚至容易地添加了一个水平滚动条),但我想我已经达到了垂直滚动条的某种限制。

It works fine (for all the code I wrote), displays the content as expected (I even added an horizontal scrollbar easily), but I guess I've reached the some kind of limit of the vertical scrollbar.

那就是当我滚动垂直栏从顶部到底部,它不会将内容滚动到列表的末尾,但只能到一些限制。

That is, when I scroll the vertical bar from the top to the bottom, it will not scroll the content to the end of the list, but only to some limit.

你知道有什么可能获得摆脱这个限制?我尝试使用 SetScrollInfo ,但它没有工作,因为极限声音不在滚动条中,而在 TListBox 本身。

Do you know any possibility to get rid of this limit? I tried with SetScrollInfo, but it didn't work since the limit sounds to be not in the scrollbar, but in the TListBox itself.

我知道创建一个专用的 TCustomControl 的解决方案:在这种情况下, SetScrollInfo 将按预期工作。但是有没有人知道仍然使用 TListBox 的解决方案/技巧?

I know the solution of creating a dedicated TCustomControl: in this case, the SetScrollInfo will work as expected. But does anyone know about a solution/trick to still use TListBox?

编辑: TListBox 覆盖此限制。如果没有,我将去专用的 TCustomControl 解决方案。

to make it clear - I don't ask for a (third-party) component solution, but to know if there is some low-level GDI message to send to the standard TListBox to override this limit. If there is none, I'll go to the dedicated TCustomControl solution.

以下是使用TSCROLLINFO的代码:

Here is the code using TSCROLLINFO:

procedure ScrollVertHuge(Handle: HWND; count: integer);
var Scroll: TSCROLLINFO;
begin
  Scroll.cbSize:= sizeof(Scroll);
  Scroll.fMask := SIF_DISABLENOSCROLL or SIF_RANGE;
  Scroll.nMin := 0;
  Scroll.nMax := count;
  SetScrollInfo(Handle,SB_VERT,Scroll,false);
end;

为了确切地说明问题:添加和绘制这两个工作当然(我的工具作为exepected),但不起作用的是垂直滚动条拖动。我重命名了这个问题的标题,并且摆脱了已经弃用的MSDN文章,这是令人困惑的。

To precise the issue: Adding and drawing both work, of course (my tool works as exepected), but what does not work is the vertical scrollbar dragging. I renamed the title of the question, and got rid of the deprecated MSDN articles, which are confusing.

推荐答案

被视为有缺陷的操作系统行为的解决方案,因为除非启用主题,否则列表框控件的默认窗口过程很好地处理缩略图。由于某些原因,当启用主题(测试在这里显示与Vista和更高版本),控件似乎依赖于Word大小的滚动位置数据 WM_VSCROLL

The below probably should be considered as a work-around for defective OS behavior, since, unless themes are enabled, the default window procedure of a listbox control handles thumb-tracking quite well. For some reason, when themes are enabled (test here shows with Vista and later), the control seems to rely upon the Word sized scroll position data of WM_VSCROLL.

首先,一个简单的项目来复制问题,下面是一个拥有者绘制虚拟( lbVirtualOwnerDraw )列表框,大约有60万项由于项目数据没有被缓存,所以不需要花费时间来填充框)。一个高大的列表框将很容易遵循以下行为:

First, a simple project to duplicate the problem, below is an owner draw virtual (lbVirtualOwnerDraw) list box with some 600,000 items (since item data is not cached it doesn't take a moment to populate the box). A tall listbox will be good for easy following the behavior:

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    procedure ListBox1Data(Control: TWinControl; Index: Integer;
      var Data: string);
    procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
      Rect: TRect; State: TOwnerDrawState);
    procedure FormCreate(Sender: TObject);
  end;

[...]

procedure TForm1.FormCreate(Sender: TObject);
begin
  ListBox1.Count := 600000;
end;

procedure TForm1.ListBox1Data(Control: TWinControl; Index: Integer;
  var Data: string);
begin
  Data := IntToStr(Index) + ' listbox item number';
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
  Rect: TRect; State: TOwnerDrawState);
begin
  // just simple drawing to be able to clearly see the items
  if odSelected in State then begin
    ListBox1.Canvas.Brush.Color := clHighlight;
    ListBox1.Canvas.Font.Color := clHighlightText;
  end;
  ListBox1.Canvas.FillRect(Rect);
  ListBox1.Canvas.TextOut(Rect.Left + 2, Rect.Top + 2, ListBox1.Items[Index]);
end;


要看到问题只是拇指跟踪滚动条,你会注意到项目被包装,从开始每个65536开始,如Arnaud在对问题的评论中所描述的。当您松开拇指时,它将卡入顶部 High(Word)中的项目。


以下解决方法在控件上截取 WM_VSCROLL ,并手动执行缩略图和项目定位。该示例为了简单起见使用了插入器类,但任何其他子类方法都可以:


Below workaround intercepts WM_VSCROLL on the control and performs thumb and item positioning manually. The sample uses an interposer class for simplicity, but any other sub-classing method would do:

type
  TListBox = class(stdctrls.TListBox)
  private
    procedure WMVScroll(var Msg: TWMVScroll); message WM_VSCROLL;
  end;

[...]

procedure TListBox.WMVScroll(var Msg: TWMVScroll);
var
  Info: TScrollInfo;
begin
  // do not intervene when themes are disabled
  if ThemeServices.ThemesEnabled then begin
    Msg.Result := 0;

    case Msg.ScrollCode of
      SB_THUMBPOSITION: Exit; // Nothing to do, thumb is already tracked
      SB_THUMBTRACK:
        begin
          ZeroMemory(@Info, SizeOf(Info));
          Info.cbSize := SizeOf(Info);
          Info.fMask := SIF_POS or SIF_TRACKPOS;
          if GetScrollInfo(Handle, SB_VERT, Info) and
              (Info.nTrackPos <> Info.nPos) then
            TopIndex := TopIndex + Info.nTrackPos - Info.nPos;
        end;
      else
        inherited;
    end;
  end else
    inherited;
end;

这篇关于如何摆脱TListBox垂直滚动限制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆