Page 1 of 1

Spin control

Posted: Fri Feb 09, 2007 3:07 am
by Robbie
Hi,

I was wondering why the proper Windows Spin control was not included in PureBasic? I think it looks a lot nicer than the one currently included...

Image

Is there any way to use the standard Windows one, or could this be included in PureBasic? I only need it for Windows. I don't know how it looks on MacOS, or Linux.

Thanks,
Robbie.

Posted: Fri Feb 09, 2007 3:12 am
by netmaestro
It's definitely a standard Windows Spin Control. If you want it to look like your picture, go to 'Compiler Options' and check 'Enable XP Skin Support'.

Posted: Fri Feb 09, 2007 3:21 am
by Robbie
I've done that, but it still doesn't look right. In PureBasic, the Up/Down part of it is outside of the textbox, but in the Windows control, it's inside. I know I'm being picky, but I care a lot about how my application will look. :)

This image shows the difference...

Image

Robbie.

Posted: Fri Feb 09, 2007 3:54 am
by Sparkie
It's a bit of a hack and you may need to fine tune the geometry, but try this.

Code: Select all

If OpenWindow(0, 0, 0, 240, 70, "SpinGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  Frame3DGadget(0, 10, 10, 107, 22, "", #PB_Frame3D_Flat)
  hBuddy = SpinGadget (1, 11, 11, 98, 20, 1, 100, #PB_Spin_Numeric) 
  hSpin = FindWindowEx_(WindowID(0), hBuddy, 0, 0) 
  SetWindowLong_(hBuddy, #GWL_EXSTYLE, GetWindowLong_(hBuddy, #GWL_EXSTYLE) &(~#WS_EX_CLIENTEDGE))
  SetWindowPos_(hBuddy, 0, 0, 0, 0, 0, #SWP_NOMOVE | #SWP_NOSIZE | #SWP_NOZORDER | #SWP_FRAMECHANGED)
  SetWindowPos_(hSpin, 0, 0, 0, 17, 20, #SWP_NOMOVE | #SWP_NOZORDER)
  SetGadgetState (1, 15) 
  SetGadgetText(1, "15") 
  Repeat 
    Event = WaitWindowEvent() 
  Until Event = #PB_Event_CloseWindow 
EndIf 
Other than that, you can also try the CreateUpDownControl_() API function to create your own. :wink:

Posted: Fri Feb 09, 2007 4:21 am
by netmaestro
Fair enough, it looks different. This looks the way you want, I hope:

Code: Select all

;================================================= 
;       Custom Spinner Control Demo 
;================================================= 

Procedure SubClass_Spin(hwnd, msg, wparam, lparam) 

  Protected OldProc = GetProp_(hwnd, "OldProc") 
  Protected String = GetProp_(hwnd, "String") 
  Protected min = GetProp_(hwnd, "Min") 
  Protected max= GetProp_(hwnd, "Max") 

  result = CallWindowProc_(OldProc, hwnd, msg, wparam, lparam) 
  Select msg 
    Case #WM_LBUTTONDOWN 
        If lparam >> 16 > 10 
          current = Val(GetGadgetText(String)) 
          If current > min 
            current -1 
            SetGadgetText(string, Str(current)) 
          EndIf 
        Else 
          current = Val(GetGadgetText(String)) 
          If current < max 
            current +1 
            SetGadgetText(string, Str(current)) 
          EndIf 
        EndIf 
    Case #WM_DESTROY 
      RemoveProp_(hwnd, "OldProc") 
      RemoveProp_(hwnd, "String") 
      RemoveProp_(hwnd, "Min") 
      RemoveProp_(hwnd, "Max") 
      SetWindowLong_(hwnd, #GWL_WNDPROC, OldProc)
  EndSelect 

  ProcedureReturn result 
  
EndProcedure 

Procedure CustomSpinner(GadgetNumber, x, y, width, min, max, initialvalue) 
  If GadgetNumber = #PB_Any 
    ctrlid = 1000 
    While IsGadget(ctrlid) 
      ctrlid + 1 
    Wend 
    GadgetNumber = ctrlid 
  EndIf 
  colr = ContainerGadget(#PB_Any,x-1,y-1,width+2,25,#PB_Container_BorderLess) 
  SetGadgetColor(colr,#PB_Gadget_BackColor, #Blue) 
  cont = ContainerGadget(#PB_Any,1,1,width,23,#PB_Container_BorderLess) 
  updn = CreateWindowEx_(0, "msctls_updown32", "", #WS_CHILD|#WS_VISIBLE, width-18,1,20,21,GadgetID(cont),GadgetNumber,GetModuleHandle_(0),0) 
  stringg = StringGadget(#PB_Any,5,5,width-25,20,"",#PB_String_BorderLess|#PB_String_ReadOnly) 
  CloseGadgetList():CloseGadgetList() 
  SetGadgetColor(cont,#PB_Gadget_BackColor, #White) 
  SetGadgetColor(stringg,#PB_Gadget_BackColor, #White)    
  SetGadgetText(stringg, Str(initialvalue)) 
  OldProc = SetWindowLong_(updn, #GWL_WNDPROC, @SubClass_Spin()) 
  SetProp_(updn, "OldProc", OldProc) 
  SetProp_(updn, "String", stringg) 
  SetProp_(updn, "Min", min) 
  SetProp_(updn, "Max", max) 
  ProcedureReturn stringg
EndProcedure 

If OpenWindow(0, 0, 0, 200, 170, "SpinGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) And CreateGadgetList(WindowID(0)) 
  spin = CustomSpinner(#PB_Any, 40,40,100,0,10,0) 
    ; GetGadgetText(spin) will produce the current state of the spinner
  Repeat 
    Event = WaitWindowEvent() 
    If Event = #PB_Event_Gadget 
      If EventGadget() = 0 
        SetGadgetText(0,Str(GetGadgetState(0))) 
      EndIf 
    EndIf 
  Until Event = #PB_Event_CloseWindow 
EndIf 
You can include the top two procedures in your code and it will call with one line as shown. Note that you don't set the height, it's always 25 for this one. You can tweak the numbers and make it less tall if you want.

OK Sparkie, what'd I forget? :D

Posted: Fri Feb 09, 2007 4:30 am
by Robbie
Thanks for the suggestions. They both look a LOT better. Thank you!

I'll have a play around with them and see what I can come up with. :)

It still would be nice to have the 'proper one' built in. ;)

Thanks again,
Robbie.

Posted: Fri Feb 09, 2007 4:41 am
by netmaestro
Oops, I forgot to close my gadget lists. I always forget something. Best use the latest code, it's fixed now. That was a bad bug.

Posted: Fri Feb 09, 2007 4:41 am
by Sparkie
netmaestro wrote:OK Sparkie, what'd I forget?
Tell me more about the GetProp_() / SetProp_() functions. :?

Posted: Fri Feb 09, 2007 4:43 am
by netmaestro
What did I miss on those? I'm doing a RemoveProp_() on WM_DESTROY, afaik that's all they warn about.

Posted: Fri Feb 09, 2007 4:46 am
by Sparkie
No...seriously...Tell me more about the GetProp_() / SetProp_() functions. I've never used them before :?

Posted: Fri Feb 09, 2007 4:52 am
by netmaestro
It's a way of attaching specific data of your own choosing to a window handle that it can carry with it wherever it goes. It's invaluable for subclassing gadgets because you might want different parameters for multiple created instances of the gadget and the subclass procedure has to know which is which. Globals and linklists are clunky and awkward and far inferior to using window properties. The only proviso is that MS says that any properties you set have to be removed by you at WM_DESTROY because they won't remove them for you.

Also, because you're using strings, compiled libs should be produced with threadsafe versions for use in applications which use threads.

Posted: Fri Feb 09, 2007 4:59 am
by Sparkie
Hmmm....I'll have to take a closer look tomorrow with fresh eyes and a fully charged brain. 8)

Thanks for the info...and nice job on the custom SpinGadget. :)

Posted: Fri Feb 09, 2007 4:55 pm
by Fluid Byte
Why someone should use WindowProps if he could asign a pointer with SetWindowLong_() wich holds the data of a custom structure for example?