——initgraph()函数

注意:先安装easy X插件(EasyX是针对C++的图形库,可帮助C++学习者快速上手图形和游戏编程。)

~初始化图形系统 

功 能: 初始化图形系统 
函数原型: void far initgraph (int far *graphdriver, int far *graphmode, char far *pathtodriver)
graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。pathtodriver表示存放图形驱动文件的路径。
头文件:graphics.h 

★图形模式的初始化★
不同的显示器适配器有不同的图形分辨率。即是同一显示器适配器, 在不同模式下也有不同分辨率。因此, 在屏幕作图之前,
必须根据显示器适配器种类将显示器设置成为某种图形模式, 在未设置图形模式之前, 微机系统默认屏幕为文本模式(80列, 25行字符模式),此时所有图形函数均不能工作。

设置屏幕为图形模式, 可用下列图形初始化函数:
void far initgraph(int far *gdriver, int far *gmode, char *path);
其中gdriver和gmode分别表示图形驱动器和模式, path是指图形驱动程序所在的目录路径。
有关图形驱动器、图形模式的符号常数及对应的分辨率见 表2。图形驱动程序由Turbo C出版商提供, 文件扩展名为.BGI。根据不同的图形适配器有不同的图形驱动程序。
例如对于EGA、 VGA 图形适配器就调用驱动程序EGAVGA.BGI。 
表2. 图形驱动器、模式的符号常数及数值
图形驱动器(gdriver)
图形模式(gmode)


符号常数
数值
符号常
数值
色调
分辨率
CGA
1   
CGAC0 
0  C0
320*200


CGAC1
1  C1
320*200
CGAC2
2  C2
320*200
CGAC3
3  C3
320*200
CGAHI
4 2色
640*200
MCGA
2 MCGAC0 
0 C0 320*200


MCGAC1 
1 C1 320*200
MCGAC2
2 C2 320*200
MCGAC3
3 C3 320*200
MCGAMED
4 2色
640*200
MCGAHI  
5 2色
640*480
EGA
3 EGALO
0 16色
640*200


EGAHI 
1 16色
640*350
EGA64
4 EGA64LO
0 16色
640*200


EGA64HI
1 4色
640*350
EGAMON
5 EGAMONHI
0 2色
640*350
IBM8514
6 IBM8514LO
0 256色
640*480


IBM8514HI
1 256色
1024*768
HERC
7 HERCMONOHI
0 2色
720*348
ATT400
8 ATT400C0
0 C0 320*200


ATT400C1
1 C1 320*200

ATT400C2
2 C2 320*200

ATT400C3
3 C3 320*200

ATT400MED
4 2色
320*200

ATT400HI
5 2色
320*200
VGA
9 VGALO
0 16色 
640*200


VGAMED
1
16色 
640*350

VGAHI
2 16色 
640*480
PC3270
10
PC3270HI
0 2色
720*350
DETECT
0
                          用于硬件测试

例:使用图形初始化函数设置VGA高分辨率图形模式
#include <graphics.h>
     int main()
     {
          int gdriver, gmode;
          gdriver=VGA;
          gmode=VGAHI;
          initgraph(&gdriver, &gmode, "c://tc");
          bar3d(100, 100, 300, 250, 50, 1);       /*画一长方体*/
          getch();
          closegraph();
          return 0;
     }

有时编程者并不知道所用的图形显示器适配器种类, 或者需要将编写的程序用于不同图形驱动器, Turbo C提供了一个自动检测显示器硬件的函数,  其调用格式为:
void far detectgraph (int *gdriver, *gmode)
其中gdriver和gmode的意义与上面相同。

例:自动进行硬件测试后进行图形初始化
#include <graphics.h>
     int main()
     {
          int gdriver, gmode;
          detectgraph(&gdriver, &gmode);     /*自动测试硬件*/
          printf("the graphics driver is %d, mode is %d/n", gdriver,
                 gmode);       /*输出测试结果*/
          getch();
          initgraph(&gdriver, &gmode, "c://tc");
                               /* 根据测试结果初始化图形*/
          bar3d(10, 10, 130, 250, 20, 1);
          getch();
          closegraph();
          return 0;
      }
上例程序中先对图形显示器自动检测, 然后再用图形初始化函数进行初始化设置, 但Turbo C提供了一种更简单的方法,  即用 gdriver= DETECT 语句后再跟initgraph()函数 就行了。采用这种方法后, 上例可改为:
#include <graphics.h>
     int main()
     {
          int gdriver=DETECT, gmode;
          initgraph(&gdriver, &gmode, "c://tc");
          bar3d(50, 50, 150, 30, 1);
          getch();
          closegraph();
          return 0;
     }

另外, Turbo C提供了退出图形状态的函数closegraph(), 其调用格式为:
void far closegraph(void);
调用该函数后可退出图形状态而进入文本方式(Turbo C 默认方式), 并释放用于保存图形驱动程序和字体的系统内存。
例: 
#include "graphics.h"
  #include "stdio.h"
  int main(void) 
  { 
                                                   /* request auto detection */ 
  int gdriver = DETECT, gmode, errorcode;    
                                                   /* initialize graphics mode */ 
  initgraph(&gdriver, &gmode, ""); 
                                                   /* read result of initialization */ 
  errorcode = graphresult(); 
  if (errorcode != grOk)       /* an error occurred */ 
  { 
  printf("Graphics error: %s\n", grapherrormsg(errorcode)); 
  printf("Press any key to halt:"); 
  getch(); 
  exit(1);      /* return with error code */ 
  } 
                                                   /* draw a line */ 
  line(0, 0, getmaxx(), getmaxy()); 
                                                   /* clean up */ 
  getch(); 
  closegraph(); 
  return 0; 
  }


