⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 4.输出文字.txt

📁 本书介绍了在Microsoft Windows 98、Microsoft Windows NT 4.0和Windows NT 5.0下程序写作的方法
💻 TXT
📖 第 1 页 / 共 5 页
字号:
cxClient / cxChar
        
如果在处理WM_CREATE消息处理期间取得cxChar和cyChar,则不用担心在这两个计算公式中会出现被0除的情况。在WinMain呼叫CreateWindow时,窗口消息处理程序接收一个WM_CREATE消息。在WinMain呼叫ShowWindow之后接收到第一个WM_CREATE消息,此时cxChar和cyChar已经被赋予正的非零值了。

如果显示区域的大小不足以容纳所有的内容,那么,知道窗口显示区域的大小只是为使用者提供了在显示区域内卷动文字的第一步。如果您对其他有类似需求的Windows应用程序很熟悉,就很可能知道,这种情况下,我们需要使用「滚动条」。

滚动条


滚动条是图形使用者接口中最好的功能之一,它很容易使用,而且提供了很好的视觉回馈效果。您可以使用滚动条显示任何东西--无论是文字、图形、表格、数据库记录、图像或是网页,只要它所需的空间超出了窗口的显示区域所能提供的空间,就可以使用滚动条。

滚动条既有垂直方向的(供上下移动),也有水平方向的(供左右移动)。使用者可以使用鼠标在滚动条两端的箭头上或者在箭头之间的区域中点一下,这时,「卷动方块」在卷动列内的移动位置与所显示的信息在整个文件中的近似相关位置成比例。使用者也可以用鼠标拖动卷动方块到特定的位置。图4-5显示了垂直滚动条的建议用法。


 



图4-5 垂直滚动条
 

有时,程序写作者对卷动概念很难理解,因为他们的观点与使用者的观点不同:使用者向下卷动是想看到文件较下面的部分;但是,程序实际上是将文件相对于显示窗口向上移动。Windows文件和表头文件标识符是依据使用者的观点:向上卷动意味着朝文件的开头移动;向下卷动意味着朝文件尾部移动。

很容易在应用程序中包含水平或者垂直的滚动条,程序写作者只需要在CreateWindow的第三个参数中包括窗口样式(WS)标识符WS_VSCROLL(垂直卷动)和/或WS_HSCROLL(水平卷动)即可。这些卷动列通常放在窗口的右部和底部,伸展为显示区域的整个长度或宽度。显示区域不包含卷动列所占据的空间。对于特定的显示驱动程序和显示分辨率,垂直卷动列的宽度和水平卷动列的高度是恒定的。如果需要这些值,可以使用GetSystemMetrics呼叫来取得(如前面的程序那样)。

Windows负责处理对滚动条的所有鼠标操作,但是,窗口滚动条没有自动的键盘接口。如果想用光标键来完成卷动功能,则必须提供这方面的程序代码(我们将在下一章另一个版本的SYSMETS程序中做到这一点)。

滚动条的范围和位置


每个滚动条均有一个相关的「范围」(这是一对整数,分别代表最小值和最大值)和「位置」(它是卷动方块在此范围内的位置)。当卷动方块在卷动列的顶部(或左部)时,卷动方块的位置是范围的最小值;在卷动列的底部(或右部)时,卷动方块的位置是范围的最大值。

在内定情况下,滚动条的范围是从0(顶部或左部)至100(底部或右部),但将范围改变为更方便于程序的数值也是很容易的:

SetScrollRange (hwnd, iBar, iMin, iMax, bRedraw) ;
        
参数iBar为SB_VERT或者SB_HORZ,iMin和iMax分别是范围的最小值和最大值。如果想要Windows根据新范围重画滚动条,则设置bRedraw为TRUE(如果在呼叫SetScrollRange后,呼叫了影响滚动条位置的其它函数,则应该将bRedraw设定为FALSE以避免过多的重画)。

卷动方块的位置总是离散的整数值。例如,范围为0至4的滚动条具有5个卷动方块位置,如图4-6所示。


 



