关于不规则界面,百思不得其解(50分)

  • 主题发起人 主题发起人 tonylisa
  • 开始时间 开始时间
T

tonylisa

Unregistered / Unconfirmed
GUEST, unregistred user!
关于不规则界面,百思不得其解,如金山影霸只用四个大图(1、mask.bmp 2、base.bmp 3、over.bmp 4、down.bmp)就可以实现鼠标的进入、按下、退出的几种按钮状态,而按扭也是一个不规则的图形来的。
小弟这几天都比较困惑,几天都解决不了。所以请教各位大侠啦。谢了!
 
贴个文章给你:
软件SKIN技术探秘


  大家都知道,用户界面是一个软件的面子,界面好不好往往决定了一个软件的成功与否。我知道曾经有一
个程序高手,作了一个非常实用的软件,但基本上没有什么界面,只是一个简单的基于对话框的应用程序。
结果软件上传到Download.com和HOTFiles.com时,什么好评价也没有得到,Tucows.com甚至不肯收录该软件。
一位用户email说,"A good interface will lead you to a wonder" (一个好的用户界面会给你带来奇迹)。
于是他下决心改进用户界面,花钱请美术高手设计了一个很酷的界面,再投放到那些下载网站上,结果在
HotFiles上得了4个星,Tucows上得了4头牛。

  好了,下面就言归正传,我要说的是当你请人设计了一个很酷的界面图片后,怎么把它集成到你的程序
中去?相信很多人用过OICQ,它采用了一种称作“skin(皮肤)”的技术,

  界面比较华丽。实际上到它的程序目录里看一看,就会发现它的界面用到的图片都放在skins目录下。
下面我就分析一下这些图片是怎么贴到程序窗口中去的。当然这里的分析并非针对oicq,但我想原理大同小
异,不同的只是实现细节。限于小生才疏学浅,如果本文有何不妥,欢迎指正。

  首先,制作一张图片,它用来做你的程序正常显示时的skin。我们姑且称它为main.bmp。

  因此,你想象中你的程序界面是什么样子,那么图片就应是什么样子。如果你的程序需要按钮、标签等
控件,在这幅图中应该把它们画出来。下图是一个MP3播放程序的界面,图中画出了所打算实现的各种控件。
我想不用我一一解释了吧。
  下面还要画两张图,称为over.bmp和selected.bmp。前者用于指出鼠标移动到某个控件上面时,控件的
外观(appearance)应该是什么样子;相应地,后者用于指出鼠标选中某个控件时,控件的外观应该是什么
样子。这两张图中,控件的布局(指控件的坐标、尺寸)安排应该与main.bmp相同,只是在控件的外观上有
些变化,以造成控件的动态效果
  最后一张图片是mask.bmp,它用来创建一个区域(region)对象(利用api CreateRectRgn),基于此区
域可以实现不规则程序窗口(利用api SetWindowRgn)。生成该图片的办法是main.bmp中深色的部分全涂位黑
色,其余部分为白色,黑色部分其实就是你的程序窗口最后的轮廓(另外可以在程序中生成mask.bmp,办法
是把main.bmp拷贝成一个单色位图)。利用这种方法,你的程序可以是任意不规则窗口,它只局限于你的想
象力。(这里就不贴出来了,否则有赚稿费之嫌)

  自然地,你会想到怎么在程序中把各种相关控件的信息从图片中提取出来呢?在这里我们的办法是预先
提取出各种信息并存入一个名为skin.ini的文件中,程序中读取该文件即可。提取办法很不好意思是手工提
取,比如需要某个按钮在窗口中的坐标信息,就在一个图形编辑器里确定它在图片中的坐标,然后手工写入
skin.ini。这样虽然比较麻烦,一般来说还是可以忍受的。(当然可以制作一个工具来生成skin.ini,那位
朋友感兴趣可以一试。)这里给出基于上述图片的一个skin.ini:



[SCREEN]

Mask=Mask.bmp

Main=Main.jpg

Down=Selected.jpg

Over=Over.jpg

Disabled=Main.jpg


[BUTTONINFO]

1=BUTTON_EXIT,349,8,17,17,关闭窗口,FALSE

2=BUTTON_MINIMIZE,342,7,17,17,最小化,FALSE

3=BUTTON_SAVEEQ,312,184,39,34,,FALSE

