[交流]MFC滑块控件的一个设计缺陷(ps:分数不送jf人)解决办法
[交流]MFC滑块控件的一个设计缺陷(ps:分数不送jf人)
首先声明这里的MFC版本对应的VC版本是VC6.0。
前一段时间写一个程序,其中涉及到在工具栏上创建一个滑块控件(功能大致是通过拖动滑块控件拖动客户区的一幅bmp图像)。从中我认识到MFC滑块控件的一个设计缺陷:它并没有足够的消息宏来处理它的一些动作。使用过滑块控件的朋友都有这样的经验:当用户拖动滑块时,滑动条控制将向其父窗口发送WM_HSCROLL消息,所以这个消息处理函数是在应用程序中重栽父窗口的OnHScroll()函数。在基于对话框的程序估计体会不到它的设计失误,因为一般来说对话框是滑块控件的父窗口嘛,直接重载OnHScroll()函数得了。但是当你在基于单文档或多文档的程序的工具栏上创建一个滑块控件和其它类(如视图类)进行交互时,你就会发现滑块控件的设计缺陷——把滑块控件的滑动消息交给父窗口进行处理是不明智的,因为它会限制滑块控件和其它类的交互。因为滑块控件的父窗口是某一工具栏,因为必须在该工具栏上重载OnHScroll()函数。这样滑块控件和视图的交流代码就放在这里了。这意味着滑块控件在滑动时和视图的交互必须通过它的父窗口。如果工具栏类和视图类是在同一个工程里,似乎也没什么。要命的是我碰到了这样一种情况:工具栏类是早已在另一个工程封装好了,是一个底层基类,不能派生,而且只能加载这种工具栏对象,框架加载不了自己新建的工具栏类对象。当然公司的这个工具栏基类不能派生就不是一种好的设计。但是不管怎么说,滑块控件和其它类交互必须通过它的父窗口本身就不是一种好的设计。
实际上滑块控件是有自己的消息处理的,如NM_RELEASEDCAPTURE消息。测试程序:
1. 打开MainFrm.cpp 添加创建代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
// TODO: Delete these three lines if you don 't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
//-------------------------------
// 下面是添加的代码
int index = m_wndToolBar.CommandToIndex(IDC_SLIDER);
m_wndToolBar.SetButtonInfo(index, IDC_SLIDER, TBBS_SEPARATOR, 80);
CRect rect;
m_wndToolBar.GetItemRect(index, &rect);
// 创建滑动条并显示
if (!m_Slider.Create(WS_CHILD|WS_VISIBLE | TBS_HORZ | TBS_AUTOTICKS |TBS_BOTTOM ,
rect, &m_wndToolBar, IDC_SLIDER))
{
TRACE0( "Failed to create slider ctrl\n ");
return FALSE;
}
//设置滑动的范围
m_Slider.SetRange(0,100);
m_Slider.SetPos(20);
m_Slider.ShowWindow(SW_SHOW);
//-------------------------------
return 0;
}
2. 打开视类CPP文件,添加如下的代码:
......
#include "mainfrm.h " //包含框架类的头文件
......
BEGIN_MESSAGE_MAP(CTbSliderView, CView)
......
ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER, OnReleasedcaptureSlider)
END_MESSAGE_MAP()
//当用鼠标调整滑动条的位置,释放鼠标以后,滑动条会发送这个NM_RELEASEDCAPTURE消息
/////////////////////////////////////////////////////////////////////////////
// 响应函数
void CTbSliderView::OnReleasedcaptureSlider()
{
CMainFrame * pMain = (CMainFrame*)AfxGetMainWnd();
int pos = pMain-> m_Slider.GetPos();
CString str;
Str.format(“%d”, pos)
AfxMessage(str) ; // 显示滑块控件的当前滑动到达的位置
}
我查了一下MFC的头文件,滑块控件可能可以响应下列消息:
#define NM_OUTOFMEMORY (NM_FIRST-1)
#define NM_CLICK (NM_FIRST-2) // uses NMCLICK struct
首先声明这里的MFC版本对应的VC版本是VC6.0。
前一段时间写一个程序,其中涉及到在工具栏上创建一个滑块控件(功能大致是通过拖动滑块控件拖动客户区的一幅bmp图像)。从中我认识到MFC滑块控件的一个设计缺陷:它并没有足够的消息宏来处理它的一些动作。使用过滑块控件的朋友都有这样的经验:当用户拖动滑块时,滑动条控制将向其父窗口发送WM_HSCROLL消息,所以这个消息处理函数是在应用程序中重栽父窗口的OnHScroll()函数。在基于对话框的程序估计体会不到它的设计失误,因为一般来说对话框是滑块控件的父窗口嘛,直接重载OnHScroll()函数得了。但是当你在基于单文档或多文档的程序的工具栏上创建一个滑块控件和其它类(如视图类)进行交互时,你就会发现滑块控件的设计缺陷——把滑块控件的滑动消息交给父窗口进行处理是不明智的,因为它会限制滑块控件和其它类的交互。因为滑块控件的父窗口是某一工具栏,因为必须在该工具栏上重载OnHScroll()函数。这样滑块控件和视图的交流代码就放在这里了。这意味着滑块控件在滑动时和视图的交互必须通过它的父窗口。如果工具栏类和视图类是在同一个工程里,似乎也没什么。要命的是我碰到了这样一种情况:工具栏类是早已在另一个工程封装好了,是一个底层基类,不能派生,而且只能加载这种工具栏对象,框架加载不了自己新建的工具栏类对象。当然公司的这个工具栏基类不能派生就不是一种好的设计。但是不管怎么说,滑块控件和其它类交互必须通过它的父窗口本身就不是一种好的设计。
实际上滑块控件是有自己的消息处理的,如NM_RELEASEDCAPTURE消息。测试程序:
1. 打开MainFrm.cpp 添加创建代码:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
......
// TODO: Delete these three lines if you don 't want the toolbar to
// be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
//-------------------------------
// 下面是添加的代码
int index = m_wndToolBar.CommandToIndex(IDC_SLIDER);
m_wndToolBar.SetButtonInfo(index, IDC_SLIDER, TBBS_SEPARATOR, 80);
CRect rect;
m_wndToolBar.GetItemRect(index, &rect);
// 创建滑动条并显示
if (!m_Slider.Create(WS_CHILD|WS_VISIBLE | TBS_HORZ | TBS_AUTOTICKS |TBS_BOTTOM ,
rect, &m_wndToolBar, IDC_SLIDER))
{
TRACE0( "Failed to create slider ctrl\n ");
return FALSE;
}
//设置滑动的范围
m_Slider.SetRange(0,100);
m_Slider.SetPos(20);
m_Slider.ShowWindow(SW_SHOW);
//-------------------------------
return 0;
}
2. 打开视类CPP文件,添加如下的代码:
......
#include "mainfrm.h " //包含框架类的头文件
......
BEGIN_MESSAGE_MAP(CTbSliderView, CView)
......
ON_NOTIFY(NM_RELEASEDCAPTURE, IDC_SLIDER, OnReleasedcaptureSlider)
END_MESSAGE_MAP()
//当用鼠标调整滑动条的位置,释放鼠标以后,滑动条会发送这个NM_RELEASEDCAPTURE消息
/////////////////////////////////////////////////////////////////////////////
// 响应函数
void CTbSliderView::OnReleasedcaptureSlider()
{
CMainFrame * pMain = (CMainFrame*)AfxGetMainWnd();
int pos = pMain-> m_Slider.GetPos();
CString str;
Str.format(“%d”, pos)
AfxMessage(str) ; // 显示滑块控件的当前滑动到达的位置
}
我查了一下MFC的头文件,滑块控件可能可以响应下列消息:
#define NM_OUTOFMEMORY (NM_FIRST-1)
#define NM_CLICK (NM_FIRST-2) // uses NMCLICK struct