~初始化绘图环境

HWND initgraph(
    int width,
    int height,
    int flag = NULL
);
参数:
width: 绘图环境的宽度
height: 绘图环境的高度
flag:   绘图环境的样式,默认为 NULL。可为以下值:
含义
NOCLOSE 禁用绘图环境的关闭按钮。
NOMINIMIZE 禁用绘图环境的最小化按钮。
SHOWCONSOLE 保留原控制台窗口。
返回值:创建的绘图窗口的句柄
示例:
以下局部代码创建一个尺寸为 640x480 的绘图环境:
initgraph(640, 480);
以下局部代码创建一个尺寸为 640x480 的绘图环境,同时显示控制台窗口
initgraph(640, 480, SHOWCONSOLE);
以下局部代码创建一个尺寸为 640x480 的绘图环境,同时显示控制台窗口,并禁用关闭按钮
initgraph(640, 480, SHOWCONSOLE | NOCLOSE);

——outtextxy()函数

注意:先安装easy X插件

void outtextxy(
	int x,
	int y,
	LPCTSTR str
);

void outtextxy(
	int x,
	int y,
	TCHAR c
);
功能:这个函数用于在指定位置输出字符串
参数
x:字符串输出时头字母的 x 轴的坐标值。
y:字符串输出时头字母的 y 轴的坐标值。
str:待输出的字符串的指针。
c:待输出的字符。
返回值:无
备注
该函数不会改变当前位置。
字符串常见的编码有两种:MBCS 和 Unicode。VC6 新建的项目默认为 MBCS 编码,VC2008 及高版本的 VC 默认为 Unicode 编码。LPCTSTR 可以同时适应两种编码。为了适应两种编码,请使用 TCHAR 字符串及相关函数。
默认情况下,输出字符串的背景会用当前背景色填充。使用函数 setbkmode 可以设置文字的背景部分保持透明或使用背景色填充。
示例
// 输出字符串 (VC6)
char s[] = "Hello World";
outtextxy(10, 20, s);
// 输出字符串 (VC6 / VC2008 / VC2010 / VC2012)
TCHAR s[] = _T("Hello World");
outtextxy(10, 20, s);
// 输出字符 (VC6)
char c = 'A';
outtextxy(10, 40, c);
// 输出字符 (VC6 / VC2008 / VC2010 / VC2012)
TCHAR c = _T('A');
outtextxy(10, 40, c);
// 输出数值,先将数字格式化输出为字符串 (VC6)
char s[5];
sprintf(s, "%d", 1024);
outtextxy(10, 60, s);
// 输出数值 1024,先将数字格式化输出为字符串 (VC2008 / VC2010 / VC2012)
TCHAR s[5];
_stprintf(s, _T("%d"), 1024);		// 高版本 VC 推荐使用 _stprintf_s 函数
outtextxy(10, 60, s);


——DWORD关键字

在win32中有这样的定义:
#define DWORD unsigned long
使用时添加#include<windows.h> 
表示一个32位无符号整型数,或用来表示段地址和段地址的偏移量;Windows下经常用来保存地址(或者存放指针).DWORD(双字)是因定为四个字节的,所以在定义双字类型的时候使用DWORD。DWORD是无符号的,相当于unsigned long ,它是MFC的数据类型。DWORD一般用于返回值不会出现负值情况。


——多字节字符集与Unicode字符集

visual studio配置选项“使用多字节字符集”和“使用Unicode字符集”的区别:
VS集成开发环境,字符集选择“使用多字节字符集”和“使用Unicode字符集”的直接区别就是:编译器是否增加了宏定义——UNICODE。当选择“使用Unicode字符集”时,编译器会增加宏定义——UNICODE;而选择“使用多字节字符集”时,编译器则不会增加宏定义——UNICODE。

而是否增加了宏定义UNICODE,则影响了一些Windows API的使用!!!

例1:MessageBox的使用
//windows API对MessageBox的定义如下:

WINUSERAPI
int
WINAPI
MessageBoxA(
    __in_opt HWND hWnd,
    __in_opt LPCSTR lpText,
    __in_opt LPCSTR lpCaption,
    __in UINT uType);
WINUSERAPI
int
WINAPI
MessageBoxW(
    __in_opt HWND hWnd,
    __in_opt LPCWSTR lpText,
    __in_opt LPCWSTR lpCaption,
    __in UINT uType);
#ifdef UNICODE
#define MessageBox  MessageBoxW
#else
#define MessageBox  MessageBoxA
#endif // !UNICODE
当选用“使用Unicode字符集”时,调用函数MessageBox,实际使用的是MessageBoxW,MessageBoxW关于字符串的入参类型是LPCWSTR,使用MessageBox时,字符串前需加L
::MessageBox(NULL, L"这是一个测试程序!", L"Title", MB_OK);
当选用“使用多字节字符集”时,调用函数MessageBox,实际使用的是MessageBoxA,MessageBoxA关于字符串的入参类型是LPCSTR
::MessageBox(NULL, "这是一个测试程序!", "Title", MB_OK);

