MFC框架程序中全屏显示特性的实现

MFC框架程序中全屏显示特性的实现

在开发图像显示程序以及视频应用程序时,常常需要全屏显示特性,比如ACD See和豪杰解霸等应用都有全屏显示功能。本文将介绍如何在MFC框架程序中实现视图的全屏显示,也就是说将标题、菜单、工具栏、状态栏以及窗口的所有边框全部被隐藏,视图充满整个屏幕。并提供全屏显示与框架窗口之间的快捷切换操作。

大家知道,在MFC框架中并没有提供现成的类或者函数来实现全屏显示特性,至少我到目前为止是没有发现。但是要实现这个特性也并不难。其基本思路是调整主窗口的大小和位置,使视图的显示充满屏幕。它需要以屏幕左上角为原点,处理x,y方向上的负坐标。本文拟用“使用GDI+进行图像处理”一文中的例子代码作为基础,实现视图的全屏显示。我在原来代码中增加了一个可重用的C++类CFullScreenHandler,顾名思义,这个类的作用就是专门用来实现全屏显示特性的,它封装了所有的实现细节,只要你把它加到自己的工程代码中,不用怎么修改就能是程序具备全屏显示功能。这个类中有两个重要的方法调用:第一、Maximize进入全屏显示模式,注意了,这里的全屏显示模式并不是平常我们说的窗口最大化按钮哦。第二、Restore方法用来恢复原来的窗口框架。CFullScreenHandler还提供了一个InFullScreenMode方法,用它来检查程序是否处于全屏显示状态,这些方法都通过一个CFullScreenHandler全程对象实例来调用。下面是程序的主窗口处理命令,全屏显示特性由“查看”菜单中的“全屏显示(&U)”触发执行,关键代码如下:

void CMainFrame::OnViewFullScreen()
{
  if (FullScreenHandler.InFullScreenMode())
    FullScreenHandler.Restore(this);
  else
    FullScreenHandler.Maximize(this);
}

一旦进入全屏显示方式,那么标题栏、菜单栏和工具栏都会消失。千万别忘了告诉用户如何恢复原样,在OnDraw函数中加上几句即可:

void CPictureView::OnDraw(CDC* pDC)
{
   ......
  if (*ppic) {
    ......

    pDC->DrawText(FullScreenHandler.InFullScreenMode() ?
      _T("恢复窗口按 Ctrl-U 或者在客户区双击鼠标") : _T(""), &rc, 0);
  }
}

如图一所示:

MFC框架程序中全屏显示特性的实现

图一 给用户的恢复提示

之所以一定要给用户这种提示,是因为Windows程序的一个重要的GUI特点就是界面操作的自解释。否则,当用户进入全屏显示模式后(有意或无意),如果找不到恢复的方法便会令用户感到不知所措。 

下面我们就来看看CFullScreenHandler::Maximize和Restore的工作原理:其实这些代码没有什么高深的东西,只是一些象素计算而已。Maximize首先在m_rcRestore数据成员中保存当前框架的位置,然后计算期望的屏幕尺寸。如图二所示:

MFC框架程序中全屏显示特性的实现

图二 计算期望的屏幕尺寸

获得屏幕尺寸的方法是调用GetSystemMetrics函数。 Restore函数比Maximize更简单,它用m_rcRestore成员变量中保存的值将框架恢复到原来的样子,然后调用m_rcRestore.SetRectEmpty来表示框架不再处于全屏显示状态。就这么简单。

程序中有一个地方要说明一下,那就是OnGetMinMaxInfo函数的作用。你可以试一下,如果把这个函数去掉,则当你按下工具栏中的全屏显示按钮时,框架视图确实变大了,但没有想象的那样实现全屏显示,底边留下一个状态栏——一个有些发育不良的全屏显示窗口。为什么会这样呢?经过调试后,发现问题出在WM_GETMINMAXINFO消息的处理上。在Windows中,无论什么时候以何种方式改变窗口的尺寸或大小,是拖拽窗口边缘也好,或是在代码中调用改变窗口尺寸的函数也好,总之不管你用什么方法,Windows都会首先发送WM_GETMINMAXINFO消息。这个消息的意思是说:“嘿,如果你要强迫我的尺寸变大或变小,就附上详细的MINMAXINFO结构信息,否则我用默认值处理。”大多数应用程序都不用显式处理这个WM_GETMINMAXINFO消息(也就是说让DefWindowProc窗口过程进行缺省处理),而Windows在进行缺省处理时是不会让一个窗口视图比屏幕还大的,所以我们会碰上前面讲的那个问题。解决的方法是:不要让Windows对WM_GETMINMAXINFO消息进行缺省处理,而是由我们自己处理,方法如下:

void CMainFrame::OnGetMinMaxInfo(MINMAXINFO* lpmmi)
{
 CSize sz = FullScreenHandler.GetMaxSize();
 lpmmi->ptMaxSize = CPoint(sz);
 lpmmi->ptMaxTrackSize = CPoint(sz);
}

这里CFullScreenHandler.GetMaxSize 返回的最大尺寸要比整个屏幕稍微大一点。

CSize CFullScreenHandler::GetMaxSize()
{
 CRect rc(0,0,GetSystemMetrics(SM_CXSCREEN),GetSystemMetrics(SM_CYSCREEN));
 rc.InflateRect(10,50);
 return rc.Size();
}

GetMaxSize 返回的值分别是2×10=20和2×50=100象素,比屏幕自身的水平值和垂直值稍大。至于要大多少,我认为只要一个比屏幕大的模糊值即可。如果你硬要知道屏幕的精确尺寸,自己可以计算一下。

本文配套源码