首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >VC++6.0入门——第九讲 定制应用功能程序外观

VC++6.0入门——第九讲 定制应用功能程序外观

原创
作者头像
Arya
发布2024-12-03 10:34:13
发布2024-12-03 10:34:13
1940
举报
文章被收录于专栏:后端开发专栏后端开发专栏

在文章开始之前,推荐一篇值得阅读的好文章!感兴趣的也可以去看一下,并关注作者!

题目:Go语言中的加解密利器:go-crypto库全解析

好事文章地址:https://cloud.tencent.com/developer/article/2470499

在软件开发中,数据安全和隐私保护越来越受到重视。Go 语言以其简洁高效的特性,成为了许多开发者的首选。然而,在实际项目中使用加解密时,还是需要在标准库的基础上做一些封装。go-crypto 库应运而生,它是一个专为 Golang 设计的加密解密工具库,提供了 AES 和 RSA 等多种加密算法的支持。

引出


VC++6.0入门——第九讲 定制应用功能程序外观

第九讲 定制应用功能程序外观

本章将讲述如何修改MFC AppWizard自动生成的应用程序的外观,包括工具栏和状态栏的编程,以及如何为应用程序添加一个启动画面。

在日常生活中,建筑商在盖楼时,通常都是在楼房建成之前先设计好它的外观和大小。当楼房建成之后,还可以对其外观进行翻新或改造。同样,对于MF℃应用程序来说,为了改变MFC AppWizard自动生成的应用程序外观和大小,我们既可以在应用程序窗口创建之前进行,也可以在该窗口创建之后进行。

在MFC程序中,如果想在窗口创建之后改变其外观,可以在框架类(CMainFrame)的OnCreate函数中添加具体的实现代码。读者可以查看该函数的代码,将会发现它首先调用了基类的OnCreate函数,以完成窗口的创建,这样,我们就可以在该函数的最后,但要在return语句之前添加改变窗口外观的代码。

修改图标,背景,光标

在窗口创建前修改

方式一:自己写类覆盖原有

我们不能修改F℃底层代码,但是,我们可以编写自己的窗口类并注册,然后让随后的窗口按照我们编写的窗口类去创建。下面,我们在Syle程序的CMainFrame类的 PreCreate Window函数中编写一个自己的窗口类并注册。

应用程序实例的句柄(hInstance):在本书第一章的示例中,WinMain函数是我们自己编写的,当系统调用应用程序时,它为该应用程序分配了一个句柄,并把该句柄作为WinMain函数的参数传递进来,于是,我们可以直接通过该参数来对窗口类的hInstance成员赋值。但在这里,程序代码是通过AppWizard自动生成的, WinMain函数被隐藏了。那么我们如何才能获取到当前应用程序的句柄呢?MFC为我们提供了一个全局函数:AfxGetInstanceHandle,可以用来获取当前应用程序的实例句柄。

方式二:AfxRegisterWndClass

MFC又为我们提供了一个全局函数:AfxRegisterWndClass,用来设定窗口的类型、光标、背景和图标。该函数的原型声明如下所示:

代码语言:java
复制
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW, 0,0,
		LoadIcon(NULL,IDI_WARNING));
代码语言:java
复制
	cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW,
		LoadCursor(NULL,IDC_HELP),
		(HBRUSH) GetStockObject(BLACK_BRUSH),
		0);

在窗口创建后修改

代码语言:java
复制
SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR));

对于CStyleView类来说, AppWizard并没有自动为它创建OnCreate函数,因此,我们需要为该类添加WM_CREATE消息的响应函数,然后在这个响应函数(OnCreate函数)中,调用SetClassLong函数修改视类窗口的光标和背景

代码语言:java
复制
	SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH));
	SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP));

动画图标变化

我们平常在使用一些软件时,发现它们的图标一直在不断地循环变化,给人一种动画的效果。这种功能的实现比较简单,就是预先准备好几幅图标,然后在程序中每隔一定的时间按顺序循环显示这几幅图标,从而就实现了一种动画的效果。在实际编码实现时,利用定时器和SetClassLong函数就可以完成这个功能。因为SetClassLong函数可以在窗口创建完成之后修改窗口的图标,所以我们可以在程序中每隔一定时间就调用一次这个函数,让其显示预先已准备好的一组图标中的下一幅,从而就可以实现所需的动画效果。

图标的导入

代码编写

可以看到,这个宏的返回值是一个字符串类型,也就是字符指针类型。

句柄获取方式