例2:OutputDebugString的使用
//windows API对OutputDebugString的定义如下:

WINBASEAPI
VOID
WINAPI
OutputDebugStringA(
    __in_opt LPCSTR lpOutputString
    );
WINBASEAPI
VOID
WINAPI
OutputDebugStringW(
    __in_opt LPCWSTR lpOutputString
    );
#ifdef UNICODE
#define OutputDebugString  OutputDebugStringW
#else
#define OutputDebugString  OutputDebugStringA
#endif // !UNICODE
当选则“使用Unicode字符集”时,调用函数OutputDebugString,实际使用的是OutputDebugStringW,OutputDebugStringW的入参的类型是LPCWSTR,使用OutputDebugString时,字符串前需加L
OutputDebugString(L"测试12345");
当选则“使用多字节字符集”时,调用函数OutputDebugString,实际使用的是OutputDebugStringA,OutputDebugStringA的入参类型是LPCSTR
OutputDebugString("测试12345");

因此,“使用Unicode字符集”和“使用多字节字符集”的直接区别是:
编译器是否增加了宏定义——UNICODE。而是否增加了宏定义(UNICODE)则决定了Windows API函数参数有字符串时使用的多字节字符集还是宽字符字符集。

~多字节字符集和宽字符(UNICODE)字符集的区别:

要理解字节字符集还是宽字符(UNICODE)字符集的区别,首先先理解char与wchar_t的区别

1. char与wchar_t的区别

char叫多字节字符,一个char占一个字节,之所以叫多字节字符是因为它表示一个字符时可能是一个字节也可能是多个字节。一个英文字符(如’s’)用一个char(一个字节)表示,一个中文汉字(如’我’)用2个char(两个字节)表示。
wchar_t被称为宽字符,一个wchar_t占2个字节。之所以叫宽字符是因为所有的字都要用两个字节(即一个wchar_t)来表示,不管是英文还是中文。用常量给wchar_t赋值是,需要在常量前面加 L
// Test0601.cpp : 定义控制台应用程序的入口点。
//
#include <iostream>
using namespace std;
 
//多字节字符测试
void CharTest()
{
	cout << "********多字节字符测试********" << endl;
 
	char cChar1 = 'a';
	cout << "字符1 : " << cChar1 << "    字符1的长度" << sizeof(char) << endl;
 
	char cChar2 = '我';//无法输出正确结果
	cout << "字符2 : " << cChar2 << "    字符2的长度" << sizeof(char) << endl;
 
	/*char szChar3[2] = "我";//编译不通过,提示“数组界限溢出”
	cout << "字符3 : " << szChar3 << endl;*/
 
	char szChar4[3] = "我";//前两个字节存放汉字'我',最后一个字节存放字符串结束符\0
	cout << "字符4:" << szChar4 << "    字符4的字节长度 : " << strlen(szChar4) * sizeof(char) << endl;
}
 
//宽字符测试
void WCharTest()
{
	wcout.imbue(locale("chs"));//将wcout的本地化语言设置为中文
	wcout << L"********多字节字符测试********" << endl;
 
	wchar_t wcChar1 = L's';
	wcout << L"字符1 : " << wcChar1 << L"    字符1的长度" << sizeof(wchar_t) << endl;
 
	wchar_t wcChar2 = L'中';// 正确,一个汉字用一个wchar_t表示
	wcout << L"字符2:" << wcChar2 << L"    字符2的长度" << sizeof(wchar_t) << endl;
 
	wchar_t wszChar3[2] = L"中";// 前两个字节(前一个wchar_t)存放汉字'中',最后两个字节(后一个wchar_t)存放字符串结束符\0
	wcout << L"字符3:" << wszChar3 << L"    字符3的字节长度: " << wcslen(wszChar3) * sizeof(wchar_t) << endl;
 
	wchar_t wszChar4[3] = L"中国";
	wcout << L"字符串4 : " << wszChar4 << L"    字符串4的字节长度: " << wcslen(wszChar4) * sizeof(wchar_t) << endl;
}
 
 
int main()
{
	//多字节字符测试
	CharTest();
	//宽字符测试
	WCharTest();
	system("pause");
	return 0;
}
运行结果


2. LPCSTR与LPCWSTR的区别

LPCSTR的定义如下
typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR;
typedef char CHAR;
LPCWSTR的定义如下
typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;
typedef wchar_t WCHAR;    // wc,   16-bit UNICODE character

可以看出LPCSTR与LPCWSTR的区别即为char与wchar_t的区别


多字节和宽字节对照表
多字节字符集 宽字节(UNICODE)字符集 通用
char wchar_t TCHAR
char* wchar_t* TCHAR*
LPSTR LPWSTR LPTSTR
LPCSTR LPCWSTR LPCTSTR
3. 多字节字符集及宽字节字符集的兼容
使用_T、TCHAR等实现程序对多字节字符集及宽字节字符集的兼容
























——GetTicketCount()函数

VC 获取函数执行时间GetTicketCount() 
DWORD GetTickCount(void)
返回(retrieve)从操作系统启动所经过(elapsed)的毫秒数,返回值是DWORD类型。

