Ross Wan's World!

Python, Ajax, PHP and Linux.

Archive for the ‘Uncategorized’ Category

The Python Challenge Lv.5

Posted by Ross Wan 于 2011/08/24

Lv.5

打开第5关的网页,显示的是一个山丘的图片,提示”pronounce it”???完全没有头绪.再看看网页的源代码,发现一个”可疑”的标签:

<peakhell src=”banner.p”/>

下载到 banner.p 这个文件,用文本编辑器打开,又是一堆字符,似有似无规律的字符.再看看网页源代码里的一行注释:

<!– peak hell sounds familiar ? –>

peak hell 的发音似什么?完全没有头绪……最后,Google到一点提示,确是无奈之举:< 原来关键是 pickle,它的发音跟 ‘peak hell’ 有点相似.真是晕倒~~~既然有这个关键的提示,下面就容易得多了:

import pickle

if __name__ == '__main__':
    f = open('banner.p', 'rb')
    obj = pickle.load(f)
    print('Objcet type: %s\n\n' %type(obj))
    print(obj)
    f.close()

首先,取得的对象是一个 list,而list的元素是由二元表列组成,而且,二元表列的第一个元素是” “或者”#”,第二个元素是数字.可猜测这是一个打印列表:

import pickle

if __name__ == '__main__':
    f = open('banner.p', 'rb')
    obj = pickle.load(f)
    f.close()
    new_file = open('new_file.txt', 'w')
    for line in obj:
        new_file.write(''.join([x*y for x,y in line]))
        new_file.write('\n')
    new_file.close()

上面的代码会将打印的字符写入 “new_file.txt” 这个文件里,不直接显示在系统 console 里主要是因为因某些 console 会自动断行,而显示不到最终的结果.

用编辑器打开(记得关闭编辑器的自动换行),会出现一个漂亮的图形,结果显而易见:

                                                                                              
              #####                                                                      #####
               ####                                                                       ####
               ####                                                                       ####
               ####                                                                       ####
               ####                                                                       ####
               ####                                                                       ####
               ####                                                                       ####
               ####                                                                       ####
      ###      ####   ###         ###       #####   ###    #####   ###          ###       ####
   ###   ##    #### #######     ##  ###      #### #######   #### #######     ###  ###     ####
  ###     ###  #####    ####   ###   ####    #####    ####  #####    ####   ###     ###   ####
 ###           ####     ####   ###    ###    ####     ####  ####     ####  ###      ####  ####
 ###           ####     ####          ###    ####     ####  ####     ####  ###       ###  ####
####           ####     ####     ##   ###    ####     ####  ####     #### ####       ###  ####
####           ####     ####   ##########    ####     ####  ####     #### ##############  ####
####           ####     ####  ###    ####    ####     ####  ####     #### ####            ####
####           ####     #### ####     ###    ####     ####  ####     #### ####            ####
 ###           ####     #### ####     ###    ####     ####  ####     ####  ###            ####
  ###      ##  ####     ####  ###    ####    ####     ####  ####     ####   ###      ##   ####
   ###    ##   ####     ####   ###########   ####     ####  ####     ####    ###    ##    ####
      ###     ######    #####    ##    #### ######    ###########    #####      ###      ######

可见,下一关的网址是: http://www.pythonchallenge.com/pc/def/channel.html

Have fun :)

Posted in Python, Uncategorized | Tagged: , , | Leave a Comment »

The Python Challenge Lv.3

Posted by Ross Wan 于 2011/08/20

Lv.3

One small letter, surrounded by EXACTLY three big bodyguards on each of its sides.

这关跟上一关一样,也是要解密网页源代码里的那一堆字符注释.根据上面的提示,要找出一些特殊的小写字母,它必须左右两边当且只有3个大字母,例如: bXXXaXXXc,字母a就符合要求.利用正则查找出这些字母来:

import re

if __name__ == '__main__':
    with open('mess.txt') as f:
        target_chars = []
        for line in f:
            target_chars.extend(re.findall(r'(?<=[^A-Z][A-Z]{3})[a-z](?=[A-Z]{3}[^A-Z])', '^'+line))
        target = ''.join(target_chars)
        print('Target characters: %s' % target)
        print('Next url: http://www.pythonchallenge.com/pc/def/%s.html' % target)
        f.close()

‘^’+line 在每行开头加上字符”^”(或者其它非大写字母),是为了让正则表达式匹配这个特殊情况,就是行字符串开头如这样:XXXaXXXb…,如果不在行开头加上一个非大写字符,上面的正则表达式是配置不到a字符的.

另外,在论坛区里,有人贴出这样的正则表达式:

r'([^A-Z][A-Z]{3}([a-z])[A-Z]{3}[^A-Z]’

但它会漏掉一些应匹配的小写字符,例如: ‘aXXXbXXXcXXXd’, 上面的正则表达式只匹配到’b’,没有匹配到’c’!(虽然对于本关,它一样可以得出正确的结果 :<)

运行脚本,得到如下结果:

Target characters: linkedlist

Next url: http://www.pythonchallenge.com/pc/def/linkedlist.html

得到下一关的网址: http://www.pythonchallenge.com/pc/def/linkedlist.html

Have fun :>

Posted in Python, Uncategorized | Tagged: , , | Leave a Comment »

reStructuredText: 自动处理 rst2html

Posted by Ross Wan 于 2011/08/19

因为经常都会使用到 reStructuredText,文档,Blog…等等.所以写了个自动处理 rst2html 的脚本myrst2html.py(Python 3.2):

#!/bin/python3
# coding=utf8

from docutils.core import publish_string
import sys, os, getopt

def get_last_modified_rst(path='.'):
    real_path = os.path.split(path)[0]
    last_modified_rst = ''
    last_modified = -1
    for rst in (x for x in os.listdir(path) if os.path.isfile(os.path.join(real_path,x)) and os.path.splitext(x)[1].lower()=='.rst'):
        rst = os.path.join(real_path, rst)
        rst_modified = os.path.getmtime(rst)
        if rst_modified > last_modified:
            last_modified = rst_modified
            last_modified_rst = rst
    return  last_modified_rst

