• Welcome to PlanetSquires Forums.
 

UpDown control

Started by Johan Klassen, July 22, 2020, 08:53:46 AM

Previous topic - Next topic

Johan Klassen

how do you use the UpDown control?
[edit]
I partially got it, if the up arrow is clicked on the UpDown control then UpDown.Delta = 1
if the down arrow is clicked on the UpDown control then UpDown.Delta = -1

philbar

Hi Johan,

That's about it. For each UpDown in your form, you can keep a shared integer that keeps track of the total: each time the UpDown is clicked, you add Delta to the total, and you use the total as a source of numbers in your program.

Windows gives the UpDown control an internal value, which you can access with the WinFBX function updown_getpos32(...). However, if you play with it, you'll see that Windows is, uh, perverse. When you click the Up button, the value goes down, and when you click the Down button, the value goes up. That's probably why WinFBE doesn't expose that value as a property of the UpDown.

If you're interested, I made a simple class that turns a TextBox into a Spinner. You've seen them: an UpDown is embedded in the text box and every click of the UpDown is displayed in the text, and every number in the text is set into the UpDown. Save the text below as "spinner.inc". Anyone who finds this useful is welcome to copy or modify as they wish. The comments will tell you how to use it:

/'                         Spinner "Class"
                 (Enough like a class for my purpose)
The spinner is a combination of a text box with an UpDown control so that the
value of the UpDown is always printed in the text box, and the numeric value of
the text in the box is placed in the UpDown.

WinFBE has an UpDown control, but it does not provide a way to buddy it to a text
box and no way to access the internal value of the UpDown. I learned that the
necessary style value that allows buddying can only be applied when the UpDown is
first created; it can't be added at runtime. So instead, I created a class that
will generate a spinner: you provide the text box and the class creates the UpDown
with the necessary style and buddies it for you.

Note: José's 8 Jul 20 update of WinFBX gets rid of a couple of warnings when
compiling this module.

Usage example:
   1. main BAS file:
         #include "spinner.inc"           'that is this file
   2. Designer (frmMain):
         Add a TextBox where you want your spinner to be. Remember that the width
         of the UpDown buttons will be taken from the text area of the text box.
   3. form Module Level:
         Dim Shared as Spinner spin1
   4. form Load event:
         spin1.Initialize(frmMain, frmMain.Text1, bwrap, bthousands)
         ' Creates an UpDown as a child of frmMain and merges it with Text1
         ' bwrap is a Boolean (default False) that determines whether values that
         '     go beyond the limits of the control will "wrap around" to the other
         '     limit of the range, i.e.:  ..., 98, 99, 100, 0, 1, 2, ...
         ' bthousands is a Boolean (default True) that allows Windows to format
         '     the text number with thousands separators (commas in US locale).
         '     If so, you are allowed to use commas when entering text to the box.
         spin1.SetRange(lowlimit, highlimit)       'low and high limits for the spinner
         spin1.SetVal(nstart)                      'initial value
   5. In the program:
         When you want the value of the control:
            nowvalue = spin1.GetVal()
         To set a value for the control
            spin1.SetVal(newvalue)
         To retrieve the current range of the spinner:
            spin1.GetRange(curlow, curhigh)
         To set a new range for the spinner:
            spin1.SetRange(newlow, newhigh)
   6. Use the Change event of the Textbox to detect changes in the value of the
control. Note: the Change event will respond to every keystroke entered in the
Textbox as well as any change to the value of the UpDown.
'/

type Spinner
as wfxForm form 'for example, FrmMain
as hwnd hupdown 'receives the handle of the UpDown
declare sub Initialize( form as wfxform, textbox as wfxTextBox, bwrap as boolean=false, bthousands as boolean=true )
declare function GetVal() as long
declare sub SetVal(newval as long)
declare sub SetRange(RangeLow as long, RangeHigh as long)
declare sub GetRange(byref RangeLow as long, byref RangeHigh as long)
end type

sub Spinner.Initialize(form as wfxform, textbox as wfxTextBox, bwrap as boolean=false, bthousands as boolean=true)
dim as long idc = form.getnextctrlid()
dim as long dstyle

