TL;DR If I put a control inside a TScrollBox at negative offset, is there a way to force scrollbars to appear?


TL;DR If I put a control inside a TScrollBox at negative offset, is there a way to force scrollbars to appear?

So I have this scrollbox (TScrollBox, VCL) ... If I put inside one TPanel so that it lies outside the scrollbox on the right/bottom edge, scrollbox will display scrollbars. All good and well.

If I, however, place that TPanel so that it lies outside the scrollbox on the left/top side, there are no scrollbars.

object ScrollBox: TScrollBox
Left = 40
Top = 24
Width = 225
Height = 160
TabOrder = 0
object Panel1: TPanel
Left = 88
Top = 72
Width = 217
Height = 137
Caption = 'Panel1'
TabOrder = 0
end
end
object ScrollBox1: TScrollBox
Left = 368
Top = 24
Width = 225
Height = 160
TabOrder = 1
object Panel2: TPanel
Left = -99
Top = -56
Width = 217
Height = 137
Caption = 'Panel1'
TabOrder = 0
end
end

If I understand the code correctly, this is "by design" as TControlScrollBar always sets scrollinfo.nMin to 0 and only modifies the nMax.

ScrollInfo.nMin := 0;
if FCalcRange > 0 then
ScrollInfo.nMax := Range else
ScrollInfo.nMax := 0;

Did anybody run into that and successfully solved this problem? I don't mind calling some code to update scrollbars as I'm already calling Realing to update them ...

Comments

  1. So the case where you have the panel with negative Left and Top effectively means that the HScroll pos, VScroll pos should be at 99, 56, respectively, IF you could scroll using the scroll bar. Correct? I suppose you want to keep AutoScroll to True and have the scrollbar show if you place items at negative positions (and not set the scroll bars' range yourself). Interesting requirement, but I wonder what is the scenario, before I can try to help.

    ReplyDelete
  2. Attila Kovacs I'm not sure I understood you. What container? I want panel to "stick out" on the left.

    In reality this panel is a custom MDI window which user just moved with mouse to the left and (s)he is expecting scrollbars to appear.

    ReplyDelete
  3. Actually I don't use mdiform and mdichilds but normal forms with some (quite a lot) custom handling.

    ReplyDelete
  4. I'm guessing - one way is to do what happens with MDI Forms/children for controlling scrollbar visibility/range in VCL.Forms and the TFormStyleHook class?

    ReplyDelete
  5. Based on Attila Kovacs's suggestion, this seems to be working fine:

    procedure TScrollBox.FixScrollBoxScrollbarPositions;
    var
    control: TControl;
    minx : integer;
    miny : integer;
    newx : integer;
    newy : integer;
    begin
    if ControlCount = 0 then
    Exit;

    minx := 0;
    miny := 0;
    for control in EnumControls do
    if control.Visible then begin
    minx := Min(minx, control.Left);
    miny := Min(miny, control.Top);
    end;

    minx := minx + HorzScrollBar.Position;
    miny := miny + VertScrollBar.Position;

    DisableAutoRange;
    for control in EnumControls do begin
    newx := control.Left - minx;
    newy := control.Top - miny;
    control.Left := newx;
    control.Top := newy;
    end;
    LockWindowUpdate(Handle);
    EnableAutoRange;
    HorzScrollBar.Position := HorzScrollBar.Position - minx;
    VertScrollBar.Position := VertScrollBar.Position - miny;
    LockWindowUpdate(0);
    end;

    ReplyDelete
  6. Primož Gabrijelčič thanks for posting the solution.

    ReplyDelete
  7. It is working, but not good enough :( There are some edge cases where this "fix" fails to deliver. I'm still trying to find a better approach.

    ReplyDelete
  8. Please post the fix: if you will find one😊

    ReplyDelete
  9. Fabio VITALE ATM it looks like I'll be 're-implementing' TScrollBox functionality using TPanel and two TScrollBars (and even TScrollBar will require some workaround as the implementation is just plain stupid in some parts).

    ReplyDelete

Post a Comment