Jump to content
Chris1701

Setting Scroll Bar Width problem

Recommended Posts

I've been working on a Delphi VCL app mainly meant to be used on a Windows 10 tablet (running Win 10 x64 1909) that has no keyboard or mouse, it's generally been working really well but occasionally I'll do some debugging of non-UI code on my desktop development system and not too long ago I switched from an Intel system running Windows 8.1 to a AMD system running Windows 10 x64 1909, I'm also using Rad Studio 10.4.1 with the latest updates and patches. One of the problems that I initially had was that the default scrollbars were too small to use touch on in that I couldn't reliably scroll them with my fingertip, I had posted asking about this on the old Embarcadero Delphi forums and Peter Below said that there was no way to change just your programs scrollbar width but that he used a method that changed the default system scrollbar width and then set it back when exiting the program. This is the code he gave me that doubles the scrollbar width and then resets it:

procedure TMainForm.SetScrollbarwidth;

Var
  LTemp: TNonClientMetrics;

begin

  ResetScrollBarsClick( Self );

  FillChar(LTemp, sizeof(LTemp), 0);
  LTemp.cbSize := sizeof(LTemp);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(LTemp), @LTemp, 0);
  FOldScrollbarWidth := LTemp.iScrollWidth;
  LTemp.iScrollWidth := LTemp.iScrollWidth * 2;
  SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(LTemp), @LTemp, 0);
end;

procedure TMainForm.RestoreScrollbarWidth;

var
  LTemp: TNonClientMetrics;

begin
  If FOldScrollbarWidth <= 0 then Exit;

  FillChar(LTemp, sizeof(LTemp), 0);
  LTemp.cbSize := sizeof(LTemp);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(LTemp), @LTemp, 0);
  LTemp.iScrollWidth := FOldScrollbarWidth;
  SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(LTemp), @LTemp, 0);
end;

The problem that I'm suddenly having is that this works fine on the tablet (and used to work fine on my old Intel system with Windows 8.1) but on my desktop development machine when I get to the last line of code in SetScrollbarwidth "SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(LTemp), @LTemp, 0);" that line of code is executed (the scrollbar width doubles) the program seems to hang up there; the debugger says "Running" but it never exits back to the OnCreate procedure of the main form that called SetScrollbarwidth to the next line of code and no matter how much time I leave it running it never continues and Process Explorer says that it's using zero cpu time. I also created a small sample x32 application that has a form and a button that sets the default scrollbar width back to the default which seems to be 17 and it seems to have the exact same problem, the scrollbar width is set but it doesn't continue after that last line and gets stuck there.

 

Anyone have any idea's why this is a problem on my desktop but not the tablet?

Share this post


Link to post
implementation

{$R *.dfm}

var
  lNCMtemp          : TNonClientMetrics;
  lScrollbarWidthBCK: integer = -1; // lNCMtemp.iScrollWidth;

procedure prcInitScrollBarVar;
begin
  FillChar(lNCMtemp, sizeof(lNCMtemp), 0);
  lNCMtemp.cbSize := sizeof(lNCMtemp);
  SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(lNCMtemp), @lNCMtemp, 0);  // you run 1x to get the values
  //
  lScrollbarWidthBCK := lNCMtemp.iScrollWidth;
end;

procedure prcSetRestoreScrollBarWidth(lSetIt: boolean = false; lScrollBarWidth: integer = 25);
begin
  if lSetIt then
  begin
    // lScrollbarWidthBCK    := lNCMtemp.iScrollWidth;
    lNCMtemp.iScrollWidth := lScrollBarWidth; // lNCMtemp.iScrollWidth * 2; // desired value!
  end
  else
    lNCMtemp.iScrollWidth := lScrollbarWidthBCK;
  //
  SystemParametersInfo(SPI_SETNONCLIENTMETRICS, sizeof(lNCMtemp), @lNCMtemp, 0);   // you run 2x to set the values = you see? you run it 2x!!!
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FOldScrollbarWidth := 1; // what is initial value?
  //
  Self.AutoScroll := true; // forcing the autoscroll on my form...
end;

procedure TForm1.btnSetScrollBarWidthClick(Sender: TObject);
begin
  prcSetRestoreScrollBarWidth(true, (lNCMtemp.iScrollWidth * 2));
end;

procedure TForm1.btnRestoreScrollBarWidthClick(Sender: TObject);
begin
  prcSetRestoreScrollBarWidth(false);
end;
...
initialization

prcInitScrollBarVar;

finalization

prcSetRestoreScrollBarWidth(false);

end.

Defining ScrollBars width by code, in you app, is influencing all applications on MSWindows, however, it seems that the system is locked... but it doesnt!

MSWindows is waiting for everything to be redefined according to your app!

This time, is being like 5~6.0 seconds, in my tests using:
-- VM with 2cores, 6GB RAM
-- MSWindows 20H2
-- RAD Studio 10.4.1 Arch
-- your code VCL in DEBUG or RELEASE mode

I think that is not right way to get it! Same that your app be "the unique" software in your system!

Try another approach for this task! Maybe, dont interfering with the system, but only with your application.
Then, the "answer" can be more quick!

 

image.png

Edited by emailx45

Share this post


Link to post

I also tried something like this in the past. We dropped it, because it was a bad idea after all, even for a kiosk application like ours.

 

