Visual C++ 的控制台项目默认生成的 exe 图标很大众,本文讲解怎样修改 exe 文件的图标。
注:Visual C++ Express(学习版)不支持资源编辑,无法创建资源文件,也就无法添加图标资源。
基础知识
图标属于”资源“,需要依附在资源文件中。
如果创建的项目类型是 Win32 Application 并且不是空项目,那么项目中默认是有资源文件的。否则,就需要先创建资源文件,再添加图标资源。
步骤一:添加资源文件
首先,检查一下项目中是否存在资源文件。资源文件的扩展名是 .rc,如果你的项目名称为 test,通常资源文件的文件名为 test.rc。如果项目中存在资源文件,就不用再添加了,直接进行步骤二。
如果没有资源文件,请按照以下方法添加:
Visual C++ 6.0 这样做:
- 点菜单:File -> New...,选择 Files 中的 Resource Script,并
...
在大家写程序的时候,经常会遇到“按任意键继续”这样的功能。网上能找到的方法主要有两种:
- 使用 _getch() 语句
- 使用 system("pause") 语句
现在挨个说说。
_getch()
_getch() 功能是从控制台输入一个字符(控制台不显示该输入),是 conio.h 里面声明的一个函数。
所以 _getch() 很好的实现了“按任意键继续”的功能。
system("pause")
system 的功能是通过控制台执行一个命令,是 stdlib.h 里面声明的一个函数。
该函数需要一个字符串指针参数表示命令。这里,"pause" 就是 system 函数将要执行的命令。
pause 命令的功能,可以在控制台 cmd.exe 下输入 pause /? 查看,可以看到,pause 的功能是:暂停并显示信息“Press any key to
...
getch() 函数,用于返回用户输入的字符。当连续按键时,该函数返回第一个字符和第二个字符之间,默认有 0.5 秒的延时,并且之后的连续字符,默认是每秒钟 15 次输入。这两个数值可以在控制面板中设置。
如果需要平滑的按键输入,或者同时按下多个按键,就不能用 getch() 了,需要使用另一个 Windows API 函数:GetAsyncKeyState()。该函数原型如下:
SHORT GetAsyncKeyState(
int vKey // virtual-key code
);
vKey 是要检测的按键的虚拟键码,常用的如 VK_UP、VK_DOWN 等,分别表示方向键的上、下等。需要注意:对于 26 个字母的键码,可以直接写 'A'、'B'……,而不要写 VK_A、VK_B。数字键也是,请直接写 '0'、'1'……。全部的 256 种虚拟键码,请参考 MSDN 中的 Virtual-Key Codes。
返回的 SHORT 值,如
...
(以下代码在 VC 下通过)
控制台窗口是有输入缓冲区的,当你按键后程序没有来得及处理,系统会将按键缓存,等到程序获取按键的时候,系统会把缓冲区里面之前的按键返回。
例如这个程序:
#include <graphics.h>
#include <stdio.h>
#include <conio.h>
int main()
{
printf("延时 5 秒钟。请在 5 秒钟内随便按键。\n");
Sleep(5000);
printf("延时结束。刚才您按下的按键是:\n");
while (_kbhit())
{
char c = _getch();
printf("%c", c);
};
return 0;
}
请自己执行一下前面的程序,在 5 秒延时内随便按键,等到延时结束,可以看到程序可以读出刚才的按键。
...
由于某些学校的硬性规定,课设必须用 Borland C++ 3.1(以下简称 BC) 一类 DOS 下的编程工具完成。
但是,BC 用起来很费劲,毕竟是 dos 时代的工具,无论编辑还是调试,都很吃力。尤其是图形程序,由于涉及到硬件及系统的问题,导致程序不能在 win7 及以上版本的 Windows 中运行,必须借助 dosbox 一类工具或者虚拟机才可以,麻烦多多。
本文通过一些常用的技巧,讲解怎样用 Visual C++(以下简称 VC) 编写可以在 BC 下直接编译运行的程序。
这样做的好处就是,可以节约大量的编码和调试时间。众所周知,当程序规模比较大的时候,调试时间会超过编码时间。而 VC 的强大调试功能,远不是 BC 能比的。同时,windows 下便捷的编辑环境,也比 BC 能节约很多时间。再比如有些人的显示器可以旋转,将 24 寸的显示器旋转 90 度竖着用,一屏可以阅读上百行代码,这种效率,绝对不是 BC 那一屏 20 多行代码可以比的。即便 BC 启用 43 行模式,效果仍然很差。
所以,下面的这个方法看似
...
比如坦克游戏,敌人坦克移动的四个方向通常不会用 1~4 这样四个数值表示,而是用 dx、dy 这样的 x、y 轴上的增量表示。对应关系如下:
dx = 0; dy = -1; 表示向上
dx = 0; dy = 1; 表示向下
dx = -1; dy = 0; 表示向左
dx = 1; dy = 0; 表示向右
如果用 1~4 表示 4 个方向,敌人坦克前进一步的代码要这样写:
switch(dir)
{
case 1: x += 1;
case 2: y -= 1;
case 3: x -= 1;
case 4: y += 1;
}
但是用 dx、dy 表示之后,每次只需要这样做就可以,好处很明显 :
x += dx;
y += dy;
...
我留意到群里和贴吧有不少人都在问怎样同时执行两个过程,比如:
- 贪吃蛇游戏,怎样实现双人对抗?就是控制两条蛇移动。
- 俄罗斯方块游戏,要加一个时钟,怎样使时钟和游戏同时进行?
- 打砖块游戏,怎样实现一边让小球自由移动、一边实现玩家控制木板?
有些人会想到用多线程来解决。我这里首先要说:这个问题不要用多线程,多线程要解决是另一种问题,这里不再详述,本文只讲一下怎样实现前面说的问题。(当然不用多线程解决)
先说一个简单的程序要求:有一个变量 a,初值为 0,每秒钟增加 2,按任意键停止;还有一个变量 b,初值为 0,每秒钟增加 3。现在要求将这两个功能同时执行,该怎么做?
我相信很多人都能写出来这个简单的程序:
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
void main()
{
//
...
EasyX 有一个演示鼠标操作的范例程序,这里,我们尝试通过 Windows API 获取鼠标信息。关于 API 的使用都以注释形式写到了程序中,故不再详细讲解,代码如下:
// 程序名称:通过 API 获取鼠标状态
// 编译环境:Visual C++ 6.0 / 2008 / 2010,EasyX 2011惊蛰版
//
#include <graphics.h>
#include <stdio.h>
void main()
{
initgraph(640, 480); // 初始化绘图窗口
HWND hwnd = GetHWnd(); // 获取绘图窗口句柄
POINT point;
TCHAR s[10];
while(true)
{
GetCursorPos(&point); // 获取鼠标指针位置(屏幕坐标)
ScreenToClient(hwnd, &point); // 将鼠标指针位置转换为窗口坐标
// 获取鼠标按
...
Turbo C(简称tc)是 dos 时代经典的编译器,学习编程时,有很多图形类和游戏类的程序都是用 tc 编写的。由于 c 语言标准的不完善,这些程序大多数都不能直接在 vc 里面编译。本文就讲解怎样将 tc 程序移植到 vc 下。
注:本文以 VC 6.0 为范例(高版本的 vc 大同小异),同时请安装最新版本的 EasyX 图形库。
移植前请注意:
- 确保 tc 代码可以正确运行。
- 将 tc 代码复制粘贴到 vc 里面。注意,vc 里面代码文件的扩展名要用 .cpp,不能用 .c。
- 以下解决办法不分先后顺序,哪条对应就按照哪条修改。
- 如果没找到对应的解决办法,可以暂时跳过,先改后面的。可能修改了第 3 条错误,第 2 条错误也就没有了。
- 可能解决一个问题后,会出现 10 个新问题,这不要紧。细心、耐心一些,一个一个问题慢慢处理,并不复杂。
以下正文:
错误提示:fatal error C1083: Cannot
...
通常我们使用 initgraph 创建绘图窗口,然后在里面绘图。
除此之外,我们还可以直接在 IMAGE 对象中绘图,这样就可以实现在不创建绘图窗口的前提下,直接生成图片文件。
为此,需要使用两条命令:
SetWorkingImage
该命令用于设定绘图目标。当设置为 IMAGE 对象时,之后所有的绘图操作都会针对该 IMAGE 对象。
saveimage
该命令用于保存图片。
实际上并不复杂,请看下面例子:
#include <graphics.h>
#include <stdio.h>
#include <conio.h>
void main()
{
// 创建一个 300 x 300 的 IMAGE 对象
IMAGE img(300, 300);
// 设定 img 为绘图操作的目标
SetWorking
...
由于 windows 下的 viewport 概念和过去有了很大的区别,为了避免大家混淆,EasyX 从 2011-2-24 起取消了这个函数。
下面解释一下怎样用其他函数替代 setviewport 的功能。
先说说过去的 setviewport() 的功能:
- 设置矩形区域
- 将矩形区域左上角设置为原点坐标
- 可以选择是否裁剪
对于设置裁剪,可以先定义一个区域,然后将该区域设置为裁剪区。区域的概念不仅局限于矩形,在 Windows GDI 函数中有很多定义区域的语句。下面代码定义一个矩形的区域,并设置为裁剪区:
HRGN rgn = CreateRectRgn(100, 100, 200, 200); // 定义矩形区域
setcliprgn(rgn); // 设置区域 rgn 为裁剪区
DeleteObject(rgn); // 不再使用 rgn,清理 rgn 占用的系统资源
...
刚开始用 EasyX,编译却出现上百个错误,例如:
error C2143: syntax error : missing ')' before '='
error C2072: 'initgraph' : initialization of a function
error C2059: syntax error : ')'
warning C4028: formal parameter 1 different from declaration
warning C4028: formal parameter 2 different from declaration
warning C4028: formal parameter 3 different from declaration
error C2143: syntax error : missing ')' before ''
error C2081: 'bool' : name in formal parameter
...
【错误描述】
一些程序在 VC6 下运行好好地,但是放到 VC2008 及更高版本 VC 下编译却报错误(以下仅以 VC2008 举例,高版本 VC 类似),例如使用如下语句:
outtextxy(10, 20, "Hello World");
在 VC6 下可以成功编译,但在 VC2008 下编译后会有错误。
中文版错误提示如下:
error C2665: “outtextxy”: 2 个重载中没有一个可以转换所有参数类型
英文版错误提示如下:
error C2665: 'outtextxy' : none of the 2 overloads could convert all the argument types
同样的,对于其他一些包含字符串调用的函数,例如 loadimage、drawtext 等,也会遇到类似问题。
【错误原因】
简单来说,这是由于字符编码问题引起的。
VC6 默认使用的 MBCS
...
简单来说,LPCTSTR 就表示字符串指针。
那么和 char* 又有什么区别呢?
大家用 char 表示字符时,英文占用一个字节,中文站用两个字节。这样有一个严重的问题:两个字节,究竟是两个英文字符,还是一个中文字符?为了解决这个问题,unicode 编码诞生了。
常见的 unicode 编码不管中文英文都用两个字节表示,用 wchar_t 来定义。
为了让代码适应 char 和 wchar_t 两种情况,可以用 TCHAR 宏,这个宏当项目定义为 unicode 时表示 wchar_t,否则表示 char。
对应的,还有 _T("") 宏用来表示字符串,例如 _T("abc") 在项目为 unicode 时表示 L"abc",否则表示 "abc"。
然后再看 LPCTSTR,它是以下几个概念的缩写:Long Point Const Tchar STRing,这样意思就明确了吧。
目前,点 EasyX 绘图窗口的“关闭”,会直接退出整个程序。有时候,程序需要执行完整的流程,因此,禁止关闭按钮就是一个很需要的方法。
可以通过 initgraph 函数的第三个参数禁用关闭按钮,确保程序按实际流程完整执行。
以下代码禁用关闭按钮(VC6 / VC2010 编译通过):
#include <graphics.h>
#include <conio.h>
void main()
{
initgraph(640, 480, NOCLOSE);
circle(320, 240, 100);
_getch();
closegraph();
}