• 易迪拓培训,专注于微波、射频、天线设计工程师的培养
首页 > 测试测量 > 技术文章 > LabWindows/CVI虚拟仪器: 打蜜蜂

LabWindows/CVI虚拟仪器: 打蜜蜂

录入:edatop.com    点击:

4.5 打蜜蜂

4.5.1 打蜜蜂设计方法

20 世纪80 年代开始流行电视游戏,打蜜蜂游戏是其中一款非常有特点的小游戏,相信很多70 后的人都有同图4-12 运行效果图感。利用LabWindows/CVI 开发一个简单的打蜜蜂游戏,设置好自定义的蜜蜂、飞机、炸弹、子弹、背景、音效等,按下上下左右键(↑、↓、←、→)移动飞机,按下“a”键发射子弹,一场生动的游戏便展现在眼前。

需要注意的是,在LabWindows/CVI 中,设置Picture 控件背景透明,控件中的图片并非透明,若要将图片与背景融合,可以将图片转换为图标(*.ico)格式文件,并设置图标背景透明。本例程所有图片资源与音效文件均放在同一目录下。

背景透明图标制作过程并不复杂,可将现有的一些图片资源直接转换为图标文件,并将其背景设置为透明即可。PictureToIcon 能将图片或屏幕的一部分转化为Icon 图标,调整图标大小以及从资源库中提取Icon,支持BMP 、JPEG 、GIF 、CUR、WMF 等格式转换。通过PictureToIcon 工具,可以方便地创建、编辑、载入和保存图标,并可设置图标透明度,甚至可以从.exe、.dll、.scr 和.ocx 文件中提取图标;支持16 位、24 位和32 位真彩图标,其最新版本支持图标改变大小从1×1 到256×256 。

在图标设计文件夹下找到PictureToIcon.exe 文件,双击打开该程序,如图4-13 所示。点击载入图标按钮,弹出打开对话框,选择需要转换的图像文件,如打开bee.bmp 文件,如图4-14 所示。

edatop.com

图4-13 PictureToIcon 图标转换工具

    

图4-14 打开对话框

 

在对话框中点击打开按钮,弹出图标编辑对话框,如图4-15 所示。在图中选择设置透明色复选框,点击确定按钮,弹出请确认对话框,点击是按钮即可,如图4-16 所示。

edatop.com

图4-15 图标编辑对话框

  

    图4-16 请确认对话框

 

加到主窗口后,在右侧显示获得的透明图标文件,如图4-17 所示,点击保存图标按钮进行保存。至此,一个背景透明的蜜蜂图标就做好了,依次将飞机、炸弹、子弹等做成透明图标,以备程序中调用。

edatop.com

4-17 透明图标

4.5.2 打蜜蜂程序设计

(1)面板设计

编写一个打蜜蜂游戏,游戏一开始,蜜蜂开始移动,并每隔一段时间发射一颗炸弹,如果枪(飞机)被炸弹击中,则显示击中画面,并弹出游戏结束面板,点击重新开始则继续游戏,点击退出结束游戏。如果枪(飞机)发射的子弹击中蜜蜂,同样显示击中画面,弹出游戏结束面板。面板设计如图4-18 所示,面板中主要控件属性设置如表4-9 所示。

edatop.com

(a)打蜜蜂面板

edatop.com

 (b)游戏结束面板

图4-18打蜜蜂游戏面板

表4-9控件属性设置表

常量名

控件类型

控件的主要属性

PANEL

Panel

标题:打蜜蜂回调函数:PanelCB

PICTURE

Picture

Load Image:backgraph.jpg

PICTURE_BEE

Picture

Load Image:bee.ico

PICTURE_SHOOTBEE

Picture

Load Image:shootbee.ico

PICTURE_GUN

Picture

Load Image:gun.ico

PICTURE_SHOOTGUN

Picture

Load Image:shootgun.ico

PICTURE_BOOM

Picture

Load Image:boom.ico