接下来,加载第二幅图标,本例中利用另一种方法来获得应用程序当前的实例句柄。我们已经知道,在MFC SDI应用程序中,有一个表示应用程序本身的类,本例中就是 CStyleApp,它派生于CWinApp类。该类有一个数据成员:m hInstance,标识了应用程序当前的实例,也就是说,如果我们能获取到应用程序的CWinApp对象,就可以利用这个对象来调用它的m_hInstance数据成员,从而得到应用程序当前的实例句柄。根据前面的知识,我们知道在CStyleApp的源文件中已经定义了一个CStyleApp类型的全局变量: theApp。这样,我们就可以利用这个全局对象来调用其内部的数据成员。但是,在一个源文件中要想调用另一个源文件中定义的全局变量,必须在调用这个变量之前声明这个变量是在外部定义的,声明代码如下所示,读者可以把它放到CMainFrame类的OnCreate函数定义之前:

接着,加载第三幅图标,这里我们再换一种方式来获取应用程序当前的实例句柄。 MFC提供了一个全局函数:AfxGetApp,可以获得当前应用程序对象的指针。因为这个函数是全局函数,所以在应用程序的任意地方都可以调用它。在本程序中,利用AfxGetApp函数的返回值来访问应用程序的m hInstance数据成员。

代码语言:java
复制
	// 加载图标
	m_hIcon[0] = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1));
	m_hIcon[1] = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON2));
	m_hIcon[2] = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON3));

	SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcon[0]);

	// 设置定时器
	SetTimer(1,1000,NULL);

然后,为CMainFrame类添加定时器消息(WM TIMER)的响应函数,并在该响应函数中调用SetClassLong函数改变应用程序窗口的图标。

【插曲】取模运算:数值限定在某范围

小技巧:如果希望把某个数值始终限定在一个范围内,那么最好的办法当然就是进行取模运算(%)。例如,如果希望某个变量的取值在0-10之间变化,因为0-10之间有11个数,所以就应该把这个变量对11取模。实际上,取模运算就是取余。

代码语言:java
复制
void CMainFrame::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	static int index = 0; // 静态化
	SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcon[index]);
	index = ++index%3; // 值保持在某个范围不断变化0,1,2
	CFrameWnd::OnTimer(nIDEvent);
}

工具栏编程

工具栏是Windows应用程序中一个非常重要的图形界面元素,它提供了一组顺序排列的带有位图图标的按钮。工具栏是把常用的菜单命令集合起来,以按钮的形式提供给用户使用,目的是为了方便用户的操作。在Style工程中,在Resource View选项卡的Toolbar文件夹下有一个工具栏资源:DR MAINFRAME,双击这个资源D,即可在资源编辑窗口中打开工具栏资源,如图9.13所示。可以看到,这是一些带有位图图标的按钮,用户通过这些位图就能大概知道每个按钮的功能。

按钮之间添加了一条分隔符用以区分这两组按钮。为了在刚才新添加的按钮和已有的【帮助】按钮之间添加一条分隔符,我们可以在资源编辑窗口中,用鼠标把T按钮向右拖动一点距离后再松开鼠标,此时可以看到,在帮助按钮和工按钮之间就有了一点空隙。

删除的方式

创建工具栏

插入工具栏的两种方式

显示和隐藏实现

代码语言:java
复制
void CMainFrame::OnNewTool() 
{
	// TODO: Add your command handler code here
	// 判断当前是显示,还是隐藏;如果显示,则隐藏;如果隐藏,则显示;
	if(m_newToolBar.IsWindowVisible()){
		m_newToolBar.ShowWindow(SW_HIDE);
	}else{
		m_newToolBar.ShowWindow(SW_SHOW);
	}

	RecalcLayout();
	DockControlBar(&m_newToolBar);

}
代码语言:java
复制
ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE);

对号标记的实现

代码语言:java
复制
void CMainFrame::OnUpdateNewTool(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_newToolBar.IsWindowVisible());
}

状态栏编程

代码语言:java
复制
	// 获得一下时间, 设置为窗格显示内容
	CTime t=CTime::GetCurrentTime();
	CString str = t.Format("%H:%M:%S");

	int index = 0;
	index = m_wndStatusBar.CommandToIndex(IDS_TIMER);

	// 字体宽度
	CClientDC dc(this);
	CSize sz = dc.GetTextExtent(str);
	m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NORMAL,sz.cx);

	m_wndStatusBar.SetPaneText(index,str);

进度条