:添加GetTicketCount()获取在文件中查找关键字 "BOOTING COMPLETED" 所需时间。
BOOL CLogFileHelper::IsBootingCompleted()
{
	int time,starttime=GetTickCount();
	BOOL bRet=FALSE;
	//保存每行读入的字符串内容
	CString szLine;   
	while(m_file.ReadString(szLine))
	{
		int iii=szLine.Find("BOOTING COMPLETED");
		if (iii==5)
		{
			bRet=TRUE;
			time=GetTickCount()-starttime;
			char temp[30];memset(temp,0x00,30);
			sprintf(temp, "%d", time);
			break;
		}
	}	
	return bRet;
}
注意事项
GetTickcount函数:它返回从操作系统启动到当前所经过的毫秒数,常常用来判断某个方法执行的时间,其函数原型是DWORD GetTickCount(void),返回值以32位的双字类型DWORD存储,因此可以存储的最大值是(2^32-1) ms约为49.71天,因此若系统运行时间超过49.71天时,这个数就会归0,MSDN中也明确的提到了:"Retrieves the number of milliseconds that have elapsed since the system was started, up to 49.7 days."。因此,如果是编写服务器端程序,此处一定要万分注意,避免引起意外的状况(如需避免此种情况可使用Ctime类或者是系统API的SYSTEMTIME进行判断)。
特别注意:这个函数并非实时发送,而是由系统每18ms发送一次,因此其最小精度为18ms。
当需要有小于18ms的精度计算时,应使用高精度定时器方法进行。
* 连续触发200次,实测下来,最小间隔在15ms。
* 实际状况应该是系统每秒触发64次,间隔在15、16ms之间波动。


——rand()函数

原型:int rand(void)
头文件:#include<stdlib.h>
函数说明:
1.   rand()函数其实不是真正意义上的随机数生成器,rand()函数在使用的时候还需调用srand()函数,srand()函数会设置供rand()函数使用的随机数种子,每一个种子对应一组根据算法预先生成的随机数;
2.   rand()函数可以产生0—RAND_MAX之间的一个伪随机整数,RAND_MAX的取值至少为32767;
3.  当srand()函数种子为1时与不使用srand()函数时rand()产生的随机数相同,也就是说rand()函数默认情况下初始化种子值为1;

用rand()函数随机在[x,y]内生成整数
int tmp=0;
tmp=x+rand()%(y-x+1);  
 //tmp为所求范围内的随机数,rand()%b的结果最大为b-1

srand()函数的定义
原型:srand((unsigned) time(NULL))       //产生种子
如果想要增大时间间隔可以后面乘上合适的整数—srand((unsigned)time(NULL)*a。


——loadimage()函数

功能: 是装载图标,光标,或位图。支持bmp,jpg,gif,emf,wmf,ico格式
从图片文件获取图像:
void loadimage(IMAGE* pDstImg, LPCTSTR pImgFile, int nWidth=0 , int nHeight=0 , bool bResize=false );
pDstImg:保存图像的 IMAGE 对象指针
LPCTSTR pImgFile图片文件名
int nWidth图片的拉伸宽度
int nHeight:图片的拉伸高度
bool bResize是否调整 IMAGE 的大小以适应图片

从资源文件获取图像:
void loadimage(IMAGE* pDstImg, LPCTSTR pResType, LPCTSTR pResName, int nWidth, int nHeight , bool bResize);
IMAGE* pDstImg:保存图像的 IMAGE 对象指针
LPCTSTR pResType:资源类型
LPCTSTR pResName:资源名称
int nWidth:图片的拉伸宽度
int nHeight:图片的拉伸高度
bool bResize:是否调整 IMAGE 的大小以适应图片

举例
#include “stdafx.h”
#include<graphics.h>//图形库头文件
#include<conio.h>
IMAGE img;
int main()
{
//创建窗口
initgraph(640,480);
//1.
loadimage(&img,L"图片名.jpg",100,100);//先把图片放在工程项目下
//2.在配置属性中更改字符型为多字符,则可以省略在前面加L
loadimage(&img,“图片名.jpg”,100,100);
putimage(100,100,&img);//显示图片
getch();
closegraph();
return 0;
}


——putimage()函数

功能:函数putimage()将一个先前保存在内存中的图像输出到屏幕上。
原先:void putimage(int left,int top,void *buf,int ops);
头文件:garphics.h
参数:参数(left,top)为输出屏幕图像的左上角,即输出图像的起始位置。buf指向要输出的内存中图像。参数ops控制图像以何种方式输出到屏幕上。

图像输出方式
输出方式符号名
取值
 含义
COPY_PUT 
0 图像输出到屏幕上,取代原有图像
XOR_PUT
1 图像和原有像素作异或运算
OR_PUT 
2 图像和原有像素作或运算
AND_PUT
3 图像和原有像素作与运算
NOT_PUT
4 把求反的位图像输出到屏幕上
1) COPY_PUT输出方式
图像中每个像素都直接绘制到屏幕上,取代原有图像像素,包括空白的图像像素(背景)。完全空白的图像可以用来擦除其它图像或屏幕的一部分。但通常选择xOR_PUT输出方式擦除原有图像。
2) XOR_PUT输出方式
原有屏幕每个像素与相应的图像字节作“异或”运算,其结果画到屏幕上。当某一图像和屏幕上原有图像作“异或”运算时,屏幕显示的是两个图像的合成。若相同的图像作异或运算,将有效地擦除该图像,留下原始屏幕。这种输出方式,对动画制作是非常有用的。
3) OR_PUT输出方式
每个图像字节和相应的屏幕像素作“或”运算,再将结果画到屏幕上,这种输出方式也叫“两者取一”。记住,像素中的每位和图像中的每位作“或”运算,这样所得结果是背景和图像的彩色合成图像。
4) AND_PUT输出方式
选择AND_PUT图像输出方式时,屏幕像素和图像字节中都显示的位,运算后仍显示,例如,星图像中的空白背景擦除了方块轮廓以及填充色,只有星图像复盖着的方块留下,即运算后,显示两者相同的图像。
5) NOT_PUT输出方式
NOT_PUT输出方式,除了把图像的每位求反---图像中所有黑的像素(0000)变成了白色(1111),其它方面与COPy_PUT相同。背景图像被重画后将消失。