PICTURE_BULLET

Picture

Load Image:bullet.ico

TIMER

Timer

标题:timer 回调函数:timer Interval:0.010

TIMER_BEE

Timer

标题:beerun 回调函数:beerun Interval:0.100

PANEL_POP

Panel

标题:游戏结束回调函数:PanelCB

TEXTMSG

Text Message

默认值:游戏结束!请重新开始

CMD_RESTART

Command Button

标题:重新开始回调函数:restart

CMD_QUIT

Command Button

标题:退出回调函数:quit

 

(2)程序源代码

//头文件声明
#include "windows.h"
#include "asynctmr.h"
#include "toolbox.h"
#include "mmsystem.h"
#include "bee.h"
static int panelHandle;
//声明异步定时器句柄
static int timerkey;
//声明游戏结束面板句柄
static int pophandle;
//定义发射子弹可见为1,不可见为0
static int shootflag = 0;
//定义蜜蜂炸弹可见为1,不可见为0
static int boomflag = 0;
//定义蜜蜂炸弹发射间隔
static int boomtime = 0;
//定义蜜蜂水平移动单位
static int hh = 3;
//定义蜜蜂垂直移动单位
static int vv = 2;
//定义枪(飞机)、子弹、蜜蜂、炸弹等位置信息
Rect gun;
Rect bullet;
Rect bee;
Rect boom;
Rect shootbee;
Rect panelpp;
//自定义函数
void porperty (void);
void position (void);
void popmessage (void);

int CVICALLBACK keystroke(int reserved, int timerId, int event, void *callbackData, int eventData1, int
eventData2);
//主函数
int main (int argc, char *argv[])

if (InitCVIRTE (0, argv, 0) == 0)
return –1;
if ((panelHandle = LoadPanel (0, "bee.uir", PANEL)) < 0)
return –1;
//设置枪(飞机)、子弹、蜜蜂、炸弹等控件背景透明
porperty ();
//装载异步定时器
timerkey = NewAsyncTimer (0.001, –1, 1, keystroke, 0);
DisplayPanel (panelHandle);
RunUserInterface ();
DiscardPanel (panelHandle);
//释放异步定时器资源
DiscardAsyncTimer (timerkey);
return 0;
}
//面板回调函数
int CVICALLBACK panelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)

int character;
int vk;
switch (event)

case EVENT_CLOSE:
QuitUserInterface (0);
break;
//面板尺寸改变时响应事件
case EVENT_PANEL_SIZE:
// 获得枪(飞机)、子弹、蜜蜂、炸弹等控件位置
position();
// 重新定位枪(飞机)控件Top 属性
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, panelpp.height–50);
break;

return 0;

//底端枪(飞机)子弹发射路径以及击中蜜蜂效果
int CVICALLBACK timer (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)


case EVENT_TIMER_TICK:
// 获得枪(飞机)、子弹、蜜蜂、炸弹等控件位置
position();
// 子弹向上发射路径
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_TOP, bullet.top–5);
// 当子弹超过屏幕顶端后消失
if (bullet.top < -bullet.height)
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_VISIBLE, 0);
shootflag = 0;
}
// 子弹击中蜜蜂的效果
if ((bullet.left+bullet.width>=bee.left) && (bullet.left<=bee.left+bee.width) && (bullet.top<=bee.
top+bee.height) && (bullet.top+bullet.height>=bee.top) && shootflag)
{
// 用击中后的图片替换原有图片
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_LEFT, bee.left);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_TOP, bee.top);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_VISIBLE, 1);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_VISIBLE, 0);
// 游戏停止
SetCtrlAttribute (panelHandle, PANEL_TIMER, ATTR_ENABLED, 0);
SetCtrlAttribute (panelHandle, PANEL_TIMER_BEE, ATTR_ENABLED, 0);
SetAsyncTimerAttribute (timerkey, ASYNC_ATTR_ENABLED, 0);
// 播放击中音乐
sndPlaySound("shootbee.wav", SND_SYNC);
// 弹出游戏结束面板
popmessage();
}
  break;