代码语言:java
复制
	CProgressCtrl m_progress; // 进度条	


	// 创建进度栏
	m_progress.Create(WS_CHILD | WS_VISIBLE,CRect(100,100,200,120),this,1234);
	m_progress.SetPos(50);
代码语言:java
复制
	m_progressv.Create(WS_CHILD | WS_VISIBLE | PBS_VERTICAL,CRect(100,150,120,300),this,12345);
	m_progressv.SetPos(70);
【插曲】程序调试
代码语言:java
复制
// 定义一个消息
#define UM_PROGRESS WM_USER+1
代码语言:java
复制
	// 声明消息响应函数
	afx_msg void OnProgress();
代码语言:java
复制
	// 建立消息和消息响应函数的映射关系
	ON_MESSAGE(UM_PROGRESS,OnProgress)
代码语言:java
复制
	// 发送一个消息
	PostMessage(UM_PROGRESS);
代码语言:java
复制
// 实现消息响应函数
void CMainFrame::OnProgress()
{
	// 进度条放到右下角窗格中
	int index1 = 0;
	index1 = m_wndStatusBar.CommandToIndex(IDS_PROGESS);

	// 获得一下矩形区域的大小
	CRect rect;
	m_wndStatusBar.GetItemRect(index1,&rect);

	m_progressm.Create(WS_CHILD | WS_VISIBLE,rect,&m_wndStatusBar,1234567);
	m_progressm.SetPos(50);

}
代码语言:java
复制
void CMainFrame::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here

	// 进度条放到右下角窗格中
	int index1 = 0;
	index1 = m_wndStatusBar.CommandToIndex(IDS_PROGESS);

	// 获得一下矩形区域的大小
	CRect rect;
	m_wndStatusBar.GetItemRect(index1,&rect);

	if(!m_progressm.m_hWnd){
		m_progressm.Create(WS_CHILD | WS_VISIBLE,rect,&m_wndStatusBar,1234567);
	}else{
		m_progressm.MoveWindow(rect);
	}
	
	m_progressm.SetPos(50);

	
	// Do not call CFrameWnd::OnPaint() for painting messages
}
代码语言:java
复制
	// 进度栏每间隔1s前进
	m_progressm.StepIt();

显示鼠标当前位置

view类上,点击右键,增加消息处理

代码语言:java
复制
void CStyle1View::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default

	// 状态栏第一个面板上显示鼠标的位置
	CString str;
	str.Format("x=%d,y=%d",point.x,point.y);

	// 获取框架类窗口
	((CMainFrame*) GetParent())->m_wndStatusBar.SetWindowText(str);


	CView::OnMouseMove(nFlags, point);
}

启动画面

从其他项目复制代码

代码语言:java
复制
// CG: This file was added by the Splash Screen component.

#ifndef _SPLASH_SCRN_
#define _SPLASH_SCRN_

// Splash.h : header file
//

/////////////////////////////////////////////////////////////////////////////
//   Splash Screen class

class CSplashWnd : public CWnd
{
// Construction
protected:
	CSplashWnd();

// Attributes:
public:
	CBitmap m_bitmap;

// Operations
public:
	static void EnableSplashScreen(BOOL bEnable = TRUE);
	static void ShowSplashScreen(CWnd* pParentWnd = NULL);
	static BOOL PreTranslateAppMessage(MSG* pMsg);

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CSplashWnd)
	//}}AFX_VIRTUAL

// Implementation
public:
	~CSplashWnd();
	virtual void PostNcDestroy();

protected:
	BOOL Create(CWnd* pParentWnd = NULL);
	void HideSplashScreen();
	static BOOL c_bShowSplashWnd;
	static CSplashWnd* c_pSplashWnd;

// Generated message map functions
protected:
	//{{AFX_MSG(CSplashWnd)
	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
	afx_msg void OnPaint();
	afx_msg void OnTimer(UINT nIDEvent);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};


#endif
代码语言:java
复制
// CG: This file was added by the Splash Screen component.
// Splash.cpp : implementation file
//

#include "stdafx.h"  // e. g. stdafx.h
#include "resource.h"  // e.g. resource.h

#include "Splash.h"  // e.g. splash.h

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
//   Splash Screen class

BOOL CSplashWnd::c_bShowSplashWnd;
CSplashWnd* CSplashWnd::c_pSplashWnd;
CSplashWnd::CSplashWnd()
{
}

CSplashWnd::~CSplashWnd()
{
	// Clear the static window pointer.
	ASSERT(c_pSplashWnd == this);
	c_pSplashWnd = NULL;
}