这个函数的几个重载用于在当前设备上绘制指定图像:
// 绘制图像
void putimage(
	int dstX,				// 绘制位置的 x 坐标
	int dstY,				// 绘制位置的 y 坐标
	IMAGE *pSrcImg,			// 要绘制的 IMAGE 对象指针
	DWORD dwRop = SRCCOPY	// 三元光栅操作码
);
// 绘制图像(指定宽高和起始位置)
void putimage(
	int dstX,				// 绘制位置的 x 坐标
	int dstY,				// 绘制位置的 y 坐标
	int dstWidth,			// 绘制的宽度
	int dstHeight,			// 绘制的高度
	IMAGE *pSrcImg,			// 要绘制的 IMAGE 对象指针
	int srcX,				// 绘制内容在 IMAGE 对象中的左上角 x 坐标
	int srcY,				// 绘制内容在 IMAGE 对象中的左上角 y 坐标
	DWORD dwRop = SRCCOPY	// 三元光栅操作码
);
三元光栅操作码(即位操作模式),支持全部的 256 种三元光栅操作码,常用的几种如下:
含义
DSTINVERT 目标图像 = NOT 目标图像
MERGECOPY 目标图像 = 源图像 AND 当前填充颜色
MERGEPAINT 目标图像 = 目标图像 OR (NOT 源图像)
NOTSRCCOPY 目标图像 = NOT 源图像
NOTSRCERASE 目标图像 = NOT (目标图像 OR 源图像)
PATCOPY 目标图像 = 当前填充颜色
PATINVERT 目标图像 = 目标图像 XOR 当前填充颜色
PATPAINT 目标图像 = 目标图像 OR ((NOT 源图像) OR 当前填充颜色)
SRCAND 目标图像 = 目标图像 AND 源图像
SRCCOPY 目标图像 = 源图像
SRCERASE 目标图像 = (NOT 目标图像) AND 源图像
SRCINVERT 目标图像 = 目标图像 XOR 源图像
SRCPAINT 目标图像 = 目标图像 OR 源图像
                                                          AND / OR / NOT / XOR 为布尔运算。

示例
IMAGE img;
getimage(&img, 0, 0, 100, 100);
putimage(200, 200, &img);


——SetWorkingImage()函数

功能:这个函数用于设定当前的绘图设备
原型:void SetWorkingImage(IMAGE*  pImg= NULL)
pImg:绘图设备指针。如果为 NULL,表示绘图设备为默认绘图窗口。
返回值:无
备注
如果需要对某个 IMAGE 做绘图操作,可以通过该函数将其设置为当前的绘图设备,之后所有的绘图语句都会绘制在该 IMAGE 上面。将参数置为 NULL 可恢复对默认绘图窗口的绘图操作。


——getimage()函数

功能:函数getimage()保存左上角与右下角所定义的屏幕上像素图形到指定的内存区域。
用法: 该函数调用方式为void getimage(int left,int top,int right,int bottom,void *buf);
参数: 函数中参数(left ,top)为要保存的图像屏幕的左上角,(right,bottom)为其右下角,buf指向保存图像的内存地址。
头文件:<graphics.h>
返回值: 无
调用getimage()保存屏幕图像,可用imagesize()函数确定保存图像所需字节数,再用malloc()函数分配存储图像的内存(内存分配必须小于64KB),还可以用函数putimage()输出getimage()保存的屏幕图像。

: 把带有两对角线的矩形拷贝到屏幕其它位置上:
#include<garphics.h>
#include<stdlib.h>
#include<conio.h>
void main()
{
    int driver,mode;
    unsigned size;
    void *buf;
    
    driver=DETECT;
    mode=0;
    
    initgraph(&driver,&mode,"");
    sector(15);
    rectangle(20,20,200,200);
    setcolor(RED);
    line(20,20,200,200);
    setcolor(GREEN);
    line(20,200,200,20);
    getch();
    size=imagesize(20,20,200,200);
    if(size!=-1){
        buf=malloc(size);
        if(buf){
            getimage(20,20,200,200,buf);
            putimage(100,100,buf,COPy_PUT);
            putimage(300,50,buf,COPy_PUT);
        }
    }
    outtext("press a key");
    getch();
    restorecrtmode()
}


——GetPixel()函数

