Replacement for Vertical Scroll


#1

I’m looking to find more elegant solution which will replace ugly vertical scroll when user decide to manually change size (height) of .net form.It’s not important to change visibility when form have maximal height ei. scroll is always visible. In next examle blue stripe on the right side represent place and width of the scroll.

if testForm != undefined do try(testForm.Close())catch()	
 (	
 	fn maxHW = (dotNetObject "maxCustomControls.win32HandleWrapper" (dotNetObject "System.IntPtr" (windows.getMaxHWND())))
 	fn defColor r g b = ((dotNetClass "System.Drawing.Color").FromArgb r g b)
 	fn defSize w h = (dotNetObject "System.Drawing.Size" w h)
 	fn defRect x y w h = (dotNetObject "System.Drawing.Rectangle" x y w h)
 	local maxBC = (clr = (colorMan.getColor #background) * 255.0 ; defColor clr.x clr.y clr.z)
 	local maxFC = (clr = (colorMan.getColor #Text) * 255.0 ; defColor clr.x clr.y clr.z)
 	local scrollClr = defColor 51 175 235
 	fn defForm dnFrm w: h: bg:maxBC = 
 	(
 		dnFrm.FormBorderStyle = dnFrm.FormBorderStyle.SizableToolWindow
 		dnFrm.ClientSize = (defSize w h) ; dnFrm.Text = "test form" ; dnFrm.BackColor = bg
 		dnFrm.StartPosition = dnFrm.StartPosition.CenterScreen ; dnFrm.ShowInTaskbar = false
 		dnFrm.Icon = (dotNetClass "ManagedServices.AppSDK").GetMainApplicationIcon()
 		dnFrm.MaximumSize = defSize w 500 ; dnFrm.MinimumSize = defSize w 105
 	)
 	fn defFPnl fPnl w: h: clr:maxBC =
 	(
 		fPnl.Size = defSize w h ; fPnl.BackColor = clr
 		fPnl.AutoSizeMode = fPnl.AutoSizeMode.GrowAndShrink
 		fPnl.WrapContents = fPnl.AutoSize = on
 		fPnl.FlowDirection = fPnl.FlowDirection.TopDown
 	)
 	fn defLbl rollLbl w: h: txt: bg:maxFC fg:maxBC =
 	(
 		if txt == unsupplied then rollLbl.Bounds = defRect 149 5 w h else (rollLbl.Text = txt ; rollLbl.margin = (dotNetObject "padding" 1 2 1 2))
 		rollLbl.Size = defSize w h ; rollLbl.BackColor = bg ; rollLbl.ForeColor = fg
 		rollLbl.TextAlign = rollLbl.TextAlign.MiddleLeft
 		
 	)
 	testForm = dotnetObject "Form" ; defForm testForm w:170 h:500
 	floatPnl = dotNetObject "FlowLayoutPanel" ; defFPnl floatPnl w:150 h:300
 	-- *vScroll* label shows place and size (width only) of vertical scroll 
 	vScroll = dotNetObject "Label" ; defLbl vScroll w:3 h:300 bg:scrollClr
 	floatPnl.Controls.addRange (for i = 1 to 15 collect (lblCtrl = dotnetObject "Label" ; defLbl lblCtrl w:145 h:18 txt:("Control_"+i as string);lblCtrl))
 	testForm.Controls.AddRange #(floatPnl, vScroll)
 		
 	testForm.Show(maxHW())		
 )

Thanks in advance.


#2

you want to make you own custom scrollbar, don’t you?
but another thing that you have to do is to support with this scrollbar full functionality of scrollable control… there are many rules actuality that make its functionally habitual to a user:

move on drag

be the size proportionally to number of items(scroll area)

support small and large increment

support setting the value by clicking the bar (not cursor)

and many other…

so the makings a look of the custom scrollbar is only 10% of its codding. doing the full coding you would ask yourself which scrollbar control is really ugly.


#3

I know that “background” code of original v-Scroll is very complex like the spinners of NumericUpDown control. What I especially dislike is default system color (sylver white) and width. If I not change width of form then vScroll will overlap all controls. I prefere darker GUI look also.
The rules that should have custom vScroll in my case

only the bar (not spinners at the top an bottom)

move on drag and alway visible (like shown blue stripe)

the size proportionally to number of items ei. height of container (Panel or FlowLayoutPanel)

All controlls (buttons, spinns, labels etc.) will be placed inside resizable FlowLayoutPanel.
Maybe is the best to use Label object for this, but how to create “the rails” on which will be moved :hmm:


#4

some of built-in scrollable controls have a scroll property, so they can be programmatically set. you have to update your custom scroll bar in this case.
what do i want say? it might be easier to change a look of built-in scrollbal control than implement your own from scratch.


#5

with your love to ‘custom looking’ controls you should stick with WPF long ago. :wink:

look at this sample http://www.codeproject.com/Articles/37366/Styling-A-ScrollViewer-Scrollbar-In-WPF


#6

I know. :slight_smile: But now is late.
I already created custom look of my tool with mxs+.net and I stuck with this problem. I only need simplified version of vScroll.
Also there is no need for control. Can we paint rectangle (blue stripe) to indicate location of vScroll area on empty space of form.
When user place the cursor here cursor will change icon to up-down arrow.
Now using “mouse down”, “mouse move” and “mouse Up” events this can be done, I guess?
And only rule for that will be #move on drag.


#7

Wow. The example is very cool. But code is too long. I already have many controls and knowing that WPF have some limitations I will stay away from it for now
But for the next less complex tool I will consider this for sure.
Thanks.
Now what do you think about my previous approach. Is it hard to do it?


#8

in programming it calls ‘decoration’. you don’t solve the task, you just do it to look like solved.
if you really want to make anything useful for your custom UI solutions you have to implement your own scrollable control with your own scrollbar…
the simplest solution as i see is panel with two children: scrollable panel and … user control for example.

something like:


 try(form.close()) catch() 
 (
 	global form = dotnetobject "MaxCustomControls.Maxform"
 	form.Text = "Show Test"
 	form.ShowInTaskbar = off
 	form.BackColor = form.BackColor.DarkGray
 	form.DockPadding.All = 2
 
 	form.StartPosition = form.StartPosition.Manual
 	form.Size = dotnetobject "System.Drawing.Size" 200 300
 	form.Location = dotnetobject "System.Drawing.Point" 800 200
 
 	p = dotnetobject "UserControl"
 	p.Backcolor = p.Backcolor.Gray 
 	p.Dock = p.Dock.Fill
 
 	sb = dotnetobject "UserControl"
 	sb.Backcolor = sb.Backcolor.Blue
 	sb.width = 8
 	sb.Dock = sb.Dock.Right
 	
 	global tt = dotnetobject "Button"
 	tt.Backcolor = tt.Backcolor.Yellow
 	tt.FlatStyle = tt.FlatStyle.Flat
 	tt.width = 8
 	sb.controls.add tt
 	
 	global fp = dotnetobject "FlowLayoutPanel"
 	fp.dock = fp.dock.fill
 	fp.backColor = fp.backColor.Orange
 	fp.FlowDirection = fp.FlowDirection.TopDown
 	fp.WrapContents = off
 	
 	for k=1 to 20 do
 	(
 		bt = dotnetobject "Button"
 		bt.text = k as string
 		bt.Size = dotnetobject "System.Drawing.Size" 160 24
 		fp.controls.add bt
 	)
 
 	p.controls.addrange #(fp, sb)
 		
 	form.controls.add p
 	form.ShowModeless()
 )
 fp.VerticalScroll.Value = 50 
 
 fn onSizeChanged s e =
 (
 	s.tag.controls.item[0].Height = s.tag.height*(s.Height as float/s.PreferredSize.Height) 
 )
 dotnet.addEventHandler fp "SizeChanged" onSizeChanged
 fp.tag = tt.parent
 onSizeChanged fp undefined
 

#9

From designer point of view this color styles mean “put sunglasses to save your eyes” :slight_smile:
Just change please:

tt.Backcolor = tt.Backcolor.dimgray
 sb.Backcolor = sb.Backcolor.black
 fp.backColor = fp.backColor.gray

Joking aside, the concept is good. I like it.
Is it posible to move “tt” button up an down and control scrolling?


#10

hmmm… i’ve thought it’s exactly what a custom controls are for…

well… of course it’s possible to bind ‘thumb’ location and scroll value.
for a FlowLayoutPanel it’s VerticalScroll.Value
but i don’t remember why but this value is settable but not readable. so it might be better to use another scrollable control instead of FlowLayoutPanel.


#11

Custom controls can be look nicer then default one. :wink:
I like to use FlowLayoutPanel because of FlowDirection prop. Also I don’t think about controls alignement and location.


#12

it’s because you don’t know about ContainerControl :wink:


#13

You’re the expert for programming languages. I still learn. I will explore this control.


#14

Using your example I replaced “FLP” with ContainerControl

 try(form.close()) catch() 
 (
	 global form = dotnetobject "MaxCustomControls.Maxform"
	 form.Text = "Show Test"
	 form.ShowInTaskbar = off
	 form.BackColor = form.BackColor.DarkGray
	 form.DockPadding.All = 2
 
	 form.StartPosition = form.StartPosition.Manual
	 form.Size = dotnetobject "System.Drawing.Size" 200 300
	 form.Location = dotnetobject "System.Drawing.Point" 800 200
 
	 p = dotnetobject "UserControl"
	 p.Backcolor = p.Backcolor.Gray 
	 p.Dock = p.Dock.Fill
 
	 sb = dotnetobject "UserControl"
	 sb.Backcolor = sb.Backcolor.black
	 sb.width = 8
	 sb.Dock = sb.Dock.Right
	 
	 global tt = dotnetobject "Button"
	 tt.Backcolor = tt.Backcolor.dimgray
	 tt.FlatStyle = tt.FlatStyle.Flat
	 tt.width = 8
	 sb.controls.add tt
	 
	 global fp = dotnetobject "ContainerControl"
	 fp.dock = fp.dock.fill
	 fp.backColor = fp.backColor.gray
	 --fp.FlowDirection = fp.FlowDirection.TopDown
	 --fp.WrapContents = off
	 
	 for k=1 to 20 do
	 (
		 bt = dotnetobject "Button"
		 bt.text = k as string
		bt.dock = bt.dock.Bottom
		 bt.Size = dotnetobject "System.Drawing.Size" 160 24
		 fp.controls.add bt
	 )
 
	 p.controls.addrange #(fp, sb)
		 
	 form.controls.add p
	 form.ShowModeless()
 )
 fp.VerticalScroll.Value = 50 
 
 fn onSizeChanged s e =
 (
	 s.tag.controls.item[0].Height = s.tag.height*(s.Height as float/s.PreferredSize.Height) 
 )
 dotnet.addEventHandler fp "SizeChanged" onSizeChanged
 fp.tag = tt.parent
 onSizeChanged fp undefined

Now I can get but not set VerticalScroll.value :).
Tried with this in listener when form is opened

cc = (form.controls.item[0]).controls.item[0]
-- this works
cc.verticalscroll.value
-->50
-- but this not ei. nothing happens
cc.verticalscroll.value = 30

Opposite behavior from FLP. Where did I go wrong?


#15

first of all you have to dock children(buttons) from Top


#16

because you refused ‘AutoScroll’ :wink: service you have to do all yourself. it will scroll the control, but you have to recalculate VerticalScroll.maximum when size or scroll changed, record the current scroll value, and change it if size changed… and no Scroll event for you anymore…

so everything do yourself. that’s a punishment for neglect built-in features. :slight_smile:


#17

Ok I get it. Like this

	 for k = 20 to 1 by -1 do
 	 (
 		 bt = dotnetobject "Button"
 		 bt.text = k as string
 		bt.dock = bt.dock.top
 		 bt.Size = dotnetobject "System.Drawing.Size" 160 24
 		 fp.controls.add bt
 	 )

Ok now when I run

cc = (form.controls.item[0]).controls.item[0]
 -- to see top item (works)
 cc.verticalscroll.value = 1 
 -- with this i can't see the last one (not works)
 cc.verticalscroll.value = 100

#18

Ok.
No hope I see. I need to think of something else :sad:
Thank you


#19

no hope for any help from control… but it doesn’t mean no help from me :wink:

you have SizeChanged event… it gives you all what you need. your custom scrollbar has to keep tracking about scroll value, and fire ‘scroll’ event when its thumb position was changed

you will be probably surprised when you see how everything easy


#20

I said no hope but that does not mean I give up. I almost forgot about this thread where we talk about custom timeline. This can be used as well.
But can you post example for your previous statement, please?