图4-6 具有5个卷动方块位置的卷动列
 

您可以使用SetScrollPos在滚动条范围内设置新的卷动方块位置:

SetScrollPos (hwnd, iBar, iPos, bRedraw) ;
        
参数iPos是新位置,它必须在iMin至iMax的范围内。Windows提供了类似的函数(GetScrollRange和GetScrollPos)来取得滚动条的目前范围和位置。

在程序内使用滚动条时,程序写作者与Windows共同负责维护滚动条以及更新卷动方块的位置。下面是Windows对滚动条的处理:

处理所有滚动条鼠标事件
  
当使用者在滚动条内单击鼠标时,提供一种「反相显示」的闪烁
  
当使用者在滚动条内拖动卷动方块时,移动卷动方块
  
为包含滚动条窗口的窗口消息处理程序发送滚动条消息
  
以下是程序写作者应该完成的工作:

初始化滚动条的范围和位置
  
处理窗口消息处理程序的滚动条消息
  
更新滚动条内卷动方块的位置
  
更改显示区域的内容以响应对滚动条的更改
  
像生活中的大多数事情一样,在我们看一些程序代码时这些会显得更加有意义。

滚动条消息


在用鼠标单击滚动条或者拖动卷动方块时,Windows给窗口消息处理程序发送WM_VSCROLL(供上下移动)和WM_HSCROLL(供左右移动)消息。在滚动条上的每个鼠标动作都至少产生两个消息,一条在按下鼠标按钮时产生,一条在释放按钮时产生。

和所有的消息一样,WM_VSCROLL和WM_HSCROLL也带有wParam和lParam消息参数。对于来自作为窗口的一部分而建立的滚动条消息,您可以忽略lParam;它只用于作为子窗口而建立的滚动条(通常在对话框内)。

wParam消息参数被分为一个低字组和一个高字组。wParam的低字组是一个数值,它指出了鼠标对滚动条进行的操作。这个数值被看作一个「通知码」。通知码的值由以SB(代表「scroll bar(滚动条)」)开头的标识符定义。以下是在WINUSER.H中定义的通知码:

#define SB_LINEUP       0
        
#define SB_LINELEFT           0
        
#define SB_LINEDOWN           1
        
#define SB_LINERIGHT          1
        
#define SB_PAGEUP         2
        
#define SB_PAGELEFT           2
        
#define SB_PAGEDOWN           3
        
#define SB_PAGERIGHT          3
        
#define SB_THUMBPOSITION   4
        
#define SB_THUMBTRACK         5
        
#define SB_TOP                6
        
#define SB_LEFT           6
        
#define SB_BOTTOM        7
        
#define SB_RIGHT          7
        
#define SB_ENDSCROLL          8
        
包含LEFT和RIGHT的标识符用于水平滚动条,包含UP、DOWN、TOP和BOTTOM的标识符用于垂直滚动条。鼠标在滚动条的不同区域单击所产生的通知码如图4-7所示。


 



图4-7 用于滚动条消息的wParam值的标识符
 

如果在滚动条的各个部位按住鼠标键,程序就能收到多个滚动条消息。当释放鼠标键后,程序会收到一个带有SB_ENDSCROLL通知码的消息。一般可以忽略这个消息,Windows不会去改变卷动方块的位置,而您可以在程序中呼叫SetScrollPos来改变卷动方块的位置。

当把鼠标的光标放在卷动方块上并按住鼠标键时,您就可以移动卷动方块。这样就产生了带有SB_THUMBTRACK和SB_THUMBPOSITION通知码的滚动条消息。在wParam的低字组是SB_THUMBTRACK时,wParam的高字组是使用者在拖动卷动方块时的目前位置。该位置位于卷动列范围的最小值和最大值之间。在wParam的低字组是SB_THUMBPOSITION时,wParam的高字组是使用者释放鼠标键后卷动方块的最终位置。对于其它的卷动列操作,wParam的高字组应该被忽略。

