【转】不用双缓冲实现无闪烁图象

No Comments

http://hi.baidu.com/techicey/blog/item/16a55ffcec749cf6fd037f19.html

首先说一下产生闪烁的原因,当窗口由于任何原因需要重绘时,总是先用背景色或背景图象将显示区清除,然后才显示图象,这样在短时间内背景色与显示图形交替出现,使得显示窗口看起来在闪。如果将背景刷设置成NULL,这样无论怎样重绘图形都不会闪了,但是会使得窗口的显示乱成一团,因为重绘时没有背景色对原来绘制的图形进行清除,而又叠加上了新的图形。

一般的解决方法就是采用双缓冲,创建一幅内存图象,把背景和图片先绘制到该图象,然后把绘制好的该图象显示到窗口,这样就不会产生闪烁,其实就是隐藏了图象的显示过程,原来是在前台,给你看到先在画布上刷上背景,再画上图象,现在是在后台画好了再拿出来给你看。

看起来好象解决方法是需要一次性绘制好图象,其实关键是不能让任何背景及图片在绘制时产生重叠,跟是否一次性绘制没多大关系。电脑的绘制速度还是很快的,不信可以试试把背景刷设置成NULL,这样不会闪烁,然后循环调用BitBlt把一幅小图片铺满整个窗口,虽然是多次绘制,一样不会闪烁,但是如果改变一下循环步长,让图片产生重叠,就会开始闪烁了。

知道了闪烁的原因,不用双缓冲的解决办法就不难找到了,调用ExcludeClipRect,可以排除掉绘制区域,先绘制图片,ExcludeClipRect掉图片的区域,再绘制背景,相当于把一幅挖了一个洞的画布贴到窗口,这样不产生绘制重叠部分,就不会产生闪烁了。

API代码,始终在窗口右下角显示一幅300*200的图片,窗口背景为黑色:

case WM_PAINT:
{
PAINTSTRUCT ps;
RECT rc;
HDC hMemDC;

GetClientRect(hWnd,&rc);
BeginPaint(hWnd,&ps);
hMemDC = CreateCompatibleDC(ps.hdc);
SelectObject(hMemDC,hbmp);
BitBlt(ps.hdc,rc.right-300,rc.bottom-200,300,200,hMemDC,0,0,SRCCOPY);
ExcludeClipRect(ps.hdc,rc.right-300,rc.bottom-200,rc.right,rc.bottom);
FillRect(ps.hdc,&rc,(HBRUSH)GetStockObject(BLACK_BRUSH));
DeleteDC(hMemDC);
EndPaint(m_hWnd,&ps);
return 0;
}

有时候因为刷新区域的问题,可能调整窗口但是WM_PAINT的代码不起作用,这时需要响应WM_SIZE消息,通知画面更新一下:
case WM_SIZE:
InvalidateRect(hWnd,NULL,FALSE);
break;

对于显示多幅图象,这个方法也是适用的,只要每绘制完一幅图象,ExcludeClipRect掉该图象区域就可以,但是注意如果图象有重叠,绘制顺序是反过来的,即盖在最上面的图象需要最先绘制,最后给整个窗口刷上背景就OK了。

[转]WTL学习笔记之NM_CUSTOMDRAW和WM_DRAWITEM

No Comments

最近在学习《WTL for MFC Programmer》系列文章的一些小结和感受
相同点:
1.都是通知消息,都可以被反射回控件类自行处理。
2.都和自定义控件的绘画有关。
区别:
MSDN对WM_DRAWITEM描述:
The WM_DRAWITEM message is sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
MSDN对NM_CUSTOMDRAW的描述:
Sent by some common controls to notify their parent windows about drawing operations. This notification is sent in the form of a WM_NOTIFY message.
1.可以看出,前者是对Owner-Draw风格的按钮,复选框,列表框和菜单有效的,树形控件并没在此列。所以在系列文章的第五篇中,自定义按钮是继承了COwnerDraw,树形控件是继承了CCustomDraw,MSDN中也列出了一些NM_CUSTOMDRAW有关的控件:
List view
NMLVCUSTOMDRAW
ToolTip
NMTTCUSTOMDRAW
Tree view
NMTVCUSTOMDRAW
Toolbar
NMTBCUSTOMDRAW
All other supported controls
NMCUSTOMDRAW
2.前者若想进行一些gdi动作,那基本上就是整个区域需要绘画,gdi的一些操作比较多,后者使用更简单,一些属性(比如字体颜色)只需要设置一些变量即可。
3.前者是一个独立的消息,后者是被包含在WM_NOTIFY消息中被发送的。
4.NM_CUSTOMDRAW分好多个阶段,可以通过重载某些方法来改变行为,这些方法包括OnPrePaint, OnItemPrePaint等等(细节只能看wtl源代码了,MSDN中也稍有介绍)。
猜测:他们应用在不同的控件上,但是NM_CUSTOMDRAW貌似是WM_DRAWITEM的加强版,呵呵
欢迎大家多多批评指教~
以下是在MSDN上找到的一些解释,链接是相关的一篇文章地址
所有者绘制
控制控件绘制的另一种方法是利用所有者绘制。事实上,您也许听开发人员提到过所有者 绘制控件,因为它是用于开发自定义控件最普通的技术。该技术普遍使用的主要原因在于,Windows 可为您提供很多帮助。在呈现控件的那一刻,Windows 就已经创建并填写了设备上下文,决定了控件的大小和位置,并且向您传递信息以使您了解此刻绘制的需求。对于列表控件(例如,列表框和列表视图), Windows 将为列表中的每一项调用绘制代码,这意味着您只需绘制这些项,而无需考虑控件的其他方面。注意,所有者绘制可用于大多数控件。然而,它不能用于编辑控件; 并且考虑到列表控件,它只能用于报表视图样式。
自定义绘制
对于绘制自己的控件而言,这可能是最少 为人所知的技术。事实上,许多技术能力较高的开发人员也混淆了术语所有者绘制 (owner-draw) 和自定义绘制 (custom-draw)。关于自定义控件,首先需要了解,它仅针对于指定的公共控件:标头、列表视图、rebar、工具栏、工具提示、跟踪条和树视 图。此外,尽管所有者绘制只允许绘制报告视图风格的列表视图控件,而自定义绘制则使您能够处理列表视图控件所有视图风格的绘制。使用自定义绘制的另一个明 显优势是,您可以对希望绘制的内容进行严格挑选。实现方式是,在控件绘制的每个阶段由 Windows 向代码发送一个消息。这样,您可以决定在每个阶段是自己进行所有的绘制工作,增加默认的绘制,还是允许 Windows 为该阶段执行所有的绘制。(鉴于自定义绘制是本文的一个主题,因此您很快会看到它的工作方式。)
文章地址: http://msdn2.microsoft.com/zh-cn/library/ms364048(VS.80).aspx

