【问题标题】:How can I disable the scroll-into-view behavior of TScrollBox?如何禁用 TScrollBox 的滚动显示行为?
【发布时间】:2011-08-19 07:18:27
【问题描述】:

我有一个TScrollBox,它的RichEdit 比滚动框大,所以滚动条中都会出现两个侧滚动条。然后我有一个函数DoTask 调用RichEdit.SetFocus

当我向下滚动到想要查看部分文本控件的位置,然后调用DoTask 时,ScrollBox 将自动滚动到 RichEdit 的顶部。我怎样才能避免这种情况?

【问题讨论】:

  • 不使用滚动框似乎是显而易见的解决方案,因为您的滚动条比需要的多
  • @David:如果 RichEdit 是滚动框上的唯一组件,我同意。当然我们不知道是不是这样。将具有自己滚动条的单个组件放在滚动框上会有点……奇怪,确实。
  • 是的,除了richedit还有很多控件。

标签: delphi scroll


【解决方案1】:

如果不侵入 VCL/派生自定义组件,只有一种解决方案 - TForm.SetFocusedControl 覆盖 + 如上所述重新设置滚动条的位置。我添加的一件事是禁用/启用窗口重绘以避免丑陋的跳转。 这是我最后的 sn-p:

sbContainer 是 TScrollBox 而 NoScrCtrl 是放置在其中的控件,它会获得焦点,但我们不希望它在视图中滚动。

function TForm1.SetFocusedControl(Control: TWinControl): Boolean;
var hpos, vpos: integer;
begin
  if Control = NoScrCtrl then
  begin
    sbContainer.Perform(WM_SETREDRAW, WPARAM(False), 0);
    hpos := sbContainer.HorzScrollBar.Position;
    vpos := sbContainer.VertScrollBar.Position;
    Result := inherited SetFocusedControl(Control);
    sbContainer.HorzScrollBar.Position := hpos;
    sbContainer.VertScrollBar.Position := vpos;
    sbContainer.Perform(WM_SETREDRAW, WPARAM(True), 0);
    sbContainer.Refresh;
  end
  else
    Result := inherited SetFocusedControl(Control);
end;

【讨论】:

    【解决方案2】:

    如你所愿,这里有一些建议:

    • 在表单中覆盖SetFocusedControl

      function TForm1.SetFocusedControl(Control: TWinControl): Boolean;
      begin
        if Control = RichEdit then
          Result := True
        else
          Result := inherited SetFocusedControl(Control);
      end;
      

      或者:

      type
        TCustomMemoAccess = class(TCustomMemo);
      
      function TForm1.SetFocusedControl(Control: TWinControl): Boolean;
      var
        Memo: TCustomMemoAccess;
        Scroller: TScrollingWinControl;
        Pt: TPoint;
      begin
        Result := inherited SetFocusedControl(Control);
        if (Control is TCustomMemo) and (Control.Parent <> nil) and
          (Control.Parent is TScrollingWinControl) then
        begin
          Memo := TCustomMemoAccess(Control);
          Scroller := TScrollingWinControl(Memo.Parent);
          SendMessage(Memo.Handle, EM_POSFROMCHAR, Integer(@Pt), Memo.SelStart);
          Scroller.VertScrollBar.Position := Scroller.VertScrollBar.Position +
            Memo.Top + Pt.Y;
        end;
      end;
      
    • 插入TScrollBox

      type
        TScrollBox = class(Forms.TScrollBox)
        protected
          procedure AutoScrollInView(AControl: TControl); override;
        end;
      
      procedure TScrollBox.AutoScrollInView(AControl: TControl);
      begin
        if not (AControl is TCustomMemo) then
          inherited AutoScrollInView(AControl);
      end;
      

      或者:

      procedure TScrollBox.AutoScrollInView(AControl: TControl);
      begin
        if (AControl.Top > VertScrollBar.Position + ClientHeight) xor
            (AControl.Top + AControl.Height < VertScrollBar.Position) then
          inherited AutoScrollInView(AControl);
      end;
      

    或使用以上所有内容的任何创意组合。只有您自己知道如何以及何时滚动它。

    【讨论】:

    • 我想 TScrollBox 的类助手,而不是插入器,也可以解决问题。但无法检查。
    • 我认为这行不通,@Rudy。您不能使用类助手覆盖虚拟方法。方法的原调用点不知道类助手存在,所以会继续调用原方法。
    • @Rob:你是对的。原始调用站点不会使用辅助方法。
    【解决方案3】:

    最简单的解决方案是

    var a, b : Integer;
    begin
      a := ScrollBox1.VertScrollBar.Position;
      b := ScrollBox1.HorzScrollBar.Position;
      richEdit1.SetFocus;
      ScrollBox1.VertScrollBar.Position:=a ;
      ScrollBox1.HorzScrollBar.Position:=b ;
    end;
    

    【讨论】:

      【解决方案4】:

      为了从我的主窗体中禁用滚动查看行为,我使用了以下解决方案:(C++Builder)

      bool __fastcall TMainForm::SetFocusedControl(TWinControl *Control) {
          LockWindowUpdate(Handle);
          int vpos = VertScrollBar->Position;
          int hpos = HorzScrollBar->Position;
          bool result = TForm::SetFocusedControl(Control);
          if (VertScrollBar->Position != vpos) {
              VertScrollBar->Position = vpos;
          }
          if (HorzScrollBar->Position != hpos) {
              HorzScrollBar->Position = hpos;
          }
          LockWindowUpdate(0);
          return result;
      }
      

      【讨论】:

        猜你喜欢
        • 2010-11-27
        • 2012-02-20
        • 2011-02-09
        • 1970-01-01
        • 2013-07-21
        • 2015-04-28
        • 1970-01-01
        • 1970-01-01
        • 2020-10-15
        相关资源
        最近更新 更多