我希望我能够很好地解释我的问题,以便有人帮助。
基本上,我有一个水平滚动条(范围为0到1000)和一个编辑控件,表示滚动条的位置除以1000,这样用户就可以使用滚动条来选择介于0和1之间的数字范围最多3位小数(.001,.002,...,。987等),或在编辑框中输入自己的数字。当他们滚动滚动条时,编辑控件中的数字会更改以反映新的滚动位置。输入新数字后,滚动条会将自身设置为反映输入数字的新位置。同时我也会在更改时通过滚动条或编辑控件对此数字执行一些计算,并在另一个对话框中显示结果。
这是我的问题:当用户在编辑控件中输入数字时,我无法确定使用哪些事件处理程序来产生正确的行为。
我正在使用一个名为fuelMargin的双值变量来处理我的编辑控件和一个名为fuelScroll的CScrollBar控件变量来处理滚动条。
在我的HSCROLL事件中,我将编辑控件设置为滚动位置/ 1000.那里没有问题;当用户滚动滚动条时,编辑框被正确更新。
至于编辑框,我的第一次尝试是ONCHANGE事件:
void MarginDlg::OnEnChangeFueledit()
{
CEdit* editBox;
editBox = (CEdit*)GetDlgItem(IDC_FUELEDIT);
CString editString;
editBox->GetWindowText(editString);
if (editString.Compare(".") != 0 && editString.Compare("0.") != 0
&& editString.Compare(".0") != 0 && editString.Compare("0.0") != 0
&& editString.Compare(".00") != 0 && editString.Compare("0.00") != 0)
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
}
当用户尝试输入类似.5或.05或.005的数字时,我首先需要在那里使用if语句以防止执行UpdateData()。但它确实产生了一些不稳定的行为;当用户尝试输入类似.56的内容时,在.5执行UpdateData()之后,数字变为0.5,光标移动到最左边,所以如果他们试图键入.56,他们会意外地结束键入60.5 - 这将变为1,因为我不会让他们输入低于0或高于1的数字。但是如果他们输入0.56,则会避免这种行为。
对于我的第二次尝试,我注释掉了我的ONCHANGE事件并改为举办ONKILLFOCUS活动:
void MarginDlg::OnEnKillfocusFueledit()
{
UpdateData();
UpdateData(FALSE);
if (fuelMargin > 1)
{
UpdateData();
fuelMargin = 1;
UpdateData(FALSE);
}
if (fuelMargin < 0)
{
UpdateData();
fuelMargin = 0;
UpdateData(FALSE);
}
fuelScroll.SetScrollPos(int(fuelMargin*1000));
}
所以现在用户可以完成输入他们的号码,而且只要他们点击编辑框就可以了。滚动条不会移动,在框失去焦点之前不会计算结果。
我希望在输入框中的数字时计算结果;我希望滚动条随着数字的输入而移动。但我不希望打字被打乱,即盒子里的实际数字改变了,或者光标以任何方式移动。
建议?
谢谢!
答案 0 :(得分:2)
使用第一种方法,看起来你几乎就在那里:唯一真正重要的问题是,当用户输入时,重复调用UpdateData()会混淆光标位置。
鉴于你试图在控件之间进行相当复杂的交互,我建议不要在OnChange()中进行验证,这样当用户输入时,他可以输入他想要的内容(无论如何,这是大多数数字编辑控件的工作方式)。当用户关闭对话框时,控件处于打开状态(或单击以某种方式使用数据的按钮),然后应触发验证,并显示合适的错误。
一旦你在OnChange()中无法验证,就可以通过简单地不在OnChange()中调用UpdateData()来修复“光标移动”问题。相反,只需解析“editString”中的数字,如果它在有效范围内,则更新滚动条。这样,滚动条会随着用户的输入而更新,如果它们输入的值无效,滚动条会保持不变,当它们移动到下一个阶段时,它们会收到错误。这样的事情(未经测试):
void MarginDlg::OnEnChangeFueledit()
{
CString editString;
GetDlgItem(IDC_FUELEDIT)->GetWindowText(editString);
double editValue;
if ((sscanf(editString,"%lf",&editValue) == 1)
{
if (editValue >= 0.0) && (editValue <= 1.0))
fuelScroll.SetScrollPos(int(editValue*1000));
}
}
唯一需要注意的重要问题是,如果用户键入了一些无效值或超出有效范围的数字,则编辑控件和滚动条将不同步。处理这个问题的最简单方法是确定编辑控件是“主”值:也就是说,当我们想知道用户输入的内容时,我们总是查看编辑控件,而不是滚动条,并验证数据
至于你的第二种方法,一种可能的解决方案可能是实现一个计时器消息处理程序:在计时器处理程序中你可以说相当于“如果用户没有输入任何东西一秒钟,我会假设它们”重新完成,并解析数字并更新滚动条“。不过,我不是那么热衷于解决这个问题。
答案 1 :(得分:0)
我建议观察Enter键,然后执行UpdateData()以及OnKillFocus和OnChange。用户友好性越好。
接下来,确保您的UpdateData()例程仅适用于您需要的方向:
如果在编辑控件中输入“.5”,则在引发OnChange事件时运行UpdateData()例程,但请确保仅更新滚动条。在引发OnKillFocus之前,不要担心将编辑控件更新为“0.5”。反方向的任何更新(对编辑控件)都会弄乱光标。如果您的编辑控件以某种方式绑定到此双变量并在var更改时自动更新,请考虑将double和您的编辑控件彼此分开,直到引发OnKillFocus事件。
同样的概念也适用于另一个方向。当用户滚动时,不要弄乱滚动条。只需更新编辑控件并保留即可。
我应该补充一点,如果您知道如何正确使用它们,那么XAML的数据绑定功能在这种情况下确实很有帮助。对于我们的本地类型开发人员而言,仅使用事件处理程序来实现类似功能是如此困难,这是不幸的。