📄 index.lxp@lxpwrap=x1807_252ehtm.htm
字号:
<table border="0" cellspacing="0" cellpadding="3" width="100%"><tr><td> <div align="center" id="bldcontent"> <a href="../default.htm"><img src="../images/opendocs.png" width="63" height="76" border="0"></a> <br> <div class="symbol">Your OpenSource Publisher™</div> </div> </td></tr></table> <div align="center" class="author"> <a href="../products.lxp">Products</a> | <a href="../wheretobuy.lxp">Where to buy</a> | <a href="../bookstore.lxp">Retailers</a> | <a href="../faq.lxp">FAQ</a> | <a href="../writeforus.lxp">Write for Us.</a> | <a href="#contact">Contact Us.</a> </div> <table border="0" cellspacing="3" cellpadding="0" width="100%"><tr><td width="100%"> <div class="content"> <table border="0" cellspacing="2" cellpadding="0" width="100%"><tr><td width="100%"> <div align="center"><H4 CLASS="AUTHOR"><A NAME="AEN5">Boudewijn Rempt</A><br><a href="../../https@secure.linuxports.com/opendocs/default.htm"><img src=odpyqt125.png></a><br>ISBN: 0-97003300-4-4<br><a href="../../https@secure.linuxports.com/opendocs/default.htm">Available from bookstores everywhere or you can order it here.</a><p>You can download the source files for the book <a href="pyqtsrc.tgz">(code / eps) here.</a><hr></div> <HTML><HEAD><TITLE>A parser-formatter using signals and slots</TITLE><METANAME="GENERATOR"CONTENT="Modular DocBook HTML Stylesheet Version 1.72"><LINKREL="HOME"TITLE="GUI Programming with Python: QT Edition"HREF="book1.htm"><LINKREL="UP"TITLE="Signals and Slots in Depth"HREF="c1267.htm"><LINKREL="PREVIOUS"TITLE="Disconnecting"HREF="x1631.htm"><LINKREL="NEXT"TITLE="Conclusion"HREF="x2026.htm"></HEAD><BODYCLASS="SECT1"BGCOLOR="#FFFFFF"TEXT="#000000"LINK="#0000FF"VLINK="#840084"ALINK="#0000FF"><DIVCLASS="NAVHEADER"><TABLESUMMARY="Header navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><THCOLSPAN="3"ALIGN="center">GUI Programming with Python: QT Edition</TH></TR><TR><TDWIDTH="10%"ALIGN="left"VALIGN="bottom"><A accesskey="P" href="index.lxp@lxpwrap=x1631_252ehtm.htm">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">Chapter 7. Signals and Slots in Depth</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><A accesskey="N" href="index.lxp@lxpwrap=x2026_252ehtm.htm">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1">A parser-formatter using signals and slots</A></H1><P>The use of signals and slots in the previous section was an example of using signals and slots in GUI building. Of course, you can use signals and slots to link GUI widgets with each other, and most of your slot implementations will be in subclasses of <TTCLASS="CLASSNAME">QWidget</TT> — but the mechanism works well under other circumstances. A GUI is not necessary.</P><P>In this section, I will show how signals and slots make a natural extension to the event driven nature of XML parsers. As you probably know, XML is a fairly simple mark-up language that can be used to represent hierarchical data. There are basically two ways to look at XML data. One is to convert the data in one fell swoop into some hierarchical representation (for example, dictionaries containing dictionaries). This method is the DOM (data-object-model) representation. Alternatively, you can parse the data character by character, generating an event every time a certain chunk has been completed; this is the SAX parser model.</P><P>Python contains support for both XML handling models in its standard libraries. The currently appreciated module is xml.sax, which can make use of the fast expat parser. However, expat is not part of standard Python. There is an older, deprecated module, xmllib, which uses regular expressions for parsing. While deprecated, this module is still the most convenient introduction to XML handling with Python. It's also far more ‘Pythonic' in feel than the Sax module, which is based on the way Java does things. </P><P>We'll create a special module that will use xmllib to parse an XML document and generate PyQt signals for all elements of that document. It is easy to connect these signals to another object (for instance, a PyQt <TTCLASS="CLASSNAME">QListView</TT> which can show the XML document in a treeview). But it would be just as easy to create a formatter object that would present the data as HTML. A slightly more complicated task would be to create a formatter object that would apply XSLT transformations to the XML document — that is, it would format the XML using stylesheets. Using signals and slots, you can connect more than one transformation to the same run of the parser. A good example would be a combination of a GUI interface, a validator, and a statistics calculator.</P><P>The next example is very simple. It is easy to extend, though, with special nodes for comments, a warning message box for errors, and more columns for attributes.</P><DIVCLASS="EXAMPLE"></A><P><B>Example 7-9. An XML parser with signals and slots</B></P><PRECLASS="PROGRAMLISTING">## qtparser.py — a simple parser that, using xmllib,# generates a signal for every parsed XML document.#import sysimport xmllib <IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A>from qt import *TRUE=1 <IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A>FALSE=0 </PRE><DIVCLASS="CALLOUTLIST"><DLCOMPACT="COMPACT"><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#XMLLIB"><IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A></DT><DD>We import the deprecated xmllib module. It is deprecated because the sax module, which uses the expat library, is a lot faster. The xmllib module is far easier to use, however, and since it uses regular expressions for its parsing, it is available everywhere, while the expat library must be compiled separately.</DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#TRUE"><IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A></DT><DD>It is often convenient to define constants for the boolean values true and false.</DD></DL></DIV><PRECLASS="PROGRAMLISTING">class Parser(xmllib.XMLParser): <IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A> def __init__(self, qObject, *args): <IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A> xmllib.XMLParser.__init__(self) self.qObject=qObject def start(self, document): <IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A> xmllib.XMLParser.feed(self, document) xmllib.XMLParser.close(self) </PRE><DIVCLASS="CALLOUTLIST"><DLCOMPACT="COMPACT"><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#CLASS"><IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A></DT><DD>This is the <TTCLASS="CLASSNAME">Parser</TT> class. It inherits the <TTCLASS="CLASSNAME">XMLParser</TT> class from the xmllib module. The <TTCLASS="CLASSNAME">XMLParser</TT> class can be used in two ways: by overriding a set of special methods that are called when the parser encounters a certain kind of XML element, or by overriding a variable, <TTCLASS="VARNAME">self.elements</TT>, which refers to a dictionary of tag-to-method mappings. Overriding <TTCLASS="VARNAME">self.elements</TT> is very helpful if you are writing a parser for a certain DTD or XML document type definition, though it is not the way to go for a generic XML structure viewer (such as the one we are making now).</DD><DD><P>An example for a Designer ui file could contain the following definition:</P></DD><PRECLASS="PROGRAMLISTING">self.elements={'widget' : (self.start_widget, self.end_widget) ,'class' : (self.start_class, self.end_class) ,'property': (self.start_property, self.end_property) ,name' : (self.start_name, self.end_name)} </PRE><DD><P>The keys to this dictionary are the actual tag strings. The tuple that follows the key consists of the functions that should be called for the opening and the ending tag. If you don't want a function to be called, enter None. Of course, you must implement these functions yourself, in the derived parser class.</P></DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#CONSTRUCTOR"><IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A></DT><DD>The first argument (after self, of course) to the constructor is a QObject. Multiple inheritance isn't a problem in Python, generally speaking, but you cannot multiply inherit from PyQt classes. Sip gets hopelessly confused if you do so. So we pass a <TTCLASS="CLASSNAME">QObject</TT> to the constructor of the <TTCLASS="CLASSNAME">Parser</TT> class. Later, we will have this <TTCLASS="CLASSNAME">QObject</TT> object emit the necessary signals.</DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#START"><IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A></DT><DD>The <TTCLASS="FUNCTION">start</TT> function takes a string as its parameter. This string should contain the entire XML document. It is also possible to rewrite this function to read a file line by line; the default approach makes it difficult to work with really large XML files. Reading a file line by line is a lot easier on your computer's memory. You should call <TTCLASS="FUNCTION">close()</TT> after the last bit of text has been passed to the parser.</DD></DL></DIV><PRECLASS="PROGRAMLISTING"> # # Data handling functions <IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A> # def handle_xml(self, encoding, standalone): <IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A> self.qObject.emit(PYSIGNAL("sigXML"), (encoding, standalone)) <IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A> def handle_doctype(self, tag, pubid, syslit, data): self.qObject.emit(PYSIGNAL("sigDocType"), (tag, pubid, syslit, data,)) <IMGSRC="images/callouts/4.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(4)"></A> def handle_data(self, data): self.qObject.emit(PYSIGNAL("sigData"),(data,)) <IMGSRC="images/callouts/5.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(5)"></A> def handle_charref(self, ref): self.qObject.emit(PYSIGNAL("sigCharref"),(ref,)) <IMGSRC="images/callouts/6.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(6)"></A> def handle_comment(self, comment): self.qObject.emit(PYSIGNAL("sigComment"),(comment,))<IMGSRC="images/callouts/7.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(7)"></A> def handle_cdata(self, data): self.qObject.emit(PYSIGNAL("sigCData"),(data,)) <IMGSRC="images/callouts/8.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(8)"></A> def handle_proc(self, data): self.qObject.emit(PYSIGNAL("sigProcessingInstruction"),<IMGSRC="images/callouts/9.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(9)"></A> (data,)) def handle_special(self, data): <IMGSRC="images/callouts/10.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(10)"></A> self.qObject.emit(PYSIGNAL("sigSpecial"), (data,)) def syntax_error(self, message): <B>(11)</B></A> self.qObject.emit(PYSIGNAL("sigError"),(message,)) def unknown_starttag(self, tag, attributes): <B>(12)</B></A> self.qObject.emit(PYSIGNAL("sigStartTag"), (tag,attributes)) <B>(13)</B></A> def unknown_endtag(self, tag): self.qObject.emit(PYSIGNAL("sigEndTag"),(tag,)) <B>(14)</B></A> def unknown_charref(self, ref): self.qObject.emit(PYSIGNAL("sigCharRef"),(ref,)) def unknown_entityref(self, ref): self.qObject.emit(PYSIGNAL("sigEntityRef"),(ref,)) </PRE><DIVCLASS="CALLOUTLIST"><DLCOMPACT="COMPACT"><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#DATA-HANDLING"><IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A></DT><DD>The xmllib.<TTCLASS="CLASSNAME">XMLParser</TT> class defines a number of methods that should be overridden if you want special behavior. Even though we will only use the methods that are called when a document is started and when a simple element is opened and closed, I've implemented all possible functions here.</DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#DH1"><IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A></DT><DD>Every valid XML document should start with a magic text that declares itself to be XML — note that that the .ui Designer files don't comply with this requirement. This method is fired (and thus the signal is fired) when the parser encounters this declaration. Normally, it looks like this: <TTCLASS="LITERAL"><?xml version="1.0" standalone="no"?></TT>, with the minor variation that standalone can also have the value "yes". </DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#DH2"><IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A></DT><DD>If an XML document has a documenttype, this method is called. A doctype declaration looks like this:</DD><PRECLASS="SCREEN"><!DOCTYPE book PUBLIC "-//Norman Walsh//DTD DocBk XML V3.1.4//EN" "http://nwalsh.com/docbook/xml/3.1.4/db3xml.dtd"> </PRE><DD><P>and points to a DTD — a description of what's allowed in this particular kind of XML document. </P></DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#DH3"><IMGSRC="images/callouts/4.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(4)"></A></DT><DD>There can be data in between the tags in an XML document, just as with the text in a HTML document. This function is called when the parser encounters such data.</DD><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm#DH4"><IMGSRC="images/callouts/5.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(5)"></A></DT><DD>In XML, you can use special characters that are entered with &#, a number, and closed with a semicolon. Python's xmllib will want to translate this to an ASCII character. You cannot use
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -