近来在写MFC的应用程序时,使用到RadioButton,发现了一点问题,特写了个演示程序,共享出来,供大家参考。http://download.csdn.net/source/3171605此工程在VS2008环境编译通过,其他环境未测试。从中发现的问题点:
一 在为RadioButton按钮组合追加整型变量时,默认的组中第一个按钮的变量值为0,但MFC为这个变量提供了设置最小值和最大值的功能,(当按钮组合有一定意义时,也许不希望最小值从0开始)但实际操作中发现,最小值,最大值的设置存在缺陷。
1.由于构造函数优先执行,在构造函数中对此变量的初始化还是按0为最小值进行处理,如果手动改为其他值,可能导致默认没有按钮被选中的状态出现。
2.在触发OnOK事件时,总是弹出请输入最小值最大值范围内的数的提示(请参照代码和执行结果)
默认的OnOK的触发函数中调用了CDialog的OnOK(),每次点OK按钮都会提示
当我把OnOK()的调用注释掉,换成OnClose(),执行中,没有任何反应;
当换成EndDialog(0)时,对话框才退出。二 在这里,我有点疑问,那个输入提示是怎么个执行原理,是在哪里调用了什么出现的?MFC为什么要做这个检查,如果使用默认的OnOK(),如何能避免这个问题?
一 在为RadioButton按钮组合追加整型变量时,默认的组中第一个按钮的变量值为0,但MFC为这个变量提供了设置最小值和最大值的功能,(当按钮组合有一定意义时,也许不希望最小值从0开始)但实际操作中发现,最小值,最大值的设置存在缺陷。
1.由于构造函数优先执行,在构造函数中对此变量的初始化还是按0为最小值进行处理,如果手动改为其他值,可能导致默认没有按钮被选中的状态出现。
2.在触发OnOK事件时,总是弹出请输入最小值最大值范围内的数的提示(请参照代码和执行结果)
默认的OnOK的触发函数中调用了CDialog的OnOK(),每次点OK按钮都会提示
当我把OnOK()的调用注释掉,换成OnClose(),执行中,没有任何反应;
当换成EndDialog(0)时,对话框才退出。二 在这里,我有点疑问,那个输入提示是怎么个执行原理,是在哪里调用了什么出现的?MFC为什么要做这个检查,如果使用默认的OnOK(),如何能避免这个问题?
void CDialog::OnOK()
{
if (!UpdateData(TRUE))
{
TRACE0("UpdateData failed during dialog termination.\n");
// the UpdateData routine will set focus to correct item
return;
}
EndDialog(IDOK);
}
恩,最终是在DDV_MinMaxInt()这个函数中出的错,value的值并不在我设置的最大值和最小值之间,而是按照默认的以0为最小值处理的,就是说不管怎么设置最大值和最小值,它还是从0开始的
看了,里面的value值为1,却和我设置的最大值和最小值(7和5)去验证,导致了验证失败。
我在单选按钮的单击事件中明明设置了5到7范围的值,不知这个value的1是哪来的
我想这就是MFC在处理最小值最大值时的问题了,那个value是通过参数传入的,value对应的就是单选按钮的变量,这说明当我在其单击事件中设置了正确范围的值之后,它又把那个值改变了,这我就不知道它是怎么变的了。
如果是这样的话,这应该就是其在实现时考虑不周之处了,最大值和最小值的设置完全没有实现
这就更能肯定,对这里的处理根本就没考虑最小值可能被设置成其他值的情况。所以可以肯定,单选按钮组是不支持设置最小值的,而对应的变量生成的界面中有最小值的设置框就成了Bug
void AFXAPI DDX_Radio(CDataExchange* pDX, int nIDC, int& value)
// must be first in a group of auto radio buttons
{
pDX->PrepareCtrl(nIDC);
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl); ASSERT(::GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP);
ASSERT(::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON); if (pDX->m_bSaveAndValidate) //这里当为TRUE时,value的值被清了
value = -1; // value if none found // walk all children in group
int iButton = 0; // 这里的初始值时0,没有考虑最小值被设置成其他值的情况
do
{
if (::SendMessage(hWndCtrl, WM_GETDLGCODE, 0, 0L) & DLGC_RADIOBUTTON)
{
// control in group is a radio button
if (pDX->m_bSaveAndValidate)
{
if (::SendMessage(hWndCtrl, BM_GETCHECK, 0, 0L) != 0)
{
ASSERT(value == -1); // only set once
value = iButton;
}
}
else
{
// select button
::SendMessage(hWndCtrl, BM_SETCHECK, (iButton == value), 0L);
}
iButton++;
}
else
{
TRACE(traceAppMsg, 0, "Warning: skipping non-radio button in group.\n");
}
hWndCtrl = ::GetWindow(hWndCtrl, GW_HWNDNEXT); } while (hWndCtrl != NULL &&
!(GetWindowLong(hWndCtrl, GWL_STYLE) & WS_GROUP));
}/////////////////////////////////////////////////////////////////////////////
// Listboxes, comboboxesvoid AFXAPI DDX_LBString(CDataExchange* pDX, int nIDC, CString& value)
{
pDX->PrepareCtrl(nIDC);
HWND hWndCtrl;
pDX->m_pDlgWnd->GetDlgItem(nIDC, &hWndCtrl);
if (pDX->m_bSaveAndValidate)
{
int nIndex = (int)::SendMessage(hWndCtrl, LB_GETCURSEL, 0, 0L);
if (nIndex != -1)
{
int nLen = (int)::SendMessage(hWndCtrl, LB_GETTEXTLEN, nIndex, 0L);
::SendMessage(hWndCtrl, LB_GETTEXT, nIndex,
(LPARAM)(LPVOID)value.GetBufferSetLength(nLen));
}
else
{
// no selection
value.Empty();
}
value.ReleaseBuffer();
}
else
{
// set current selection based on data string
if (::SendMessage(hWndCtrl, LB_SELECTSTRING, (WPARAM)-1,
(LPARAM)(LPCTSTR)value) == LB_ERR)
{
// no selection match
TRACE(traceAppMsg, 0, "Warning: no listbox item selected.\n");
}
}
}
确实应该是个bug
不过表现出来的是, 刚点进去添加变量时, 最大最小那些地方都是disabled
但是如果我选成bool或者别的,再选回来变成int的话, 最大最小就可以设置了
所以显而易见是一个小bug