函数功能:该函数检索指定坐标点的像素的RGB颜色值。
原型:COLORREF GetPixel(HDC hdc, int nXPos, int nYPos)
           hdc:设备环境句柄。
           nXPos:指定要检查的像素点的逻辑X轴坐标。
           nYPos:指定要检查的像素点的逻辑Y轴坐标。
返回值:返回值是该象像点的RGB值。如果指定的像素点在当前剪辑区之外;那么返回值是CLR_INVALID。
备注:该像素点必须在当前剪辑区的边界之内。并不是所有设备都支持GetPixel函数。应用程序应调用GetDeviceCaps函数来确定指定的设备是否支持该函数。


——GetImageBuffer()函数

功能:用于获取绘图设备的显示缓冲区指针。
原型:DWORD* GetImageBuffer(IMAGE* pImg = NULL);
           pImg:绘图设备指针。如果为 NULL,表示默认的绘图窗口。
返回值:返回绘图设备的显示缓冲区指针。
备注
获取到的显示缓冲区指针可以直接读写。
在显示缓冲区中,每个点占用 4 个字节,因此:显示缓冲区的大小 = 宽度 × 高度 × 4 (字节)。像素点在显示缓冲区中按照从左到右、从上向下的顺序依次排列。访问显示缓冲区请勿越界,否则会造成难以预料的后果
显示缓冲区中的每个点对应 RGBTRIPLE 类型的结构体:
struct RGBTRIPLE {
	BYTE rgbtBlue;
	BYTE rgbtGreen;
	BYTE rgbtRed;
}
RGBTRIPLE 在内存中的表示形式为:0xrrggbb (bb=蓝,gg=绿,rr=红),而常用的 COLORREF 在内存中的表示形式为:0xbbggrr。注意,两者的红色和蓝色是相反的,请用 BGR 宏交换红色和蓝色。
如果操作绘图窗口的显示缓冲区,请在操作完毕后,执行 FlushBatchDraw() 使操作生效。

示例
以下代码通过直接操作显示缓冲区绘制渐变的蓝***r />
#include <graphics.h>
#include <conio.h>
 
int main()
{
	// 初始化绘图窗口
	initgraph(640, 480);
 
	// 获取指向显示缓冲区的指针
	DWORD* pMem = GetImageBuffer();
 
	// 直接对显示缓冲区赋值
	for(int i = 0; i < 640 * 480; i++)
		pMem[i] = BGR(RGB(0, 0, i * 256 / (640 * 480) ));
 
	// 使显示缓冲区生效(注:操作指向 IMAGE 的显示缓冲区不需要这条语句)
	FlushBatchDraw();
 
	// 按任意键退出
	_getch();
	closegraph();
}


——FlushBatchDraw()函数

功能:用于执行未完成的绘制任务。
// 执行未完成的绘制任务
void FlushBatchDraw();
// 执行指定区域内未完成的绘制任务
void FlushBatchDraw(
	int left,
	int top,
	int right,
	int bottom
); 
left:指定区域的左部 x 坐标。
top:指定区域的上部 y 坐标。
right:指定区域的右部 x 坐标。
bottom:指定区域的下部 y 坐标。
返回值:无


——#pragma once

作用:为了避免同一个头文件被包含(include)多次。
C/C++中有两种宏实现方式:一种是#ifndef方式;另一种是#pragma once方式。

区别:
//方式一:
#ifndef  __SOMEFILE_H__
#define   __SOMEFILE_H__
... ... // 声明、定义语句
#endif
//方式二:
#pragmaonce
... ... // 声明、定义语句
(1) #ifndef
#ifndef的方式受C/C++语言标准支持。它不仅可以保证同一个文件不会被包含多次,也能保证内容完全相同的两个文件(或者代码片段)不会被不小心同时包含。
缺点就是如果不同头文件中的宏名不小心“撞车”,可能就会导致你看到头文件明明存在,但编译器却硬说找不到声明的状况——这种情况有时非常让人郁闷。
由于编译器每次都需要打开头文件才能判定是否有重复定义,因此在编译大型项目时,ifndef会使得编译时间相对较长,因此一些编译器逐渐开始支持#pragma once的方式。
(2) #pragma once
#pragma once 一般由编译器提供保证:同一个文件不会被包含多次。注意这里所说的“同一个文件”是指物理上的一个文件,而不是指内容相同的两个文件。
你无法对一个头文件中的一段代码作pragma once声明,而只能针对文件。
好处是,你不必再担心宏名冲突了,当然也就不会出现宏名冲突引发的奇怪问题。大型项目的编译速度也因此提高了一些。
缺点就是如果某个头文件有多份拷贝,本方法不能保证他们不被重复包含。当然,相比宏名冲突引发的“找不到声明”的问题,这种重复包含很容易被发现并修正。
另外,这种方式不支持跨平台!

联系:
#pragma once 方式产生于#ifndef之后,因此很多人可能甚至没有听说过。目前看来#ifndef更受到推崇。因为#ifndef受C/C++语言标准的支持,不受编译器的任何限制;
而#pragma once方式却不受一些较老版本的编译器支持,一些支持了的编译器又打算去掉它,所以它的兼容性可能不够好。
 方式一由语言支持所以移植性好,方式二 可以避免名字冲突


——mciSendString()函数