def rst2html(rst_filename, target_filename=None):
    print(rst_filename)
    rst_file = open(rst_filename)
    print(1)
    source = rst_file.read()
    print(2)
    rst_file.close()
    print('Source: %s' % rst_filename)
    target_filename = target_filename and target_filename or os.path.splitext(rst_filename)[0]+'.html'
    target_file = open(target_filename, 'w')
    print('Target: %s' % target_filename)
    target_html = publish_string(
        source=source,
        writer_name='html',
        settings_overrides={'output_encoding': 'unicode'}
    )
    target_file.write(target_html)
    target_file.close()
    print('Done!')

def main():
    try:
        optlist, args = getopt.getopt(sys.argv[1:], '')
        rst_filename, target_filename = None, None
        if not args:
            last_rst = get_last_modified_rst()
            rst_filename = last_rst
        else:
            rst_filename, target_filename = (args + [None])[:2]
        rst2html(rst_filename, target_filename)
    except Exception as e:
        print(e)

if __name__ == '__main__':
    main()

执行方式:

python3 myrst2html.py [rst_file] [target_file]

参数 rst_file 和 target_file 分别是要转换的 rst 文件和转换的目标 html 文件.如果没提供 target_file, 则自动以 rst_file 命名目标文件;如果两个参数都不提供,则自动查找当前目录最后修改的 rst 文件,然后进行转换 :>

Have fun :)

Posted in Python, Uncategorized | Tagged: , , , | Leave a Comment »

The Python Challenge Lv.1

Posted by Ross Wan 于 2011/08/18

Lv.1

根据图片:

K->M

O->Q

E->G

可以猜到规律,就是将字母右移2位进行影射解密.字符影射翻译,Python str本身就提供了这方法: translate.

import string

mess = “””g fmnc wms bgblr rpylqjyrc gr zw fylb. rfyrq ufyr amknsrcpq ypc dmp. bmgle gr gl zw fylb gq glcddgagclr ylb rfyr’q ufw rfgq rcvr gq qm jmle. sqgle qrpgle.kyicrpylq() gq pcamkkclbcb. lmu ynnjw ml rfc spj. “””

translation = mess.translate(str.maketrans(string.ascii_letters, string.ascii_lowercase[2:]+’ab’+string.ascii_uppercase[2:]+’AB’))

print(translation)

得到以下译文:

“i hope you didnt translate it by hand. thats what computers are for. doing it in by hand is inefficient and that’s why this text is so long. using string.maketrans() is recommended. now apply on the url. “

根据译文的提示,对网页的 url 进行上面的字符影射翻译:

map -> ocr

得到下一关地址:

http://www.pythonchallenge.com/pc/def/ocr.html

Python 字符串提供的 translate 是相当方便的,假如不用这内置的方法,也是有很多办法解决的,毕竟这是有规律的字符影射:

for char in mess:
    print(ord(‘a’)<=ord(char)<=ord(‘z’) and chr((ord(char)+2-ord(‘a’))%26+ord(‘a’)) or char, end=”)

:) 这样这可以打印出上面的译文.

Have fun~~

Posted in Python, Uncategorized | Tagged: , , , | Leave a Comment »

Django: 将基于0.96的 Apps 迁移到 1.0

Posted by Ross Wan 于 2008/11/04

Django 1.0 发布后,其 API 基本上已经稳定下来,但它对以往的 0.9x 版本有不少的不兼容地方。这个教程就是帮助大家将基于 Django 0.96的项目或者 Apps(应用)迁移到 1.0。而且,网上大多数教程都是基于0.96的,了解0.96与1.0的兼容问题,有助于大家更好学习和利用以往的教程。

常见的变迁

这是用户从 Django 0.96迁移到1.0时最常遇到的需要作出的的变迁。

Unicode

Django 1.0已经完全使用 Unicode 字符串(如 u’foo’)。虽然在大多数情况下,使用普通的字符串(raw string)也不会出问题,但更新至 Unicode 字符串可以避免一些莫名其妙的问题。

详情参阅: Unicode data in Django

Models

maxlength 重命名为 max_length

这是为了统一字段格式。

__unicode__ 取代 __str__

将 model 里面的 __str__ 方法替换为 __unicode__ 方法,并且确保在 __unicode__ 方法内使用的字符串全部是 Unicode 字符串(如 u’foo’)。

移除 prepopulate_from 参数

移除 model 字段内的 prepopulate_from 参数,将它移到 admin.py 里的 ModelAdmin 类里面。

移除 core 参数

移除 model 字段内的 core 参数,因为 admin 接口现在已经提供相同的功能。你不必担心到影响 inline editing,可以放心的删除所有对 core 的引用。

admin.py 模块取代 Admin 类

移除所有 models 内的 Admin 内部类,因为它不起任何作用了。现在使用 admin.py 文件来注册 Apps 到 admin。当然,留着它不理也常会影响到应用的正常运行。

示例

0.96版本下的 models.py 文件的内容:

class Author(models.Model):
    first_name = models.CharField(maxlength=30)
    last_name = models.CharField(maxlength=30)
    slug = models.CharField(maxlength=60, prepopulate_from=('first_name', 'last_name'))

    class Admin:
        list_display = ['first_name', 'last_name']

    def __str__(self):
        return '%s %s' % (self.first_name, self.last_name)

1.0版本下的 models.py 文件的内容:

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    slug = models.CharField(max_length=60)

    def __unicode__(self):
        return u'%s %s' % (self.first_name, self.last_name)

1.0版本新增的 admin.py 文件的内容:

from django.contrib import admin
from models import Author

class AuthorAdmin(admin.ModelAdmin):
    list_display = ['first_name', 'last_name']
    prepopulated_fields = {
        'slug': ('first_name', 'last_name')
    }

admin.site.register(Author, AuthorAdmin)

Admin

一个全新、完全重构过的 Admin 后台管理接口,这是 Django 1.0最大的变化之一。Admin 现在并不需要在 modle 里面作定义。Admin 的框架使用 Django 新的 form-handing 库重写过,变得更为具扩展性。

这意味着你必须重写 Admin 类的定义。正如上面的示例,以前 models 内的 Admin 类的定义被 admin.py 文件内的 admin.site.register() 方法替代了。下面将详细讲解如何重写一个 Admin 的定义。

另见: djangosnippets 上的一个贡献者写了一个脚本,可以自动扫描 models.py 并生成相应的 admin.py 文件。

新的 inline 语法

新的 edit_inline 参数选项移至 admin.py。示例:

旧的0.96的 model.py:

class Parent(models.Model):
...

class Child(models.Model):
    parent = models.ForeignKey(Parent, edit_inline=models.STACKED, num_in_admin=3)

对应新的1.0的 admin.py:

class ChildInline(admin.StackedInline):
    model = Child
    extra = 3

class ParentAdmin(admin.ModelAdmin):
    model = Parent
    inlines = [ChildInline]

admin.site.register(Parent, ParentAdmin)

见: InlineModelAdmin objects 有详细的说明。

简化 fields 语法,或者使用 fieldsets

旧的语法同样可以照常使用,使需要用 fieldsets 代替 fields。

旧的0.96的 model.py:

class ModelOne(models.Model):
    ...

    class Admin:
        fields = (
            (None, {'fields': ('foo','bar')}),
        )

class ModelTwo(models.Model):
    ...

    class Admin:
        fields = (
            ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
            ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
        )

新的1.0的 admin.py:

class ModelOneAdmin(admin.ModelAdmin):
    fields = ('foo', 'bar')

class ModelTwoAdmin(admin.ModelAdmin):
    fieldsets = (
        ('group1', {'fields': ('foo','bar'),   'classes': 'collapse'}),
        ('group2', {'fields': ('spam','eggs'), 'classes': 'collapse wide'}),
    )

另见:

URLs

更新根目录下的 urls.py

如果需要使用 admin 来进行后台管理,你必须更新 root 下的 urls.py 文件。

旧的0.96的 urls.py:

from django.conf.urls.defaults import *

urlpatterns = patterns('',
    (r'^admin/', include('django.contrib.admin.urls')),

    # ... the rest of your URLs here ...
)

新的1.0的 urls.py:

from django.conf.urls.defaults import *

# The next two lines enable the admin and load each admin.py file:
from django.contrib import admin
admin.autodiscover()

urlpatterns = patterns('',
    (r'^admin/(.*)', admin.site.root),

    # ... the rest of your URLs here ...
)

Views

django.forms 替代 newforms

newforms 将被重命名为 forms,而 oldforms 将会被移除。如果你在应用中使用了 newforms,建议修改 import 语句:

旧的:

from django import newforms as forms

新的:

from django import forms

详情见 forms documentation

使用新的 API 处理上传的文件

旧的 API 将不再有效。示例:

像这样的上传的文件:

def my_view(request):
f = request.FILES['file_field_name']
...

你必须作如下的变迁:

Old (0.96) New (1.0)
f[‘content’] f.read()
f[‘filename’] f.name
f[‘content-type’] f.content_type

FileField

django.db.models.FileField 的内部现实已经改变了。假设一个 model 的 FileField 叫做 myfile,你必须作出如下的变迁:

Old (0.96) New (1.0)
myfile.get_content_filename() myfile.content.path
myfile.get_content_url() myfile.content.url
myfile.get_content_size() myfile.content.size
myfile.save_content_file() myfile.content.save()
myfile.get_content_width() myfile.content.width
myfile.get_content_height() myfile.content.height

Templates

Autoescapeing(自动转义)

现在,模板系统将对输出变量中的 HTML 标签自动进行转义操作。说情参看 Automatic HTML escaping

如果要禁用个别变量进行自动转义(auto-escaping),可以使用 safe 过滤器(filter):

默认会进行自动转义: {{ data }}
加上 safe 过滤器后会禁止进行转义: {{ data|safe }}

如果要对模板内的一部分输出内容禁止进行转义,可以使用 autoescape 标签(tag):

{% autoescape off %}
... 这部分内容将不会进行自动转义 ...
{% endautoescape %}

不常见的变迁

如果经过上面的处理,代码依然无法正常运行。请查阅:

Posted in Uncategorized | Tagged: , , , , , | Leave a Comment »

Archlinux:安装配置笔记

Posted by Ross Wan 于 2008/02/25

近段时间,从 Ubuntu 转到 Archlinux 下,渐渐地喜欢上 Archlinux 这个 Linux 发行版 :)首先,Archlinux 遵循 K.I.S.S 哲学,跟我不谋而合:) 其次,Archlinux 轻快,它是基于 i686 进行优化的,官方的 pkg 软件包也是基于 i686 的,而且它不会默认安装一些累赘的东西。当然,Pacman 的安装软件方式也是我喜欢它的原因。

Archlinx 的安装配置不算复杂,而且官方的 wiki 提供了详尽的参考文档。下面只是记录一些值得留意的地方。

在安装之前的准备

我是在 Windows 下硬盘安装的,方式跟硬盘安装 Ubuntu 差不多,都是利用 Grub for DOS 引导安装,网上也有不少的教程可以参阅。值得注意的地方是,从 0.8 版本开始,Archlinux 的安装盘 ISO 里已经包括了 PPPOE 和 HWDetect 工具,不用另外下载了 :)

挂载 ISO

在进入安装之前,提示按“Enter”键会得到一个临时的 Bash Console,如果是硬盘安装的话,必须在这里先行挂载 ISO:(假设 iso 文件放在 sda1)

#mkdir /root/win
#mount -t vfat /dev/sda1 /root/win
#mount -o loop -t iso9660 /root/win/Archlinux-i686-2007.08-2.core.iso /src

注意,在 Archlinux 下,IDE 硬盘的分区也被识别为 sdxx。

接下来就可以运行 /arch/setup 进行系统的安装。

挂载文件系统

安装的时候,会要求对硬盘进行分区,如果不想改动硬盘分区表或者保留数据,可以直接跳到“Set Filesystem Mountpoints”进行系统文件的挂载。首先要挂载的是 Swap 分区,然后是根分区,最后是自定义的分区,建议将 home 单独分区。挂载的时候,会询问是否格式化分区,可以选择否。

配置 rc.conf 文件

根据官方的文档进行配置就 OK 了,唯一要注意的地方是设置 local,对于中文来说,建议设置成“zh_CN.UTF-8”,不要写成“zh_CN.utf8”,因为可能造成一些问题。在 Deamons ,可以关闭 crond(!crond),它是计划任务来的,没什么用。在 MOD_BLACKIST,可以加入 net-pf-10 和 pcskr 来分别屏蔽 Ipv6 和系统的蜂鸣:

MOD_BLACKLIST=(net-pf-10 pcspkr)

配置 hosts 文件

这步骤很重要也很容易被忽略,很多人只在 rc.conf 里设置 hostname,而没有在这里设置。

127.0.0.1      localhost.localdomain   localhost yourname

yourname 为你在 rc.conf 的 hostname 设置的名字。

