简体   繁体   English

如何摆脱TListBox垂直滚动限制?

[英]How to get rid of TListBox vertical scroll limit?

I've implement a log viewer using a TListBox in virtual mode . 在虚拟模式下使用TListBox实现了一个日志查看器

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. 也就是说,当我从顶部向底部滚动垂直条时,它不会将内容滚动到列表的末尾,而只会滚动到某个限制。

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. 我尝试使用SetScrollInfo ,但它没有工作,因为限制听起来不在滚动条中,而是在TListBox本身。

I know the solution of creating a dedicated TCustomControl : in this case, the SetScrollInfo will work as expected. 我知道创建专用TCustomControl的解决方案:在这种情况下, SetScrollInfo将按预期工作。 But does anyone know about a solution/trick to still use TListBox ? 但有没有人知道仍然使用TListBox的解决方案/技巧?

Edit: 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. 编辑:说清楚 - 我不要求(第三方)组件解决方案,但要知道是否有一些低级GDI消息要发送到标准TListBox以覆盖此限制。 If there is none, I'll go to the dedicated TCustomControl solution. 如果没有,我将转到专用的TCustomControl解决方案。

Here is the code using TSCROLLINFO: 这是使用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;

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. 我重命名了问题的标题,并删除了令人困惑的已弃用的MSDN文章。

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 . 出于某种原因,当启用主题时(此处的测试显示在Vista及更高版本中),控件似乎依赖于WM_VSCROLL的Word大小滚动位置数据。

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). 首先,一个复制问题的简单项目,下面是一个拥有大约600,000个项目的所有者绘制虚拟( lbVirtualOwnerDraw )列表框(因为项目数据没有被缓存,所以不需要花一点时间填充该框)。 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;


To see the problem just thumb-track the scroll bar, you'll notice how the items are wrapped to begin from the start for every 65536 one as described by Arnaud in the comments to the question. 要查看问题只是通过拇指跟踪滚动条,您将会注意到项目是如何包装的,从每个65536开始,如Arnaud在问题评论中所述。 And when you release the thumb, it will snap to an item in the top High(Word) . 当您松开拇指时,它将捕捉到顶部High(Word)


Below workaround intercepts WM_VSCROLL on the control and performs thumb and item positioning manually. 下面的解决方法拦截控件上的WM_VSCROLL并手动执行拇指和项目定位。 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;

For a custom log viewer I wrote, I use a TListView in virtual mode, not a TListBox . 对于我写的自定义日志查看器,我在虚拟模式下使用TListView ,而不是TListBox Works great, no 32K limits, no need to fiddle with SetScrollInfo() at all. 效果很好,没有32K限制,根本不需要使用SetScrollInfo() Just set the Item.Count and the rest is handled automatically. 只需设置Item.Count ,其余部分自动处理。 It even has an OnDataHint event that can be used to optimize data access by letting you load only the data that the TListView actually needs. 它甚至还有一个OnDataHint事件,可以通过让您只加载TListView实际需要的数据来优化数据访问。 You don't get that with a TListBox . 你没有用TListBox得到它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM