index.lxp@lxpwrap=x6082_252ehtm.htm
来自「GUI Programming with Python」· HTM 代码 · 共 1,086 行 · 第 1/2 页
HTM
1,086 行
<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>Implementing configurations settings for Kalam</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="Application Configuration"HREF="c6013.htm"><LINKREL="PREVIOUS"TITLE="The Python way of handling configuration settings"HREF="x6053.htm"><LINKREL="NEXT"TITLE="Settings in Qt 3.0"HREF="x6300.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=x6053_252ehtm.htm">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">Chapter 18. Application Configuration</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><A accesskey="N" href="index.lxp@lxpwrap=x6300_252ehtm.htm">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1">Implementing configurations settings for <SPANCLASS="APPLICATION">Kalam</SPAN></A></H1><P>Working with configuration settings can be divided into two main procedures: giving your application classes access to the configuration data, and loading and saving that data. We'll start by looking at the first problem, and then at loading and saving. In the next chapter, we'll round out <SPANCLASS="APPLICATION">Kalam</SPAN> by creating a preferences dialog.</P><DIVCLASS="SECT2"><H2CLASS="SECT2">Handling configuration data in your application</A></H2><P>Before we start saving and restoring configuration settings, we should have a clear idea of how to handle them in the application. Configuration data typically must be available everywhere in the application, because all objects must be able to query and store settings at will.</P><P>In other languages, such as Visual Basic, you would use a module with global variables to store configuration data; in a language like Java or C++, you would use a singleton object—that is, an object with a hidden constructor that can only be instantiated once. Python, however, does not support these constructions.</P><P>Of course, there is an alternative. In a sense, class definitions are global. Every module that imports a certain class gets exactly the same class. Keep in mind that a class is just an object, of the type <TTCLASS="VARNAME">class</TT>. You can associate variables not only with an object, as in:</P><PRECLASS="PROGRAMLISTING">class SomeClass: def __init__(self): self.someVariable=1someInstance=SomeClass()print someInstance.someVariable </PRE><P>But also with a class:</P><PRECLASS="PROGRAMLISTING">class SomeClass: classVariable=1print SomeClass.classVariable </PRE><P>These class variables are accessed via the <SPAN><ICLASS="EMPHASIS">name</I></SPAN> of the class, instead of the name of an instance of that class. Class variables are shared by all instances of a class.</P><P>The ideal solution to creating a "global" configuration repository is to define a class that contains all configuration data as class variables. It's also possible to encapsulate the configuration data repository in a single class variable. You cannot call functions on a class - there is no equivalent to the ‘static' methods of Java. If we need functions to work on the configuration data, we must either define those functions at module level, or as functions of an object that is a class variable of the configuration module. An example would be a function to create a <TTCLASS="CLASSNAME">QFont</TT> out of a fontname string.</P><P>Well — that was the theory. Let's now look at the code needed to implement configuration data for <SPANCLASS="APPLICATION">Kalam</SPAN>. It's pretty similar to the snippets we saw above:</P><PRECLASS="PROGRAMLISTING">"""kalamconfig.py - Configuration class for the Kalam Unicode Editorcopyright: (C) 2001, Boudewijn Remptemail: boud@rempt.xs4all.nl"""import sys, osfrom qt import *class Config: APPNAME = "kalam" APPVERSION = "ch13" CONFIGFILE = ".kalam-ch13" currentStyle="Platinum" viewmanager="tabmanager" app_x=0 app_y=0 app_w=640 app_h=420 fontfamily="courier" pointsize=12 weight=50 italic=0 encoding=22def getApplicationFont(): return QFont(Config.fontfamily, Config.pointsize, Config.weight, Config.italic, Config.encoding ) </PRE><P>As you can see, it's just a simple matter of a class with a bunch of class variables that represent pertinent values. However, because these values will be saved to a file, you cannot associate real objects with the keys. To make it easier to retrieve a font based on the values stored in the configuration file, there is module-level helper function, <TTCLASS="FUNCTION">getApplicationFont()</TT>, which constructs a <TTCLASS="CLASSNAME">QFont</TT> on the fly.</P><P>A similar function exists to set the font:</P><PRECLASS="PROGRAMLISTING">def setApplicationFont(qfont): Config.fontfamily = qfont.family() Config.pointsize = qfont.pointSize() Config.weight = qfont.weight() Config.italic = qfont.italic() Config.encoding = qfont.encoding() </PRE><P>As you can see, we store our settings in a flat namespace, in which every key must be unique. This is just like the properties system used in Java, but more complex systems can be very useful. For instance, the Windows registry is one gigantic tree, and even the files created by <TTCLASS="FILENAME">ConfigParser</TT> have sections and subsections. For highly complex configuration needs, there is the <TTCLASS="FILENAME">shlex</TT> Python module, which you can use to define configuration languages.</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2">Saving and loading the configuration data</A></H2><P>Retrieving and saving the configuration data can be made as complex or easy as you want. We have already discussed the possibility of using <TTCLASS="FILENAME">_winreg</TT> or <TTCLASS="FILENAME">ConfigParser</TT> for the saving and retrieving of configuration data.</P><P>What we are going to, however, is far more simple. When we load the settings, we just read every line in the configuration file, and add a variable to the <TTCLASS="CLASSNAME">Config</TT> class that represents the value:</P><PRECLASS="PROGRAMLISTING">def readConfig(configClass = Config): sys.stderr.write( "Initializing configuration\n") try: for line in open(os.path.join(os.environ["HOME"], Config.CONFIGFILE)).readlines(): k, v=tuple(line.split("=")) v=v[:-1] if v=="None\n": v=None elif type: try: v=int(v) except ValueError: pass setattr(configClass, k, v) except IOError: sys.stderr.write( "Creating first time configuration\n") </PRE><P>To add the variable to the <TTCLASS="CLASSNAME">Config</TT> we use the standard Python function <TTCLASS="FUNCTION">setattr()</TT> — this function is one of the delights that make Python so dynamic.</P><P>Note the special treatment of the value that is represented by "None" in the configuration file: if "None" is encountered the value of the configuration key is set to a real None object. This contrast with the situation where the value is simply empty: then the value is set to an empty string ("").</P><P>Currently, the configuration file format only supports two types: strings and integers. The distinction is made by brute force: we simply try to convert the value to an integer, and if we succeed, it stays an integer. If the conversion raises a <TTCLASS="VARNAME">ValueError</TT>, we assume the value should remain a string.</P><P>By now you might be wondering <SPAN><ICLASS="EMPHASIS">when</I></SPAN> we will be reading in the configuration values. The simple answer is that we will do so when the <TTCLASS="FILENAME">KalamConfig</TT> module is first imported. At the bottom of the module the function <TTCLASS="FUNCTION">readConfig(Config)</TT> is called, and is only executed once:</P><PRECLASS="PROGRAMLISTING">readConfig() </PRE><P>Saving the configuration values to disk is a simple matter of looping over the contents of the attributes of the <TTCLASS="CLASSNAME">Config</TT> class — that is, the <TTCLASS="VARNAME">__dict__</TT>, <TTCLASS="VARNAME">__methods__</TT> and <TTCLASS="VARNAME">__members__</TT> dictionaries that are part of the object's hidden attributes. We retrieve these with the <TTCLASS="FUNCTION">dir()</TT> function:</P><PRECLASS="PROGRAMLISTING">def writeConfig(configClass = Config): sys.stderr.write( "Saving configuration\n") configFile=open(os.path.join(os.environ["HOME"],".kalamrc"),"w+") for key in dir(Config): if key[:2]!='__': val=getattr(Config, key) if val==None or val=="None": line=str(key) + "=\n" else: line=str(key) + "=" + str(val) + "\n" configFile.write(line) configFile.flush() </PRE><P>The actual values are retrieved with the opposite of <TTCLASS="FUNCTION">setattr()</TT>: <TTCLASS="FUNCTION">getattr()</TT>. As a first check, attributes with a double underscore as prefix are not saved: those are internal attributes to the <TTCLASS="CLASSNAME">Config</TT> class. If the value is the <TTCLASS="VARNAME">None</TT> object, we print the string "None". Because it is quite possible that some values are <TTCLASS="CLASSNAME">QString</TT> objects, and because you cannot save these, everything is converted to a plain Python string.</P><P>Finally, you might need functions that get and set more complex objects in the <TTCLASS="CLASSNAME">Config</TT>. These can be simple module level functions that work on the class:</P><PRECLASS="PROGRAMLISTING">def getTextFont(): return QFont(Config.fontfamily, Config.pointsize, Config.weight, Config.italic, Config.encoding )def setTextFont(qfont): Config.fontfamily = qfont.family() Config.pointsize = qfont.pointSize() Config.weight = qfont.weight() Config.italic = qfont.italic() Config.encoding = qfont.encoding() </PRE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2">Using configuration data from the application</A></H2><P>By now we have a simple configuration data mechanism, and it's time to use it. Earlier we defined a few settings: the position and size of the application window, the widget style that is to be used, and the interface paradigm. First, we will write some code to actually use these settings. Then we will write code to save changes when the application is closed.</P><DIVCLASS="SECT3"><H3CLASS="SECT3">Font settings</A></H3><P>The font to be used in the editor window can be set and retrieved with the get and set functions we defined above. The <TTCLASS="CLASSNAME">KalamView</TT> class is the place to use this setting.</P><PRECLASS="PROGRAMLISTING">"""from qt import *import kalamconfigfrom resources import TRUE, FALSEclass KalamView(QWidget): def __init__(self, parent, doc, *args): apply(QWidget.__init__,(self, parent) + args) ... self.editor=QMultiLineEdit(self) self.editor.setFont(kalamconfig.getTextFont()) self.layout.addWidget(self.editor) </PRE><P>We import the configuration module, <SPAN><ICLASS="EMPHASIS">not</I></SPAN> the <TT
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?