4=BUTTON_LOADEQ,271,184,39,34,,FALSE

5=BUTTON_USEEQ,234,184,39,34,,TRUE

6=BUTTON_LAST,341,143,35,30,最后一首,FALSE

7=BUTTON_NEXT,304,143,35,30,Sonraki,FALSE

8=BUTTON_PREV,267,143,35,30,謓ceki,FALSE

9=BUTTON_STOP,342,105,37,30,停止播放,FALSE

10=BUTTON_PAUSE,305,105,37,30,暂停,FALSE

11=BUTTON_PLAY,268,105,37,30,播放,FALSE

12=BUTTON_FIRST,230,143,35,30,第一首,FALSE

13=BUTTON_EJECT,231,105,37,30,弹出,FALSE

14=BUTTON_MENU,12,8,17,17,菜单,FALSE


[PROGRESSINFO]

1=PROGRESS_POS,进度,12,66,371,28,V

2=PROGRESS_VOL,音量,16,94,103,37,V


[TEXTINFO]

1=TEXT_POS,Arial,TRUE,FALSE,-13,65535l,310,46,54,14,

2=TEXT_LEN,Arial,TRUE,FALSE,-13,65535l,260,46,54,14,

3=TEXT_HINT,Arial,FALSE,FALSE,-13,0l,19,46,200,14,

4=TEXT_SONG,Arial,FALSE,FALSE,-13,0l,19,25,352,14,

  可以看出,该文件主要存储了所需要的图片的文件名,以及各个按钮的名称、坐标以及提示信息
(tool tip)等等,其实具体存储哪些信息可由程序员自己定义,比如你当然可以存储菜单的颜色
(oicq中就是这样存的)。

  好了,原材料都准备好了,下面就看怎么加工了。

  程序开始执行后,我们处理WM_INITDIALOG消息,根据mask.bmp生成一个区域,并基于此区域使窗口不
规则化。然后在处理WM_PAINT消息时把main.bmp贴到窗口中,这时我们的窗口实际上已经穿上了一层漂亮
的skin。但它还不能响应用户事件。要想具备响应能力,下面有两种方案:

  第一种:这种方案生成了一系列控件窗口。

  根据skin.ini中存储的各控件的坐标,生成窗口(按钮、标签等等),设置其属性位自绘(OWNERDRAW),
并将它们子类化(SUBCLASS),使之响应WM_DRAWITEM(某些窗口如按钮、菜单等)或者WM_PAINT消息。在这
些消息的处理函数里面根据窗口的当前状态(鼠标未移动到窗口、鼠标移动到窗口中和鼠标选中)从相对应
的图片(main.bmp、move.bmp和select.bmp)中提取出相应的小图片(即控件对应的图片)。提取方法是根
据skin.ini保存的窗口坐标,用BitBlt函数从源图贴到控件窗口中。还要响应鼠标事件,在响应函数里面除
了上述的外表绘制工作外,还应加入实际应用有关的处理。

  第二种:这种方案并不生成任何控件窗口。

  在程序的主窗口的窗口函数里响应鼠标事件,当鼠标移动到某个“控件”(实际上是控件所在的矩形区
域,区域的坐标可以从skin.ini里得到)里面时,从move.bmp中提取出对应“控件”的小图片,在“控件”
所在位置加以显示。提取办法与第一中方案相同。同样地,当鼠标选中某个“控件”时,则从select.bmp中
提取出对应“控件”的小图片,在“控件”所在位置加以显示。

  好了,到现在我们对skin技术已经有了一定的了解。可以看出,其实现原理实际上并不困难,我们完全
可以做到。当然,有些skin的实现与这里所说的看起来是不相同的,它们既没有图片,也没有skin.ini,其
实它们只不过把图片放到程序的资源中去了,控件的坐标信息放到程序中去了而已,归根结底原理是大同小
异的。本文偏重原理分析,如果有机会我会做一个例子来加以说明。
 
BitBlt()函数只能切割方形的区域,但是如果图片按钮是一个不规则的图形(就好像金山影霸的蝴蝶的界面),这样用BitBlt()
函数好像做不到啊。还没有什么解决的方法啊。多帮忙啦。谢谢!
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
D
回复
0
查看
2K
DelphiTeacher的专栏
D
后退
顶部