Boudewijn Rempt
|
Qt Class | Python Class | Implemented | Description |
---|---|---|---|
QArray | list | No | Array of simple types. |
QByteArray | String | No | Use a string wherever a method wants a QByteArray |
QPointArray | No equivalent | Yes | Array of QPoint objects — you can also store QPoint objects in a Python list, of course. |
QCollection | Dictionary | No | Abstract base class for QDict, QList and QMap. |
QDict | Dictionary | No | Just like Python dictionaries, but more complicated in use. |
QList | list | No | Just like Python lists, but more complicated |
QMap | Dictionary | No | Use a Python dictionary — however, when translating a Python prototype to C++, note that a QMap is based on values, not on references; the keys indexing the dictionary are copies of the original objects, not references. |
QCache | No equivalent | No | A QCache is a low-level class that caches string values so that two variables containing the same text don't use the memory twice. There are similar caches for integers and non-Unicode texts. Python performs the same trick; see the note: Python and Caching. |
QValueList | list | No | A low-level class that implements a list of values (instead of references to objects). |
QVariant | No equivalent | Partially | QVariant is a wrapper class that makes it possible to use C++ as if it were a loosely-typed language (which Python already is). This class is used for implementing class properties (I find it to be a monstrosity compared to Visual Basic's Variant type). |
Python and caching: Python caches certain often-used values and shares those values across variables. Numbers from 0 to 99 (inclusive) are cached, and strings are always cached. Qt uses the same trick from strings and some other objects
Python 2.2a4 (#1, Oct 4 2001, 15:35:57) [GCC 2.95.2 19991024 (release)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> a=1 >>> b=1 >>> id(a) 135268920 >>> id(b) 135268920 >>> a=100 >>> b=100 >>> id(a) 135338528 >>> id(b) 135338504 >>> a="bla" >>> b="bla" >>> id(a) 135563808 >>> id(b) 1355638
Files and other IO
Qt's file classes include the following:
QDir — directory information
QFile — file handling
QFileInfo — file information
QIODevice — abstract IO device
QBuffer — helper class for buffered IO
QTextStream — abstract class for text IO
QTextIStream — text input IO
QTextOSStream — text output IO
QAsyncIO — abstract base for asynchronous IO
QDataSink — asynchronous data consumer
QDataSource — asynchronous data produced of data
QDataStream — binary IO
QIODeviceSource — a datasource that draws data from a QIODevice, like QFile.
Qt's file and IO handling classes are divided into three groups: classes to handle files on a file system, classes that work on streams, and asynchronous IO classes. We have already seen an example of working with QDir. QFile is Qt's equivalent of the Python file object; it is almost fully implemented in PyQt, with some changes due to naming conflicts. QFileInfo is a useful class that encapsulates and caches information including name, path, creation date and access rights. You could use the various function in Python's os.path module, but those don't cache information.
The base class for all these IO-oriented classes is QIODevice, which is completely implemented in PyQt. You can subclass it for your own IO classes. Qt divides its stream handling into text streams and binary streams. Only the text stream handling in implemented in PyQt, with the QTextStream, QTextIStream and QTextOStream classes. QTextStream is the base class, QTextIStream provides input stream functionality and QTextOStream output stream functionality. One problem remains with these stream classes — operator overloading. C++ relies on the >> and << operators to read from and write to a stream. PyQt doesn't support this yet, so you cannot actually make use of the streaming capabilities. Instead, you will have to limit yourself to using read() to read the entire contents of the stream.
The asynchronous IO classes, the buffer class and the binary IO classes have not been implemented yet. You can easily substitute the various Python modules for file and IO handling. You can use asyncore in place QAsyncIO. The Python file object is buffered by nature, if you open() your files with the bufsize parameter set.
Date and time
QDate — representation of a data
QTime — clock and time functions
QDateTime — combination of QDate and QTime
While Python has a time module, this only presents a low-level interface to the system date and time functions (and the sleep() function, which halts processing for a while). It does not provide a high-level encapsulation of dates and times. PyQt, however, provides just that with QDate and QTime. QDate is especially suited to data arithmetic, and can hold dates from 1752 to 8000. The first limit is based on the date that our Gregorian calendar was introduced; if you need the Julian calendar (or perhaps Vikram Samvat or other exotic calendars), you must write your own Date class.
Mime
QMimeSource — a piece of formatted data
QMimeSourceFactory — a provider of formatted data
Python mimetools and the MimeWriter modules are not exactly equivalent to the PyQt QMimeSource and QMimeSourceFactory classes. The Python modules are optimized for the handling of mime-encoded e-mail messages. The PyQt classes are a more generalized abstraction of formatted data, where the format is identified by the IANA list of MIME media types. QMimeSource is used extensively in the drag'n'drop subsystem, in the clipboard handling, and in the production of images for rich text widgets.
An example is given in the application.py script that is included with PyQt. Below, I show a relevant fragment of that example, which takes a bit of html-formatted text with an <img> tag to a certain name, which is resolved using QMimeSourceFactory:
Example 10-20. Using QMimeSourceFactory (application.py)
... fileOpenText = \ '''<img source="fileopen"> Click this button to open a <em>new file</em>.<br><br> You can also select the <b>Open</b> command from the <b>File</b> menu.''' ... QWhatsThis.add(self.fileOpen,fileOpenText) QMimeSourceFactory.defaultFactory().setPixmap('fileopen',openIcon) ...
Text handling
QString — string handling
QRegExp — regular expressions that work on a string.
QChar — one Unicode character
QValidator — validates input text according to certain rules
QTextCodec — conversions between text encodings
QTextDecoder — decode a text to Unicode
QTextEncoder — encode a text from Unicode
Qt's string handling really excels: it is thoroughly based upon Unicode, but provides easy functionality for other character encodings. However, plain Python also provides Unicode string functionality, and the interplay between Python strings and PyQt QStrings can be quite complex.
For most purposes, however, the conversions are transparent, and you can use Python strings as parameters in any function call where a QString is expected. If you run across more complex problems, you can consult Chapter 8, on String Objects in Python and Qt.
Threads
QMutex
Python threads and Qt threads bite each other frequently. Qt thread support itself is still experimental, and with Unix/X11, most people still use the un-threaded Qt library. The C++ Qt thread class QMutex has not been ported to PyQt, so you cannot serialize access to gui features.
Python thread support is far more mature, but doesn't mix too well with PyQt — you don't want two threads accessing the same gui element. You're quite safe though, as long as your threads don't access the gui. The next example shows a simple pure-python script with two threads:
Example 10-21. thread1.py — Python threads without gui
# # thread1.py # import sys import time from threading import * class TextThread(Thread): def __init__(self, name, *args): self.counter=0 self.name=name apply(Thread.__init__, (self, ) + args) def run(self): while self.counter < 200: print self.name, self.counter self.counter = self.counter + 1 time.sleep(1) def main(args): thread1=TextThread("thread1") thread2=TextThread("thread2") thread1.start() thread2.start() if __name__=="__main__": main(sys.argv)
The next example has a Qt window. The threads run quite apart from the window, and yet everything operates fine— that is, until you try to close the application. The threads will continue to run until they are finished, but it would be better to kill the threads when the last window is closed. Killing or stopping threads from outside the threads is not supported in Python, but you can create a global variable, stop, to circumvent this. In the threads themselves, you then check whether stop is true.
Example 10-22. Python threads and a PyQt gui window
# # thread2.py - Python threads # import sys, time from threading import * from qt import * class TextThread(Thread): def __init__(self, name, *args): self.counter=0 self.name=name apply(Thread.__init__, (self, ) + args) def run(self): while self.counter < 200: print self.name, self.counter self.counter = self.counter + 1 time.sleep(1) class MainWindow(QMainWindow): def __init__(self, *args): apply(QMainWindow.__init__, (self,) + args) self.editor=QMultiLineEdit(self) self.setCentralWidget(self.editor) self.thread1=TextThread("thread1") self.thread2=TextThread("thread2") self.thread1.start() self.thread2.start() def main(args): app=QApplication(args) win=MainWindow() win.show() app.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()")) app.exec_loop() if __name__=="__main__": main(sys.argv)
Another technique (though dangerous!) is to have the GUI use a timer to periodically check the variables produced by the threads. However, concurrent access of a variable can lead to nasty problems.
URL's
The Qt URL-handling classes are quite equivalent to Python's urllib module. It's up to you to choose which you prefer.
QUrl
QUrlInfo
QUrlOperator
Qt modules that overlap with Python modules
In addition, there are two Qt modules that are also available completely as Python modules: the XML module (wrapped by Jim Bublitz) and the Network module. The Python equivalent of Qt's XML module, for simple tasks, xmllib, and for more complicated problems xml.sax. While xmllib is deprecated, it is still very useful and one the simplest ways of handling XML data. The xml.sax module depends on the presence of the expat parser, which is not available on every system.
The Qt network module has not been completely wrapped in PyQt yet. It is mainly useful if you want to program your own network clients and servers, and intend to move your code to C++ one day. Python offers equivalent modules for every service, and a lot more, too (such as http and gopher clients). You might find Qt's socket objects a bit more convenient than Python's offerings. Another possible reason to use the Qt socket classes is that they are better implemented on Windows than the Python socket classes.
Table 10-2. Qt and Python network classes
Qt Class | Python Class | Implemented | Description |
---|---|---|---|
QSocket | socket | Partially implemented | Low level network connection object. Note that Python's socket module is useful both for clients and servers, while Qt's QSocket is for clients only: servers use QServerSocket. |
QSocketDevice | socket | No | This class is mostly intended for use inside Qt - use QIODevice instead, which is completely implemented in PyQt. |
QServerSocket | socket, SocketServer | Partially implemented | The server-side complement of QSocket. Again, Python's socket module servers both for server and client applications. Python offers the server-specific SocketServer module. |
QHostAddress | No real equivalent | Partially — not the functionality for IPv6. | A platform and protocol independent representation of an IP address. |
QDns | No real equivalent | Not implemented | Asynchronous DNS lookups — it's not implemented, all Python libraries do automatic synchronous DNS lookups, as do the QSocket derived Qt classes. |
QFtp | ftplib | Not implemented | This class is seldom used: it's easier to just open an URL either with QUrlOperator or one of the Python Internet protocol handling libraries like urllib. |