dstyle = bs_notify or ws_visible or uds_alignright or uds_setbuddyint or uds_arrowkeys or uds_hottrack
if bwrap then
dstyle = dstyle or uds_wrap
end if
if not bthousands then
dstyle = dstyle or uds_nothousands
end if

this.hupdown = form.pwindow->AddControl("UpDown", , idc,,,,,, dstyle)
UpDown_SetBuddy(this.hUpDown, textbox.HWindow)
end sub

/' From WinFBX:
      DECLARE FUNCTION AddControl(  BYREF wszClassName AS WSTRING, _
                                    BYVAL hParent AS HWND = NULL, _
                                    BYVAL cID AS LONG_PTR = 0, _
                                    BYREF wszTitle AS WSTRING = "", _
                                    BYVAL x AS LONG = 0, BYVAL y AS LONG = 0, _
                                    BYVAL nWidth AS LONG = 0, BYVAL nHeight AS LONG = 0, _
                                    BYVAL dwStyle AS LONG = -1, BYVAL dwExStyle AS LONG = -1, _
                                    BYVAL lpParam AS LONG_PTR = 0, _
                                    BYVAL pWndProc AS SUBCLASSPROC = NULL, _
                                    BYVAL uIdSubclass AS UINT_PTR = &HFFFFFFFF, _
                                    BYVAL dwRefData AS DWORD_PTR = NULL) _
      AS HWND
'/

function spinner.GetVal() as long
return updown_getpos32(this.hupdown)
end function

sub spinner.SetVal(newval as long)
updown_setpos32(this.hupdown, newval)
end sub

sub spinner.SetRange(RangeLow as long, RangeHigh as long)
   if rangelow > rangehigh then swap rangelow, rangehigh
updown_setrange32(this.hupdown, rangelow, rangehigh)
end sub

sub spinner.GetRange(byref RangeLow as long, byref RangeHigh as long)
updown_getrange32(this.hupdown, @rangelow, @rangehigh)
end sub

Johan Klassen

thank you philbar for the nice example  :)

Johan Klassen

#3
@philbar
I saw a post earlier about UpDown but now I can't find it, it mentioned that a certain variable declared as long should be a long ptr
did you edit your copy of AfxCtl.inc?
because I am getting 2 warnings
Passing different pointer types, at parameter 2 (pLow) of UPDOWN_GETRANGE32()
Passing different pointer types, at parameter 3 (pHigh) of UPDOWN_GETRANGE32()
[edit]
found it, in GetRange32 Word Ptr should be Long Ptr

philbar

Yes, that was in the WinFBX section. José modified the updown_getrange32() function so that now it points to long values instead of short ones. If you download the latest WinFBX and save the AFX folder to the FreeBasic \inc\ folder in the WinFBE Suite, you'll get rid of those annoying warnings.

Johan Klassen

@philbar
there's something wrong with your code or with me, when I click the UpArrow it only sets the TextBox to 0, repeatedly clicking the UpArrow has no effect but when I click the DownArrow it increments the value in the TextBox
I tried to figure out your code but eludes me

philbar

Here's a simple example that works for me. My form has a TextBox, a Label, and a Button. In the main program, just before the Application.run, I added
#include once "spinner.inc"

' frmMain form code file
''
''
dim shared as Spinner spin1         'allocate a spinner

Function frmMain_Button1_Click( ByRef sender As wfxButton, ByRef e As EventArgs ) As LRESULT
   frmmain.Label1.Text = "Value is " + str(spin1.GetVal)       'Display the value
   Function = 0
End Function

''
''
Function frmMain_Load( ByRef sender As wfxForm, ByRef e As EventArgs ) As LRESULT
   spin1.Initialize(frmmain, frmmain.Text1, false, true)       'create the spinner
   spin1.SetRange(-10000, 50000)                               'set the range
   spin1.SetVal(500)                                           'initial value
   Function = 0
End Function


Johan Klassen

thanks, I complete missed the SetRange  :-[