 |
|
 |
Thanks!
Just what I was looking for.
|
|
|
|
 |
|
 |
If I'd convert the number into text, for example I'd like to show 1,2,3,... like "One", "Two",.... is there a way?
|
|
|
|
 |
|
|
 |
|
 |
Of course there's a way. This got to be one of the most common exercises when learning programming. The logic is pretty simple too. Just split the number into digits and process from leftmost digit to the right. The only exception is if the two rightmost digits form a number between 10 and 19.
There's plenty of samples on the web. Just Google it. Here's the one I found: CodeGuru: Convert Numbers to Various Display Formats
[^]
|
|
|
|
 |
|
 |
First of all, congratulations for this job.
I needed a spin control who accepted and validated float values, so this has been very useful for me. Also I needed that the button had a "tracking" or "dragging" feature. This control is like the Spin Ctrl that can be pressed up or down, but also you can hold the mouse and drag it up/down so the value changes rapidly.
Many applications have this kind of control. Some implementations have a little middle "thumb" button between the arrows and the cursor will change to an up/down cursor while hovering over this button.
Now, after digging in this and other c++ sites, I wonder why it is so difficult to find any reference to this kind of control.
I added a small modification on this code - yet it is simple and does not include a middle "thumb" button nor custom redraw. I'm afraid I'm not an experienced programmer, so i think my code is awkward - but still, there is it.
void CNumSpinCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bLButtonHold = TRUE;
m_ctrlCursorPos = point;
GetCursorPos(&m_scrCursorPos);
CSpinButtonCtrl::OnLButtonDown(nFlags, point);
}
void CNumSpinCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
m_bLButtonHold = FALSE;
if (m_bTrack)
{
m_bTrack = FALSE;
ShowCursor(TRUE);
ClipCursor(NULL);
SetCursorPos(m_scrCursorPos.x,m_scrCursorPos.y);
SetCursor(LoadCursor(NULL, IDC_ARROW));
ReleaseCapture();
}
CSpinButtonCtrl::OnLButtonUp(nFlags, point);
}
void CNumSpinCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bLButtonHold)
{
int delta = m_ctrlCursorPos.y-point.y;
if (delta || (m_ctrlCursorPos.x-point.x) )
{
if (!m_bTrack)
{
m_bTrack = TRUE;
SetCapture();
}
else
{
SetCursor(LoadCursor(NULL, IDC_SIZENS));
SetCursorPos(m_scrCursorPos.x,m_scrCursorPos.y);
double val = GetPos () + m_Delta * delta;
const bool can_wrap = (UDS_WRAP & GetStyle());
if (can_wrap)
{
if (delta < 0) // wrap down
{
double abs_eps = fabs(EPS * max (val, m_MinVal));
if (abs_eps < EPS)
abs_eps = EPS;
if (m_MinVal - val > abs_eps)
val = m_MaxVal;
}
else // wrap up
{
double abs_eps = fabs(EPS * max (val, m_MaxVal));
if (abs_eps < EPS)
abs_eps = EPS;
if (val - m_MaxVal > abs_eps)
val = m_MinVal;
}
}
//After 'warp', limit values
if (val > m_MaxVal)
val=m_MaxVal;
if (val < m_MinVal)
val=m_MinVal;
SetValueForBuddy (val);
}
}
}
CSpinButtonCtrl::OnMouseMove(nFlags, point);
}
Most of this last member was taken from OnDeltaPos - but to be applied when 'tracking' the mouse movement.
Now, It would be nice if any REAL programmer made real "CSpinTrackCtrl" for us
Regards..
Emilio Le Roux
www.moscafilms.com.br/emilioleroux
"It's never too late to get some sleep"
|
|
|
|
 |
|
 |
Emilio,
I've seen a few applications that implement this behaviour in various ways. WordPerfect for example has the little bar in between the arrows that can be dragged up or down. Paint Shop Pro has a drop down arrow to the right of the spin control that shows a little slider control when you click on the drop down.
Personally, I never found these sliders very useful, so I am not really interested in implementing one. Usually I either adjust the number by a few increments or I simply type in the exact number that I need.
Also, the standard Windows spin control provides similar behaviour. If you click and hold down the mouse button on an arrow, the increment increases the longer the button is held.
Damir
|
|
|
|
 |
