关于作者

用户名:yancy
笔名:yancy
地区:
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

快速通道

在线留言



GNU/linux

访问统计:
文章个数:51
评论个数:8
留言条数:0




Powered by BlogDriver 2.1

FreeArena

 

拥抱自由,拥抱GNU。

文章

多文件项目和 GNU Make 工具
摘要:作者:Goerge Foot 本文将首先介绍为什么要将你的C源代码分离成几个合理的独立档案,什么时 候需要分,怎么才能分的好。然后将会告诉你 GNU Make 怎样使你的编译和连 接步骤自动化。对于其它 Make 工具的用户来说,虽然在用其它类似工具时要 做适当的调整,本文的内容仍然是非常有用的。如果对你自己的编程工具有怀 疑,可以实际的试一试,但请先阅读用户手册。 查看全文

- 作者: yancy 2005年09月8日, 星期四 14:26  回复(0) |  引用(0) 加入博采

proc文件系统面面谈
摘要:http://www.linuxaid.com.cn 02-01-16 21:34 6414p ideal 查看全文

- 作者: yancy 2005年08月22日, 星期一 15:11  回复(0) |  引用(0) 加入博采

iptable tips
	echo -n "Create some usefull chains (IPv4): "
echo -n "LDROP "
$iptables -N LDROP
$iptables -A LDROP -p tcp -j LOG --log-level info --log-prefix "TCP Drop "
$iptables -A LDROP -p udp -j LOG --log-level info --log-prefix "UDP Drop "
$iptables -A LDROP -p icmp -j LOG --log-level info --log-prefix "ICMP Drop "
$iptables -A LDROP -p gre -j LOG --log-level info --log-prefix "GRE Drop "
$iptables -A LDROP -f -j LOG --log-level emerg --log-prefix "FRAG. Drop "
$iptables -A LDROP -j DROP

echo -n "WATCH "
$iptables -N WATCH
$iptables -A WATCH -m limit -j LOG --log-level warn --log-prefix "ACCEPT "
$iptables -A WATCH -j ACCEPT

# Log and drop portscans:
echo -n "SCAN "
$iptables -N SCAN
$iptables -A SCAN -m limit --limit 30/m -j LOG --log-prefix "PORTSCAN " --log-ip-options --log-tcp-options --log-level 1
$iptables -A SCAN -j DROP

# Log and drop DOS attacks:
echo -n "DOS "
$iptables -N DOS
$iptables -A DOS -p tcp --syn -m limit -j LOG --log-prefix "SYN Flood "
$iptables -A DOS -p icmp -m limit -j LOG --log-prefix "PING Flood "
$iptables -A DOS -j DROP

# if you want to use the following two chains you MUST adjust the limit to
# the expected rate of new connections. Same goes for ICMP echo request.
#
# Drop new connections (syn-flood protection):
echo -n "SAFEDROP "
$iptables -N SAFEDROP
$iptables -A SAFEDROP -p tcp -m state --state NEW -m limit --limit 1/s -j LDROP
$iptables -A SAFEDROP -p tcp -m state --state NEW -j DOS
$iptables -A SAFEDROP -j LDROP

# Accept new connections (syn-flood protection):
echo -n "SAFEACCEPT "
$iptables -N SAFEACCEPT
$iptables -A SAFEACCEPT -p tcp -m state --state NEW -m limit --limit 1/s -j ACCEPT
$iptables -A SAFEACCEPT -p udp -m state --state NEW -j ACCEPT
$iptables -A SAFEACCEPT -p tcp -m state --state NEW -j DOS

echo -n "ICMP "
# If you deny all ICMP messages you head for trouble since it would
# break lots of tcp/ip algorithm
$iptables -N ICMP
# Ping of death:
$iptables -A ICMP -p icmp --icmp-type echo-request -m limit --limit 1/s -j WATCH
# $iptables -A ICMP -p icmp --icmp-type echo-request -j DOS
# others:
$iptables -A ICMP -p icmp --icmp-type echo-reply -j ACCEPT
$iptables -A ICMP -p icmp --icmp-type destination-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type network-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type host-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type protocol-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type port-unreachable -j ACCEPT
$iptables -A ICMP -p icmp --icmp-type fragmentation-needed -j WATCH
$iptables -A ICMP -p icmp --icmp-type source-route-failed -j WATCH
$iptables -A ICMP -p icmp --icmp-type network-unknown -j WATCH
$iptables -A ICMP -p icmp --icmp-type host-unknown -j WATCH
$iptables -A ICMP -p icmp --icmp-type network-prohibited -j WATCH
$iptables -A ICMP -p icmp --icmp-type host-prohibited -j WATCH
$iptables -A ICMP -p icmp --icmp-type TOS-network-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type TOS-host-unreachable -j WATCH
$iptables -A ICMP -p icmp --icmp-type communication-prohibited -j WATCH
$iptables -A ICMP -p icmp --icmp-type host-precedence-violation -j LDROP
$iptables -A ICMP -p icmp --icmp-type precedence-cutoff -j LDROP
$iptables -A ICMP -p icmp --icmp-type source-quench -j WATCH
$iptables -A ICMP -p icmp --icmp-type redirect -j LDROP
$iptables -A ICMP -p icmp --icmp-type network-redirect -j LDROP
$iptables -A ICMP -p icmp --icmp-type host-redirect -j LDROP
$iptables -A ICMP -p icmp --icmp-type TOS-network-redirect -j LDROP
$iptables -A ICMP -p icmp --icmp-type TOS-host-redirect -j LDROP
$iptables -A ICMP -p icmp --icmp-type router-advertisement -j WATCH
$iptables -A ICMP -p icmp --icmp-type router-solicitation -j WATCH
$iptables -A ICMP -p icmp --icmp-type time-exceeded -j WATCH
$iptables -A ICMP -p icmp --icmp-type ttl-zero-during-transit -j WATCH
$iptables -A ICMP -p icmp --icmp-type ttl-zero-during-reassembly -j WATCH
$iptables -A ICMP -p icmp --icmp-type parameter-problem -j WATCH
$iptables -A ICMP -p icmp --icmp-type ip-header-bad -j WATCH
$iptables -A ICMP -p icmp --icmp-type required-option-missing -j WATCH
$iptables -A ICMP -p icmp --icmp-type timestamp-request -j LDROP
$iptables -A ICMP -p icmp --icmp-type timestamp-reply -j LDROP
$iptables -A ICMP -p icmp --icmp-type address-mask-request -j LDROP
$iptables -A ICMP -p icmp --icmp-type address-mask-reply -j LDROP
$iptables -A ICMP -p icmp -j LDROP
echo

