七. 界面编程--Windows编程课程学习笔记

Posted ling_xiao007

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七. 界面编程--Windows编程课程学习笔记相关的知识,希望对你有一定的参考价值。

7.1更改窗口大小、标题、风格

7.1.1 在窗口创建之前更改

如果希望在应用程序窗口创建之前修改它的大小、标题和风格,应该在CMainFrame类的PreCreateWindow成员函数进行。该函数有个类型是CREATESTRUCT结构的参数,如果在修改了这个参数中的成员变量的值,那么这种改变会反映到MFC底层代码中,当MFC底层代码调用CreateWindowEx函数去创建窗口时,它就会使用改变后的参数值去创建这个窗口。

1)更改窗口大小

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)

    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
    //TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式
    cs.cx = 400;
    cs.cy = 200;
    return TRUE;

2)更改应用程序标题

    框架的默认窗口样式是WS_OVERLAPPEDWINDOW和FWS_ADDTOTITLE样式的组合。其中FWS_ADDTOTITLE是MFC特定的一种样式,指示框架将文档标题添加到窗口标题上。因此,如果想让窗口显示自己的标题,只需将窗口的FWS_ADDTOTITLE样式去掉即可。设置窗口标题的代码之前加上:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)

    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
    //TODO: 在此处通过修改
    //  CREATESTRUCT cs 来修改窗口类或样式
    cs.cx = 400;
    cs.cy = 200;
 
    cs.style = cs.style & ~FWS_ADDTOTITLE;
//  cs.style = WS_OVERLAPPEDWINDOW;
 
    cs.lpszName = "标题";
    return TRUE;

7.1.2在窗口创建之后更改其风格

在应用程序窗口创建之后修改它的风格属性,可在CMainFrame类的OnCreate函数中调用SetWindowLong函数实现。

SetWindowLong(HWND hWnd, int nIndex, LONGdwNewLong)

该函数的作用是改变制定窗口的属性(包括设置新的窗口风格、设置新的窗口过程、设置新的应用程序实例局柄等)。要改变窗口的风格,则将该函数的第二个参数指定为GWL_STYLE,然后由第三个参数指定新的窗口风格。

如果是在已有类型的基础上进行修改的话,那么可以利用GetWindowLong这个函数获得这个窗口的现有类型,然后修改。例如:

    SetWindowLong(m_hWnd, GWL_STYLE, GetWindowLong(m_hWnd, GWL_STYLE) & ~WS_MAXIMIZEBOX);

7.1.3 在窗口创建之后更改标题与大小

在应用程序窗口创建之后修改标题,可在CMainFrame类的OnCreate函数中调用SetWindowText函数实现。

在应用程序窗口创建之后修改大小,可在CMainFrame类的OnCreate函数中调用SetWindowPos函数实现。

7.2 修改光标、图标、背景

7.2.3 在窗口创建前更改

之前对于窗口的大小、标题和风格是在创建窗口时设定的。而光标、图标和背景是在设计窗口类时指定的。窗口类的设计与注册是由MFC底层代码自动完成的,我们不可能、也不应该去修改MFC底层代码。但是我们可以编写自己的窗口类注册,然后让随后的窗口按照我们编写的窗口类去创建。

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT&cs)

    if( !CFrameWnd::PreCreateWindow(cs) )
        return FALSE;
    …
WNDCLASSMyWnd;
    MyWnd.cbClsExtra = NULL;MyWnd.cbWndExtra = NULL;
    MyWnd.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    MyWnd.hCursor = LoadCursor(NULL, IDC_CROSS);
    MyWnd.hIcon = LoadIcon(NULL, IDI_WARNING);
    MyWnd.hInstance = AfxGetInstanceHandle();
    MyWnd.lpfnWndProc = ::DefWindowProc;
    MyWnd.lpszClassName = "Hello";
    MyWnd.lpszMenuName = NULL;
    MyWnd.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&MyWnd);
    cs.lpszClass = "hello";
return TRUE;

     上述代码的运行结果是:仅仅是程序的标题栏图标发生了改变,但窗口的背景和光标没有改变。原因是:视类窗口覆盖在主窗口上面,我们看到的窗口实际上是视类窗口,而上述代码修改的是框架类窗口的背景和光标。应用程序的图标属于框架窗口,因此上述程序运行后,图标发生了改变。    

结论:在MFC中,如果要修改应用程序窗口的图标,则应该框架类中进行,因为框架窗口才有标题栏;如果要修改程序窗口的背景和光标,则应该在视类中进行。解决方法:在视类的PreCreateWindow函数中添加代码:   cs.lpszClass= "hello";。

同时MFC为我们提供了一个全局函数AfxRegisterWndClass()。

LPCTSTR AFXAPI AfxRegisterWndClass(UINTnClassStyle, HCRSOR hCursor = 0, HBRUSH hbrBackground = 0, HICON hIcon = 0);

7.2.2 在窗口创建之后更改

要在应用程序窗口创建之后修改它的光标、图标和背景,可在OnCreate函数中调用SetClassLong函数实现。DWORD SetClassLong(HWNDhWnd, int nIndex, LONG dwNewLong)

该函数的作用是:重新设置指定窗口所属窗口类的WNDCLASS结构体中指定数据成员的属性(包括设置新的窗口背景画刷、光标、图标和窗口类样式)。

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

    if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
        return -1;
    …
SetClassLong(m_hWnd,GCL_HICON, (LONG)LoadIcon(NULL, IDI_WARNING));
    return 0;

 
 
int CMyMFCAppView::OnCreate(LPCREATESTRUCT lpCreateStruct)

    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
       …
    //7.2.2 在窗口创建之后更改光标、标题栏图标、窗口背景
    SetClassLong(m_hWnd, GCL_HBRBACKGROUND, (LONG)GetStockObject(BLACK_BRUSH));
    SetClassLong(m_hWnd, GCL_HCURSOR, (LONG)LoadCursor(NULL, IDC_CROSS));
    return 0;

7.3 模拟动画图标

7.3.1 加载图标资源

添加IDI_ICON1-4资源,气候在框架类定义一个图标句柄成员变量,添加数组时,类型设置为HICON [4]方能设置成功。在视类添加一下代码。

    m_hIcons[0] = ::LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
    m_hIcons[1] = ::LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2));
    m_hIcons[2] = ::LoadIcon(AfxGetApp()->m_hInstance,MAKEINTRESOURCE(IDI_ICON3));
    m_hIcons[3] = AfxGetApp()->LoadIcon(IDI_ICON4);

其中LoadIcon第一个参数,加载第一幅时,AfxGetInstanceHandle可以获取应用程序当前句柄。第二个参数,通过MAKEINTRESOURSE宏将ID转换为相应的资源表示符字符串。第二幅应用theApp的获取应用程序的CWinApp对象,其数据成员m_hInstance得到实例句柄。但是App文件中已经定义了一个theApp全局变量,所以在框架类OnCreate函数前extern CMyMFCApp theApp。第三幅加载,用AfxGetApp全局函数实现。

7.3.2设置定时器

在框架类OnCreate函数添加SetTime函数,没1000ms触发一次定时器消息。

    SetTimer(1, 1000, NULL);

在框架类添加定时器消息(WM_TIMER)的响应函数,并在响应函数调用SetClassLong函数改变应用程序窗口图标。

void CMainFrame::OnTimer(UINT_PTR nIDEvent)

    //TODO: 在此添加消息处理程序代码和/或调用默认值
    static int index = 1;
    SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcons[index]);
    index = ++index % 4;
    CFrameWnd::OnTimer(nIDEvent);
    CFrameWnd::OnTimer(nIDEvent);

因为程序每次发送定时器消息都会调用OnTimer函数,所以把index定义为静态(分配在栈中)。

7.4工具栏编程

7.4.1 在工具栏添加按钮

在资源的toolbar中在IDR_MAINFRAME的最右边添加一个按钮IDM_TEST。并在菜单栏【帮助】下添加一个同ID的按钮,Caption设置为Test。添加一个命令响应函数OnTestShow。可以将T按钮享有拖动一点,此时帮助与T按钮有一定空隙。想要删除只需del。

void CMainFrame::OnTestShow()

    //TODO: 在此添加命令处理程序代码
    MessageBox("Teston toolbar");

7.4.2创建工具栏——4个步骤

Step1:创建工具栏资源;

Step2:构造CToolBar对象;主框架添加私有变量

Step3:调用Create或CreateEx函数创建Window工具栏(工具栏也是窗口)

Step4:调用LoadToolBar函数加载工具栏资源。

7.4.3 创建自定义工具栏

在TOOLBAR添加新资源,在框架类加加一个CToolBar类型的成员变量,调用create函数创建工具栏,与CToolBar相关联,可以在框架类的OnCreate函数实现。添加一下代码。

 <span style="white-space:pre">	</span>if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
        | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
        !m_newToolBar.LoadToolBar(IDR_TOOLBAR1))
    
        TRACE0("Failed to create toolbar\\n");
        return-1;      // fail to create
    
    m_newToolBar.EnableDocking(CBRS_ALIGN_ANY);
    DockControlBar(&m_newToolBar);

CreateEx函数创建工具栏,并与工具栏对象:m_newToolBar关联,停靠位置设置为CBRS_RIGHT。调用LoadToolBar加载资源。调用EnableDocking函数允许工具栏停靠客户区任意位置。最后调用DockControlBar函数,让工具栏停靠在主框架窗口上。

7.4.4 显示和隐藏工具栏

在【视图】自此阿达您下载添加一个菜单项。ID属性为IDM_VIEW_NEWTOOLBAR,Caption为“新的工具栏”。接着添加命令响应函数。在响应函数中,实现先前新建的工具栏的显示与隐藏。可以调用ShowWindow函数。之后需要调整他们的位置,调用RecalcLayout函数。限制或隐藏后再次调用框架类DockControlBar函数。让工具栏停靠在主框架窗口上,使用DockControlBar函数。

void CMainFrame::OnViewNewtoolbar()

    //TODO: 在此添加命令处理程序代码
    if (m_newToolBar.IsWindowVisible())
        m_newToolBar.ShowWindow(SW_HIDE);
    else
        m_newToolBar.ShowWindow(SW_SHOW);
    RecalcLayout();
    DockControlBar(&m_newToolBar);

如何让新建的工具栏舍在原先显示位置显示。需要调用ShowControlBar函数。

下面,添加复选编辑。为此为菜单项添加一个UPDATE_COMMAND_UI函数。内部添加代码。

void CMainFrame::OnUpdateViewNewtoolbar(CCmdUI *pCmdUI)

    //TODO: 在此添加命令更新用户界面处理程序代码
    // 添加复选框
    pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());

7.5 状态栏编程

7.5.1 状态栏的提示行与指示器

状态栏分为两部分:提示行与指示器。左边最长的部分为提示行,通常用于显示菜单项或工具按钮的提示信息。右边由若干窗格组成的部分为状态栏指示器,通常用来显示大小写键、数字锁定键等信息。

框架程序专门提供了一个indicators数组来管理提示行与指示器。如果要修改状态栏的外观,则只需在indicators数组中添加或减少相应的字符串资源ID即可。

① 在资源编辑器中新增字符串资源ID:

      ID_TIMER                          时钟

② 将新的字符串资源ID添加到indicators数组中

③ 获取系统当前时间(加在CMainFrame的OnCreate函数的后部)

    CTime t = CTime::GetCurrentTime();
    CString str = t.Format("%H:%M:%S");

④ 将字符串显示到状态栏的窗格上,调用CStatusBar类的成员函数SetPaneText。如果不知道窗格的索引,可以调用CStatusBar类的成员函数CommandToIndex获得。m_wndStatusBar.CommandToIndex(ID_TIMER)

    m_wndStatusBar.SetPaneText(1, str);
⑤ 调整窗格大小

CStatusBar类的成员函数:SetPaneInfo,该函数可以为指定的窗格设置新的ID、样式和宽度。

    CClientDC dc(this);
    CSize sz = dc.GetTextExtent(str);
    m_wndStatusBar.SetPaneInfo(1, ID_TIMER, SBPS_NORMAL,sz.cx);