|
 |
Of course different users have different needs. In graphic applications or CG, it is very important to have responsive controls. For instance, when selecting colors, or scaling / rotating objects, bump, specular values... you drag the mouse and the screen gives immediate feedback. A slider works well for defined range values (such as RGB color values) but in most cases you need some kind of infinite response. But if you are a more scientific-math-office oriented user, the control is nothing but a little bonus feature.
In this case, the standard windows spin behavior is not similar. It justs acts as clicking repeteadly until you get the desired value or you get old, whichever comes first. I know there's some user defined acceleration, but it's not a responsive control.
Anyway, since you don't find this control useful, there's no point on discussing it here.
Thanks for your reply, and for the great job here!
Emilio
Emilio Le Roux
www.moscafilms.com.br/emilioleroux
|
|
|
|
 |
|
 |
Hi Emilio,
Well this does the trick ! Only one small line of code needed in OnDeltapos:
BOOL CNumSpinCtrl::OnDeltapos(NMHDR* pNMHDR, LRESULT* pResult)
{
if (m_bTrack)
return TRUE;
...
...
}
Now the only thing left is to do the same for the Edit control attached to it
|
|
|
|
 |
|
 |
Hi,
Thanks for your CNumSpinCtrl contribution.
The code works fine when the spin control buttons are used, but needs fixing when values are directly entered manually into the CEdit buddy control. This is because the buddy value is being used without any range validation. This situation readily fixed with a single extra line to GetPos(), i.e.,
double CNumSpinCtrl::GetPos()
{
CWnd* pEdit = GetBuddy();
ASSERT( pEdit );
CString str;
pEdit->GetWindowText (str);
double val = atof (str);
ValidatePos( val ); // Perform range validation
return val;
}
and by adding a new member ValidatePos():
void CNumSpinCtrl::ValidatePos( double &val )
{
if( val >= m_MaxVal )
val = m_MaxVal;
else if( val <= m_MinVal )
val = m_MinVal;
}
On the host dialog side, it is necessary to override the OnOk() and OnKillEditFocusValue() members in order to create a consistent keyboard editing behaviour, i.e.,
void CTestDlg::OnOK()
{
double val = m_spinVal.GetPos();
m_spinVal.SetValueForBuddy( val );
}
and
void CTestDlg::OnKillfocusEditValue()
{
double val = m_spinValue.GetPos();
m_spinVal.SetValueForBuddy( val );
}
These minor changes really make CNumSpinCtrl shine!
All the best,
HardHat
|
|
|
|
 |
|
 |
Thank you for your comments. Indeed, one have to check for valid range on manually entered values. However, I did not add such validation checks to the control because it really depends on the purpose of the dialog.
If a dialog is designed to interact with the user in "real time", i.e. automatically apply changes as the user enteres data in each control, then I usually set up a timer inside OnChangeEdit. Then when the timeout occurs, I check if the input is valid and apply changes, otherwise ignore input or respond otherwise.
If a dialog does not update anything in real-time, then the only time I check for valid input is in OnOK (or before each page change for property page sheets and tabbed dislogs). Easy way of checking for ranges is to add my DDX_DoubleRange to DoDataExchange function . See this article for details: http://www.codeproject.com/useritems/dialogdatavalidation.asp[^]
Thanks,
Damir
|
|
|
|
 |
|
 |
... saved me some time. Got my five.
ade me;
while(myKitchen.beerInFridge()) {
me.watchTV();
me.consumeBeer(myKitchen.getBeerCan());
}
|
|
|
|
 |
|
 |
In my project, The CNumSpinCtrl(or CSpinButtonCtrl) can't display on toolbar!!!
why?
|
|
|
|
 |
|
 |
I am sorry, but I never tried adding CNumSpinCtrl to a toolbar. I am sure however, that it is the same as adding a regular CSpinButtonCtrl.
|
|
|
|
 |
|
 |
