对话框到子控件的切换
例子:见附件
贴图:
原始界面
被嵌入对话框中的对话框跳出了主窗口
关键字:SetWindowLong,SetWindowPos,SetParent,WS_POPUP,WS_CHILD
背景:准备做一个播放器,底层接口做好了,只需传入一个窗口句柄,就可以在该窗口上面播放媒体了。本来想在一个对话框上放置一个static控件,将static控件句柄传给底层接口就好。普通播放没问题,电影都在static上。但是要求全屏播放,这下就难住了。因为static无法全屏啊。
目的:能将某窗口全屏,但又能将该窗口嵌入另一窗口中。
方案:
(1)动态更改static控件的style,并将其父窗口句柄更为NULL,看控件可不可以跳出对话框。此方案实施过,成功。static控件跳出了对话框,成为一个独立的窗口。但是该窗口没法控制,回不去。此方案似乎有问题。由于时间关系,没有深入研究,估计再鼓捣鼓捣说不定能搞出来。
(2)作一个主窗口,上面放一个static,调整其大小到合适位置。再作一个对话框,将该窗口覆盖在static上方,动态更改该对话框,这样就是两个对话框前后重叠,好像是主窗口中的控件了。实施过,成功。但是毛病是控制比较复杂,要算来算去的。后面的主窗口的标题还爱变灰,明眼人一看就知道是两个窗口。不行。
(3)同样是做两个窗口,但是用在播放电影的那个对话框把它当作子控件嵌入到主窗口中,在需要全屏的时候,将其属性更改成窗口,那它就跳出主窗口而全屏了。由于本身是窗口,可以控制它,在需要恢复的时候,再将其嵌入到主窗口中,又成了子控件了。本文就讨论此方案。
步骤:
1,创建一个以对话框为基础的项目。在对话框中添加一个Static : IDC_FULLSCREEN,拉出适当的大小形状。以容纳另一个窗口。
2,插入一个对话框资源。去掉上面默认的所有控件。必须修改对话框以下属性:
a)VisibleTRUE
b)StyleChild
根据需要修改Title bar。可以自己看看效果。如果有标题栏,则可以在static中移动该窗口。
3,生成一个新类CMyDlg
a)对该类重载以下两个函数,以免用户敲入回车和Esc键将该窗口关闭。
void OnOK(){return;}
void OnCancel(){return;}
b)由于需要与主窗口(也就是其父窗口)通信,在该对话框跳出父窗口后,还需要再次嵌入到父窗口中,所以增加一个父窗口类的实例指针。
CWnd* m_pParent;
c)在CMyDlg的构造函数中,将传递过来的父窗口指针保存起来以备后用:
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent),m_pParent(pParent)
{
}
4,有了上面的窗口后,我们不能像普通控件拖到对话框中,所以需要在主窗口类中定义一个指针成员变量保存播放窗口,并动态创建之。
CMyDlg*pDlg;
并在对话框类的构造函数中将其赋值为NULL。在析构中delete pDlg。
5,在对话框的OnInitDialog函数中初始化CMyDlg;如下:
// TODO: 在此添加额外的初始化代码
CWnd* pS = (CWnd*)GetDlgItem(IDC_FULLSCREEN);
if (pS ==NULL)
{
AfxMessageBox("Error");
return FALSE;
}
if ( pDlg==NULL )
{
pDlg = new CMyDlg(pS);
pDlg-Create( CMyDlg::IDD,pS );
pDlg-ShowWindow(SW_NORMAL);
}
在创建CMyDlg时,将其父窗口指向static窗口。
6,这时可以运行程序了。当然编译的时候需要添加一些头文件之类的琐碎事情,自己可以搞定。我们可以发现播放窗口在主窗口的static控件中出现了,如果有标题栏,还可以移动。如果播放窗口的边框有resizing的属性,还可以改变大小。玩够了后结束程序,继续。
7,现在增加将播放窗口跳出主窗口的动作。主要用到的是SetWindowLong函数修改其现有的属性。在一个按钮被按下的事件中处理,主要的功能就是去掉子窗口属性(WS_CHILD)添加弹出窗口属性(WS_POPUP),然后设置其父窗口为NULL。
将代码中注释掉的代码恢复后,就达到全屏的效果了。
void CfullscreenDlg::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
if ( pDlg == NULL ) return;
HWND hWnd = pDlg-GetSafeHwnd();
if ( hWnd == NULL ) return;
::SetWindowLong( hWnd , GWL_STYLE, (::GetWindowLong(hWnd,GWL_STYLE) ) & (~WS_CHILD) & (~WS_DISABLED) | WS_POPUP );
pDlg-SetParent(NULL);
//if ( ! ::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), 0) )
//{
//AfxMessageBox("NO");
//}
}
8,现在运行程序,单击按钮后,我们发现播放窗口真的跳出来了。按下Esc键,退出程序。我们来添加恢复到嵌入主窗口中的功能。
9,为了简单起见,我们直接在CMyDlg类中实现。给CMyDlg增加一个消息处理函数:鼠标左键弹起,在消息处理中,无非也是修改窗口属性。代码如下:
void CMyDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if ( m_pParent != NULL )
{
HWND hWnd = GetSafeHwnd();
if ( hWnd == NULL ) return;
LONG newStyle = ::GetWindowLong( hWnd,GWL_STYLE)
& (~WS_POPUP)
| WS_CHILD
| WS_DISABLED ;
::SetWindowLong( hWnd , GWL_STYLE, newStyle) ;
SetParent(m_pParent);
}
CDialog::OnLButtonUp(nFlags, point);
}
到此目的达到。