⑥ 在OnTimer中添加相关代码。

7.6 在状态栏中添加鼠标坐标显示

方法一:调用SetWindowText函数设置状态栏提示行文本

需添加头文件并把m_wndStatusBar改为公有

    CString str;
    str.Format("x=%d, y=%d", point.x, point.y);
    ((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);

方法二:利用CFrameWnd类的成员函数SetMessageText实现,该函数的作用是在状态栏的提示行中设置文本。

    ((CMainFrame*)GetParent())->SetMessageText(str);

方法三:利用CFrameWnd类的成员函数GetMessageBar可以返回状态栏对象的指针,这样也不用再访问CMainFrame类的保护成员变量:m_wndStatusBar。

    ((CMainFrame*)GetParent())->GetMessageBar()->SetWindowText(str);

在提示行中显位图(借助位图按钮的方法)

在框架类添加CBitmapButton m_bmp变量。

    CRect rc(100, 4, 120, 20);
    if (!m_bmp.Create("", WS_CHILD | WS_VISIBLE | BS_OWNERDRAW, rc, &m_wndStatusBar, 0))
        return FALSE;
    if (!m_bmp.LoadBitmaps(IDB_BITMAP1, NULL, NULL, NULL))
        return FALSE;

7.7添加启动界面

7.7.1 利用VC++组件库中提供的类完成

单击[Project \\ Add to Project \\Components and controls…],在弹出的组件和控件库对话框中双击“Visual C++ Components”目录,在该目录下找到Splashscreen组件。

替换splsh.bmp位图文件可替换启动界面;

更改SetTimer(1, 2000, NULL)可设定启动画面的停留时间。

7.7.2 VS添加启动画面

1)新建一个ID_BITMAP3的位图资源。

2)现在项目下新建一个类CSplashWnd,基类为CWnd;

3)在该类下添加一个protected型的变量CBitmap m_bitmap

4)添加一个Create函数加载位图,创建窗口;

public:
    BOOL Create();
 
BOOL CSplashWnd::Create()

    if (!m_bitmap.LoadBitmap(IDB_BITMAP3))
        return false;
    BITMAP bm;
    m_bitmap.GetBitmap(&bm);
    return CreateEx(0, AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
        NULL, WS_POPUP | WS_VISIBLE, 0,0, bm.bmWidth, bm.bmHeight, NULL, NULL);

5)显示窗口发送WM_PAINT消息,映射此消息;

void CSplashWnd::OnPaint()

	CPaintDC dc(this); // device context for painting
					   // TODO: 在此处添加消息处理程序代码
					   // 不为绘图消息调用 CWnd::OnPaint()
	CDC dcimage;
	if (!dcimage.CreateCompatibleDC(&dc)) return;
	BITMAP bm;
	m_bitmap.GetBitmap(&bm);
	CBitmap* pOldBitmap = dcimage.SelectObject(&m_bitmap);
	dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcimage, 0, 0, SRCCOPY);
	dcimage.SelectObject(pOldBitmap);

6)在App类中包含新类的头文件后,在InitInstance()函数中添加以下代码:

    CSplashWnd *pSplashWindow = new CSplashWnd;//创建对象
    pSplashWindow->Create();
    pSplashWindow->CenterWindow();
    pSplashWindow->ShowWindow(SW_SHOW);  //显示窗口
    pSplashWindow->UpdateWindow();
    Sleep(2000); //表示启动画面持续时间
    pSplashWindow->DestroyWindow(); //销毁启动画面
    delete pSplashWindow; //删除

 

以上是关于七. 界面编程--Windows编程课程学习笔记的主要内容,如果未能解决你的问题,请参考以下文章

七. 界面编程--Windows编程课程学习笔记

Windows编程课程学习笔记

Windows编程课程学习笔记

二. MFC框架程序分析--Windows编程课程学习笔记

二. MFC框架程序分析--Windows编程课程学习笔记

六. 对话框编程--Windows编程课程学习笔记