最近在学习《WTL for MFC Programmer》系列文章的一些小结和感受相同点:1.都是通知消息,都可以被反射回控件类自行处理。2.都和自定义控件的绘画有关。
区别:MSDN对WM_DRAWITEM描述:The WM_DRAWITEM message is sent to the parent window of an owner-drawn button, combo box, list box, or menu when a visual aspect of the button, combo box, list box, or menu has changed.
MSDN对NM_CUSTOMDRAW的描述:Sent by some common controls to notify their parent windows about drawing operations. This notification is sent in the form of a WM_NOTIFY message.
1.可以看出,前者是对Owner-Draw风格的按钮,复选框,列表框和菜单有效的,树形控件并没在此列。所以在系列文章的第五篇中,自定义按钮是继承了COwnerDraw,树形控件是继承了CCustomDraw,MSDN中也列出了一些NM_CUSTOMDRAW有关的控件:List view    NMLVCUSTOMDRAWToolTip    NMTTCUSTOMDRAWTree view    NMTVCUSTOMDRAWToolbar    NMTBCUSTOMDRAWAll other supported controls    NMCUSTOMDRAW2.前者若想进行一些gdi动作,那基本上就是整个区域需要绘画,gdi的一些操作比较多,后者使用更简单,一些属性(比如字体颜色)只需要设置一些变量即可。3.前者是一个独立的消息,后者是被包含在WM_NOTIFY消息中被发送的。4.NM_CUSTOMDRAW分好多个阶段,可以通过重载某些方法来改变行为,这些方法包括OnPrePaint, OnItemPrePaint等等(细节只能看wtl源代码了,MSDN中也稍有介绍)。
猜测:他们应用在不同的控件上,但是NM_CUSTOMDRAW貌似是WM_DRAWITEM的加强版,呵呵欢迎大家多多批评指教~
以下是在MSDN上找到的一些解释,链接是相关的一篇文章地址所有者绘制
控制控件绘制的另一种方法是利用所有者绘制。事实上,您也许听开发人员提到过所有者 绘制控件,因为它是用于开发自定义控件最普通的技术。该技术普遍使用的主要原因在于,Windows 可为您提供很多帮助。在呈现控件的那一刻,Windows 就已经创建并填写了设备上下文,决定了控件的大小和位置,并且向您传递信息以使您了解此刻绘制的需求。对于列表控件(例如,列表框和列表视图), Windows 将为列表中的每一项调用绘制代码,这意味着您只需绘制这些项,而无需考虑控件的其他方面。注意,所有者绘制可用于大多数控件。然而,它不能用于编辑控件; 并且考虑到列表控件,它只能用于报表视图样式。
自定义绘制
对于绘制自己的控件而言,这可能是最少 为人所知的技术。事实上,许多技术能力较高的开发人员也混淆了术语所有者绘制 (owner-draw) 和自定义绘制 (custom-draw)。关于自定义控件,首先需要了解,它仅针对于指定的公共控件:标头、列表视图、rebar、工具栏、工具提示、跟踪条和树视 图。此外,尽管所有者绘制只允许绘制报告视图风格的列表视图控件,而自定义绘制则使您能够处理列表视图控件所有视图风格的绘制。使用自定义绘制的另一个明 显优势是,您可以对希望绘制的内容进行严格挑选。实现方式是,在控件绘制的每个阶段由 Windows 向代码发送一个消息。这样,您可以决定在每个阶段是自己进行所有的绘制工作,增加默认的绘制,还是允许 Windows 为该阶段执行所有的绘制。(鉴于自定义绘制是本文的一个主题,因此您很快会看到它的工作方式。)
文章地址: http://msdn2.microsoft.com/zh-cn/library/ms364048(VS.80).aspx

重装OS的一些笔记

No Comments

windows 7 系统下安装Windows 7

http://www.21andy.com/blog/20090827/1349.html
1、下载 Windows 7 ISO镜像,用虚拟光驱拷贝至非C盘(如d:\win7)
2、开机按F8 – 修复系统 – 选择最后一项命令修复 – 在命令框输入 d:\win7\sources\setup.exe,开始安装
3、进入安装界面、选择custom安装
4、选择安装语言、格式化C盘
5、OK了,装好后是一个纯系统(非双系统)。

Windows 7下硬盘安装Ubuntu 10.04

http://www.linuxidc.com/Linux/2010-05/25875.htm

、在Windows7中下载并安装EasyBCD_1.7.2

2、将 Ubuntu-10.04-desktop-i386.iso文件复制到C盘根目录,用压缩软件打开,再打开casper目录,把initrd.lz、 vmlinuz二个文件解压到C盘根目录下。

3、运行EasyBCD_1.7.2进入操作窗口后,
点Add/Remove Entries
再点右下边的NeoGrub
再点Install NeoGrub
再点Save
选中NeoGrub Bootloader,再点Configure

4、在出现menu.lst记事本窗口中输入以下内容并保存:
root
kernel /vmlinuz iso-scan/filename=/Ubuntu-10.04-desktop-i386.iso boot=casper splash
initrd /initrd.lz
boot

5、电脑重启后,就会发现启动菜单会多了一项NeoGrub Bootloader,选择后会进入Ubuntu 10.04光盘系统。按快捷键运行(Alt+F2),在运行框内输入:
sudo umount -l /isodevice

最后点桌面上的Ubuntu安装图标及可开始正常安装
安装成功后,重启电脑会直接进入Ubuntu 10.04,打开终端输入以下命令:
sudo update-grub
再次重启及可出现Windows7引导菜单

Recover Grub 2 via LiveCD

https://wiki.ubuntu.com/Grub2#Recover%20Grub%202%20via%20LiveCD

  • First, grab a copy of the latest Ubuntu LiveCD and boot it.
  • Open a terminal and type

$ sudo fdisk -l

  • Now, you need to remember which device listed is your linux distribution, for reference, /dev/sda1 will be used. Now we need to mount the filesystem to /mnt

$ sudo mount /dev/sda1 /mnt

  • If you have /boot on a separate partition, that need’s to be mounted aswell. For reference, /dev/sda2 will be used.

$ sudo mount /dev/sda2 /mnt/boot Make sure you don’t mix these up, pay attention to the output of FDISK

  • Now mount the rest of your devices and some other things needed in the chroot

$ sudo mount --bind /dev /mnt/dev
$ sudo mount --bind /proc /mnt/proc
$ sudo mount --bind /sys /mnt/sys

  • Now chroot into your system

$ sudo chroot /mnt

You should be chroot’d into your system as root, you can now run commands as root, without the need for sudo.

  • Now you need to edit the /etc/default/grub file to fit your system

$ nano /etc/default/grub

  • When that is done you need to run update-grub to create the configuration file. If you have a separate /boot partition you need to mount it first!

$ update-grub

  • To install GRUB 2 to the MBR, next you need to run grub-install /dev/sda

$ grub-install /dev/sda

  • If you encounter any errors, try grub-install –recheck /dev/sda

$ grub-install --recheck /dev/sda

  • Press Ctrl+D to exit out of the chroot.
  • Once you exit back to your regular console, undo all the mounting, first the /dev and others

$ sudo umount /mnt/dev
$ sudo umount /mnt/sys
$ sudo umount /mnt/proc

  • Now you can unmount the root system. (But if you have a separate boot partition which you mounted earlier, you have to unmount this first, or you will get a “device busy” error message.)

$ sudo umount /mnt

  • And you should be free to restart your system right into GRUB 2 and then into your system installation.

If you had alternate OS entries, update-grub might say “Cannot find list of partitions!”. Ignore it and continue – once you can boot into your linux installation, do so and then rerun update-grub and grub-install /dev/sda as root.

WinInet, WinHttp, Winsock, ws2_32的基本解释

No Comments

http://www.hackpig.cn/post/500.html

在Windows平台进行网络程序开发, 可以使用不同的库, 但是最常用的还是微软自己开发的库。具体说来,有:

(1)Winsock,工作于网络层和传输层的开发库,对于编写TCP,UDP,以及原始IP通信程序非常合适。函数原形也基本符合Unix socket标准。Windows平台上的大多数程序,如QQ,讯雷等都基于其开发。

(2)ws2_32,是Winsock的升级版本,在兼容的基础上增加了不符合Unix socket标准,但更适合Windows平台的库函数,一般以WSA*开头。

现代的大多数Windows平台程序也都开始依赖于此库。

(3)WinInet,Windows Internet扩展库,工作于应用协议层,提供了http,ftp,gopher协议的实现,为基于以上三种协议的程序开发提供基础平台,需要说明的是,尽管WinInet工作于应用层,但其本身wininet.dll的实现并不依赖于winsock.dll或ws2_32.dll,而是独立存在的。至少目前的版本是这样。基于WinInet的应用程序最著名的例子就是IE了。

(4)WinHttp,也是工作于应用协议层,提供了http协议的实现。看起来与WinInet有重复的部分,没错,WinHttp就是为了替换WinInet中的http部分的,它更加健壮稳定,而且还为http服务器端开发提供了库函数。如果进行现代http的开发,建议使用WinHTTP而不是WinInet。使用WinHTTP进行开发的著名例子就是Google的浏览器Chrome,但是Chrome2.0以后版本google放弃了winhttp而是使用了自己开发的http库,这也是为了使chrome实现跨平台的重要举措。另外,WinHttp.dll也不依赖于winsock或ws2_32,也是独立运行的。

如果基于socket编程的话,Winows平台与其它平台函数基本相同,实现跨平台比较容易。

如果基于http进行编程的话,不同平台库差别很大,如果不考虑跨平台使用WinHttp,如果考虑跨平台可以考虑使用libwww。

另外,wsock和wininet或winhttp也可以同时使用。

LZ78算法

No Comments

http://202.117.96.226:8090/dmtjs/course/ch04/tcp040404.html?ttype=1&tcode=menu4_040404

4.4.4 LZ78算法