BEGIN_MESSAGE_MAP(CSplashWnd, CWnd)
	//{{AFX_MSG_MAP(CSplashWnd)
	ON_WM_CREATE()
	ON_WM_PAINT()
	ON_WM_TIMER()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CSplashWnd::EnableSplashScreen(BOOL bEnable /*= TRUE*/)
{
	c_bShowSplashWnd = bEnable;
}

void CSplashWnd::ShowSplashScreen(CWnd* pParentWnd /*= NULL*/)
{
	if (!c_bShowSplashWnd || c_pSplashWnd != NULL)
		return;

	// Allocate a new splash screen, and create the window.
	c_pSplashWnd = new CSplashWnd;
	if (!c_pSplashWnd->Create(pParentWnd))
		delete c_pSplashWnd;
	else
		c_pSplashWnd->UpdateWindow();
}

BOOL CSplashWnd::PreTranslateAppMessage(MSG* pMsg)
{
	if (c_pSplashWnd == NULL)
		return FALSE;

	// If we get a keyboard or mouse message, hide the splash screen.
	if (pMsg->message == WM_KEYDOWN ||
	    pMsg->message == WM_SYSKEYDOWN ||
	    pMsg->message == WM_LBUTTONDOWN ||
	    pMsg->message == WM_RBUTTONDOWN ||
	    pMsg->message == WM_MBUTTONDOWN ||
	    pMsg->message == WM_NCLBUTTONDOWN ||
	    pMsg->message == WM_NCRBUTTONDOWN ||
	    pMsg->message == WM_NCMBUTTONDOWN)
	{
		c_pSplashWnd->HideSplashScreen();
		return TRUE;	// message handled here
	}

	return FALSE;	// message not handled
}

BOOL CSplashWnd::Create(CWnd* pParentWnd /*= NULL*/)
{
	//if (!m_bitmap.LoadBitmap(IDB_SPLASH))
	if (!m_bitmap.LoadBitmap(IDB_BITMAP1))
		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, pParentWnd->GetSafeHwnd(), NULL);
}

void CSplashWnd::HideSplashScreen()
{
	// Destroy the window, and update the mainframe.
	DestroyWindow();
	AfxGetMainWnd()->UpdateWindow();
}

void CSplashWnd::PostNcDestroy()
{
	// Free the C++ class.
	delete this;
}

int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	// Center the window.
	CenterWindow();

	// Set a timer to destroy the splash screen.
	SetTimer(1, 20000, NULL);

	return 0;
}

void CSplashWnd::OnPaint()
{
	CPaintDC dc(this);

	CDC dcImage;
	if (!dcImage.CreateCompatibleDC(&dc))
		return;

	BITMAP bm;
	m_bitmap.GetBitmap(&bm);

	// Paint the image.
	CBitmap* pOldBitmap = dcImage.SelectObject(&m_bitmap);
	dc.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY);
	dcImage.SelectObject(pOldBitmap);
}

void CSplashWnd::OnTimer(UINT nIDEvent)
{
	// Destroy the splash screen window.
	HideSplashScreen();
}

app中加入代码

代码语言:java
复制
		// CG: The following block was added by the Splash Screen component.
\
	{
\
		CCommandLineInfo cmdInfo;
\
		ParseCommandLine(cmdInfo);
\

\
		CSplashWnd::EnableSplashScreen(cmdInfo.m_bShowSplash);
\
	}
代码语言:java
复制
public:
	virtual BOOL PreTranslateMessage(MSG* pMsg);
代码语言:java
复制
BOOL CStyle1App::PreTranslateMessage(MSG* pMsg)
{
	// CG: The following lines were added by the Splash Screen component.
	if (CSplashWnd::PreTranslateAppMessage(pMsg))
		return TRUE;

	return CWinApp::PreTranslateMessage(pMsg);
}

总结

VC++6.0入门——第九讲 定制应用功能程序外观

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引出
  • 第九讲 定制应用功能程序外观
    • 修改图标,背景,光标
      • 在窗口创建前修改
      • 在窗口创建后修改
    • 动画图标变化
      • 图标的导入
      • 代码编写
    • 工具栏编程
      • 创建工具栏
      • 显示和隐藏实现
      • 对号标记的实现
    • 状态栏编程
      • 进度条
      • 显示鼠标当前位置
    • 启动画面
      • 从其他项目复制代码
      • app中加入代码
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档