2010年4月30日星期五

如何进行软件的可用性测试(usability testing) 要点总结(上)

最近在做一个小软件交付前的可用性测试,看了一些资料,在网上找到一个还不错的总结,这里我做一个简单的翻译,本篇文章比较长,希望对一些需要进行可用性测试的朋友有所帮助。

什么是软件的可用性测试(usability testing)?
一个用来记录和衡量一个交互系统的交互质量的方法。

[1]
实验室或现场测试:
运行测试...
  和真正的最终用户(即'测试者')
  使用代表性任务
  在一个'真实的'环境

进行记录/协议 ...
  所有重要事件
  用户和观察员的全部评论
  主观印象

控制/测量
  脑力负荷

[2]
形成性评价
  一个测试组(小于5)
  一个交互系统
  要求测试人员的意见
  目标:找到关键事件

总结性评价
  两个或多个测试人员小组(大于 12)
  测量测试人员的的计算机水平
  两个或两个以上的接口版本
  衡量脑力负荷
  询问测试人员的意见
  性能比较
  分析与应用统计数据
  目标:选择最好的系统

[3]
必要的组件

情景/任务
  选择适当的工作环境

真正的最终用户作为测试者
  选择所有目标群体
  [任务,性别,年龄,经验,等级,工作各部门,使用语言,...]

交互系统
  最小硬件/最大软件

观察员
  项目经理,设计师,软件开发人员,培训教员,额外的最终用户

数据记录
  音频/视频,日志文件,问卷调查

[4]
重要的制约

每个测试者的测试时间要小于2.5小时
  否则最终用户迅速变得很累!

只作重要功能的测试
  高频率的使用
  关键任务方面

只测试主要交互类型
  典型的使用,避免重复

测试完整的任务
  最终用户应该会成功!

社会心理方面
  不要责怪用户/测试者!

[5]
重要行动

测试者的简报
  “我们测试软件,而不是你!”
  “你可以随时取消测试!”
  - 解释测试环境
  - 如果要记录数据时要求用户的允许

记录数据/关键事件
  是否所有设备准备好了吗?
  视频中的日期/时间戳是否正确?
  协议中的日期/时间是否正确?

收集所有测试材料
  将所有的测试材料夹在一起,放入一个文件夹中

测试人员汇报情况
  给予时间让测试者提问,付给测试者工资,并感谢用户!

 

参考文献:
Jakob Nielsen, Usability engineering. Academic, 1993

http://www.idemployee.id.tue.nl/g.w.m.rauterberg/publications/UE_Tutorial.pdf

2010年4月27日星期二

VLC如何进行RTSP的支持(源码阅读心得)

今天天气很好,心情大好,Hanyionet和大家分享一下阅读VLC的源码的一些心得。

先小小吹捧和介绍一下VLC。
大家都知道VLC是一个免费,开放源码,跨平台媒体播放器,并集合先进的流媒体功能可以通过IPv4或IPv6的高带宽网络进行流媒体传输。它还支持多种视频格式和流协议。VLC的编解码基于著名的开源项目FFmpeg的libavcodec的开源库。VLC同时提供不同的接口(命令行,网络,图形用户界面,远程登录),以及提供流行的语言如C,C++,C#,Python,和Java可以使用的APIs,这使得VLC变得高度灵活,并且用于任何类型播放或流媒体处理。

VLC支持RTSP功能是通过使用liveMedia库,这个库是live555开源项目一部分。VLC支持RTSP协议,可用于在线或离线转码,视频点播服务和单播或组播流。除了这些以外,VLC还提供各种接口和API,VLC还允许被集成在一个更复杂的环境,可以让我们建立一个更先进的视频应用程序。

进入正题,VLC到底是如何进行RTSP的支持。

VLC对RTSP的支持的实现的方式是通过一种输出链(output chains)。VLC读取各种类型的视频输入(文件,流,DVD等),然后通过定义一个或多个输出链(output chains)的内容,然后用于播放流。一个链可以连接到另一个链条,然后就可以形成一个比较复杂的工作流程。下图为一个简单的例子说明。图中VLC设置并读取本地文件,然后转码,并通过使用两个链将数据传输到一个多播地址。链1将读取文件,然后转码。链2读取链1输出的转码文件,然后将流发送到至指定地址。整个过程类似UNIX管道的工作方式。

VLC RTSP example hanyionet

Enjoy!

2010年4月25日星期日

不要抱怨,不要过于计较

今天想写一篇短文,谈谈两种行为:抱怨和过分计较。过分计较和抱怨这两种行为和心态,几乎是共生的。请观察一下,那些喜欢抱怨的人往往就是平日在工作上最爱计较的人。

很多人都读过《不抱怨的世界》,谈不要抱怨,这本书说的比我好上万倍,这里就直接引书中几句,关于抱怨这个行为漂亮精确的分析。

《不抱怨的世界》作者认为:“抱怨就是自夸,没有人会喜欢爱吹牛的人。”

人们为什么会抱怨,书中谈到,“没有安全感、质疑自己的重要性、不确定自我价值的人,才会吹牛和抱怨。他们会昭告自己的成就,希望看到听者眼中投射出赞赏的目光。他们也会抱怨自己遭逢的困难,以博取同情;或是把它当作藉口,以逃避自己向往却没有完成的目标。他们会抱怨,其实是因为自觉不配得到他们想要的东西。他们缺乏自我肯定,于是便藉由抱怨,把自己想要的东西推开。”

所以不要抱怨吧,现在开始,请散播阳光和喜乐,这样会给自己的家庭和工作带来正面的影响力。

 

我主要来聊聊“过于计较”这种行为。

很多人在读研究所的时候总是过于计较自己是否做得过多事情,自己的时间是否被占用,计较自己是教授的免费劳动力。很多人总是斤斤计较自己的时间,计较着读完硕士的时间等等,我认为这只是和小学生一般的“读书升级”的幼稚心态,其实人生中的真正积累和收获不是因为一个硕士头衔而得到任何的变化。过于计较的人,以最小的代价获得最大的收获为傲,认为那些花很多时间去做对自己无用的人很笨,在我看来,那些爱计较的人才是一种真正的蠢蛋。

在上班时,过于计较的人总是喜欢进行比较,他们爱发表例如此类的言论:“我只是编程的我不是测试的,这些代码又不是我要维护”等等。他们做这些所谓“不是他们的事”的时候总是不甘不愿的,超级影响团队士气。遇到这种人,最好的方法就是把他踢出项目组,然后项目组的其他同仁一起加倍诚恳和努力把项目搞定。相信我....这绝对是最好的方法,我的痛苦经验就是和爱计较的人一起做了一个项目,他一个人搞得整个团队乌烟瘴气,士气全无,项目做得很痛苦,请想想我们玩过的三国志,如果一个部队士气全无,那么这个部队就几乎毫无战斗力。

过分计较的人是无法进行真正的积累的,知识和生活经验的积累往往从所谓的“困境”当中,或者是那些过分计较的人眼中的“做免费劳动力”的过程中。

不要过于计较自己的外在得失,要做的事情很简单就是花费心力将该做的事情做好。其实看事情要大方向,大格局地看事情,不要过于计较那一点的得失。曾经看过一篇文章,谈到“生命就是一种长期而持续的积累过程”。人生的“大格局”就是“一种长期而持续的积累过程”,我们所要坚持的大方向也就是“长期而持续的积累”,而不是不断地计较自己的外在得失。

最后给自己拍拍手,居然欢叽叽歪歪写一篇所谓的大道理的“自爽文”。

2010年4月18日星期日

FFmpeg和SDL的API

使用FFmpeg的API和SDL的API进行视频的解码和显示,似乎还是有点技术含量的东西,我最近收到一些email询问视频的解码和显示的实现,今天hanyionet就献上博文一篇简单地说明一下如何使用这些API,其实使用这些API其实一点都不难,不要被复杂描述吓到。我们所要做就是先要了解视频的解码和显示到底是怎样的一个过程,然后了解各个API的作用。


进行解码和视频的现实一般来说就是这样的步骤:
初始化-->解码-->图像缩放-->视频显示
以下是一个简单的过程流程图,在每一个步骤中给出一些比较重要的API。

Process flow of video decode module new

可以看出,不同的步骤的实现,就是找到并使用相对应的API。
图中的API的具体说明,今天一同给出。

FFmpeg API

描述

av_register_all()

Initializes libavformat and registers all the muxers, demuxers and protocols.

avcodec_find_decoder(…)

Finds a decoder with a matching codec ID.

avcodec_alloc_context()

Allocates an AVCodecContext and sets its fields to default values.

avcodec_alloc_frame()

Allocates an AVFrame and sets its fields to default values.

sws_getContext(…)

Returns an SwsContext to be used in sws_scale().

sws_scale(…)

Scales the data in source according to our settings in our SwsContext c. srcStride and dstStride are the source and destination linesize.

avcodec_decode_video(…)

Decodes a video frame from buffer into picture.

 

SDL API

描述

SDL_SetVideoMode()

Set up a video mode with the specified width, height, and bits-per-pixel.

SDL_CreateYUVOverlay()

It is used to create a YUV overlay of the specified width, height and format for the provided display.

SDL_BlitSurface()

This performs a fast blit from the source surface to the destination surface.

SDL_FreeSurface()

Frees (deletes) a SDL surface.

SDL_UpdateRect()

Makes sure the given area is updated on the given screen.

SDL_Flip()

It is used to swap screen buffers. On hardware that supports double-buffering, this function sets up a flip and returns.

SDL_FreeYUVOverlay()

Free a YUV video overlay.

其实要理解FFmpeg的API还有一个非常重要的地方就是理解,各种数据结构的具体内容,譬如AVFrame和AVCodecContext,个人认为这两个结构是比较重要的。
了解的这些API的使用方法后,现在应该做的就是找一个例子例如ffplay.c或者http://dranger.com/ffmpeg/里的例程,体会一下,最后使用这些API搭建出属于自己的视频播放程序。

Enjoy!

2010年4月13日星期二

一些书摘分享

因为师兄在度长假,项目头不在,项目无法继续,所以我也给自己放了10天加长版的复活节假期,明天开假期就结束了,又要开始努力工作。这个假期里,读了很多以前想读的但是没有时间读五花八门的书,并且在很多地方大把大把地浪费时间。
最近读书时,做了一些书摘,以下是个人认为比较好的观点,在这里给出和大家分享:

上司分配给下属的工作并不是打算要你百分之百地完成。也就是说一般分配给你的是120%~130%,而你完成110%就足够了。这种时候,也需要通过提高业绩,来增强回绝130%工作量的底气。

“选定不必做的事比选定需要做的事”起码重要两倍以上。这是因为增加要做的事也不一定能有效地管理时间,但是只要我们能够确定哪些事我们不必做,就能切实有效地管理时间。

《时间投资法》


拥有信息的人-聪明人合法地从没有信息的人-不聪明的人那里卷走金钱。只要你成为信息的提供者,那么你就可以轻松收集到你所需要的信息。

开口说话或者写电子邮件的时候,一定要清楚地意识以下四个方面:

1. 要清楚自己希望向对方传递什么样的一个整体感觉。

2. 要清楚用框架对这个整体感觉进行分解后,会变成什么样的结构。

3. 要清楚简化后,最重要的信息内容是什么。

4. 要清楚这这个信息内容中,有必要向对方传递的层次信息是什么。

提升10倍人脉的建议:

1. 给予信息

2. 提高电子邮件的质量,扩大联系。

3. 有效利用公共邮件列表,使之成为大家集结的重要阵地

4. 善于利用午餐会

5. 尊重自己的交流方式

《效率提升10倍的google化知性生产技巧》

吸引力法则(想什么给什么,像万有引力,改变思想就可以改变状况),想象,学会使用自己的身体,更要学会使用自己的心灵。预先创造生活。心和想法非常重要。想象美好的人际关系。爱自己。我要什么的方式思考。感恩。

《秘密》

 

升官是和老板认为你是有多少本事有关和一个人的未来价值,而不是你真实的实力。观察组织未来的需求,做好准备,积极主动幽默开朗。推销自己的想法。不要批评任何人。

《老板选谁一起喝啤酒》

幸福就是,当你设定一个目标,你在奋斗的时候感觉快乐,你实现目标的时候也感觉快乐。

《幸福的方法》

 

在新大陆经济环境中,能坚持到最后的企业多数都是项目型企业,他们也将成为今后的主流。因为比起容易因循守旧的金字塔式组织结构,项目型组织结构能更快更灵活地应对市场变化,更适合企业不断创新和发展的需求。
成功人士具有以下三个共同特征。第一,他们深知人生就是不断挑战,不断冒险的过程;第二,做自己想做的事情,而不管别人是怎么看的,也不计较收入的多少;第三,具有强烈的欲望,不断进取。一句话,他们是典型的“冒险家”。他们并不追求“安居乐业”,而是不断挑战自我,证明自我,即使失败了,也会笑着面对人生。

《再启动》

还有部分书摘,这里我就不给出具体出处:

建立自信,是成功的不二法则,自信不需要与任何人做比较,在这个世界上,每个人都有自己的特质与优点,我们不需要和任何人比较,也不需要永远认为自己不如其他人。如果总是抱着“我比不上其他人”的想法而对任何事情退缩,那将永远没有扭转命运的可能。
如果你觉得自己很努力了,那么就问问自己:我是否努力得感动了别人甚至是感动了自己呢?
不能只有专业化,工作需要职业化。
学历可以作为一种衡量我们工作能力的信号。即使毕业于同一所大学,在找工作时,根据你的专业不同,受到的评价也就不同。入学难度高的专业的毕业生要比其他专业的毕业生拥有一定的优势。
读书无须太多规矩,重在以量取胜,带着问题读书,对信息加以筛选。

2010年4月7日星期三

文献管理软件JabRef

进入正题前,照例先闲话几句,很久没有更新博客了,上个月回了一趟国,陪陪家人,和老同学朋友叙旧。在一些饭局中,听了一些了解行业本质的人对一些行业的见解和经济趋势的分析,才真的发现自己认识的肤浅,真感到“听君一席话,胜读十年书”。

JabRef 今天写一些文献管理软件的安装和使用,首先简单提一下BibTex。BibTeX作为TeX 组件,提供了参考文献生成功能。一般来说BibTeX工具是用来和LaTeX一起使用。JabRef也是一种BibTeX参考文献管理软件。最重要的是它是开源的比起大名鼎鼎的EndNote,其实并不逊色,EndNote在Word里用起来非常方便,最大的缺点就是要$$。我们可以使用JabRef来建立数据库也就是纯文本的bib文件,也可以从例如IEEE文献库里自动导入文献条目,用它来管理文献条目也是相当简单的,例如我们可以使用它来生成BibTeXkey,然后把库bib文件和pdf文件放在同一目录下,将pdf文件命名为BibTeXkey名,然后就可以进行关联。我只是非常简单地谈一下使用。具体使用请移步:“文献管理软件 JabRef 快速入门”http://blog.solrex.org/articles/jabref-quick-guide.html

JabRef作为EndNote的替代,Mike Brookes 开发了一个很好的Word的add-on。
如果要安装使用Word 2007或 2003下的JabRef add-on请移步:http://www.ee.ic.ac.uk/hp/staff/dmb/perl/index.html
这里写一点快速上手的简单说明:

1. 下载MiKTeX(从http://miktex.org/)
MiKTeX的是LaTeX的排版环境,我们使用它,主要是因为MiKTeX包含BibTeX之类的'引擎'可以用来生成各种期刊格式。

2. 安装JabRef(从http://jabref.sourceforge.net/)并重新定位JabRef文档
不幸的BibTeX之不支持文件名带空格,如果你的JabRef文件中名字有空格,必须重新定位JabRef文件到一个没有空格目录。

3. 设定Path
The macro requires that it can access the BibTeX package from the default path. The simplest way to set this is to go to
Start>>Settings>>Control Panel>> System>>Advanced>>Enviromental Variables>>System Variables
here you need to edit the “Path” entry by adding the path of the BibTeX executable, failure to do so will cause an “Error 53″ The path to my BibTeX executable is C:\Program Files\MiKTeX 2.5\miktex\bin

4. 将Word Startup Folder 设为可视

5. 下载Macro
这个Marco也就是Bibtex4Word.dot,你可以在http://www.ee.ic.ac.uk/hp/staff/dmb/perl/index.html找到

Marco要求,它可以访问从默认路径BibTeX包。最简单的方法设置:
如果使用Win7或Vista

放入C:\Users\*用户名*\AppData\Roaming\Microsoft\Word\STARTUP

如果使用XP
放入 "C:\Document and Settings\*用户名*\Application Data\Microsoft\Word\STARTUP"

6. 如果打开 Microsoft Word 2007
在 Add-Ins里可以找到我们的Add-on,然后你就可以开始开始引用(Citing)了。在Word 2003可以直接看到Bibtex4Word toolbar。

 

详细使用及具体安装步骤请参考:

Word 2007 and Jabref http://freetimeblog.awardspace.com/?p=52
How to use JabRef (BibTeX) with Microsoft Word 2003 http://www.medicalnerds.com/how-to-use-jabrefbibtex-with-microsoft-word-2003/
Bibtex4Word - Home http://www.ee.ic.ac.uk/hp/staff/dmb/perl/index.html

2010年2月27日星期六

C++开发游戏手柄代码 (Developing the Joystick Code)

还是坚持每周一博,照例写正文前废话一段:最近天气越来越好,不下雪了,偶尔下点雨,下了一次冰雹,但可以看到10+的温度了,晚上6点坐车回家的时候天还是是微亮。哈,德国的春天终于来了。
迫于项目时间的压力,项目只剩下最后一周的时间,本周的工作效率还不错,写了非常多的代码,突然发现,我最近最能集中心力,最具生产力的时段是下午5到6点,就是回家前一个小时,似乎所有最有创造力的生产和想法都是在这个小时产生的,很奇怪。最近,所里的咖啡机又坏了,苦了很多人,有一个意大利同事对我说说,没有咖啡就不能Coffee in, Code out,没法编程了。还好我不喝咖啡,每天只喝茶,所里提供的各种奇怪的茶包(德国的茶包的种类真是多的恐怖,各种奇怪的口味都有,喝过一种咖喱口味的茶)。

好了闲话不多谈,今天谈谈关于游戏手柄joystick的代码开发,最近接触了一些多媒体子系统的Win32 API,其实非常容易,通过一些google可以找到非常多的源代码和示例代码,可以非常快的利用多媒体的Win32 API开发出一些很有趣的东西,游戏手柄joystick代码开发就是一个很经典的例子。支持游戏手柄现在是一个Win32的标准的一部分,多媒体子系统单独的Win32 API,其中支持游戏手柄是一个组成部分。但是关于游戏手柄的功能和数据结构没有定义在标准windows.h头文件,而是位于mmsystem.h中头文件。
上代码之前,一些说明:

[1]

要使用游戏手柄的Win32 API
#include <windows.h>
#include <mmsystem.h>

编译器请使用VS2005以上版本。

[2]

当然了不要忘记加入winmm.lib。

[3]

JOYSTATE数据类型包括描述游戏手柄的State
例如

1: typedef WORD JOYSTATE; 
2: const JOYSTATE JOY_NONE = 0x0000L, 
3: JOY_LEFT = 0x0001L, 
4: JOY_RIGHT = 0x0002L, 
5: JOY_UP = 0x0004L, 
6: JOY_DOWN = 0x0008L,


[4]

我们要做的事就是,写出以下方法:

BOOL InitJoystick(); 
void CaptureJoystick(); 
void ReleaseJoystick(); 
void CheckJoystick();

 

[5]

写CaptureJoystick()和 ReleaseJoystick()的方法就是使用使用两个Win32 functions就是:joySetCapture() 和 joyReleaseCapture() 。
JOYINFO structure用于检索游戏手柄状态通过joyGetPos() function。

[6]

以下代码结合了Qt,也可以不需要Qt运行,只需要删除Qt部分的代码即可,使用了Qt的signal slot机制,利用了QTime的timeout()不断对CheckJoystick()进行调用,以及时更新Joystick状态。

[7]

BTP_Joystick以下的代码的主体部分来自网上的一些示例代码,我进行了一些修改和裁剪,编译和使用没有任何问题,我使用的是北通小手柄 BTP-C024 USB游戏手柄(如附图所示)进行测试,运行很好。以下代码非常简单,应该很容易理解,不要问我,为什么不能用,或者如何使用,如果不能用,请google或再看看代码(你已经有了完整的代码),呵呵。

 

 

 

 

1  /*
2   * \file GameEngine.h
3   * \class GameEngine
4   * \date   2010
5   * \bug
6   * \warning
7   *
8   */
9 
10 #ifndef GAMEENGINE_H_
11 #define GAMEENGINE_H_
12
13 #include <QtGui>
14
15 #include <windows.h>
16 #include <mmsystem.h>
17
18 //-----------------------------------------------------------------
19 // Joystick Flags
20 //-----------------------------------------------------------------
21 typedef WORD    JOYSTATE;
22 const JOYSTATE  JOY_NONE  = 0x0000L,
23                 JOY_LEFT  = 0x0001L,
24                 JOY_RIGHT = 0x0002L,
25                 JOY_UP    = 0x0004L,
26                 JOY_DOWN  = 0x0008L,
27                 JOY_FIRE1 = 0x0010L,
28                 JOY_FIRE2 = 0x0020L,
29                 JOY_FIRE3 = 0x0030L,
30                 JOY_FIRE4 = 0x0040L;
31
32 class GameEngine : public QObject
33 {
34     Q_OBJECT
35
36 public:
37
38     GameEngine();
39     ~GameEngine();
40
41     void HandleJoystick(JOYSTATE jsJoystickState);
42    
43     BOOL InitJoystick();
44     void CaptureJoystick();
45     void ReleaseJoystick();
46    
47     UINT m_uiJoystickID;
48     RECT m_rcJoystickTrip;
49     HWND m_hWindow;
50
51 protected:
52
53 private slots:
54     void CheckJoystick();
55
56 signals:
57     void joystickLeft();
58     void joystickRight();
59     void joystickUp();
60     void joystickDown();
61     void joystickButton1();
62     void joystickButton2();
63     void joystickButton3();
64     void joystickButton4();
65
66 private:
67     QTimer *_poller;
68
69 };
70
71 #endif /* GAMEENGINE_H_ */

 

1   /*
2    * \file GameEngine.cpp
3    * \class GameEngine
4    * \date   2010
5    * \bug
6    * \warning
7    *
8    */
9  
10  #include <QDebug>
11 
12  #include "GameEngine.h"
13 
14 
15  GameEngine::GameEngine()
16  {
17   
18      InitJoystick();
19      CaptureJoystick();
20 
21      //start timer to trigger every 100 ms 
22      _poller = new QTimer(this);
23      connect(_poller, SIGNAL(timeout()), this, SLOT(CheckJoystick()));
24      _poller->start(100); 
25  }
26 
27  GameEngine::~GameEngine()
28  {
29 
30  }
31 
32  BOOL GameEngine::InitJoystick()
33  {
34      // Make sure joystick driver is present
35      UINT uiNumJoysticks;
36      if ((uiNumJoysticks = joyGetNumDevs()) == 0)
37          return FALSE;
38 
39      // Make sure the joystick is attached
40      JOYINFO jiInfo;
41      if (joyGetPos(JOYSTICKID1, &jiInfo) != JOYERR_UNPLUGGED)
42          m_uiJoystickID = JOYSTICKID1;
43      else
44          return FALSE;
45     
46      // Calculate the trip values
47      JOYCAPS jcCaps;
48      joyGetDevCaps(m_uiJoystickID, &jcCaps, sizeof(JOYCAPS));
49      DWORD dwXCenter = ((DWORD)jcCaps.wXmin + jcCaps.wXmax) / 2;
50      DWORD dwYCenter = ((DWORD)jcCaps.wYmin + jcCaps.wYmax) / 2;
51      m_rcJoystickTrip.left = (jcCaps.wXmin + (WORD)dwXCenter) / 2;
52      m_rcJoystickTrip.right = (jcCaps.wXmax + (WORD)dwXCenter) / 2;
53      m_rcJoystickTrip.top = (jcCaps.wYmin + (WORD)dwYCenter) / 2;
54      m_rcJoystickTrip.bottom = (jcCaps.wYmax + (WORD)dwYCenter) / 2;
55      return TRUE;
56  }
57 
58  void GameEngine::CaptureJoystick()
59  {
60      // Capture the joystick
61      if (m_uiJoystickID == JOYSTICKID1)
62      {
63         joySetCapture(m_hWindow, m_uiJoystickID, NULL, TRUE);
64          qDebug() << " Capture Joystick success!";
65      }
66  }
67 
68  void GameEngine::ReleaseJoystick()
69  {
70      // Release the joystick
71      if (m_uiJoystickID == JOYSTICKID1)
72      joyReleaseCapture(m_uiJoystickID);
73  }
74 
75  void GameEngine::CheckJoystick()
76  {
77  if (m_uiJoystickID == JOYSTICKID1)
78  {
79     JOYINFO jiInfo;
80     JOYSTATE jsJoystickState = 0;
81     if (joyGetPos(m_uiJoystickID, &jiInfo) == JOYERR_NOERROR)
82     {
83          // Check horizontal movement
84          if (jiInfo.wXpos < (WORD)m_rcJoystickTrip.left)
85              jsJoystickState |= JOY_LEFT;
86            else if (jiInfo.wXpos > (WORD)m_rcJoystickTrip.right)
87              jsJoystickState |= JOY_RIGHT;
88             // Check vertical movement
89             if (jiInfo.wYpos < (WORD)m_rcJoystickTrip.top)
90              jsJoystickState |= JOY_UP;
91             else if (jiInfo.wYpos > (WORD)m_rcJoystickTrip.bottom)
92              jsJoystickState |= JOY_DOWN;
93             // Check buttons
94             if(jiInfo.wButtons & JOY_BUTTON1)
95              jsJoystickState |= JOY_FIRE1;
96             if(jiInfo.wButtons & JOY_BUTTON2)
97              jsJoystickState |= JOY_FIRE2;
98          if(jiInfo.wButtons & JOY_BUTTON3)
99              jsJoystickState |= JOY_FIRE3;
100         if(jiInfo.wButtons & JOY_BUTTON4)
101             jsJoystickState |= JOY_FIRE4;
102     }
103
104     // Allow the game to handle the joystick
105     HandleJoystick(jsJoystickState);
106     }
107 }
108
109 void GameEngine::HandleJoystick(JOYSTATE jsJoystickState)
110 {
111     //这里加入你自己对jsJoystickState的处理,以下只是极简单的示范
112     //通过HandleJoystick得到JOYSTATE
113    
114     //qDebug() << " get information about Joystick!" ;
115     if (jsJoystickState == JOY_UP)
116     {
117         qDebug() << " get Joystick -- JOY_UP!" ;   
118     }
119     else if (jsJoystickState == JOY_DOWN)
120     {
121         qDebug() << " get Joystick -- JOY_DOWN!" ;
122     }
123     else if (jsJoystickState == JOY_LEFT)
124     {
125         qDebug() << " get Joystick -- JOY_LEFT!" ;
126     }
127     else if (jsJoystickState == JOY_RIGHT)
128     {
129         qDebug() << " get Joystick -- JOY_RIGHT!" ;
130     }
131     else if (jsJoystickState == JOY_FIRE1)
132     {
133         qDebug() << " get Joystick -- JOY_FIRE1!" ;
134     }
135     else if (jsJoystickState == JOY_FIRE2)
136     {
137         qDebug() << " get Joystick -- JOY_FIRE2!" ;
138     }
139     else if (jsJoystickState == JOY_FIRE3)
140     {
141         qDebug() << " get Joystick -- JOY_FIRE3!" ;
142     }
143     else if (jsJoystickState == JOY_FIRE4)
144     {
145         qDebug() << " get Joystick -- JOY_FIRE4!" ;
146     }
147 }
148

Enjoy!

2010年2月20日星期六

Qt 自定义 Combo Box

这星期效率还不错,延续了上周的状态,写了非常多的代码,但是大部分都是低复杂度的”简单代码”,写了一些Gui。和一些同事不一样,我很喜欢写Gui,因为写完马上就可以看到成果,很有成就感,而且用Qt写Gui感觉就像堆积木,很简单,只要找到自己需要的API,我个人非常喜欢Qt风格的C++的应用程序接口,很清晰且简单,相当直觉化。

customize_combo_box_qt这里和大家很简单谈一些我最近用Qt写Gui的发现的好玩特性,也许Qt的标准控件已经不能满足你了,其实,我们同样可以很容易地进行自定义控件,这里使用Combo Box作为例子。

以下代码会构建出我们自定义的Combo Box,如附图所示,这里使用了Qt Style Sheet。

 

 

// set some self defined colors
QColor royalBlue;
QColor orange;
royalBlue.setRgb(65, 105, 225);
orange.setRgb(255, 165, 000);

// set default color
myComboBox->setStyleSheet("* { background-color: rgb(65, 105, 225) }");

myComboBox->insertItem(0, "blue");
myComboBox->setItemData(0, royalBlue, Qt::BackgroundRole);

myComboBox->insertItem(1, "red");
myComboBox->setItemData(1, Qt::red, Qt::BackgroundRole);

myComboBox->insertItem(2, "green");
myComboBox->setItemData(2, Qt::green, Qt::BackgroundRole);

myComboBox->insertItem(3, "yellow");
myComboBox->setItemData(3, Qt::yellow, Qt::BackgroundRole);

myComboBox->insertItem(4, "orange");
myComboBox->setItemData(4, orange, Qt::BackgroundRole);

myComboBox->insertItem(5, "cyan");
myComboBox->setItemData(5, Qt::cyan, Qt::BackgroundRole);

myComboBox->insertItem(6, "purple");
myComboBox->setItemData(6, Qt::magenta, Qt::BackgroundRole);

 

 

也许还不过瘾,我们还可以通过QPalette来自定义我们的Combo Box,以下是一个简单例子。

 QPalette myPalette = myComboBox->palette();

 // outline around the menu
 myPalette.setColor(QPalette::Window, Qt::red);    
 myPalette.setColor(QPalette::WindowText, Qt::white);

 // customize myComboBox button
 myPalette.setColor(QPalette::Button, Qt::darkCyan);  
 myPalette.setColor(QPalette::ButtonText, Qt::white);
 
 // customize myComboBox menu
 myPalette.setColor(QPalette::Base, Qt::darkCyan);  
 myPalette.setColor(QPalette::Text, Qt::white);

 // customize highlight button and menu
 myPalette.setColor(QPalette::Highlight, Qt::blue);   
 myPalette.setColor(QPalette::HighlightedText, Qt::red);
 
 // customize the disabled color
 myPalette.setColor(QPalette::Disabled, QPalette::Button, Qt::gray);
 myPalette.setColor(QPalette::Disabled, QPalette::ButtonText, Qt::lightGray);
 
 myComboBox->setPalette(myPalette);