更新系统

建议在执行 #pacman -Syu 之前,先更新 pacman!

#pacman -Sy
#pacman -S pacman

在设置更新源方面,对于电信来说:

ftp://mirror.pacific.net.au/linux/archlinux
http://mirros.lcuc.org.cn/archlinux
ftp://cle.linux.org.tw/pub/ArchLinux
http://mirror.lupworld.com/archlinux

可以提高 pacman 的下载速度,使它支持多线程,具体可以参考网上教程。

配置 xorg.conf

除了使用 xorgconfig 来产生 xorg.conf 文件外,也可以使用:

#hwdetect -x

对于 ATI 的显卡,如果安装的驱动是 Catalyst ,必须将 fglrx 加入来 /etc/rc.conf 文件的 MODULES 里。然后使用下面的命令将 fglrx 模块加入到 xorg.conf 里:

aticonfig –initial

配置 PS/2 鼠标的滚轮

在 /etc/X11/xorg.conf 文件里找到鼠标的 InputDevice Section,将 Protocol 和 ZAxixMapping Option 修改为:

Option      “Protocol” “ExplorerPS/2”
Option      “ZAxisMapping” “4” “5”

配置 GDM

我是利用 GDM 来启动 Gnome 桌面的,如果想系统启动的时候默认进入 X,随了将 gdm 加入到 /etc/rc.conf 的 Deamons 里,还要修改 /etc/inittab 文件,将 “id:3:initdefault:” 改为 “id:5:initdefault:”。

用户和组

#useradd -m-s /bin/bash username

添加一个普通用户,并在 /home 下建立用户的主文件夹。

将用户添加入组:

#passwd usermod -aG audio,video,lp,optical,network,storage,wheel,dbus,hal,sys,power username

加入 power 组,允许用户重启和关机;如果想该用户管理系统,建议将其加和 sys 组。

保存音量

在 Gnome 桌面下,普通用户退出系统的时候可能不能保存音量设置。尝试以下的方法:

#pacman -S alsa-utils
#alsactl store

还不行的话,执行下面命令进行设置 ALSA:

#alsaconfig

编辑 Gnome 的菜单

建议安装 Alacarte 菜单编辑器,这也是 Ubuntu 下默认使用的菜单编辑器。

#pacman -S alacarte

Sudo

首先安装 Sudo:

#pacman -S sudo

编辑 /etc/sudoers 文件,建议使用 #visudo 来编辑!

yourname   ALL=(ALL) ALL
# 允许普通用户直接拔号…
yourname    ALL=NOPASSWD:/usr/sbin/pppoe-start
yourname    ALL=NOPASSWD:/usr/sbin/pppoe-stop
yourname    ALL=NOPASSWD:/usr/sbin/pppoe-status

Fcitx 输入法

官方的文档是建议修改用户的 ~/.bashrc 文件来启动 Fcitx 的,但可能导致 Gnome 下终端问题。所以,建议修改 ~/.xprofile 文件启动 Fcitx。

export LANG=en_US.UTF-8
export XMODIFIERS=@im=fcitx
export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
env LC_CTYPE=zh_CN.UTF-8
fcitx &

注销的问题

如果注销的时候显示“您目前正以 Unknown 的身份登录…”,可以执行:

#passwd -a yourname yourname

美化 LCD 字体

在官方的文档中(参见这里), 建议 LCD 用户安装 cairo-lcd、libxft-lcd、freetype2-lcd 来优化字体的显示。不过,freetype2-lcd 不能直接用 pacman 来安装,需要自己编译:( 对于普通新手来说,貌似有点难度,所以我编译了并提供下载:

http://wstudio.web.fc2.com/product/freetype2-lcd-2.3.5-3-i686.pkg.tar.gz

下载完之后进入文件所在目录,执行:

#pacman -U freetype2-lcd-2.3.5-3-i686.pkg.tar.gz

Posted in Uncategorized | 2 Comments »

wxPython 入门指南

Posted by Ross Wan 于 2008/02/11

什么是 wxPython?

       WxPython 是 C++ GUI 库 wxWidgets(以前叫 wxWindows) 的 Python 封装,目前,wxWidgets 是一个相当稳定、高效、面向对象的 GUI 库,而且可以运行在Windows、Unix(GTK/Motif/Lesstif)和 Macintosh 平台上。因此,wxPython 是一个可以开发跨平台 GUI 应用程序的工具集(toolkits),跟 pyQT、pyGTK 或者 Tkinter 相像。在 windows 下,不像 Tkinter 或者 pyGTK 的应用程序,wxPython 拥有跟 microsoft 本地 GUI MFC 开发的应用程序窗口相似的外观,因为 wxPython 是构建在本地 GUI classes 上的。还有,wxPython 非常简单,易于学习和使用。

第一个 wxPython 应用程序:“Hello,World”

       这是一个小巧的 “Hello,World”应应用程序,下面是代码:

#!/usr/bin/env python
import wx
app = wx.PySimpleApp()
frame = wx.Frame(None, wx.ID_ANY, “Hello World”)
frame.Show(True)
app.MainLoop()

       在 GTK 环境下,你将会看到如下效果:

        在引入 wxPython GUI(import wx)后,我们实例化一个新的 wxPySimpleAPP 和 wxFrame 对象。在 wxPython 里,一个 frame 是一个带有标题栏,最大化、最少化和关闭按钮…等等的窗口。然后我们通过 “.Show()”使这个 Frame 显示出来。最后,我们开始这个应用程序的 MainLoop,监视和处理窗口的事件。

       注意: wxFrame 构造函数的形式

wx.Frame(Parent, Id, “Hello World”)

        wxPython 大多数的构造函数都有相同的形式:一个父对象作为第一个传入参数,接着一个 ID 作为第二个参数。正如示例那样,可以传入 None 和 wx.ID_ANY 作为默认的参数(表示这个 Frame 对象没有父对象和系统识别的 ID)。

创建 wxPython 应用程序

       在这个部分,我们将创建一个小型的编辑器。这有助于你了解 wxPython 的潜在能力和使用便捷。

概述

       当人们在讨论 GUI 时,不外乎就是窗口、菜单、鼠标、图标等等。我很可能认为一个 wxWindow 对象表示一个显示在屏幕上的窗口?!但这是错误的想法!在 wxPython 里, 一个 wxWindow 是屏幕上可以显示的任意组件,它是所有可视元件的父类。wxWindow 定义所有可视 GUI 组件的通用的行为,包括定位(positioning)、显示(showing)、取得焦点(giving focus)等等。wxFrame 对象才是代表屏幕上显示的窗口,它继承于 wxWindow,实现了窗口所有的行为。所以,要创建一个窗口,请创建一个 wxFrame 对象(或者一个它的子类的对象,例如 wxDialog)。

一个实例

增加编辑组件(edit component)

       第一步,就是向我们的 “hello world”程序添加一个新的编辑组件:

#!/usr/bin/env python
import wx
class MainWindow(wx.Frame):
    “”” We simply derive a new class of Frame. “””
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(200,100))
        self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
        self.Show(True)
app = wx.PySimpleApp()
frame=MainWindow(None, wx.ID_ANY, ‘Small editor’)
app.MainLoop()

       注意:我们继承了 wxFrame 类并且重写了它的 __init__ 方法,在方法里面,定义了一个 一个简单的文本编辑组件 wx.TextCtrl。

增加菜单

import wx
ID_ABOUT=101
ID_EXIT=110
class MainWindow(wx.Frame):
    def __init__(self,parent,id,title):
        wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (200,100))
        self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
        self.CreateStatusBar() # A Statusbar in the bottom of the window 在窗口的下端创建一个状态栏
        # Setting up the menu 创建菜单
        filemenu= wx.Menu()
        filemenu.Append(ID_ABOUT, “&About”,” Information about this program”)
        filemenu.AppendSeparator()
        filemenu.Append(ID_EXIT,“E&xit”,” Terminate the program”)
        # Creating the menubar 创建菜单栏
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,“&File”) # Adding the “filemenu” to the MenuBar 向菜单栏添加“文件”菜单
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content 设置 Frame 窗口的菜单栏
        self.Show(True)
app = wx.PySimpleApp()
frame = MainWindow(None, -1, “Sample editor”)
app.MainLoop()

定义事件处理

       灵活的事件处理是 wxPython 的最大优点之一。 一个事件其实就是 wxPython 传递给应用程序的一个信息,表示有“某些事件”发生。通常,你要做的就是定义特定事件的处理方法。通过 EVT_* 来实现,如下:

EVT_MENU(self, ID_ABOUT, self.OnAbout)

       换句话说,现在 ID_ABOUT 菜单事件将绑定到 self.OnAbout 方法上。OnAbout 方法的一般定义如下:

def OnAbout(self, event):

       enent 是 wxEvent 的子类对象。当事件处理方法接收到一个事件时,它可以做两样事情:

  • 跳过这个事件
  • 捕获并处理这个事件

       现在再看看我们的程序:

import os
import wx
ID_ABOUT=101
ID_EXIT=110
class MainWindow(wx.Frame):
    def __init__(self,parent,id,title):
        wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (200,100))
        self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
        self.CreateStatusBar() # A Statusbar in the bottom of the window 在窗口的下端创建一个状态栏
        # Setting up the menu 创建菜单
        filemenu= wx.Menu()
        filemenu.Append(ID_ABOUT, “&About”,” Information about this program”)
        filemenu.AppendSeparator()
        filemenu.Append(ID_EXIT,“E&xit”,” Terminate the program”)
        # Creating the menubar 创建菜单栏
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,“&File”) # Adding the “filemenu” to the MenuBar 向菜单栏添加“文件”菜单
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content 设置 Frame 窗口的菜单栏
        wx.EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the method self.OnAbout 绑定事件
        wx.EVT_MENU(self, ID_EXIT, self.OnExit)   # attach the menu-event ID_EXIT to the method self.OnExit 绑定事件
        self.Show(True)
    def OnAbout(self,e):
        d= wx.MessageDialog( self, ” A sample editor \n”
                            ” in wxPython”,“About Sample Editor”, wx.OK)
                            # Create a message dialog box 创建一个消息对话框
        d.ShowModal() # Shows it 显示消息对话框
        d.Destroy() # finally destroy it when finished 完成后销毁
     def OnExit(self,e):
        self.Close(True)  # Close the frame 关闭窗口
app = wx.PySimpleApp()
frame = MainWindow(None, -1, “Sample editor”)
app.MainLoop()

更进一步

       如果一个编辑器不能保存或者打开文档,那么这个编辑器是没有用的。这需要使用到通用的对话框。下面是 OnOpen 方法的实现代码:

def OnOpen(self,e):
        “”” Open a file 打开文件”””
        self.dirname = ”
        dlg = wx.FileDialog(self, “Choose a file”, self.dirname, “”, “*.*”, wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.filename=dlg.GetFilename()
            self.dirname=dlg.GetDirectory()
            f=open(os.path.join(self.dirname,self.filename),’r’)
            self.control.SetValue(f.read())
            f.close()
        dlg.Destroy()

       在 OnOpen 方法里面:

  • 通过 wx.FileDialog 构造函数创建一个文件对话框。
  • 调用 ShowModal 方法,将会返回与用户所按按钮(OK 或者 Cancel 按钮)相对应的值。
  • 如果需要,我们可以取得所选文件的文件名和路径,并且将文件的内容输出在编辑器的文本域上。最后我们销毁这个对话框。

延伸

当然,目前这个编辑器跟像样的编辑器还有段距离,但是添加其它高级特性不会太艰难。你或许可以在上面的示例中得到灵感 :)

  • 拖放(Drag and Drop)
  • 多文档界面(MDI)
  • 标签式显示或者打开多个文件(Tab view/multiple files)
  • 查找或者替换对话框(Find/Replace dialog)
  • 打印对话框(Print dialog)
  • 宏命令支持(Macro-commands in Python using the eval function)


关于窗口(Windows)

       在这个部分,我们将讲述 wxPython 的 windows 以及 windows 的 contents。我们将会创建一个计算价格的应用程序的例子。