You can do what you have implemented here using a standard CEdit and CSpinCtrl as follows:
1: Set the range of value. If you want a step of 0.1 and a min equal to 0.0 and a max equal to 10.0, the range of value of your spin control would be 0-100 (100 = 10/0.1)
pSpin->SetRange(0,100);
2: Write a handler for WM_VSCROLL in the parent class
void CYourDialog::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if (nSBCode == SB_ENDSCROLL)
return;
if (pScrollBar->GetDlgCtrlID() === IDC_SPIN)
{
CString strValue;
strValue.Format("%3.1f", (nPos / 10.0)); ((CSpinButtonCtrl*)pScrollBar)->GetBuddy()->SetWindowText(strValue);
}
}
When converting the values you just need to Call GetPos() and devide by the scale factor.
Of course this doesn't invalidate the excellent work you have done!
Roger Allen
Sonork 100.10016
I think I need a new quote, I am on the prowl, so look out for a soft cute furry looking animal, which is really a Hippo in disguise. Its probably me.
|
|
|
|
 |
|
 |
Actually, that is exactly what this control is doing. The only difference is that all the code is encapsulated into one class.
1. When user sets numerical value range and delta, they are converted into corresponding integer range. This way spinning acceleration works properly.
2. In OnDeltaPos the integer delta is converted to the user delta. Then SetWindowText sets value for buddy control.
Thanks for you comment.
Damir
|
|
|
|
 |
|
 |
OK, I admit it, I only read the article and didn't look at the actual code.
But I still gave you a 5!
Roger Allen
Sonork 100.10016
I think I need a new quote, I am on the prowl, so look out for a soft cute furry looking animal, which is really a Hippo in disguise. Its probably me.
|
|
|
|
 |
|
 |
Thanks for the hard work on this control. It has saved me lots of time!
Jim Hawkins
Scientific and Engineering Software Developer
|
|
|
|
 |
|
 |
I have a MDI Project,and in this project
there is a dlgbar.
I place a edit and spin on the dlgbar.
CNumSpinCtrl Can't work!
Why?
Believe it or not,you can try it!
|
|
|
|
 |
|
 |
I tried it. It works.
I took a few minutes to build an MDI project with a CDialogBar. I added CNumSpinCtrl member to the dialog bar class. Then I subclassed in WM_INITDIALOG message. Everything works! If you want to take a look at my sample project I can e-mail it to you.
Damir
|
|
|
|
 |
|
 |
I tried using this control in my project. I was able to include the files and also build the project successfully. But when I run the application and try to open the dialog box that contains the control, I get a software exception. On debugging the application, I get:
unhandled exception in app.exe(MFC42D.DLL):0xc00000fd:stack overflow
On clicking , it gives me an exception in the function OnWndMsg() of file wincore.cpp.
Can you advise on this? I need to get done on this asap!
Thanks
-suman.
|
|
|
|
 |
|
 |
Hi!
First of all thanks for the nice control. It's just perfect.
There is one small bug however:
sometimes the control will, after modifying the values, set the real decimal value in the window. e.g. if I had 0.10 and pressed "up" I'd get 11.
I found that the problem was not in the derived control but was caused by a "stubbornness" of the base control. I found, this can be prevented by returning a nonzero value via pResult in OnDeltapos(), thus Telling the base control it didn't change.
That fixed the problem for me.
I thought that might help some people out there...Regards,
Nick
|
|
|
|
 |
|
 |
Thanks Nik. Someone else before pointed out to me that using ON_NOTIFY_REFLECT_EX is better. It gives the parent a chance to process OnDeltaPos after NumSpinControl is done processing it. I made another small fix to trimming trailing zeros logic. I should be posting an update soon. Damir
|
|
|
|
 |
|
 |
I got the same problem, I have a 0.6 value, then a 7.0 appear when clicking "up" button. very frustrating.
Mat
|
|
|
|
 |
|
 |
I got the same problem, I have a 0.6 value, then a 7.0 appear when clicking "up" button. very frustrating.
Mat
|
|
|
|
 |
|
 |
I got the same problem, I have a 0.6 value, then a 7.0 appear when clicking "up" button. very frustrating.
Mat
|
|
|
|
 |