return 0; 
}  
//顶端蜜蜂运动路径以及蜜蜂炸弹击中枪(飞机)效果
int CVICALLBACK beerun (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_TIMER_TICK:
// 间隔一定时间,蜜蜂发射炸弹,炸弹垂直下落
boomtime++;
if (boomtime>=50)
{

boomtime = 0;

if (boomtime == 0 && (!boomflag))
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_VISIBLE, 1);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_LEFT, bee.left);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_TOP, bee.top+bee.height);
sndPlaySound("boom.wav", SND_SYNC);
boomflag = 1;
}
else
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_TOP, boom.top+20);
}
// 重新获得炸弹、蜜蜂等位置信息
position();
if (boom.top>=panelpp.height)
{
boomflag = 0;
}
// 蜜蜂到达边界自动反弹,并重新计算位置
if (bee.left <= 10 || bee.left + bee.width >= panelpp.width – 10)
{
hh = -hh;
}
if (bee.top <= 10 || gun.top - bee.top <= 100)
{
vv = -vv;
}
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_LEFT, bee.left+hh*(int)Random
(0, 10)); 
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_TOP, bee.top+vv*(int)Random
(0, 10));
// 蜜蜂炸弹击中枪(飞机)效果
if ((boom.left+boom.width>=gun.left) && (boom.left<=gun.left+gun.width) && (boom.top+
boom.height–30>=gun.top) && (boom.top+boom.height<=gun.top+gun.height) && (boomflag))
{
// 用击中后的图片替换原有图片
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTGUN, ATTR_VISIBLE, 1);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTGUN, ATTR_LEFT, gun.left);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTGUN, ATTR_TOP, gun.top);
// 游戏停止
SetCtrlAttribute (panelHandle, PANEL_TIMER, ATTR_ENABLED, 0);
SetCtrlAttribute (panelHandle, PANEL_TIMER_BEE, ATTR_ENABLED, 0);

SetAsyncTimerAttribute (timerkey, ASYNC_ATTR_ENABLED, 0);
sndPlaySound("dead.wav", SND_SYNC);
popmessage();
}
break;
}
return 0;
}
//退出按钮
int CVICALLBACK quit (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
DiscardPanel (pophandle);
QuitUserInterface (0);
break;
}
return 0;
}
//重新开始按钮
int CVICALLBACK restart (int panel, int control, int event,
void *callbackData, int eventData1, int eventData2)
{
switch (event)
{
case EVENT_COMMIT:
// 参数重置
shootflag = 0;
boomflag = 0;
boomtime = 0;
porperty();
// 开始游戏
SetCtrlAttribute (panelHandle, PANEL_TIMER, ATTR_ENABLED, 1);
SetCtrlAttribute (panelHandle, PANEL_TIMER_BEE, ATTR_ENABLED, 1);
SetAsyncTimerAttribute (timerkey, ASYNC_ATTR_ENABLED, 1);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_VISIBLE, 1);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_VISIBLE, 1);
DiscardPanel (pophandle);
break;
}
return 0;
}
//设置枪(飞机)、子弹、蜜蜂、炸弹等控件背景透明
void porperty (void)


SetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_PICT_BGCOLOR, VAL_TRANSPARENT);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_PICT_BGCOLOR, VAL_TRANSPARENT);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_PICT_BGCOLOR, VAL_TRANSPARENT);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_PICT_BGCOLOR, VAL_TRANSPARENT);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_PICT_BGCOLOR, VAL_TRANSPARENT);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTGUN, ATTR_PICT_BGCOLOR, VAL_TRANS-
PARENT);
//一些控件初始态不可见
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_VISIBLE, 0);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTGUN, ATTR_VISIBLE, 0);