放置一个可视组件

       在一个 frame 里,我可以用一些 wxWindow 子类附加到 frame contents 上。以下是一些常用的组件:

  • wxMenuBar 菜单栏
  • wxStatusBar 状态栏
  • wxToolBar 工具栏
  • wxControl 的子类。是显示数据或者处理用户输入的组件,常见的 wxControl 包括 wxButton、wxStaticText、wxTextCtrl 和 wxComboBox。
  • wxPanel 可以容纳多种 wxControl 对象。可以按 Tab 键跳转 wxPanel 中的控件的焦点。

       所有的可视组件(wxWindow 对象和子对象)都能容纳子组件(sub-elements)。例如,wxFrame 可以容纳 wxPanel 对象,而 wxPanel 又可以容纳 wxButton、wxStaticText 和 wxTextCtrl 等对象。下面是一个完整的层次图:

       注意,这仅仅是描述某些可视组件的关联,而并不是他们放置在 frame 上的方式。要放置组件在 frame 上,有几个可选的方式:

  1. 通过精确的像素坐标,手工定位每个组件的在父窗口中的位置。但因为会遇到诸如在不同平台字体大小不同等问题,这个方式是不被推荐的。
  2. 使用 wxLayoutConstraints ,但十分复杂。
  3. 通过使用像 Delphi  方式的  LayoutAnchors,可以降低使用  wxLayoutConstraints 的难度。
  4. 使用 wxSizer 的子类。

       下面将集中讲解 Sizers。

Sizers

       一个 sizer(wxSizer 的子类)可以处理组件在窗口(window 或者 frame)中的可视布局:

  • 计算每个组件的合适大小。
  • 基于特定的准则定位组件的位置。
  • 当 frame 改变大小时,可以动态地改变组件的大小或者位置。

       常用的 sizers :

  • wxBoxSizer,顺序地安排组件的放置,可以垂直对齐或者水平对齐(horizontally or vertically)。
  • wxGridSizer,将组件放置在一个 Grid 结构上面。
  • wxFlexGridSizer,类似于 wxGridSizer,不同之处是,它提供更多的灵活性。

       可以通过 sizer.Add(window,options…) 或者 size(AddMany…) 来添加组件到 sizers。sizers 也可以嵌套。如下图:

       注意,上面也可以使用 wxGridSizer 实现,将6个 wxButton 放置在一个2行3列的 grid 上。

       在下面的例子里,我们利用2个嵌套的 sizers,外面的 sizer 是 vertical 布局,嵌套在里面的 sizer 是 horizontal 布局:

import os
import wx
ID_ABOUT=101
ID_OPEN=102
ID_EXIT=110
ID_EXIT=200
class MainWindow(wx.Frame):
    def __init__(self,parent,id,title):
        wx.Frame.__init__(self,parent,wx.ID_ANY, title, size = (200,100))
        self.control = wx.TextCtrl(self, 1, style=wx.TE_MULTILINE)
        self.CreateStatusBar() # A Statusbar in the bottom of the window 在窗口的下端创建一个状态栏
        # Setting up the menu 创建菜单
        filemenu= wx.Menu()
        filemenu.Append(ID_OPEN, “&Open”,” Open a file to edit”)
        filemenu.AppendSeparator()
        filemenu.Append(ID_ABOUT, “&About”,” Information about this program”)
        filemenu.AppendSeparator()
        filemenu.Append(ID_EXIT,“E&xit”,” Terminate the program”)
        # Creating the menubar 创建菜单栏
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,“&File”) # Adding the “filemenu” to the MenuBar 向菜单栏添加“文件”菜单
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content 设置 Frame 窗口的菜单栏
        wx.EVT_MENU(self, ID_ABOUT, self.OnAbout) # attach the menu-event ID_ABOUT to the method self.OnAbout 绑定事件
        wx.EVT_MENU(self, ID_EXIT, self.OnExit)   # attach the menu-event ID_EXIT to the method self.OnExit 绑定事件
        wx.EVT_MENU(self, ID_OPEN, self.OnOpen)
        self.sizer2 = wx.BoxSizer(wx.HORIZONTAL)
        self.buttons=[]
        for i in range(0,6):
            self.buttons.append(wx.Button(self, ID_BUTTON1+i, “Button &”+`i`))
            self.sizer2.Add(self.buttons[i],1,wx.EXPAND)
        # Use some sizers to see layout options
        self.sizer=wx.BoxSizer(wx.VERTICAL)
        self.sizer.Add(self.control,1,wx.EXPAND)
        self.sizer.Add(self.sizer2,0,wx.EXPAND)
        #Layout sizers
        self.SetSizer(self.sizer)
        self.SetAutoLayout(1)
        self.sizer.Fit(self)
        self.Show(1)
    def OnAbout(self,e):
        d= wx.MessageDialog( self, ” A sample editor \n”
                            ” in wxPython”,“About Sample Editor”, wx.OK)
                            # Create a message dialog box 创建一个消息对话框
        d.ShowModal() # Shows it 显示消息对话框
        d.Destroy() # finally destroy it when finished 完成后销毁
     def OnExit(self,e):
        self.Close(True)  # Close the frame 关闭窗口
     def OnOpen(self,e):
        “”” Open a file 打开文件”””
        dlg = wx.FileDialog(self, “Choose a file”, self.dirname, “”, “*.*”, wx.OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            self.filename=dlg.GetFilename()
            self.dirname=dlg.GetDirectory()
            f=open(os.path.join(self.dirname, self.filename),‘r’)
            self.control.SetValue(f.read())
            f.close()
        dlg.Destroy()
app = wx.PySimpleApp()
frame = MainWindow(None, -1, “Sample editor”)
app.MainLoop()

       sizer.Add 方法有3个参数:第1个参数指定添加进 sizer 的控件。第2个参数指定一个系数,相对于其它控件的大小比率,0  表示当前控件或者 sizer 不会变大。第3个参数通常是 wxGROW(或者 wxEXPAND),表示当前控件会根据需要被重设大小,如果设置为 wxSHAPED,sizer 里的控件会保持一致的 aspect ratio。

       如果第2个参数被设置为0,表示控件不会被重设大小,这时,第3个参数表示对齐方式,居中、垂直或者水平对齐 可以用 wxALIGN_CENTER_HORIZONTAL, wxALIGN_CENTER_VERTICAL 和 wxALIGN_CENTER。

       也可以选择 wxALIGN_LEFT,wxALIGN_TOP,wxALIGN_RIGHT,and wxALIGN_BOTTOM 的组合值。例如,默认的对齐方式是:wxALIGN_LEFT | wxALIGN_TOP。

       sizer  和 交窗口(parent window)的区别:sizer 是窗口的布局方式,而并不代表窗口本身!在上例中,6个按钮是被创建到父窗口上(frame 或者 window),而不是 sizer 上。如果你尝试创建一个可视的组件到 sizer 上的话(例如 wx.Button(sizer,…),程序将会崩溃!

       一旦你创建了可视的组件并添加到 sizers(或者嵌套的 sizers),你就可以让 frame 或者 window 重设 sizer:

window.SetSizer(sizer)
window.SetAutoLayout(true)
sizer.Fit(window)

       调用 .SetSizer() 设置 window(或者 frame)的 sizer。调用 .SetAutoLayout() 让 window 使用指定的 sizer 来布局里面的组件。最后,调用 .Fit() 让 sizer 计算所有元件的初始大小和位置。注意,你必须在 window 或者 frame 首次显示前对 sizer 进行设置(如果希望使用 sizers 对 content 进行布局的话)。

验证器(Validators)

       对于对话框或者输入表单,你可以设置一个验证器(wxValidator)来简化下面的数据操作:表单的数据加载,验证输入的数据或者从表单中提取数据。 wxValidator 也可以监听键盘或者输入域的其它事件。要使用一个验证器,你必须创建一个 wxValidator 的子类(wxTextValidator 或者 wxGenericalValidator 是 wxPython 的现成类)。然后调用 myInputField.SetValidator(myValidator) ,将 myValidator 与输入域关联。

       注意:你的 wxValidator 子类必须实现 wxValidator.clone() 方法。

一个实例

在 panel 上放置一个 label

import wx
class Form1(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        self.quote = wx.StaticText(self, -1, “Your quote :”, wx.Point(20, 30), wx.Size(200, -1))
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, ” Our first Control”)
Form1(frame,-1)
frame.Show(1)
app.MainLoop()

       注意下面这行代码:

        self.quote = wx.StaticText(self, -1, “Your quote :”, wx.Point(20, 30), wx.Size(200, -1))

       wx.Point 用作定位参数,wx.Size 参数是可选的。

增加更多控件

       下面介绍一些最常使用的控件:

  • wxButton 是最基本的控件。现在的代码来用绑定按钮的单击事件:

EVT_BUTTON(Control, Id, callback function)

  • wxTextCtrl 可以让用户输入一小行的文本,它可以触发两个事件:

EVT_TEXT(control, Id ,callback function )

        当文本发生改变时会触发。

EVT_CHAR(control,callback function )

       在文本域上按键时会触发。

  • wxComboBox 是一个组合框,类似于 wxTextCtrl,除了可能触发 wxTestCtrl 的事件外,wxComboBox 也有自己的事件:

EVT_COMBOBOX(control, id, callback function)

  • wxCheckBox 复选框。
  • wxRadioBox 单选框。

       下面是表单1(Form1)的代码:

import wx
class Form1(wx.Panel):
    def __init__(self, parent, id):
        wx.Panel.__init__(self, parent, id)
        self.quote = wx.StaticText(self, -1, “Your quote :”,wx.Point(20, 30))
        # A multiline TextCtrl – This is here to show how the events work in this program, don’t pay too much attention to it
        self.logger = wx.TextCtrl(self,5, “”,wx.Point(300,20), wx.Size(200,300),wx.TE_MULTILINE | wx.TE_READONLY)
        # A button
        self.button =wx.Button(self, 10, “Save”, wx.Point(200, 325))
        wx.EVT_BUTTON(self, 10, self.OnClick)
        # the edit control – one line version.
        self.lblname = wx.StaticText(self, -1, “Your name :”,wx.Point(20,60))
        self.editname = wx.TextCtrl(self, 20, “Enter here your name”, wx.Point(150, 60), wx.Size(140,-1))
        wx.EVT_TEXT(self, 20, self.EvtText)
         wx.EVT_CHAR(self.editname, self.EvtChar)
        # the combobox Control
        self.sampleList = [‘friends’, ‘advertising’, ‘web search’, ‘Yellow Pages’]
        self.lblhear = wx.StaticText(self,-1,“How did you hear from us ?”,wx.Point(20, 90))
        self.edithear=wx.ComboBox(self, 30, “”, wx.Point(150, 90), wx.Size(95, -1),
                   self.sampleList, wx.CB_DROPDOWN)
        wx.EVT_COMBOBOX(self, 30, self.EvtComboBox)
        wx.EVT_TEXT(self, 30, self.EvtText)
        # Checkbox
        self.insure = wx.CheckBox(self, 40, “Do you want Insured Shipment ?”,wx.Point(20,180))
        wx.EVT_CHECKBOX(self, 40,   self.EvtCheckBox)
        # Radio Boxes
        self.radioList = [‘blue’, ‘red’, ‘yellow’, ‘orange’, ‘green’, ‘purple’,
                      ‘navy blue’, ‘black’, ‘gray’]
        rb = wx.RadioBox(self, 50, “What color would you like ?”, wx.Point(20, 210), wx.DefaultSize,
                        self.radioList, 3, wx.RA_SPECIFY_COLS)
        wx.EVT_RADIOBOX(self, 50, self.EvtRadioBox)
    def EvtRadioBox(self, event):
        self.logger.AppendText(‘EvtRadioBox: %d\n’ % event.GetInt())
    def EvtComboBox(self, event):
        self.logger.AppendText(‘EvtComboBox: %s\n’ % event.GetString())
    def OnClick(self,event):
        self.logger.AppendText(” Click on object with Id %d\n” %event.GetId())
    def EvtText(self, event):
        self.logger.AppendText(‘EvtText: %s\n’ % event.GetString())
    def EvtChar(self, event):
        self.logger.AppendText(‘EvtChar: %d\n’ % event.GetKeyCode())
        event.Skip()
    def EvtCheckBox(self, event):
        self.logger.AppendText(‘EvtCheckBox: %d\n’ % event.Checked())
app = wx.PySimpleApp()
frame = wx.Frame(None, -1, ” Quote Control”)
Form1(frame,-1)
frame.Show(1)
app.MainLoop()

       现在,这个类(Form1)包括了很多控件,我们定义了一个 wxTextCtrl 控件来显示控件发送的各种事件。

wxNoteBook

       有时,可能因为表单太大而不能在一页完全显示,这时可以使用 wxNoteBook。wxNoteBook 可以允许用户在多页间跳转,只需要单击相应的标签即可。我们用 wxNoteBook 代替 Form1 放置于 Frame 上,然后调用 wxNoteBook 的 AddPage 方法,将 Form1 放置在 wxNoteBook 上:

app = wx.PySimpleApp()
frame = wx.Frame(None,-1,” Demo with Notebook“)
nb = wx.Notebook(frame,-1)
form1=Form1(nb, -1)
nb.AddPage(form1, “Absolute Positioning”)
frame.Show(1)
app.MainLoop()

使用 Sizers 来改进组件的布局

       使用绝对的定位通常不能满足布局的要求,因为当窗口的大小改变,组件的布局也会随之改变,导致窗口的外观变得丑陋。庆幸的是,wxPython 提供丰富的类来改善组件的布局。

  • wxBoxSizer 是最常用的简单布局对象。它可以使一组组件成行或者成列的排列,有需要的时候会对它们进行重新的排列(例如全局的大小发生变化)。
  • wxGridSizer 和 wxFlexGridSizer 是两个非常重要的工具,使组件按照表格进行布局。

参考资料:

Posted in Uncategorized | 1 Comment »

两个 Alpha 发布:jQuery UI 1.5 和 jQuery Enchant 1.0

Posted by Ross Wan 于 2008/02/09

       jQuery UI 1.5 测试版对原先的源代码进行了一次翻修,修复了多处 bugs,而且对 API 进行了一些调整。目前这个测试版本还需要通过大量的测试,才能达到 Release Candidate。

       另外,一个新的插件 jQuery Enchant 将会带来大量高级的特效(像 clipshakeexplode)。

下载

示例

Posted in Uncategorized | Leave a Comment »

jQuery 1.2.3 发布

Posted by Ross Wan 于 2008/02/09

       在相隔 jQuery 1.2.2 发布不到一个月的时间,jQuery 1.2.3 发布了!这也是对 jQuery 1.2 的 Bug 修补版本。查看具体已修复的 Bugs ,可以单击这里

下载

       查看最新的 jQuery 源代码,可以使用下面的 Subversion 指令 Check out:

svn co http://jqueryjs.googlecode.com/svn/tags/1.2.3

关于更新

       这个版本主要修复了 jQuery 1.2.2 中的一对未解决的 bugs。从这个版本开始,会兼容 Adobe AIR,而且未来的 jQuery UI 1.5 将会基于 jQuery 1.2.3 。另外,增加了一些较小的特性,将有助于插件的开发者。

Posted in Uncategorized | Leave a Comment »

jQuery 1.2.2:两周年礼物

Posted by Ross Wan 于 2008/01/25

       1月15日,是 jQuery 的两周年纪念日,当天,jQuery 发布了新的版本 jQuery 1.2.2 作为生日礼物!新版本修补了旧版( jQuery 1.2 )的大量 Bug。详情可以查看 bug tracker

下载

       如果想查看 jQuery 的源代码,可以使用下面的 Subversion 指令 Check out:

svn co http://jqueryjs.googlecode.com/svn/tags/1.2.2

重要更新

       在这个版本中, Brandon Aaron 和 David Serduke 投入了大量的精力。虽然 David Serduke 是 jQuery 核心开发组的新晋成员,但他已经对 jQuery 作出了意义深远的贡献!

       jQuery 1.2.2 是一个 Bug 修补和性能优化的版本,它已经修补了120多个Bug,并且通过了1157多个测试。

$(DOMElement) 速度提升300%(300% Speed Improvements to $(DOMElement))

       通过微小的改进,jQuery 再次提升了一个台阶,这次提升特别有益将 Dom element 传递给 function 的参数。(例如:$(this))

       下面是几个主流浏览器的测试结果:

Browser 1.2.1 (ms) 1.2.2 (ms)
Firefox 2 0.041 0.015
Firefox 3 0.033 0.01
Safari 3 0.017 0.005
Opera 9 0.023 0.004
Internet Explorer 6 0.04 0.03

改进 .ready().(ready() Overhaul)

       以往的 $(document).ready() 实现代码过于冗长,在这个版本中,对它作了大量的改进。

  • 对 IE 浏览器的 $(document).ready() 作了一个彻底的改良。当中使用了一个新的技术,灵感来于 Diego Perini 。它的实现很巧妙,使得不再需要 document.write() :)
  • 对于所有浏览器,将会等待 CSS 加载并生效,像 DOM 的 .ready() 一样。特别地,使 Safari 和Opera 也可以实现这个功能。
  • $(document).bind(‘ready’,fn); ── 你现在可以通过传统的 .bind() 方法来绑定 document 的 ready 事件。当然,.ready() 方法仍然可以照常使用 :)