在介绍LZ78算法之前,首先说明在算法中用到的几个术语和符号:

  1. 字符流(Charstream):要被编码的数据序列。
  2. 字符(Character):字符流中的基本数据单元。
  3. 前缀(Prefix): 在一个字符之前的字符序列。
  4. 缀-符串(String):前缀+字符。
  5. 码字(Code word):码字流中的基本数据单元,代表词典中的一串字符。
  6. 码字流(Codestream): 码字和字符组成的序列,是编码器的输出。
  7. 词典(Dictionary): 缀-符串表。按照词典中的索引号对每条缀-符串(String)指定一个码字(Code word)。
  8. 当前前缀(Current prefix):在编码算法中使用,指当前正在处理的前缀,用符号P表示。
  9. 当前字符(Current character):在编码算法中使用,指当前前缀之后的字符,用符号C表示。
  10. 当前码字(Current code word): 在译码算法中使用,指当前处理的码字,用W表示当前码字,String.W表示当前码字的缀-符串。

1. 编码算法

          LZ78的编码思想是不断地从字符流中提取新的缀-符串(String),通俗地理解为新“词条”,然后用“代号”也就是码字(Code word)表示这个“词条”。这样一来,对字符流的编码就变成了用码字(Code word)去替换字符流(Charstream),生成码字流(Codestream),从而达到压缩数据的目的。

          在编码开始时词典是空的,不包含任何缀-符串(string)。在这种情况下编码器就输出一个表示空字符串的特殊码字(例如“0”)和字符流中(Charstream)的第一个字符C,并把这个字符C添加到词典中作为一个由一个字符组成的缀-符串(string)。在编码过程中,如果出现类似的情况,也照此办理。在词典中已经包含某些缀-符串(String)之后,如果“当前前缀P +当前字符C”已经在词典中,就用字符C来扩展这个前缀,这样的扩展操作一直重复到获得一个在词典中没有的缀-符串(String)为止。此时就输出表示当前前缀P的码字(Code word)和字符C,并把P+C添加到词典中作为前缀(Prefix),然后开始处理字符流(Charstream)中的下一个前缀。

         LZ78编码器的输出是码字-字符(W,C)对,每次输出一对到码字流中,与码字W相对应的缀-符串(String)用字符C进行扩展生成新的缀-符串(String),然后添加到词典中。LZ78编码的具体算法如下:

步骤1: 在开始时,词典和当前前缀P都是空的。
步骤2: 当前字符C :=字符流中的下一个字符。
步骤3: 判断P+C是否在词典中:

  1. 如果“是”:用C扩展P,让P := P+C ;
  2. 如果“否”:
    1. 输出与当前前缀P相对应的码字和当前字符C;
    2. 把字符串P+C 添加到词典中。
    3. 令P :=空值。
  3. 判断字符流中是否还有字符需要编码
    1. 如果“是”:返回到步骤2。
    2. 如果“否”:若当前前缀P不是空的,输出相应于当前前缀P的码字,然后结束编码。

2. 译码算法

在译码开始时译码词典是空的,它将在译码过程中从码字流中重构。每当从码字流中读入一对码字-字符(W,C)对时,码字就参考已经在词典中的缀-符串,然后把当前码字的缀-符串string.W 和字符C输出到字符流(Charstream),而把当前缀-符串(string.W+C)添加到词典中。在译码结束之后,重构的词典与编码时生成的词典完全相同。LZ78译码的具体算法如下:
步骤1: 在开始时词典是空的。
步骤2: 当前码字W :=码字流中的下一个码字。
步骤3: 当前字符C := 紧随码字之后的字符。
步骤4: 把当前码字的缀-符串(string.W)输出到字符流(Charstream),然后输出字符C。
步骤5: 把string.W+C添加到词典中。
步骤6: 判断码字流中是否还有码字要译

  1. 如果“是”,就返回到步骤2。
  2. 如果“否”,则结束。

[例4.6] 编码字符串如表4-13所示,编码过程如表4-14所示。现说明如下:
(1) “步骤”栏表示编码步骤。
(2) “位置”栏表示在输入数据中的当前位置。
(3) “词典”栏表示添加到词典中的缀-符串,缀-符串的索引等于“步骤”序号。
(4) “输出”栏以(当前码字W, 当前字符C)简化为(W, C)的形式输出。

表4-13 编码字符串

位置    1    2    3    4    5    6    7    8    9
字符    A    B    B    C    B    C    A    B    A

表4-14 编码过程

步骤    位置    词典    输出
1         1        A        (0,A)
2         2        B       (0,B)
3         3       B C     (2,C)
4         5      B C A   (3,A)
5         8      B A      (2,A)

与LZ77相比,LZ78的最大优点是在每个编码步骤中减少了缀-符串(String)比较的数目,而压缩率与LZ77类似。

Older Entries