Windows Mobile(WinCE)的轻量级图像查看器






3.13/5 (8投票s)
演示如何在 Pocket PC 屏幕上显示任何大小的 BMP 或 JPEG 图像并滚动到其极限

引言
本文旨在解释为 Pocket PC 编码图像查看器的原理。该示例应用程序很简单。没有缩放或旋转图像等高级功能。事实上,示例中我只想解释 3 个要点
- 如何将窗口切换到全屏模式。
- 如何加载 JPEG 图像并将其绘制到窗口上。
- 图像大于屏幕区域时如何滚动图像(通过使用触笔)。
图像查看器示例快速预览
wmimgvwr
是一个使用 Visual Studio 2005 编码的 C++/MFC 应用程序。您可以为 PPC 2003 或 Windows Mobile 5 构建最终的可执行文件。vmimgvwr
有两种打开图像的方式
- 在不带参数启动的情况下,将显示一个“打开文件”对话框(CFileDialog)(**图 1**)。CFileDialog 的主要问题是它只能访问“\我的文档”文件夹中的文件和文件夹。
- 通过传递完整的图像路径来启动它,例如,应用程序可以通过调用CreateProcess API 函数来启动
wmimgvwr
PROCESS_INFORMATION procInfo;
CreateProcess( L"\\Apps\\wmimgvwr.exe",
L"\\Images\\fig1.bmp",
NULL,
NULL,
FALSE,
NULL,
NULL,
NULL,
NULL,
&procInfo );

图 1
窗口的左上角有一个关闭按钮。实际上,它不是一个按钮,而是一个图片控件(**图 2**)。当您滚动图像时,该按钮不可见。因此,您可以查看所有图像细节(**图 3**)。
![]() 图 2 |
![]() 图 3 |
理解源代码
现在是时候解释源代码的主要点了。
1. 如何将窗口切换到全屏模式
Pocket PC 的屏幕分辨率较低(320x240 或 240x240)。因此,最好利用所有分辨率来显示图像,对吗?wmimgvwr
是一个对话框应用程序。它是一个没有标题栏或系统菜单的对话框。但是,这还不够。我们需要一些代码来将对话框切换到全屏模式。请查看 wmimgvwrDlg.cpp(**第 91 行**)
// *** FULL SCREEN - BEGIN
SHINITDLGINFO shidi;
(void) ::ZeroMemory(&shidi, sizeof(shidi));
shidi.dwMask = SHIDIM_FLAGS;
shidi.dwFlags = SHIDIF_FULLSCREENNOMENUBAR;
shidi.hDlg = this->m_hWnd;
::SHInitDialog(&shidi);
this->uf_full_screen();
// *** FULL SCREEN - END
SHInitDialog 用于使用 SHIDIF_FULLSCREENNOMENUBAR 将对话框设置为全屏,它会移除对话框中的命令栏。令人惊讶的是,结果并不是一个全屏窗口,但它仍然是必需的。请记住,函数 uf_full_screen()
包含了其余的必要代码(wmimgvwrDlg.h,**第 60 行**)
void uf_full_screen(BOOL _bMove = TRUE)
{
HWND hBar = ::SHFindMenuBar(this->m_hWnd);
::CommandBar_Show( hBar, FALSE );
this->SetForegroundWindow();
::SHFullScreen( this->m_hWnd,
SHFS_HIDETASKBAR | SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON );
RECT cliRect;
this->GetClientRect(&cliRect);
if ( _bMove )
{
cliRect.top -= vg_wintask_h;
cliRect.bottom += vg_wintask_h;
this->MoveWindow(&cliRect);
}
}
函数的前两行包含隐藏命令栏的代码(SHFindMenuBar 和 CommandBar_Show)。接下来,SHFullScreen 授予对话框窗口覆盖任务栏和 SIP 按钮的权限。这是我找到的描述 SHFullScreen 实际功能的最佳方式,因为调用它并不会产生全屏窗口。此外,您必须在调用它之前调用 SetForegroundWindow。
最后,您必须调整窗口大小以覆盖所有屏幕。我的意思是窗口也必须覆盖任务栏区域。那么,任务栏的高度是多少?通常是 26 像素,但我们永远无法确定。请查看变量 vg_wintask_h
(wmimgvwrDlg.h,**第 73 行**)。它的值是任务栏的高度。 wmimgvwr.cpp,**第 52 行** 显示了它如何获取该值。
2. 如何加载 JPEG 图像文件并将其绘制到窗口上
位图绘制在窗口的客户区域。因此,您只需要加载位图文件,获取句柄,然后使用适当的函数进行绘制。MFC 为我们提供了 CBitmap 和 CDC 类。两者都足以加载和显示位图文件,但 JPEG 文件呢?
您可能会认为这是一个问题,因为没有 CJPEG 类来加载 JPEG 文件并将其转换为位图。事实上,即使是像 LoadImage 这样的基本函数也只接受位图、图标或光标文件进行加载。别担心;您不必在互联网上搜索 Windows CE 的 JPEG 库。请查看定义在 wmimgvwrDlg.cpp(**第 183 行**)中的 uf_load_bitmap
成员函数。有一个很棒的函数叫做 SHLoadImageFile,它允许应用程序加载各种类型的图像并将它们全部转换为位图!然后,应用程序可以将 CBitmap 类附加到 SHLoadImageFile 返回的位图句柄上,并轻松处理它。请注意,它可以加载 GIF 和 PNG 文件。
3. 图像大于屏幕区域时如何滚动图像(通过使用触笔)
将位图绘制到窗口的客户区域是一个简单的过程,只需调用 BitBlt 函数并传递正确的参数。如何控制这些参数值可能是一个问题。定义在 wmimgvwrDlg.cpp(**第 125 行**)中的成员函数 OnPaint
在每次窗口需要重绘时都会被调用。以下代码在调用 OnPaint
时始终执行
dc.BitBlt( this->m_img_pos.dc_x,
this->m_img_pos.dc_y,
this->m_img_pos.dc_crop_cx,
this->m_img_pos.dc_crop_cy,
&this->m_dcMem,
this->m_img_pos.bmp_x,
this->m_img_pos.bmp_y,
SRCCOPY );
成员变量 m_img_pos
是在 globals.h 中定义的结构。一些字段在 uf_load_bitmap
中初始化,另一些在 uf_calc_bmp_pos
成员函数(wmimgvwrDlg.cpp,**第 148 行**)中初始化。uf_calc_bmp_pos
执行以下操作:如果图像小于窗口的客户区域,则图像在窗口中居中。否则,图像的中心部分会绘制在窗口的客户区域。
图像滚动在 PreTranslateMessage
成员函数(wmimgvwrDlg.cpp,**第 227 行**)中控制。请注意关闭按钮的可见状态是如何控制的(**第 239 行**和**第 301 行**)。WM_MOUSEMOVE
消息被处理以处理滚动,只有当图像不适合窗口时才会发生滚动。m_img_pos
结构中的两个布尔字段控制图像滚动:bmp_scroll_x
和 bmp_scroll_y
。
bmp_x
和 bmp_y
字段是根据触笔动作的值进行更改的字段。最后,如果确实发生了滚动,则会调用 Invalidate 来强制重绘窗口的客户区域(**第 295 行**)。
尽情享受吧。希望这有帮助。
历史
2007 年 11 月 23 日 -- 初始版本