.bind(“mouseenter”) / .bind(“mouseleave”)

       .hover() 方法的核心功能将分拆成两个跨浏览器的事件:mouseenter 和 mouseleave。它们跟 mouseover 和 mouseout 不同(These are different from mouseover and mouseout as those events will fire as you move in and out of child elements (which is generally not desired))。例如,下面的两种实现都可以在 jQuery 1.2.2 上正常工作:

$(“li”).hover(function(){
  $(this).addClass(“hover”);
}, function(){
  $(this).removeClass(“hover”);
});

$(“li”).bind(“mouseenter”, function(){
  $(this).addClass(“hover”);
}).bind(“mouseleave”, function(){
  $(this).removeClass(“hover”);
});

.bind(“mousewheel”)

       基于 Brandon Aaron 的一个新的插件,jQuery 支持 mousewheel 事件。例如:

$(“div”).bind(“mousewheel”, function(event, delta){
  if ( delta < 0 )
    $(this).append(“up”);
  else
    $(this).append(“down”);
});

Complex :not()

       尽管 :not() 不是 CSS 3 规范的一部分,但它已经成了常规的功能请求。现在,你可以对 :not() selectors 使用复合的表达式。示例:

$(“.hover:not(li.active)”)

$(“li:not(.active,.hover,:contains(test))”)

Accept Headers

       对正常的 jQuery Ajax 操作,Ajax 现在发送额外的 Accept header ,使得服务器知道我们请求的 content 的类型。如果你指定了Ajax 的  dataType 参数,Ajax 将会小心处理所有的 header 设定。现在支持的 dataType 如下:

  • xml “application/xml, text/xml”
  • html “text/html”
  • script “text/javascript, application/javascript”
  • json “application/json, text/javascript”
  • text “text/plain”
  • Everything else: “*/*”

 Bug Fixes

       下面是部分重要的修补:

  • .clone() overhaul
  • Script evaluation overhaul
  • height() / width() overhaul
  • Cross-frame DOM manipulation
  • A few memory leaks have been resolved

Posted in Uncategorized | 1 Comment »