功能:mciSendString函数向MCI设备发送命令字符串。 在命令字符串中指定发送命令的设备。mciSendString是用来播放多媒体文件的API指令,可以播放MPEG、AVI、WAV、MP3等
导入库文件
#include <MMSystem.h>    
#pragma comment(lib, "winmm.lib")
函数声明
MCIERROR mciSendString(
      LPCTSTR lpszCommand,
      LPTSTR  lpszReturnString,
      UINT    cchReturn,
      HANDLE  hwndCallback
);
参数
lpszCommand:指向指定MCI命令字符串的以null结尾的字符串的指针。 有关列表,请参阅多媒体命令字符串。
lpszReturnString:指向接收返回信息的缓冲区的指针。 如果不需要返回信息,该参数可以为NULL。
cchReturn:由lpszReturnString参数指定的返回缓冲区的大小(以字符为单位)。
hwndCallback:如果在命令字符串中指定了“notify”标志,则处理回调窗口。
返回值:如果成功返回零,否则返回错误。

实现思路
对mciSendString函数的使用,关键是构造播放命令。通常出错,都是命令行没有写正确的缘故。那么播放音频可以分成三个步骤:
  1. 打开音频文件,命令为 “open yellow.mp3 alias start”  注意这里的格式空格!!!,意思是打开音频文件“yellow.mp3”,并使用“start”这个标号作为音频文件的代码,下面对“start”操作就是对“yellow.mp3”操作。其中,“yellow.mp3”这里可以填音频文件路径,但是注意路径不要有空格;若路径有空格,可以给路径加上双引号。“start”是“yellow.mp3”的代号,名称可以任意,有 alias 指定
  2. 循环播放音频,命令为“play start repeat”,意思是循环播放“start”代号的音频文件。其中,“repeat”表示循环播放,如果不加,则默认只播放一遍
  3. 关闭音频文件,命令为“close start”,意思是关闭“start”代号的音频文件。当不播放音频文件是,可以关闭文件,节约资源

编程实现循环播放音频文件
int _tmain(int argc, _TCHAR* argv[])
{
    // 打开音频文件
    ::mciSendString("open yellow.mp3 alias start", NULL, 0, NULL);
    // 循环播放
    // 循环播放适用于.mp3格式,但不适用.wav格式
    ::mciSendString("play start repeat", NULL, 0, NULL);           
    printf("play music...\n");
    system("pause");
    // 关闭音频文件
    ::mciSendString("close start", NULL, 0, NULL);           
    printf("close music!\n");
    system("pause");
    return 0;
}
:.WAV音频文件,在设置循环播放“repeat”时,不能播放成功,去掉“repeat”正常播放。而.MP3音频文件,则正常。所以推测,可能循环播放仅适用于.MP3格式,不适用于.WAV等其他音频格式文件。


——kbhit()函数

函数名:kbhit()(VC++6.0下为_kbhit())
功能及返回值: 检查当前是否有键盘输入,若有则返回一个非0值,否则返回0
用 法:int kbhit(void);
包含头文件: include <conio.h>
#include <conio.h>
#include <iostream>
using namespace std;
int main()
{
while(!kbhit()) //当没有键按下
{
cout<<"无键按下"<<endl;
}
cout<<"有键按下"<<endl; //有键按下时输出这
system("pause");
}
kbhit() 在执行时,检测是否有按键按下,有按下返回非0值,一般是1,没有按下返回0;是非阻塞函数
getch() 在执行时,检测按下什么键,如果不按键该函数不返回;是阻塞函数类似地


——setcolor()函数

功能:该方法用于设置画笔的颜色,可以通过Color类中的预定义颜色来设置,也可以通过指定RGB值来设置。该方法是设置颜色的主要方法,通过改变画笔颜色,可以绘制出色彩缤纷的图形。
语法:public void setColor (int color)
参数:color为颜色值。


也可以直接使用系统Color类中定义的颜色,如下所示。


Color.BLACK:黑色。


Color.BLUE:蓝色。


Color.CYAN:青绿色。


Color.DKGRAY:灰黑色。


Color.YELLOW:黄色。


Color.GRAY:灰色。


Color.GREEN:绿色。


Color.LTGRAY:浅灰色。


Color.MAGENTA:红紫色。


Color.RED:红色。


Color.TRANSPARENT:透明。


Color.WHITE:白色。
RGB颜色设置方法:
setColor( RGB(int r,int g,int b))
例如  setColor( RGB(220,255,220) )


——settextstyle()函数

功能:设置图形文本当前字体、文本显示方向(水平显示或垂直显示)以及字符大小。
用法:此函数调用方式为void settextstyle(int font,int direction,int charsize);
参数font为文本字体参数,direction为文本显示方向,charsize为字符大小参数。
头文件:<graphics.h>

图形文本标准字体
字体符号名 
 等价值
含义
DEFAULT_FONT
0 8*8点阵字型(缺省字体)
TRIPLEx_FONT 
1 笔划式三倍字型(三倍字体)
SMALL_FONT
2 笔划式小字型(小字体)
SANS_SERIF_FONT
3  笔划式字(Sanserif字体)
GOTHIC_FONT
4 笔划黑体字型(哥特体)
在设置字体之前,被选字体的.CHR文件必须装在initgraph()中指定的driverpath(驱动程序路径)目录或子目录里。
缺省时图形文本显示方向为水平方向,但可以设置图形文本显示方向为垂直方向(逆时针转90度)。


图形文本显示方向
显示方向符号名
 等价值