- 作者: yancy 2005年08月22日, 星期一 14:38  回复(0) |  引用(0) 加入博采

RPM 打包技术与典型 SPEC 文件分析
摘要:杨爱林 Linux 研发工程师 2005 年 7 月 本文分为两部分,第一部分阐述了 rpm 工具的功能以及 rpmbuild 工具,详细的介绍了 spec文件的书写规则以及关键部分,第二部分对一个典型的 spec 文件做了详细的分析。 查看全文

- 作者: yancy 2005年07月25日, 星期一 12:50  回复(0) |  引用(0) 加入博采

使用WxPython进行Win32下Python编程(五)
 如果你检查wxPython窗口布局的工具条,会看到许多可用的选择,但我们选用了强制力机制作用于交易编辑对话框:

    # 创建控件
    wxStaticText(self, -1, "Date:", wxDLG_PNT(self, 5,5))
    self.date = wxTextCtrl(self, ID_DATE, "",
                      wxDLG_PNT(self, 35,5), wxDLG_SZE(self, 50,-1))

    wxStaticText(self, -1, "Comment:", wxDLG_PNT(self, 5,21))
    self.comment = wxTextCtrl(self, ID_COMMENT, "",
                      wxDLG_PNT(self, 35, 21), wxDLG_SZE(self, 195,-1)

  这些代码展示了如何在对话框上面创建标签和文本框。注意wxDLG_PNT和wxDLG_SZE的用法,它们分别将对话框单位转化为 wxPoint和wxSize。(上面用到的-1表示高度使用缺省尺寸。)不用像素而使用对话框单位来定义对话框意味着当对话框中使用的字体改变时不会受到太大的影响。wxPoint和wxSize总是用像素来定义的,这样当从一台机器转到另一台使用不同字体的机器上时,这些转换函数允许所用的实际像素值自动进行调整。这就使得在有着完全不同的窗口管理机制的平台之间转移程序变得容易。图8演示了同样的程序在RedHat linux 6.0下的情况,你可以看出对于大部分来说,尽管在表单上使用了完全不同的字体,这些控件的占位仍然适当。看上去wxTextCtrl在这个平台上高了几个对话框单位,所以也许应该在行之间多留一些空间。把它做为一个练习留给你。

图8.在Redhat Linux 6.0上运行的Doubletalk编辑器



  下一个将要定义的控件是wxListCtrl,它用来显示帐号和金额行:

    self.lc = wxListCtrl(self, ID_LIST,
                         wxDLG_PNT(self, 5,34), wxDLG_SZE(self, 225,60),
                         wxLC_REPORT)

    self.lc.InsertColumn(0, "Account")
    self.lc.InsertColumn(1, "Amount")
    self.lc.SetColumnWidth(0, wxDLG_SZE(self, 180,-1).width)
    self.lc.SetColumnWidth(1, wxDLG_SZE(self,  40,-1).width)

  注意这个控件的宽度是225个对话框单位,这一点很重要。因为这个控件横跨整个对话框,你知道正在处理的空间。当需要决定放置的地方或如何设置其它控件的大小时,你可以使用这个值。

  不要使用这个列表框列的自动大小调整功能,让我们使用确定的大小。但是你仍然可以用对话框单位来处理它,通过使用从wxSize(从wxDLG_SZE中返回)对象中提取出来的宽度属性。我们应该提醒以下几点:

balance字段被禁止了,因为你仅想用它来显示一个值。

使用一个wxStaticLine控件来绘制一长横穿对话框的线。

一个wxComboBox被用来从一个列表中选择存在的帐户名。

使用标准的ID定义wxID_OK和wxID_CANCEL分别用于OK和Cancel按钮,并且将OK按钮设为缺省按钮。

调用基类的Fit()方法来初始化对话框窗口的大小。这个函数根据在每个子类中指定的尺寸信息来计算整个所需的大小。

  下面是创建这些控件的剩余的代码:

    wxStaticText(self, -1, "Balance:", wxDLG_PNT(self, 165,100))
    self.balance = wxTextCtrl(self, ID_BAL, "",
                              wxDLG_PNT(self, 190,100), 
                              wxDLG_SZE(self, 40, -1))
    self.balance.Enable(false)

    wxStaticLine(self, -1, wxDLG_PNT(self, 5,115), 
                           wxDLG_SZE(self, 225,-1))

    wxStaticText(self, -1, "Account:", wxDLG_PNT(self, 5,122))
    self.account = wxComboBox(self, ID_ACCT, "",
                       wxDLG_PNT(self, 30,122), wxDLG_SZE(self, 130,-1),
                       accountList, wxCB_DROPDOWN | wxCB_SORT)

    wxStaticText(self, -1, "Amount:", wxDLG_PNT(self, 165,122))
    self.amount = wxTextCtrl(self, ID_AMT, "",
                         wxDLG_PNT(self, 190,122), 
                         wxDLG_SZE(self, 40, -1))

    btnSz = wxDLG_SZE(self, 40,12)
    wxButton(self, ID_ADD, "&Add Line", wxDLG_PNT(self, 52,140), btnSz)
    wxButton(self, ID_UPDT, "&Update Line", wxDLG_PNT(self, 97,140),
             btnSz)
    wxButton(self, ID_DEL, "&Delete Line", wxDLG_PNT(self, 142,140),
             btnSz)

    self.ok = wxButton(self, wxID_OK, "OK", wxDLG_PNT(self, 145,5),
                       btnSz)
    self.ok.SetDefault()
    wxButton(self, wxID_CANCEL, "Cancel", wxDLG_PNT(self, 190,5), btnSz)

    # 重新设置窗口大小,来适应控件
    self.Fit()

  最后一件要做的事情是创建一些事件处理器,然后给对话框控件填入数据。对控件的事件处理几乎同前面讨论过的菜单的处理一样,所以这里应该没有什么问题:

    # 设置一些事件处理器
    EVT_BUTTON(self, ID_ADD,  self.OnAddBtn)
    EVT_BUTTON(self, ID_UPDT, self.OnUpdtBtn)
    EVT_BUTTON(self, ID_DEL,  self.OnDelBtn)
    EVT_LIST_ITEM_SELECTED(self,   ID_LIST, self.OnListSelect)
    EVT_LIST_ITEM_DESELECTED(self, ID_LIST, self.OnListDeselect)
    EVT_TEXT(self, ID_DATE, self.Validate)

    # 用当前值初始化控件
    self.date.SetValue(self.trans.getDateString())
    self.comment.SetValue(self.trans.comment)
    for x in range(len(self.trans.lines)):
        account, amount, dict = self.trans.lines[x]
        self.lc.InsertStringItem(x, account)
        self.lc.SetStringItem(x, 1, str(amount))

    self.Validate()

  这段代码所做的最后一件事情是调用Validate()方法,正如你可能猜到的,它负责校验对话框的数据;在本例中,校验日期的正确性,并且校验所有交易行的总和应该为0。当字段改变时对日期进行校验(通过代码列出的EVT_TEXT()调用),并且在任何时候当增加或修改一行时检查平衡。只要有不正确的,禁止OK按钮。下面是Validate代码:

def Validate(self, *ignore):
    bal = self.trans.balance()
    self.balance.SetValue(str(bal))
    date = self.date.GetValue()
    try:
        dateOK = (date == dates.testasc(date))
    except:
        dateOK = 0

    if bal == 0 and dateOK:
        self.ok.Enable(true)
    else:
        self.ok.Enable(false)

  注意balance字段被更改了。我们要做的下一件事情是增加一行的功能。为了做到这一点,需要使用帐号(account)和数量(amount)字段的值,把它们加到交易中,然后还要把它们加到列表控件中:

def OnAddBtn(self, event):
    account = self.account.GetValue()
    amount = string.atof(self.amount.GetValue())
    self.trans.addLine(account, amount)

    # update the list control
    idx = len(self.trans.lines)
    self.lc.InsertStringItem(idx-1, account)
    self.lc.SetStringItem(idx-1, 1, str(amount))

    self.Validate()
    self.account.SetValue("")
    self.amount.SetValue("")

  再次调用Validate来检查是否交易的各行是平衡的。对于修改(Update)和删除(Delete)按钮的事件处理器很相似,这里就不再列出了。

  这些基本上就是全部内容了!wxPython使用tab键在字段之间进行切换,按了回车键自动完成,按了ESC键取消,还有一些别的。

wxPython 结论

  这一小段刚刚能够触及wxPython功能的表面。除了在这里演示的之外,还有更多的窗口和控件类型,并且许多高级的特性使得它们具有很高的灵活性,并且可以实现许多跨平台的动态GUI应用。同Python的灵活性相融合,你最终得到的是一个快速创建世界级应用的强大工具。

  想要了解关于wxPython的更多的信息,包括大量的文档和例程,参观wxPython主页http://www.wxPython.org。

  想要了解关于底层的wxWindows框架的更多的信息,请参观它的主页http://www.wxwindows.org/。

- 作者: yancy 2005年07月17日, 星期日 23:36  回复(0) |  引用(0) 加入博采

使用WxPython进行Win32下Python编程(四)
 在文件对话框成功完成之后,要做的第一件事就是询问对话框被选中的路径名是什么,然后使用这个路径来修改框架的标题,然后打开一个BookSet文件。

  看一下后面一行。它重新使BookSet菜单有效,因为现在已经存在一个打开文件了。它实际是两行语句合成一句,相当于这两行:

            menu = self.GetMenuBar()
            menu.EnableTop(1, true)

  因为当用户打开一个文件时,让他们确实地看到一些东西是有意义的,你应该创建并且显示其中一个视图,用上面的OnMenuOpen处理函数中最后几行代码。在下面,我们会看到。

wxListCtrl

  日志视图是由wxListCtrl组成,其中每一个交易都有一个单行的小计。这个控件放置在wxMDIChildFrame中,并且因为它是框架中唯一的东西,所以不用担心设置或维护大小,框架会自动维护它。(不幸地是,因为某些平台在不同的时间发送第一个改变大小(resize)事件,有时候窗口显示时,它的子窗口大小会不正确。)

class JournalView(wxMDIChildFrame):
    def __init__(self, parent, bookset, editID):
        wxMDIChildFrame.__init__(self, parent, -1, "")
        self.bookset = bookset
        self.parent = parent
 
        tID = wxNewId()
        self.lc = wxListCtrl(self, tID, wxDefaultPosition, 
                             wxDefaultSize, wxLC_REPORT)
        ## Forces a resize event to get around a minor bug...
        self.SetSize(self.GetSize())
 
        self.lc.InsertColumn(0, "Date")
        self.lc.InsertColumn(1, "Comment")
        self.lc.InsertColumn(2, "Amount")
 
        self.currentItem = 0
        EVT_LIST_ITEM_SELECTED(self, tID, self.OnItemSelected)
        EVT_LEFT_DCLICK(self.lc, self.OnDoubleClick)
 
        menu = parent.MakeMenu(true)
        self.SetMenuBar(menu)
        EVT_MENU(self, editID, self.OnEdit)
        EVT_CLOSE(self, self.OnCloseWindow)
 
        self.UpdateView()

  图6 显示出应用程序处理的很好,并且看上去象一个正规的Windows应用程序。

图6.Doubletalk交易清单


  wxListCtrl有很多的特性,但是对你来说都应该熟悉。在wxPython包装的下面,它同在Windows资源浏览器右边的面板用的是同样的控件。所有相同的选项都是可用的:大图标,小图标,列表模式,和报告模式。你利用它们的列头(header)来定义列,然后为列表控件设置一些事件。当双击时,需要能够对交易进行编辑,那么为什么需要两个事件处理呢?当列表控件的一条被选中时,它会发送一个事件,但是它并不留意双击。另一方面, wxWindow基类报告双击,但它并不知道列表控件。所以通过截获两个事件,你可以简单地实现你需要的功能。这里给出事件处理代码:

    def OnItemSelected(self, event):
        self.currentItem = event.m_itemIndex
 
    def OnDoubleClick(self, event):
        self.OnEdit()

  在创建和建立列表控件之后,为这个框架创建了一个菜单条。这里你调用了在父框架中的生成菜单的方法,要求它增加Edit Transaction菜单项。

  __init__方法所做的最后一件事是调用一个方法从BookSet中填充这个列表框。我们将其划分为一个单独的方法,这样不管什么时候BookSet数据发生改变,都可以被单独调用。下面是UpdateView方法:

    def UpdateView(self):
        self.lc.DeleteAllItems()
        for x in range(len(self.bookset)):
            trans = self.bookset[x]
            self.lc.InsertStringItem(x, trans.getDateString())
            self.lc.SetStringItem(x, 1, trans.comment)
            self.lc.SetStringItem(x, 2, str(trans.magnitude()))
 
        self.lc.SetColumnWidth(0, wxLIST_AUTOSIZE)
        self.lc.SetColumnWidth(1, wxLIST_AUTOSIZE)
        self.lc.SetColumnWidth(2, wxLIST_AUTOSIZE)
 
        self.SetTitle("Journal view - %d transactions" %
                      len(self.bookset))

  将数据放入一个列表中相当容易;只要插入每个列表项。在报告模式下,你插入一个列表项作为第一列,然后设置剩下列的值。对于例子中的每一列,只要从交易中取得一些数据,然后将其发送到列表控件中。如果你使用图标或图标和文本,要用不同的方法来处理它们。

  现在在列表控件中已经有数据了,你应该重新设置列的大小。或者可以指定实际的像素宽度,或者让列表根据数据的宽度自动调整列的宽度。

  JournalView类要做的最后一件事是允许交易的编辑。在前面我们看到,当一个列表项被双击,一个名为OnEdit的方法被调用。代码为:

    def OnEdit(self, *event):
        if self.currentItem:
            trans = self.bookset[self.currentItem]
            dlg = EditTransDlg(self, trans,
                               self.bookset.getAccountList())
            if dlg.ShowModal() == wxID_OK:
                trans = dlg.GetTrans()
                self.bookset.edit(self.currentItem, trans)
                self.parent.UpdateViews()
            dlg.Destroy()

  这个看上去象我们在主框架中对文件对话框的操作,并且的确你将会发现,在使用对话框时会经常使用这种模式。在这里需要注意的事情是调用在父窗口中的UpdateViews()。这就是如何管理,让BookSet的所有的视图保持更新。只要一个交易更新了,这个方法就会被调用,然后在所有的视图中循环,通知视图用它们的UpdateView()方法更新自身。

wxPython窗口布局

wxPython包含了许多强大的技术,用于控制你的窗口和控件的布局。它提供了几种可以替换的机制和几种有效的方法来完成同一件事情。允许程序员在特别的环境下使用可以工作最好或最习惯的机制。

约束

有一个叫做wxLayoutConstraints的类,它允许一个窗口位置和大小的说明是相对于它的“兄弟”(同级控件)和它的“父亲”(父控件)。每一个wxLayoutContraints对象是由八个wxIndividualLayoutConstraint对象组成,这些对象定义了不同类型的关系,就象哪一个窗口在这个窗口的上面,这个窗口的相对宽度是什么,等等。你通常需要指出八个中的四个约束条件,以便窗口被完全限定。例如,这个按钮将定位于它的父控件的中间,并且将总是占距父控件宽度的50%:

b = wxButton(self.panelA, 100, ' Panel A `)
lc = wxLayoutConstraints()
lc.centreX.SameAs (self.panelA, wxCentreX)
lc.centreY.SameAs (self.panelA, wxCentreY)
lc.height.AsIs ()
lc.width.PercentOf (self.panelA, wxWidth, 50)
b.SetConstraints(lc);

布局算法

名为wxLayoutAlgorithm的类实现了在MDI或SDI框架中子窗口的布局。它向框架的子控件发送 wxCalculateLayoutEvent事件,向它们查询它们的大小的信息。因为使用了事件系统,因此这个技术可以应用于任何窗口,甚至那些不需要知道布局的类。然而你可能希望将wxSashLayoutWindow类用在你的子窗口上,因为这个类提供了用于请求事件的处理器,和可以指定窗口大小的存取器。可以有选择地使用基类中的框格行为(sash behavior)使窗口可以由用户调整大小。wxLayoutAlgorithm被典型地应用在IDE风格的应用程序中,这种应用程序除了有MDI客户窗口或其它主要编辑窗口之外,还有几个可调整的窗口。可调整窗口可能包括了工具条,工具窗口,显示错误或警告消息的窗口。

大小管理器(sizer)

为了简化简单布局的编程,一个wxSizer类家族被加入到wxPython库中。这些类纯粹是用Python实现的,代替了从 wxWindows中封装C++代码。它们有点象是Java中布局管理的再现,你选择要用的sizer,然后向它增加窗口或其它sizer,这样它们将全部遵从布局的相同规则。例如,这个代码片段创建了五个按钮,它们在一个框子中水平排列,并且最后一个按钮允许伸缩以便填充框子中所分配的剩余的空间:

box = wxBoxSizer(wxHORIZONTAL)
box.Add(wxButton(win, 1010, "one"), 0)
box.Add(wxButton(win, 1010, "two"), 0)
box.Add(wxButton(win, 1010, "three"), 0)
box.Add(wxButton(win, 1010, "four"), 0)
box.Add(wxButton(win, 1010, "five"), 1)

资源

wxWindows库有一个可用的简单对话框编辑器,它可以帮助你安排一个对话框中控件的布局,并且生一个可在交叉平台上移植的资源文件。这个文件可以在运行时装入到程序中,并且可以立即转化成一个带有特别控件在上面的窗口。这个方法唯一的缺陷是你没有机会实现所生成窗口的子类化,但是如果用存在的控件类型和事件处理能够做你需要的任何事情,它应该执行的很好。最后,将会出现一个为wxPython特别设计的应用程序生成工具,它将为你或者生成资源文件或者生成实际的Python源代码。

强制力

最后,有一种强制力(brute force)机制,用来通过编程来指明每一个组件的精确位置。有时候一个窗口的布局需要不能适应任何一种sizer,或者不能保证约束的复杂性,或者布局算法。对于这些情况,你可以重新回到手工方式去处理,但是对于比Edit Transaction对话框复杂多的东西,你可能不想去尝试它。

wxDialog and friends

  下一步是建立一个用来编辑交易的对话框。对象由日期,说明,和不定数目的交易记录组成,每条记录都有一个帐户名和一个余额。我们知道,所有的记录加起来应该为0,并且日期应该为一个有效日期。另外,为了编辑日期和说明,你需要能够增加,编辑,和删除记录。图7显示了对于这个对话框的一个可能的布局,并且是这个例子中所使用的。

图7. wxPython Doubletalk交易编辑器

  因为这里有很多的代码,让我们一步步地仔细检查这个类的初始化过程。下面是第一部分:

class EditTransDlg(wxDialog):
    def __init__(self, parent, trans, accountList):
        wxDialog.__init__(self, parent, -1, "")
        self.item = -1
        if trans:
            self.trans = copy.deepcopy(trans)
            self.SetTitle("Edit Transaction")
        else:
            self.trans = Transaction()
            self.trans.setDateString(dates.ddmmmyyyy(self.trans.date))
            self.SetTitle("Add Transaction")

  这是想当简单的东西。只是调用了父类的__init__方法,做一些初始化工作,并且判断是否你正在编辑一个存在的交易或创建一个新的交易。如果正在编辑一个存在的交易,使用Python拷贝模块来生成对象的拷贝。这样做因为你可能正好在编辑交易,并不想让被编辑的交易的任何部分留在 BookSet中。如果对话框被用来增加一条新交易,则创建一条,然后修改它的日期,通过从日期中截去时间。在交易中的缺省日期包括了当前的时间,但是这个对话框只具备了处理日期部分。

- 作者: yancy 2005年07月17日, 星期日 23:35  回复(0) |  引用(0) 加入博采

使用WxPython进行Win32下Python编程(三)
 用Python创建一个Doubletalk浏览器

  Ok, 现在让我们做些有用的东西,用这种方法学习更多关于wxPython框架的知识。就象其它的GUI工具包所展示的,我们将创建一个小型的应用程序,围绕着Doubletalk类库(它允许浏览和编辑交易)。

MDI框架

  我们打算实现一个多文档界面(译注,即MDI),子框架除了为独立的“文档”外,其中还包含着交易数据的不同视图。如同前面的例子,要做的第一件事就是创建一个应用程序类,并且在它的OnInit方法中创建一个主框架:

from wxPython.wx import *

class DoubleTalkBrowserApp(wxApp):
    def OnInit(self):
        frame = MainFrame(NULL)
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = DoubleTalkBrowserApp(0)
app.MainLoop()

  因为我们正在使用MDI,所以需要一个特别的类用来做为框架的基本类。这里的给出主程序框架的初始化方法的代码:

class MainFrame(wxMDIParentFrame):
    title = "Doubletalk Browser - wxPython Edition"
    def __init__(self, parent):
        wxMDIParentFrame.__init__(self, parent, -1, self.title)
        self.bookset = None
        self.views = []
        
        if wxPlatform == '__WXMSW__':
            self.icon = wxIcon('chart7.ico', wxBITMAP_TYPE_ICO)
            self.SetIcon(self.icon)

        # 创建一个状态条,在右边显示时间和日期
        sb = self.CreateStatusBar(2)
        sb.SetStatusWidths([-1, 150])
        self.timer = wxPyTimer(self.Notify)
        self.timer.Start(1000)
        self.Notify()
        
        menu = self.MakeMenu(false)
        self.SetMenuBar(menu)
        menu.EnableTop(1, false)
        
        EVT_MENU(self, ID_OPEN,  self.OnMenuOpen)
        EVT_MENU(self, ID_CLOSE, self.OnMenuClose)
        EVT_MENU(self, ID_SAVE,  self.OnMenuSave)
        EVT_MENU(self, ID_SAVEAS,self.OnMenuSaveAs)
        EVT_MENU(self, ID_EXIT,  self.OnMenuExit)
        EVT_MENU(self, ID_ABOUT, self.OnMenuAbout)
        EVT_MENU(self, ID_ADD,   self.OnAddTrans)
        EVT_MENU(self, ID_JRNL,  self.OnViewJournal)
        EVT_MENU(self, ID_DTAIL, self.OnViewDetail)
        EVT_CLOSE(self, self.OnCloseWindow)

  图4显示了到现在应用程序的状态。

图4. 第一个MDI wxPython程序  


  很明显,我们没有展示全部的代码,但是随着我们一点一点地学习,我们将最终将其变得完整。

  注意,使用wxMDIParentFrame作为MainFrame的基类。通过使用这个类,你会自动地获得为实现MDI应用程序的所有需要的东西,不需要关心在外表后面发生了什么。wxMDIParentFrame 类有着与wxFrame类同样的接口,只是拥有一些额外的方法。通常将一个单文档接口程序改为一个多文档程序只是象改变应用程序派生类的基类一样容易。对于wxMDIParentFrame 类,存在相对应的wxMDIChildFrame类,用于作文档窗口,在后面就会看到。如果你需要处理MDI父窗口的客户区域(或背景区域),你可以使用 wxMDIClientWindow类。你可以使用它来在所有子窗口的后面放置一个背景图像。

图标

  前面的代码做的下一件事情是创建一个图标,并将其与框架相连。通常的Windows 应用程序从资源文件中装入象图标一样的资源项,资源文件与执行码链在一起。因为wxPython程序没有二进制执行文件,你需要通过指定全路径的.ico 文件来创建图标。将图标指定给框架只要调用框架的SetIcon方法。

时间

  你可能已经注意到在图4中,状态条有两段,在第二段中显示着日期和时间。下面的在初始化方法中的几行代码实现了这个功能。框架的 CreateStatusBar方法使用一个可选参数,这个参数指明了要创建的段的值,并且可以将一个整数列表传给SetStatusWidths,用来指明对于每一段应保留多少像素。-1意味着第一段应该占满剩余的空间。

  为了更新日期和时间,你创建了一个wxPyTimer 对象。在wxPython中有两种定时器类。第一个就是这里所用的wxPyTimer,它接收一个函数或方法作为一个回调函数。另一个是wxTimer 类,它是为了被继承,并且当时间到期时,调用派生类里的要求的函数。在例子中,你指明当定时器到期时,Nofify方法应该被调用。然后启动定时器,告诉它每1000毫秒激活(即,每秒钟)。下面列出Notify方法的代码:

    # 激活处理
    def Notify(self):
        t = time.localtime(time.time())
        st = time.strftime(" %d-%b-%Y   %I:%M:%S", t)
        self.SetStatusText(st, 1)

  首先使用Python的time模块来得到当前时间,并且将日期格式化为一种好看的,人类可读的格式串。然后通过调用框架的SetStausText方法,你可以将这个字符串放进状态条,在这个例子中为第一段中。

主菜单

  在下面的几行代码,如你所见,我们将菜单的创建放入一个独立的方法中。这样做主要有两个原因。第一个就是减少在__init__ 方法中的混乱,从而更好的组织类的功能。第二个原因由于MDI,需要这样做。对于所有的MDI应用程序,每一个子框架可以拥有它自已的菜单条,当这个框架被选中时会自动更新(译注:我想是父框架)。

  我们的例子所使用的方法既可以从BookSet菜单中增加也可以删除一个单独的菜单项,要看一个视图能否选择交易进行编辑。下面列出 MakeMenu方法的代码。注意参数是怎样控制是否将Edit Transaction菜单项加入到菜单中的。根据需要,这个项只是允许或禁止可能会更好理解一些,但是那样你将不能看到,当活动窗口改变时, wxPython是如何自动改变菜单的。还要注意,你没有创建Window菜单。wxMDIParentFrame已经为你想到了:

    def MakeMenu(self, withEdit):
        fmenu = wxMenu()
        fmenu.Append(ID_OPEN,  "&Open BookSet",  "Open a BookSet file")
        fmenu.Append(ID_CLOSE, "&Close BookSet",
                 "Close the current BookSet")
        fmenu.Append(ID_SAVE,  "&Save", "Save the current BookSet")
        fmenu.Append(ID_SAVEAS,  "Save &As", "Save the current BookSet")
        fmenu.AppendSeparator()
        fmenu.Append(ID_EXIT, "E&xit",   "Terminate the program")
        
        dtmenu = wxMenu()
        dtmenu.Append(ID_ADD, "&Add Transaction",
                  "Add a new transaction")
        if withEdit:
            dtmenu.Append(ID_EDIT, "&Edit Transaction",
                  "Edit selected transaction in current view")
        dtmenu.Append(ID_JRNL, "&Journal view",
                  "Open or raise the journal view")
        dtmenu.Append(ID_DTAIL,"&Detail view",
                  "Open or raise the detail view")
        
        hmenu = wxMenu()
        hmenu.Append(ID_ABOUT, "&About",
                 "More information about this program")
        
        main = wxMenuBar()
        main.Append(fmenu, "&File")
        main.Append(dtmenu,"&Bookset")
        main.Append(hmenu, "&Help")
        
        return main

  如果你跳回到__init__方法,注意到在你创建菜单然后将它连到窗口之后,菜单条的EnableTop方法被调用了。这就是如何禁止整个 BookSet子菜单。(因为还没有BookSet文件打开,你还不能真正地对它做任何事。)使用Enable方法可以让你通过ID号对独立的菜单项允许或禁止。

  __init__方法的最后几行代码将事件处理器同各个菜单项连接。当我们解开在这些选项之后的功能时,将一个一个地查看它们。但是首先,这里有简单一些的:

def OnMenuExit(self, event):
        self.Close()

    def OnCloseWindow(self, event):
        self.timer.Stop()
        del self.timer
        del self.icon
        self.Destroy()

    def OnMenuAbout(self, event):
        dlg = wxMessageDialog(self,
          "This program uses the doubletalk package to\n"
          "demonstrate the wxPython toolkit.\n\n"
          "by Robin Dunn",
          "About", wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

  用户从File菜单中选择Exit,然后OnMenuExit方法被调用,这个方法要求窗口将自已关闭。无论何时当窗口需要关闭时,不管是因为Close方法被调用,还是因为用户点击了标题条上的关闭按钮,OnCloseWindow方法被调用。如果你想用象“你确实想退出吗?”这样的信息提示用户,就在这里实现它。如果他决定不退出,只要调用方法event.Veto(true)。

  大部分的程序需要一个比wxMessageDialog所提供的更富有想象的About对话框,但是出于我们的目的,这样就很好了。不要忘了调用对话框的Destroy方法,否则你可能泄漏内存。

wxFileDialog

  在对BookSet做事情之前,你需要先打开一个文件。为了打开文件,使用wxFileDialog通用对话框。这个对话框同所有你看到的Windows应用程序的文件->打开对话框一样,全部都封装在了一个同wxPython兼容良好的类接口中了。

  这里是捕捉文件->打开事件的事件处理器,图5显示了执行后的对话框:

    def OnMenuOpen(self, event):
    # This should be checking if another is already open,
    # but is left as an exercise for the reader...
        dlg = wxFileDialog(self)
        dlg.SetStyle(wxOPEN)
        dlg.SetWildcard("*.dtj")
        if dlg.ShowModal() == wxID_OK:
            self.path = dlg.GetPath()
            self.SetTitle(self.title + ' - ' + self.path)
            self.bookset = BookSet()
            self.bookset.load(self.path)
            self.GetMenuBar().EnableTop(1, true)
            
            win = JournalView(self, self.bookset, ID_EDIT)
            self.views.append((win, ID_JRNL))
            
        dlg.Destroy()

图5. wxPython浏览一个Doubletalk交易文件


  开始是创建文件对话框,并且告诉它如何动作。接着显示对话框,给用户一个机会,选择一个BookSet文件。注意,这一次你检查了 ShowModal方法的返回值。这就是对话框如何告诉你结果是什么。缺省的,对话框理解其中的与按钮相连的wxID_OK和wxID_CANCEL消息识别(ID)号,并且当它们被点击时做正确的事情。对于你所创建的对话框,如果愿意也可以指定其它的返回值。

- 作者: yancy 2005年07月17日, 星期日 23:35  回复(0) |  引用(0) 加入博采

使用WxPython进行Win32下Python编程(二)
 哪里可以得到wxPython

  wxPython的最新版本可以在http://alldunn.com/wxPython/上找到。你可以从这个站点下载一个Win32系统的自安装软件,其中包含一个已经生成好的扩展模块,HTML帮助格式文档,和一组示例程序。

  也可以从这个站点获得Linux RPM,wxPython源码,原始的HTML文档,和其它站点的链接,邮件列表,wxPython FAQ,等等。

  如果你想自已从源代码创建wxPython,你也需要wxWindows源代码,可以从http://www.wxwindows.org/得到。

下一步去哪里?

  这一章的其它内容给出一个使用wxPython的基本介绍,通过一个简单的例子,讲述了一个wxPython应用程序的基本结构。然后我们创建一个调用更多的例子,讲述了一些这个工具包中更多的高组特性,使用了你已经熟悉的Doubletalk金融模型的类。(文章是如此,谁知道 Doubletalk是个什么东东)

使用wxPython

  实践证明,学习的最好方法就是动手,接着做实验,观察得到的结果。所以你应该下载和安装wxPython,启动你常用的文本编辑器,准备执行在下面几节所读到的东西。

一个简单的例子

  应该对下面的小wxPython程序进行熟悉,当读到跟着的解释时,可以回过头来进行参考:

from wxPython.wx import *

class MyApp(wxApp):
    def OnInit(self):
        frame = wxFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

  当运行这个程序时,你应该看到象图1的窗口显示出来。

图1. 一个基本的wxPython程序

  要做的第一件事情就是导入整个wxPython库,使用 from wxPython import * 语句。这是编wxPython程序的通常习惯,但是你可以根据需要明确地执行更多限制的导入。

  每一个wxPython应用程序需要从wxApp派生出一个类,并且为其提供一个OnInit方法。框架(即窗口)会调用这个方法作为自身初始化序列的一部分。Oninit通常是用来创建窗口,和对于程序开始运行完全必需的操作。在例子中,你创建了一个没有父亲的框架,标题是“Hello from wxPython”,然后显示它。我们也可以在它的构造函数中为框架指定位置和大小,但是因为没有,所以这里使用了缺省值。OnInit方法的最后两行可能对于所有应用程序来说都是一样的。SetTopWindow方法告诉wxWindows 这个框架是应用程序主框架其中之一(在这个例子中只有一个),并且你返回true来表明成功。当所有项层窗口实关闭,应用程序结束。

  脚本的最后两行可能又是对于所有的wxPython应用程序是一样的。你创建了一个应用程序类的实例,并且调用它的MainLoop方法。 MainLoop是应用程序的心脏:在这里事情被处理,并且被发送到各个窗口,当最后一个窗口关闭后,它返回。幸运的是,wxWindows对你屏蔽了各种GUI工具包在事件处理上的不同。

  大多数情况下,你会想要定制应用程序的主框架,所以使用普通的wxFrame是不够的。你可能希望,从wxFrame派生出自已的类进行定制。下一个例子定义了一个框架类,并且在应用程序中的OnInit方法中创建了一个实例。注意除了在OnInit中创建的类的名字,MyApp代码的其它部分同以前的例子是一样的。这个代码的显示结果如图2。

from wxPython.wx import *

ID_ABOUT = 101
ID_EXIT  = 102

class MyFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
        
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About","More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
        
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
        
        self.SetMenuBar(menuBar)
        
        
class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

图2 一个带菜单的wxPython程序


  这个例子显示了一些wxFrame内建的一些功能。例如,为框架创建一个状态条只要简单地调用一个方法。框架本身会自动地管理它的位置,大小,和绘制。另一方面,如果你想定制状态条,从你自已的wxStatusBar派生类创建实例,并将其附加到框架上。

  在这个例子中也演示了创建一个简单的菜单条和一个下拉菜单。期待的菜单功能全部都支持:层叠子菜单,可核选的项,弹出菜单等等;你要做的只是创建一个菜单对象,向它追加菜单项。菜单项可以是象这里显示的文本,或其它的菜单。每一项你可以有选择地指定一些简单的帮助性文本,就象我们所做的。当菜单项被选中,这些文本会自动地显示在状态条上。

在wxPython中的事件

  上一个例子没有做的一件事情就是:展示如何让菜单自动做一些事情。如果你运行这个例子,并且从菜单中选中Exit,什么都没有发生。下一个例子改正了这个小问题。

  为了在wxPython中处理事件,任何方法(或同样方式的独立函数)都可以使用工具包中的帮助性函数与任意事件相连。wxPython也提供了一个wxEvent 类,和一整串派生类,包含了事件的细节。每次当发生一个事件,一个方法被调用,一个从wxEvent 派生的对象被做为一参数传递,事件对象的实际类型要依赖于事件的类型。wxSizeEvent用于当窗口改变大小,wxCommandEvent用于菜单选择和按钮点击,wxMouseEvent用于(可以猜到)鼠标的移动,等等。

  为了解决上一个例子中的小问题,你要做的就是,在MyFrame构造函数中增加两行,并且增加处理事件的一些方法。我们也演示了一个通用对话框,wxMessageDialog。下面就是代码,黑体部分表示新的部分,运行结果见图3。

from wxPython.wx import *
 
ID_ABOUT = 101
ID_EXIT  = 102
 
class MyFrame(wxFrame):
    def __init__(self, parent, ID, title):
        wxFrame.__init__(self, parent, ID, title, wxDefaultPosition, wxSize(200, 150))
        self.CreateStatusBar()
        self.SetStatusText("This is the statusbar")
        menu = wxMenu()
        menu.Append(ID_ABOUT, "&About", "More information about this program")
        menu.AppendSeparator()
        menu.Append(ID_EXIT, "E&xit", "Terminate the program")
        menuBar = wxMenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

        EVT_MENU(self, ID_ABOUT, self.OnAbout)
        EVT_MENU(self, ID_EXIT,  self.TimeToQuit)

    def OnAbout(self, event):
        dlg = wxMessageDialog(self, "This sample program shows off\n"
                              "frames, menus, statusbars, and this\n"
                              "message dialog.",
                              "About Me", wxOK | wxICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def TimeToQuit(self, event):
        self.Close(true)

class MyApp(wxApp):
    def OnInit(self):
        frame = MyFrame(NULL, -1, "Hello from wxPython")
        frame.Show(true)
        self.SetTopWindow(frame)
        return true

app = MyApp(0)
app.MainLoop()

图3 带有一个About对话框的程序


  在这里调用的EVT_MENU函数是一个帮助性函数,是为了将事件与方法连在一起。有时候,如果你将函数调用翻译成英语,它可以帮助我们理解发生了什么。第一个说的是,“对于任一个菜单项选中事件,发送窗口本身和一个ID_ABOUT的ID号,调用self.OnAbout方法。”

  有很多EVT_*帮助性函数,所有的都对应某个事件类型,或事件。下面将常用的一些事件列出,见表1。请参阅wxPython文档了解更多的细节。

表1 常见wxPython事件函数 事件函数

事件描述

EVT_SIZE 由于用户干预或由程序实现,当一个窗口大小发生改变时发送给窗口。

EVT_MOVE 由于用户干预或由程序实现,当一个窗口被移动时发送给窗口。

EVT_CLOSE 当一个框架被要求关闭时发送给框架。除非关闭是强制性的,否则可以调用event.Veto(true)来取消关闭。

EVT_PAINT 无论何时当窗口的一部分需要重绘时发送给窗口。

EVT_CHAR 当窗口拥有输入焦点时,每产生非修改性(Shift键等等)按键时发送。

EVT_IDLE 这个事件会当系统没有处理其它事件时定期的发送。

EVT_LEFT_DOWN 鼠标左键按下。

EVT_LEFT_UP 鼠标左键抬起。

EVT_LEFT_DCLICK 鼠标左键双击。

EVT_MOTION 鼠标在移动。

EVT_SCROLL 滚动条被操作。这个事件其实是一组事件的集合,如果需要可以被单独捕捉。

EVT_BUTTON 按钮被点击。

EVT_MENU 菜单被选中。

- 作者: yancy 2005年07月17日, 星期日 23:34  回复(0) |  引用(0) 加入博采

使用WxPython进行Win32下Python编程(一)
摘要:使用WxPython进行Win32下Python编程(一) 作者:Mark Hammond 和 Andy Robinson 翻译:limodou 节选自O'Reilly出版的《Win32下的Python编程》第20章。 查看全文

- 作者: yancy 2005年07月17日, 星期日 23:33  回复(0) |  引用(0) 加入博采

用Vim进行C/C++编程介绍
摘要:原文章发布于 2000.11.27 by 赵如飞翻译整理[网友投稿] Introduction to Programming in C/C++ with Vim Written By: Kmj 用Vim进行C/C++编程介绍 作者:Kmj [小赵] 翻译整理 Vi has been one of the most, if not the most, popular editing tools for programmers since Bill Joy first created it. 查看全文

- 作者: yancy 2005年07月6日, 星期三 14:17  回复(0) |  引用(0) 加入博采