//获得枪(飞机)、子弹、蜜蜂、炸弹等控件位置
void position (void)
{
//枪(飞机)
GetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_LEFT, &gun.left);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, &gun.top);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_HEIGHT, &gun.height);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_WIDTH, &gun.width);
//子弹
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_LEFT, &bullet.left);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_TOP, &bullet.top);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_HEIGHT, &bullet.height);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_WIDTH, &bullet.width);
//蜜蜂
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_LEFT, &bee.left);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_TOP, &bee.top);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_HEIGHT, &bee.height);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BEE, ATTR_WIDTH, &bee.width);
//击中蜜蜂
GetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_LEFT, &shootbee.left);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_TOP, &shootbee.top);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_HEIGHT, &shootbee.height);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_SHOOTBEE, ATTR_WIDTH, &shootbee.width);
//炸弹
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_LEFT, &boom.left);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_TOP, &boom.top);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_HEIGHT, &boom.height);
GetCtrlAttribute (panelHandle, PANEL_PICTURE_BOOM, ATTR_WIDTH, &boom.width);
//面板
GetPanelAttribute (panelHandle, ATTR_HEIGHT, &panelpp.height);
GetPanelAttribute (panelHandle, ATTR_WIDTH, &panelpp.width);
}

//游戏结束面板
void popmessage (void)

pophandle = LoadPanel (0, "bee.uir", PANEL_POP);
//以模态对话框形式显示游戏结束面板
InstallPopup (pophandle);
}
//异步定时器回调函数
int CVICALLBACK keystroke(int reserved, int timerId, int event, void *callbackData, int eventData1, int
eventData2)

int left;
int right;
int up;
int down;
int a;
switch (event)
{
case EVENT_TIMER_TICK:
// 获得虚拟键↑↓←→的按键状态,以及是否按下a 键
right = GetAsyncKeyState(VK_RIGHT);
left = GetAsyncKeyState(VK_LEFT);
up = GetAsyncKeyState(VK_UP);
down = GetAsyncKeyState(VK_DOWN);
a = GetAsyncKeyState('A');
// 向左移动
if (left != 0)
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_LEFT, gun.left–2);
}
// 向右移动
if (right != 0)
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_LEFT, gun.left+2);
}
// 向上移动
if (up != 0)
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, gun.top–2);
}
// 向下移动
if (down != 0)
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, gun.top+2);

}
// 按下a 键,发射子弹
if (a && (!shootflag))
{
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_LEFT, gun.left+gun.
width/2–8); 
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_TOP, gun.top);
SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_VISIBLE, 1);
sndPlaySound("bullet.wav", SND_SYNC);
shootflag = 1;
}
break;

return 0; 
}

 

(3) 程序注释

① sndPlaySound 函数播放指定音频文件。此函数为PlaySound 函数的子集,主要是为保持向后兼容而设置。文件声明在mmsystem.h 中,导入库为winmm.lib 。函数原型为:

BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound);

lpszSound :指定播放音频文件名,该参数可以是WAVE 文件名或是在系统注册表WIN.INI

中定义的系统事件音频文件。如果该参数设置为NULL 则停止正在播放的音频文件。fuSound:播放标志。

播放标志说明如表4-10 所示。

表4-10 播放标志说明

常量名

常量值

说明

SND_ASYNC

0x0001

用异步方式播放音频文件

SND_LOOP

0x0008

重复播放音频文件,与SND_ASYNC 标志同时使用

SND_MEMORY

0x0004

播放载入到内存中的音频文件

SND_NODEFAULT

0x0002

不播放缺省音频文件

SND_NOSTOP

0x0010

立即播放音频文件

SND_SYNC

0x0000

同步播放音频文件

返回值:成功返回True ,否则返回False 。

 

② GetAsyncKeyState 函数判断按键是处于按下状态,还是处于弹起状态。函数原型为:

SHORT GetAsyncKeyState(int vKey);

vKey:虚拟键值。

返回值:返回指定键是否处于按下状态,若为1,则键被按下,否则为弹起状态。