为了给使用者提供回馈,Windows在您用鼠标拖动卷动方块时移动它,同时您的程序会收到SB_THUMBTRACK消息。然而,如果不通过呼叫SetScrollPos来处理SB_THUMBTRACK或SB_THUMBPOSITION消息,在使用者释放鼠标键后,卷动方块会迅速跳回原来的位置。

程序能够处理SB_THUMBTRACK或SB_THUMBPOSITION消息,但一般不同时处理两者。如果处理SB_THUMBTRACK消息,在使用者拖动卷动方块时您需要移动显示区域的内容。而如果处理SB_THUMBPOSITION消息,则只需在使用者停止拖动卷动方块时移动显示区域的内容。处理SB_THUMBTRACK消息更好一些(但更困难),对于某些型态的数据,您的程序可能很难跟上产生的消息。

WINUSER.H表头文件还包括SB_TOP、SB_BOTTOM、SB_LEFT和SB_RIGHT通知码,指出滚动条已经被移到了它的最小或最大位置。然而,对于作为应用程序窗口一部分而建立的滚动条来说,永远不会接收到这些通知码。

在滚动条范围使用32位的值也是有效的,尽管这不常见。然而,wParam的高字组只有16位的大小,它不能适当地指出SB_THUMBTRACK和SB_THUMBPOSITION操作的位置。在这种情况下,需要使用GetScrollInfo函数(在下面描述)来得到信息。

在SYSMETS中加入卷动功能


前面的说明已经很详尽了,现在,要将那些东西动手做做看了。让我们开始时简单些,从垂直卷动着手,因为我们实在太需要垂直卷动了,而暂时还可以不用水平卷动。SYSMET2如程序4-3所示。这个程序可能是滚动条的最简单的应用。

程序4-3 SYSMETS2.C 
        
/*------------------------------------------------------------------
        
    SYSMETS2.C -- System Metrics Display Program No. 2
        
            (c) Charles Petzold, 1998
        
------------------------------------------------------------------*/
        
#include <windows.h>
        
#include "sysmets.h"
        
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
        
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
        
                 PSTR szCmdLine, int iCmdShow)
        
{
        
    static TCHAR szAppName[] = TEXT ("SysMets2") ;
        
    HWND   hwnd ;
        
    MSG    msg ;
        
    WNDCLASS wndclass ;
        
    wndclass.style           = CS_HREDRAW | CS_VREDRAW ;
        
    wndclass.lpfnWndProc  = WndProc ;
        
    wndclass.cbClsExtra   = 0 ;
        
    wndclass.cbWndExtra   = 0 ;
        
    wndclass.hInstance       = hInstance ;
        
    wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
        
    wndclass.hCursor         = LoadCursor (NULL, IDC_ARROW) ;
        
    wndclass.hbrBackground        = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
        
    wndclass.lpszMenuName         = NULL ;
        
    wndclass.lpszClassName        = szAppName ;
        

    if (!RegisterClass (&wndclass))
        
    {
        
    MessageBox (NULL, TEXT ("This program requires Windows NT!"),
        
           szAppName, MB_ICONERROR) ;
        
    return 0 ;
        
    }
        

    hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 2"),
        
                   WS_OVERLAPPEDWINDOW | WS_VSCROLL,
        
                   CW_USEDEFAULT, CW_USEDEFAULT,
        
                   CW_USEDEFAULT, CW_USEDEFAULT,
        
                   NULL, NULL, hInstance, NULL) ;
        
    ShowWindow (hwnd, iCmdShow) ;
        
    UpdateWindow (hwnd) ;
        

    while (GetMessage (&msg, NULL, 0, 0))
        
    {
        
       TranslateMessage (&msg) ;
        
        DispatchMessage (&msg) ;
        
    }
        
    return msg.wParam ;
        
}
        
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
        
{
        
    static int  cxChar, cxCaps, cyChar, cyClient, iVscrollPos ;
        
    HDC         hdc ;    
        
    int         i, y ;   
        
    PAIN

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -