Hi
I Have Some Problem with ScrollBox As Below

1- If I Put a ScrollBox On a form and Put Some Objects such as TButton,TImage , .... on it If I move an object to right (or down) and trepass right side (or Down) of ScrollBox the horizontal (or vertical) scrollBar will be appear But If Imove an object to left (or up) and trepass left side (or top) of ScrollBox no scrollBar will be appear
2- how cane I Scroll Vertical ScrollBar of the ScrollBox by mose wheel (middle scrolling button of mouse)

as brief I want scroll a scrollbox vertically as same as DBGride vertical scrollBar

thanks

Dani AI

Generated

Brief summary and practical fixes for the two issues raised by , with notes on 's suggestions.

A scrollbox’s scrollbars represent positive client coordinates (an origin at 0,0). Trying to place controls “above” or “left of” that origin (negative Top/Left) will not produce the behaviour you expect because the scrollable origin itself cannot go negative. The simplest, robust patterns are: put all content inside a single inner container (a panel) and give that container extra top/left margin, or keep a runtime “content offset” so every child control’s actual Top/Left is >= 0. Implement the latter by computing the minimum Top/Left across children and, if negative, shift every child by -MinTop/-MinLeft (do this whenever you add/move controls).

For mouse-wheel scrolling that behaves like a DBGrid (rows, clamped at top/bottom) the most reliable approach is to handle wheel input in the ScrollBox itself (subclass it) and translate the WM_MOUSEWHEEL delta into a pixel move using the system wheel-lines setting and a row/line height. That avoids application-level message hooks (fragile during form destruction) and gives deterministic clamping to the scrollbar range. Example override (adjust LineHeight to your row height):

type
  TWheelScrollBox = class(TScrollBox)
  protected
    function MouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override;
  end;

function TWheelScrollBox.MouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean;
const
  WHEEL_DELTA = 120;
var
  Lines: UINT;
  DeltaPixels, NewPos, LineHeight: Integer;
begin
  if not SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, @Lines, 0) then Lines := 3;
  LineHeight := 20; // set to your logical row height
  DeltaPixels := MulDiv(WheelDelta, Integer(Lines) * LineHeight, WHEEL_DELTA);
  NewPos := VertScrollBar.Position - DeltaPixels;
  if NewPos < 0 then NewPos := 0;
  if NewPos > (VertScrollBar.Range - VertScrollBar.PageSize) then
    NewPos := VertScrollBar.Range - VertScrollBar.PageSize;
  VertScrollBar.Position := NewPos;
  Result := True;
end;

Notes: choose LineHeight to match your rows (DBGrid.DefaultRowHeight or a control’s Height). Prefer this local override to an Application.OnMessage hook (as hinted, global hooks can cause lifecycle bugs). Always clamp the scrollbar position to [0, Range-PageSize] to prevent “infinite” scrolling.

Recommended Answers

All 3 Replies

1) ScrollBox, as any other componet, use positive positions, having the origin (0,0) on top-left, so you can't place anything above the top, it would be a negative value on top property, so it will be clipped away.

The only work around -if you realy need to do this- is that, when a component is placed above top, let say you need a top=-10, then set top to 0 on this objet and, on ALL other objects in your scrollbox, add 10 to theirs top, so relative positions remain as desired (grafically no scroll bar, but the "backgroud" fall down with all your component on it).

2) Step by step:

-Place a TApplicationEvents on your form, i named it MouseWheelEvent.
-Define a event handler on it for the "OnMessage" event to handle it all, it should look like this:

procedure TGPagView.MouseWheelEventMessage(var Msg: tagMSG;
var Handled: Boolean);
var i: SmallInt;
begin
//Form is active?
if Active then begin
//Was it a wheel move?
if (Msg.message = WM_MOUSEWHEEL) then begin
//Extract mouse wheel movement (positive, negative, small, etc)
i:= HiWord(Msg.wParam);
//Cancel the message so it don't do anything more
Handled:= true;
//Do whatever you need using i as a wheel movement measure...
Form.Caption:= 'Wheel moved '+IntToStr(i)+' ticks.';
end;
end;
end;

Important notice: While the form is not totally freed, it will catch events and try to process them, so be aware, becuase after usual form.close moving the wheel WILL raise errors!

You need to place a "Action:= caFree;" on the FormClose event or you will get crazy debuging it (I did)!

1) ScrollBox, as any other componet, use positive positions, having the origin (0,0) on top-left, so you can't place anything above the top, it would be a negative value on top property, so it will be clipped away.

The only work around -if you realy need to do this- is that, when a component is placed above top, let say you need a top=-10, then set top to 0 on this objet and, on ALL other objects in your scrollbox, add 10 to theirs top, so relative positions remain as desired (grafically no scroll bar, but the "backgroud" fall down with all your component on it).

2) Step by step:

-Place a TApplicationEvents on your form, i named it MouseWheelEvent.
-Define a event handler on it for the "OnMessage" event to handle it all, it should look like this:

procedure TGPagView.MouseWheelEventMessage(var Msg: tagMSG;
var Handled: Boolean);
var i: SmallInt;
begin
//Form is active?
if Active then begin
//Was it a wheel move?
if (Msg.message = WM_MOUSEWHEEL) then begin
//Extract mouse wheel movement (positive, negative, small, etc)
i:= HiWord(Msg.wParam);
//Cancel the message so it don't do anything more
Handled:= true;
//Do whatever you need using i as a wheel movement measure...
Form.Caption:= 'Wheel moved '+IntToStr(i)+' ticks.';
end;
end;
end;

Important notice: While the form is not totally freed, it will catch events and try to process them, so be aware, becuase after usual form.close moving the wheel WILL raise errors!

You need to place a "Action:= caFree;" on the FormClose event or you will get crazy debuging it (I did)!

Hello BitFarmer
Thank you for your attention. But it is not what that I want!
I can using ScrolBy ruttine of ScrollBox for Scrolling ScrollBox By Mouse Wheel But it will scroll indefinitly so if you try to scroll ScrollBox By cliking mouse on Scroll Bar it will Scroll Properly.
I want scroll ScrollBox By mouse wheel as same as Scrolling by Klicking on ScrollBar.
I send you a Sample code that you can see what happend when using mouse wheel
thanks

I have seen your example: You want the scroll bar to detect and display correctly when button.top=-55, but you simple can't, negative tops are objets OUT of the scrollbox, it can hold components with top as big as needed, and the scroll bar will reflect it, but negative tops or lefts are simple object clipped away, out of reach.

Just try to set top to -55 visually on the IDE, the component disapear, there is nothing above the top.

I would just avoid this situation: If the most upper componet you have on your scrollbox has a top of 35, for instance, get this value -in a for loop of all its components, for instance- and put on a variable. Each time you scroll, inc. or dec. this value, and don't let scroll up if this value is zero. This will make objets to stop on top of the panel.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.