As stated already, a spin control cannot display its value to the user. If you want to inform the user about the value of the control as it is being incremented or decremented, you can add another, usually text-based, control, such as an edit box. This control is called the buddy window of the spin control. The control should be positioned on one horizontal side of the spin control. After adding that new control, you should let the spin control know on what side the accompanying control is positioned, left or right. To do this visually, select the appropriate value in the Alignment field of the Properties window. If you are programmatically creating the control, to position the spin control to the left edge of the buddy window, add the UDS_ALIGNLEFT style. On the other hand, if you want the spin control on the right side of the buddy window, apply the UDS_ALIGNRIGHT style instead. Just like at design time you cannot apply both styles, at run time, do not add both the UDS_ALIGNLEFT and the UDS_ALIGNRIGHT styles. If you want the spin control to use an already existing and previously added control as its buddy window, visually set the Auto Buddy property to True or programmatically add the UDS_AUTOBUDDY style. In this case, the control that was just previously added to the host, before adding the spin control, would be used as its buddy. After specifying what control would be the buddy window of the spin control, when the user clicks the arrows of the button, the buddy would display its current value. If you want to make sure that the buddy window displays only integral values, whether decimal or hexadecimal, change the Set Buddy Integer property to True. If you are programmatically creating the control, you can add the UDS_SETBUDDYINT style: SpinCtrl->Create(WS_CHILD | WS_VISIBLE | UDS_SETBUDDYNT,
CRect(60, 10, 80, 35), this, 0x128);
After creating the control, to indicate what control would display the value of the spin control, we saw that you can use the Alignment or the Auto Buddy properties. If you did not do this at design time and if you want to explicitly specify the name of the control that would act as the buddy window, you can call the CSpinButtonCtrl::SetBuddy() member function. Its syntax is: CWnd* SetBuddy(CWnd* pWndBuddy); The pWndBuddy argument is the new control that would serve as buddy. Here is an example that sets an existing label on the dialog box (the label was created as a Static Text control and identified as IDC_SPIN_BUDDY) as the spin control's buddy window: BOOL CSpinDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CSpinButtonCtrl *SpinCtrl = new CSpinButtonCtrl;
CStatic *SpinBuddy;
SpinCtrl->Create(WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT,
CRect(60, 10, 80, 35), this, 0x128);
SpinBuddy = reinterpret_cast<CStatic *>(GetDlgItem(IDC_SPIN_BUDDY));
SpinCtrl->SetBuddy(SpinBuddy);
return TRUE; // return TRUE unless you set the focus to a control
}
If the buddy window has already been set and you want to find what control performs that role, you can call the CSpinButtonCtrl::GetBuddy() member function. Its syntax is: CWnd* GetBuddy() const;
By default, a spin control is used to show some natural numbers from one range to another. Normally, the values of a spin control are decimal integers. Alternatively, if you prefer the values to be given in hexadecimal format, set the range accordingly and call the CSpinButtonCtrl::SetBase() member function. Its syntax is: int SetBase(int nBase); Using this member function, if you want the value to be decimal, pass the nBase argument as 10. If you want hexadecimal values, pass the argument as 16. Here is an example: BOOL CSpinDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CSpinButtonCtrl *SpinCtrl = new CSpinButtonCtrl;
CStatic *SpinBuddy;
SpinCtrl->Create(WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT,
CRect(60, 10, 80, 35), this, 0x128);
SpinCtrl->SetBase(16);
SpinBuddy = reinterpret_cast<CStatic *>(GetDlgItem(IDC_SPIN_BUDDY));
SpinCtrl->SetBuddy(SpinBuddy);
return TRUE;
}
To find out the current base, decimal or hexadecimal, that a spin control is using for its values, call the CSpinButtonCtrl::GetBase() member function. Its syntax: UINT GetBase() const; The value held by a spin control is referred to as its position. If you want to specify the value of a spin buttoan, call the CSpinButtonCtrl::SetPos() member function. Its syntax: int SetPos(int nPos); This member function takes as argument the new value of the spin control. Here is an example: BOOL CSpinDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CSpinButtonCtrl *SpinCtrl = new CSpinButtonCtrl;
CStatic *SpinBuddy;
SpinCtrl->Create(WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT,
CRect(60, 10, 80, 35), this, 0x128);
SpinCtrl->SetPos(36);
SpinBuddy = reinterpret_cast<CStatic *>(GetDlgItem(IDC_SPIN_BUDDY));
SpinCtrl->SetBuddy(SpinBuddy);
SpinBuddy->SetWindowText("4");
return TRUE;
}
To explore the spin control, the user click one of its arrow buttons or presses the arrow keys to increase or decrease the control's value. The only actual thing the spin control provides is the value it holds. It is up to you to decide what to do with such a value. This means that, on a regular basis, you will need to retrieve the current value of the control and do whatever you want with it.. To get the position of a spin control, call the CSpinButtonCtrl::GetPos() member function. Its syntax is: int GetPos() const; This member function returns the value of the spin control at the time the member function is called.
One of the most important actions you should perform after creating a spin control is to specify its lowest and its highest values. The default range is 100 (lowest) to 0 (highest). This causes the spin control to count in decrement. If you do not want this (bizarre) behavior, you must explicitly set the lower and higher values. To set the minimum and maximum values of a spin control, call either the CSpinButtonCtrl::SetRange() or the CSpinButtonCtrl::SetRange32() member functions. Their syntaxes are: void SetRange(int nLower, int nUpper); void SetRange32(int nLower, int nUpper); In both cases the nLower argument holds the minimum value and the nUpper argument specifies the maximum value. Here is an example: BOOL CSpinDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CSpinButtonCtrl *SpinCtrl = new CSpinButtonCtrl;
SpinCtrl->Create(WS_CHILD | WS_VISIBLE | UDS_SETBUDDYINT,
CRect(60, 10, 80, 35), this, 0x128);
SpinCtrl->SetRange(-12, 1244);
return TRUE;
}
If the control exists already and you want to get its minimum and maximum values, call either the CSpinButtonCtrl::GetRange() or the CSpinButtonCtrl::GetRange32() member functions. The possible syntaxes used are: DWORD GetRange() const; void GetRange(int &lower, int& upper) const; void GetRange32(int &lower, int &upper) const;
Based on the range of values that a spin control can handle, the user can increment and decrement the control's value. By default, the values are are incremented by adding 1 and decrement by adding -1 to the current value. If you want to increment and decrement by a different value, you have two main options. You can write a routine to take care of this, or call the CSpinButtonCtrl::SetAccel() member function. Its syntax is: BOOL SetAccel(int nAccel, UDACCEL* pAccel); The SetAccel() member function takes a UDACCEL value and its size as arguments. The UDACCEL class is defined as follows: typedef struct { UINT nSec; UINT nInc; }UDACCEL, FAR *LPUDACCEL; The nSec member variable is a semi-timer that ticks at a specified rate of seconds. The nInc member variable of this structure defines the incremental value to apply when the nSec value has passed. The nAccel argument of the SetAccel() member function is the size of the UDACCEL class. In the following example, a spin control was added to a dialog box and a control variable named m_Spin was added for it. When the user clicks the arrow buttons or presses the arrow keys, the value of the spin control is incremented by 5: BOOL CDlgSpin::OnInitDialog() { CDialog::OnInitDialog(); // TODO: Add extra initialization here UDACCEL udAccel; int SizeOfAccel = sizeof(UDACCEL); udAccel.nSec = 100; udAccel.nInc = 5; m_Spin.SetAccel(SizeOfAccel, &udAccel); m_Spin.SetRange(12, 168); return TRUE; } If a spin control has been created already, to find its incremental value, you can call the CSpinButtonCtrl::GetAccel() member function. Its syntax is: UINT GetAccel(int nAccel, UDACCEL* pAccel) const; Once a spin control is ready to hold values, its default value is the lowest specified with the SetRange() or the SetRange32() member function. For example, if you create a spin control that can hold values from 15 to 62, when the control displays at startup, it would assume a value of 15.
When the user clicks one of the arrow buttons of a spin control or presses an up or a down arrow key when the control has focus, the operating system sends a UDN_DELTAPOS message to the parent window of the spin control, notifying this parent that the position (the value) of the control is about to be changed. The syntax of the event fired by the UDN_DELTAPOS message is: OnDeltaPosSpin(NMHDR* pNMHDR, LRESULT* pResult); Because this event is fired before the value of the spin control is changed, you can use it to check, validate, allow or deny the change. The first argument, pNMHDR, is an NMHDR value. The NMHDR structure is sometimes used to carry information about a message. It is defined as follows: typedef struct tagNMHDR { HWND hwndFrom; UINT idFrom; UINT code; } NMHDR; The hwndFrom member variable is a handle to the window that is sending the message. The idFrom is the identifier of the control that is sending the message. The code member is the actual notification code. When implementing the event of the UDN_DELTAPOS message, instead of using the value of the NMHDR argument, Visual C++ takes the liberty of casting the pNMHDR pointer into a pointer to NM_UPDOWN. Therefore, the event provided to you appears as follows: void CDlgSpin::OnDeltaPosSpinNew(NMHDR* pNMHDR, LRESULT* pResult) { NM_UPDOWN* pNMUpDown = (NM_UPDOWN*)pNMHDR; // TODO: Add your control notification handler code here *pResult = 0; } The NM_UPDOWN structure is defined as follows: typedef struct _NM_UPDOWN { NMHDR hdr; int iPos; int iDelta; } NMUPDOWN, FAR *LPNMUPDOWN; This structure was specifically created to carry notification information for a spin control. The first member variable of the NM_UPDOWN structure, hdr, is an NMHDR. The hdr member itself carries additional information about the message being sent, as mentioned above. The iPos member variable is the value of the current position of the spin control. The iDelta member is the intended change that would be performed on the spin control.
|
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|