对话框与子窗口之间的切换,以及如何卡入到控件里

来源:互联网 发布:vscode错误提示 编辑:程序博客网 时间:2024/04/29 22:20

关键字: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);
  }
  到此目的达到。

 

卡入对话框到控件

 

CWnd* pS = this->GetDlgItem(IDC_STATIC_Rong);
 if(pS)
 {
  
  AFX_MANAGE_STATE(AfxGetStaticModuleState());
  CMyDlg* pDlg = new CMyDlg(pS);
  pDlg->Create(CMyDlg::IDD, pS);
  pDlg->SetParent(pS);

  HWND hwnd = pDlg->GetSafeHwnd();
  ::SetWindowLong(hwnd, GWL_STYLE, 0);
  pDlg->ShowWindow(SW_MAXIMIZE);
 }