none
关于对话框内工具栏对象无法响应ON_UPDATE_COMMAND_UI的问题 RRS feed

  • 问题

  •         现在我编写了这样一个MFC 常规DLL,里面导出一个类CStereoManager,里面有一个函数ShowStereo,这个函数负责新建两个窗口出来,其代码如下: 

        
    void CStereoManager::ShowStereo(const char *leftimage,const char *rightimage)
    {
        AfxSetResourceHandle(theApp.m_hInstance);
    
    	 m_pLeftFrmWnd = new CStereoFrmWnd();
    	 m_pRightFrmWnd = new CStereoFrmWnd();
    
    	//创建左窗口
       CString wndClass = _T("");
    
    	try
    	{
    		//wndClass = AfxRegisterWndClass(
    		//	CS_DBLCLKS,
    		//	::LoadCursor(NULL,IDC_ARROW),
    		//	::GetSysColorBrush(COLOR_BTNFACE),
    		//	::LoadIcon(NULL, IDI_APPLICATION));
    
    		wndClass = ::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE), 0);
    
    	}
    	catch (CResourceException* pEx)
    	{
    		TCHAR   szCause[255];
    		CString strFormatted;
    
    		pEx->GetErrorMessage(szCause, 255);
    
    		// (in real life, it's probably more
    		// appropriate to read this from
    		//  a string resource so it would be easy to
    		// localize)
    
    		strFormatted = _T("The data file could not be opened because of this error: ");
    		strFormatted += szCause;
    
    		AfxMessageBox(strFormatted);
    
    		pEx->Delete();
    	}
    	
    	RECT rc;
    	rc.top = 0;
    	rc.left = 0;
    	rc.bottom = 600;
    	rc.right = 800;
    	CString   csWndName="左窗口";		
    	CString csWindowName = csWndName;
    	if( !m_pLeftFrmWnd->Create(wndClass,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL))
    	{
    		TRACE0("创建窗口失败!\n");
    		return 	;
    	}
        //创建右窗口
    	csWindowName  = _T("右窗口");
    
    	CString wndClass1 = _T("");
    
    	try
    	{
    		//wndClass1 = ::AfxRegisterWndClass(
    		//	CS_DBLCLKS,
    		//	::LoadCursor(NULL, IDC_ARROW),
    		//	::GetSysColorBrush(COLOR_BTNFACE),
    		//	::LoadIcon(NULL, IDI_APPLICATION));
    
    		wndClass1 = ::AfxRegisterWndClass(CS_DBLCLKS,0,::GetSysColorBrush(COLOR_BTNFACE), 0);
    	}
    	catch (CResourceException* pEx)
    	{
    
    		TCHAR   szCause[255];
    		CString strFormatted;
    
    		pEx->GetErrorMessage(szCause, 255);
    
    		// (in real life, it's probably more
    		// appropriate to read this from
    		//  a string resource so it would be easy to
    		// localize)
    
    		strFormatted = _T("The data file could not be opened because of this error: ");
    		strFormatted += szCause;
    
    		AfxMessageBox(strFormatted);
    
    		pEx->Delete();
    	}
    	
    	rc.top = 0;
    	rc.left = 0;
    	rc.bottom = 600;
    	rc.right = 800;
    	if( !m_pRightFrmWnd->Create(wndClass1,csWindowName,WS_OVERLAPPEDWINDOW,rc,NULL,NULL))
    	{
    		TRACE0("创建窗口失败!\n");
    		return 	;
    	}
    
    
    	int  MNum=0;
    	int Width=0;
    	int Height=0;
    	int XVIRTUALSCREEN=0;
    	int YVIRTUALSCREEN=0;
    	int CXMAXTRACK=0;
    	int CYMAXTRACK=0;
    	int ARRANGE=0;
    	SYSTEM_INFO siSysInfo;
    	GetSystemInfo(&siSysInfo); 
    	MNum=GetSystemMetrics(SM_CMONITORS);
    	ARRANGE= GetSystemMetrics(ARW_TOPLEFT);
    	if(MNum==1)
    	{
    		Width=GetSystemMetrics(SM_CXSCREEN);
    		Height=GetSystemMetrics(SM_CYSCREEN);
    		XVIRTUALSCREEN=GetSystemMetrics(SM_CXVIRTUALSCREEN);
    		YVIRTUALSCREEN=GetSystemMetrics(SM_CYVIRTUALSCREEN);
    
    		CXMAXTRACK=GetSystemMetrics(SM_CXMAXTRACK);
    		CYMAXTRACK=GetSystemMetrics(SM_CYMAXTRACK);
    		Width=Width-50;
    		m_pLeftFrmWnd->SetWindowPos(NULL,Width,0,XVIRTUALSCREEN,YVIRTUALSCREEN,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );	
    		m_pRightFrmWnd->SetWindowPos(NULL,Width,0,XVIRTUALSCREEN,YVIRTUALSCREEN,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );	
    	}
    	if(MNum==2)
    	{
    		ARRANGE= GetSystemMetrics(ARW_TOPLEFT);
    		Width=GetSystemMetrics(SM_CXSCREEN);
    		Height=GetSystemMetrics(SM_CYSCREEN);
    		XVIRTUALSCREEN=GetSystemMetrics(SM_CXVIRTUALSCREEN);
    		YVIRTUALSCREEN=GetSystemMetrics(SM_CYVIRTUALSCREEN);
    		CXMAXTRACK=GetSystemMetrics(SM_CXMAXTRACK);
    		CYMAXTRACK=GetSystemMetrics(SM_CYMAXTRACK); 
    		m_pLeftFrmWnd->SetWindowPos(NULL,0,0,Width,Height,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );	
    		m_pRightFrmWnd->SetWindowPos(NULL,Width,0,XVIRTUALSCREEN,YVIRTUALSCREEN,SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE );
    	}
    
    	m_pLeftFrmWnd->ShowWindow(SW_NORMAL);
    	m_pRightFrmWnd->ShowWindow(SW_SHOWMAXIMIZED);
    
    	m_pLeftFrmWnd->ShowWindow(SW_NORMAL);
    	m_pRightFrmWnd->ShowWindow(SW_SHOWMAXIMIZED);
    
    	// zjc 09.05.13. modified begin
    	m_pLeftFrmWnd->CreateTStereoView();
    	
    	// zjc 09.05.13. modified end
    	//加载图像
    	if(leftimage!=NULL)
    	{
    	  m_pLeftFrmWnd->OpenImagefile(leftimage);
    	}
    
    	m_pRightFrmWnd->CreateTStereoView();
    	if(rightimage!=NULL)
    	{
    	  m_pRightFrmWnd->OpenImagefile(rightimage);
    	}
     
    	AfxSetResourceHandle(AfxGetApp()->m_hInstance);
    	return ;
    }
    

          其中新建两个窗口对象为    CStereoFrmWnd *m_pLeftFrmWnd;

    CStereoFrmWnd *m_pRightFrmWnd;

    CStereoFrmWnd  派生自CFrameWnd 。其效果图如下: 

       

       

        
        现在的问题是如果我把它放在一个对话框程序中调用,那么上面出现的窗口的工具栏按钮就无法响应ON_UPDATE_COMMAND_UI,但是如果放在一个单文档程序调用,上面出现的窗口的工具栏按钮就可以响应ON_UPDATE_COMMAND_UI。我上网查了资料,究其原因在于大多数基于MFC文档视结构的程序,CToolBar对象都位于CMainFrame内,由于CMainFrame可以处理OnIdle消息,并最 终在CCmdUI::DoUpdate内实现对工具栏父窗口(即MainFrame::OnCmdMsg)的消息分发,所以在文档视图框架下,工具栏对 ON_UPDATE_COMMAND_UI的响应是没有问题的。但如果工具栏位于对话框内,则无法响应ON_UPDATE_COMMAND_UI,这是由于CDialog没有对OnIdle的处理,从而无法实现对 DoUpdate的调用。网上有文章介绍一种方法,是在Dialog类内实现WM_INITMENUPOPUP的消息映射,但这种办法只能解决对话框内菜 单项的响应。但是网上的解决办法无法适用我的情况,因为它们的工具栏是和对话框联系在一起的,但是我的工具栏是和DLL的新建窗口联系在一起的。

        我尝试给新建窗口添加WM_KICKIDLE消息响应函数,但是并没有达到我的效果,好像某个操作就会把所有按钮变灰了。

        现在请教各位大侠,怎么修改才能使对话框程序调用也能让新建窗口响应ON_UPDATE_COMMAND_UI呢?

     
    前无古人,后无来者
    2009年8月6日 14:53

答案

  • WM_KICKIDLE是MFC的消息循环才有的,比如MFC对话框的模态循环,或者CWinApp的。如果你写DLL,那么消息循环由调用DLL的人控制。
    你可以自己把发WM_KICKIDLE的更新函数写好,然后让DLL的调用者在消息循环空闲的时候调用你的函数。

    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    • 已标记为答案 Tim Li 2009年8月11日 8:11
    2009年8月6日 16:14
    版主