Yes, it takes time. Sometimes, even other 3rd party application would completely lock up.

 

I would strongly recommend to drop this approach. It will take a bit of work to roll your own scrollbar (for a general TWinControl, and maybe a TDBGrid), but you will end up with something that fully suits your needs and can be customized to run differently in Touch and in Desktop mode.

  • Like 2

Share this post


Link to post

Thanks for the idea's but I'm kind of an old time guy and I just don't have the knowledge to make my own components or descendants of existing components to replace this changing of the system default scrollbar width so that's kind of out for me.

 

Just to give a few more details that perhaps I should have included, the main form of this VCL application uses a Raize Components TrzDBGrid now I could replace that component with any other dbgrid that does the same thing but it's a navigation problem that it's too hard to scroll or search in the dbgrid using touch when the scroll bar which I understand from Peter is a windows common control and there's no way in either the default dbgrid or any of the alternate dbgrid's I have access to (the SMComponents dbgrid or the Alpha Controls dbgrid) to make it replace the windows common control with an alternate scrollbar and as I said my skills just aren't up to creating my own dbgrid descendant or my own scrollbar.

 

Btw Peter Below has been a VIP in the Delphi forums for more than 15 years and he's helped me out more times than I can count (and he's never steered me wrong) so I don't think he would have suggested something that was very problematic and in fact he said he's used this method for the same reason.

Share this post


Link to post

then, if trusth him... why any doubt about.

just use it and be happy

Edited by emailx45

Share this post


Link to post

I still don't quite understand why you're marking it so hard. 

You said your primary audience is using touch. Why don't you just place some big buttons right next to the DBGrid?
972558082_Screenshot2020-11-17095905.thumb.png.68569303ab779b52038ecfdcb945bef5.png

  • Like 2

Share this post


Link to post
6 hours ago, emailx45 said:

then, if trusth him... why any doubt about.

just use it and be happy

Yeah but as I said it works fine on the Windows 10 tablet and it did work fine on my old i7-6850K Intel Windows 8.1 desktop but on my new Ryzen-3950X Windows 10 desktop the line of code that sets the width works but gets stuck on that last line of code and never exits from the procedure setting the scrollbar width so I can;t debug code on my desktop anymore which makes it real hard to fix problems.

Share this post


Link to post
4 hours ago, Der schöne Günther said:

I still don't quite understand why you're marking it so hard. 

You said your primary audience is using touch. Why don't you just place some big buttons right next to the DBGrid?
972558082_Screenshot2020-11-17095905.thumb.png.68569303ab779b52038ecfdcb945bef5.png

Because that only allows me to scroll to the top or bottom and up or down one item at a time, with the expanded scroll bar I can scroll up or down a page at a time making navigation of the dbgrid much easier; if there's a way to create a button that scrolls the dataset or dbgrid by a page at a time up or down I haven't been able to find it. I suppose I could determine the number of lines in the dbgrid and then scroll up or down in a loop by that number but I vaguely recall trying something like that before using this double the scrollbar width method and there was some kind of problem with it I couldn't resolve.

Share this post


Link to post

You can make those buttons do what you want, which includes "Page up" or "page down". To be honest, I remember that being a bit tricky. I should be able to access that projects source in a few hours (in case no one else has a solution at hand).

Share this post


Link to post
31 minutes ago, Chris1701 said:

if there's a way to create a button that scrolls the dataset or dbgrid by a page at a time up or down I haven't been able to find it.

 

procedure TMyForm.ButtonScrollPageUp(Sender: TObject);
begin
  PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEUP, 0);
end;

procedure TMyForm.ButtonScrollPageDown(Sender: TObject);
begin
  PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEDOWN, 0);
end;

 

  • Thanks 1

Share this post


Link to post
On 11/17/2020 at 8:50 AM, Anders Melander said:

 


procedure TMyForm.ButtonScrollPageUp(Sender: TObject);
begin
  PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEUP, 0);
end;

procedure TMyForm.ButtonScrollPageDown(Sender: TObject);
begin
  PostMessage(MyGrid.Handle, WM_SCROLL, SB_PAGEDOWN, 0);
end;

 

I'll give it a try and get back to you.

Share this post


Link to post

I would suggest that you try AlphSkins, you can give it a try, just remember all grids component are not supported by default, but will be skinned by adding them to ThirdParty list in SkinManager as shown in this screenshot

image.thumb.png.5aee6c8bf67d9a9ef81b23805abb44d0.png

 

After that you can control these component in sSkinManager

image.thumb.png.85461c02d4cf30c6d1ccbfbcc57f9513.pngimage.thumb.png.aa8e90fe647724db580294f85d6b7666.png 

 

Also there is special package to handle the DB-Aware controls https://www.alphaskins.com/dwnld.php , ScrollOptions in supported controls are individually assigned. 

 

The lifetime license is $190 and it does worth every cent, the author is always there providing great and fast support, and always adding features, every version is just better, try it for yourself and see if it does fit your need.

  • Like 1

Share this post


Link to post

I actually own Alpha Controls and have a lifetime license, I'll take a look into this too

Share this post


Link to post
On 11/19/2020 at 10:16 PM, Chris1701 said:

I actually own Alpha Controls and have a lifetime license, I'll take a look into this too

I couldn't get it to work with the Raize controls dbgrid so I had to switch to the Alpha Controls dbgrid and it worked fine so problem solved

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×