③ GetKeyPressEventVirtualKey 函数当回调函数响应EVENT_KEYPRESS 事件时,调用GetKeyPressEventVirtualKey 函数获得虚拟键值。如果回调函数eventData1 参数包含字符而非虚拟键时,函数返回0 值。函数原型为:

int GetKeyPressEventVirtualKey (int eventData2); eventData2 :面板或控件回调函数的eventData2 参数。

返回值:返回虚拟键值,如有非虚拟键按下,返回0。

④ GetKeyPressEventCharacter 函数当回调函数响应EVENT_KEYPRESS 事件时,调用GetKeyPressEventCharacter 函数获得按键字符。如果回调函数eventData1 参数包含虚拟键而非字符时,函数返回0 值。函数原型为:

int GetKeyPressEventCharacter (int eventData2);

eventData2 :面板或控件回调函数eventData2 参数。

返回值:返回字符值,如有非字符按下,返回0。

⑤ InstallPopup 函数显示模态对话框。函数原型为:

int InstallPopup (int Panel_Handle);

一般来说,在Windows 应用程序中,对话框分为模态对话框和非模态对话框两种。二者的区别在于当对话框打开时,是否允许用户进行其他对象的操作。模态对话框(Modal Dialogue Box, 又称模式对话框),是指在用户要操作对话框以外的窗口时,必须首先响应该对话框,如单击确定或取消按钮等关闭对话框。非模态对话框(Nonmodal Dialogue Box ,又称无模式对话框),与模态对话框不同,当用户打开非模态对话框时,依

 

然可以操作其他窗口。

⑥ 按键处理

在本例程中,按键处理采用异步定时器查询方式,需要将定时器的触发时间设置极短,这样会占用大量系统资源。另外,也可以停止异步定时器,采用LabWindows/CVI 事件响应机制,在面板回调函数panelCB 中添加EVENT_KEYPRESS 事件代码,程序如下:

int CVICALLBACK panelCB (int panel, int event, void *callbackData,
int eventData1, int eventData2)

int character;
int vk;
switch (event)

case EVENT_KEYPRESS:
// 获得虚拟键↑↓←→的按键状态,以及是否按下a 键
vk = GetKeyPressEventVirtualKey (eventData2);
character = GetKeyPressEventCharacter (eventData2);
switch (vk)
{
case VAL_LEFT_ARROW_VKEY:
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_LEFT, gun.left–10);
break;
case VAL_RIGHT_ARROW_VKEY:
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_LEFT, gun.left+10);
break;
case VAL_UP_ARROW_VKEY:
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, gun.top–10);
break;
case VAL_DOWN_ARROW_VKEY:
SetCtrlAttribute (panelHandle, PANEL_PICTURE_GUN, ATTR_TOP, gun.top+10);
break;

if (('a' == tolower (character)) && (!shootflag))

{
  SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_LEFT, gun.left+
gun.width/2–8);  
  SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_TOP, gun.top);
  SetCtrlAttribute (panelHandle, PANEL_PICTURE_BULLET, ATTR_VISIBLE, 1);
  sndPlaySound("bullet.wav", SND_SYNC);
  shootflag = 1;
}

以上程序中,获得虚拟键值和字符可以用GetKeyPressEventVirtualKey 和GetKeyPress

EventCharacter 函数,也可以采用EVENT_KEYPRESS 事件的eventData1 参数获得相关数据,即将以上两个函数用以下代码代替。

vk = eventData1 & 0xFF00;

character = eventData1 & 0x00FF;

(4)运行效果图

点击工具栏中的Debug Project 按钮,程序开始运行,其效果如图4-19 所示。

edatop.com

图4-19 运行效果图

点击浏览:矢量网络分析仪、频谱仪、示波器,使用操作培训教程

上一篇:LabWindows/CVI虚拟仪器: 打字练习
下一篇:LabWindows/CVI虚拟仪器游戏设计之: 下雪场景

微波射频测量操作培训课程详情>>
射频和天线工程师培训课程详情>>

  网站地图