说明
HORIZ_DIR
   0 从左到右显示(水平方向)
VERT_DIR
   1 从底向上显示(垂直方向)

在垂直显示时,文本字符串从底部向上显示,目前还没有现成的规定从上到下或从左到右的显示,但若需要也可设计。
对点阵字体,字符大小可以在0到10之间选择。对于笔划字体,charsize(字符大小参数)=0表示以缺省比例显示即4倍或由函数setusercharsize()设置的用户自定字符的比例放大显示。最大有效的charsize值为0。
如果有错误参数值传给函数settextstyle(),graphresult()函数将给出值-11(表示一般图形错误),当前的文本型式保持不变。

:下面的程序中使用了settextstyle()函数,显示不同的文本字体和大小
#include<graphics.h>

#include<conio.h>

void main()

{

int driver,mode;

mode=0;

initgraph(&driver,&mode,"");

outtext("Normal");

settextstyle(GOTHIC_FONT,HORIZ_DIR,2);

outtext("Gothic");

settextstyle(TRIPLEx_FONT,HORIZ_DIR,2);

outtext("Triplex");

settextstyle(SANS_SERIF_FONT,HORIZ_DIR,7);

outtext("Sans serif");

getch();

restorecrtmode();

}


——sleep()函数

标准库中无sleep函数,但在某些编译系统中是有的,在有些系统库中也有,要根据环境而定。
linux系统中
原型:unsigned int sleep(unsigned intseconds)
头文件:unistd.h
传入挂起时间,成功返回0,不成功则返回余下的秒数(这里sleep(1),暂停1s)。
windows系统中
原型:void Sleep(DWORD dwMilliseconds)
头文件:windows.h
提供挂起的毫秒数,并且需包含windows.h。Sleep函数(注意大写)
例如:
<span style="font-size:18px;">#include<iostream>
#include<windows.h>
using namespace std;
int main()
{
Sleep(3000);//暂停3秒  S要大写
return 0;
}
</span>


——timeGetTime()函数

函数以 毫秒 计的系统时间。该时间为从系统开启算起所经过的时间。
在SDK中,可以用 DWORD timeGetTime(VOID)函数获取系统时间,其返回值是毫秒单位的。可以用其实现延时功能的函数。
void Delay(DWORD delayTime)
{
    DWORD delayTimeBegin;
    DWORD delayTimeEnd;
    delayTimeBegin = timeGetTime();
    do{
         delayTimeEnd = timeGetTime();
    }while(delayTimeEnd - delayTimeBegin < delayTime)
}
在使用timeGetTime()函数之前应先包含头文件#include <Mmsystem.h>或#include <Windows.h>并在project->settings->link->Object/library modules中添加winmm.lib 
也可以在文件头部添加 #pragma comment( lib,"winmm.lib" )
命令行:#pragma comment( lib,"xxx.lib" )时预编译处理指令,让vc将winmm.lib添加到工程中去进行编译。
备注
该函数与timeGetSystemTime()函数的唯一不同是timeGetSystemTime()函数使用MMTIME结构返回系统时间。TimeGetSystemTime()比timeGetTime()需要更多的系统开销。注意timeGetTime()函数是一个双字。这个值在0到2^32之间。大约49.71天。如果在代码中直接将该值用于计算,会导致一些问题,特别是用该值来控制代码的执行。一般利用两个timeGetTime()函数返回值的不同来用于计算。

Windows NT:该函数的时间精度是五毫秒或更大一些,这取决于机器的性能。可用timeBeginPeriod和timeEndPeriod函数提高timeGetTime函数的精度。如果使用了,连续调用timeGetTime函数,一系列返回值的差异由timeBeginPeriod和timeEndPeriod决定。QueryPerformanceCounter QueryPerformanceFrequency函数用于分辨率要求更高的时间测量。
Windows95 默认分辨率是1毫秒,无论是否调用timeBeginPeriod和timeEndPeriod函数。


——BeginBatchDraw ( )与EndBatchDraw( )

当我们需要绘制连续的动画时,一直刷新屏幕会产生闪屏,我们可以用他们来解决这个问题。
void BeginBatchDraw();	// 开始批量绘制
void EndBatchDraw(int left, int top, int right, int bottom);	// 结束批量绘制,并执行指定区域内未完成的绘制任务
本质上就是一个封装的双缓存
运行BeginBatchDraw后,所有的绘图都不再显示在屏幕上,而是在内存中进行
直到碰到EndBatchDraw,之前所有在内存中绘图的成品将一并展示在屏幕中

实例:
setbackground(&background);
	while (1)
	{
		BeginBatchDraw();
		setbackground(&background);  //画图
		setgold(&wy1, &wy2, xx, yy); //画图
		xx += 200;
		yy += 200;
		Sleep(1000);
		EndBatchDraw();
	}
在while外我们先绘制了一面背景,之后我们遇到了BeginBatchDraw,那么以下操作都不会显示在屏幕上
		setbackground(&background);  //画图
		setgold(&wy1, &wy2, xx, yy); //画图
		xx += 200;
		yy += 200;
		Sleep(1000);
直到遇到EndBatchDraw,我们之前那些操作才会一并显示出来。
因为我们使用他们往往是需要动态的画面,所以我们常常在BeginBatchDraw后就直接清屏cleardevice或直接用背景来覆盖之前的图