index.lxp@lxpwrap=x6082_252ehtm.htm
来自「GUI Programming with Python」· HTM 代码 · 共 1,086 行 · 第 1/2 页
HTM
1,086 行
CLASS="CLASSNAME">Config</TT> class from the configuration module. After creating the editor widget, we simply set the font with a call to <TTCLASS="FUNCTION">self.editor.setFont(kalamconfig.getTextFont())</TT>. </P></DIV><DIVCLASS="SECT3"><H3CLASS="SECT3">Window geometry</A></H3><P>Applying the geometry is just as easy. It's very pleasant for users when an application pops up its windows at the same place and in the same size as the user left them. This is part of session management, which is very advanced in the KDE environment, but less so for Windows. Qt 3 offers support for session management with <TTCLASS="CLASSNAME">QSessionManager</TT> and <TTCLASS="CLASSNAME">QApplication</TT>, but we'll take care of session management ourselves at this time.</P><P>Setting the correct size and position of a window, and also the correct widget style, is done in the central application object, <TTCLASS="CLASSNAME">KalamApp</TT>:</P><PRECLASS="PROGRAMLISTING">from qt import *...import kalamconfig...class KalamApp(QMainWindow): """KalamApp is the toplevel application window of the kalam unicode editor application. """ def __init__(self, *args): apply(QMainWindow.__init__,(self, ) + args) ... self.initSettings() ... # # GUI initialization # def initSettings(self): qApp.setStyle(kalamconfig.getStyle()) self.setGeometry(kalamconfig.Config.app_x, kalamconfig.Config.app_y, kalamconfig.Config.app_w, kalamconfig.Config.app_h) </PRE><P>Here, too, we import the <TTCLASS="FILENAME">kalamconfig</TT> module. The function <TTCLASS="FUNCTION">initSettings()</TT> is called from the constructor {<TTCLASS="FUNCTION">__init__()</TT>} </P><P>This function will be extended with other application level settings during development of <SPANCLASS="APPLICATION">Kalam</SPAN>.</P></DIV><DIVCLASS="SECT3"><H3CLASS="SECT3">Determining the widget style</A></H3><P> First, we set the desired widget style. Users can also set the widget style using a command-line option, and Qt can even figure out which style fits best with a users platform. But some people have strong preferences, and will want to configure their preferred style. It is easy enough to determine and use the platform default if no special style is set. </P><P>The <TTCLASS="FUNCTION">getStyle()</TT> and <TTCLASS="FUNCTION">setStyle</TT> are quite interesting, from a Python point of view:</P><PRECLASS="PROGRAMLISTING">def __extractStyle(style): if type(style) == InstanceType: return style.__class__.__name__ elif type(style) == StringType: return style else: return "QPlatinumStyle" </PRE><P>I wanted this to be as flexible as possible, showing the dynamic nature of Python. The <TTCLASS="FUNCTION">__extractStyle</TT> function takes the current style object that is used by the application. We find this by calling <TTCLASS="FUNCTION">qApp.style()</TT>. <TTCLASS="VARNAME">qApp</TT> is a global variable that points to the <TTCLASS="CLASSNAME">QApplication</TT> object.</P><P>An instance in Python has a number of ‘hidden' fields and methods that each have a special meaning. One of these is <TTCLASS="FUNCTION">__init__()</TT>, which is called when the object is first created. Another is <TTCLASS="VARNAME">__class__</TT>, which returns the class that the object was created from. You can use this to make more instances, but in this case we are interested in the string that contains the name of the class. You can retrieve the name with another ‘hidden' variable of the <TTCLASS="CLASSNAME">class</TT> class: <TTCLASS="VARNAME">__name__</TT>.</P><PRECLASS="PROGRAMLISTING">def setStyle(style): if type(style) == types.StringType: Config.currentStyle = style elif type(style) == types.InstanceType: Config.currentStyle = __extractStyle(style) </PRE><P>Setting the style in the context of <TTCLASS="FILENAME">kalamconfig</TT> means setting the "currentStyle" attribute of <TTCLASS="CLASSNAME">Config</TT> to a string that represents the style. If the input to <TTCLASS="FUNCTION">setStyle()</TT> is already a string (that is, if the type is <TTCLASS="VARNAME">types.StringType</TT>), then we simply set it. Otherwise, we use the function defined above to get a string that equals the name of the style class.</P><PRECLASS="PROGRAMLISTING">def getStyle(): # Basic sanity check - you don't want to eval arbitrary code if not hasattr(Config, "currentStyle"): print "ok", repr(qApp.style()) Config.currentStyle = __extractStyle(qApp.style()) if (Config.currentStyle[0] != "Q" or Config.currentStyle[-5:] != "Style" or Config.currentStyle.find(" ") > 0): Config.currentStyle = "QPlatinumStyle" try: # you shouldn't use eval for this, but it is a nice opportunity # for showing how it works. Normally you'd use a dictionary of # style names. return eval(Config.currentStyle)() except NameError, e: print "No such style: defaulting to Platinum" return QPlatinumStyle() </PRE><P>Getting a <TTCLASS="CLASSNAME">QStyle</TT> object of the right type is a bit more complex. Of course, you will most often use a simple dictionary that maps style names to style classes:</P><PRECLASS="PROGRAMLISTING"> styleDict = { "platinum": QPlatinumStyle, ...} </PRE><P>This is not particularly flexible. Here, we use <TTCLASS="FUNCTION">eval</TT> to create an object from the name of a class. Look carefully at:</P><PRECLASS="PROGRAMLISTING"> return eval(Config.currentStyle)() </PRE><P>This means that, if the variable <TTCLASS="VARNAME">Config.currentStyle</TT> contains a string that is equal to classname and that is known to Python (that is, it can be found in one of the imported modules), <TTCLASS="FUNCTION">eval()</TT> will return that class. The brackets after eval make an instance of the class.</P><P>Beware: using <TTCLASS="FUNCTION">eval</TT> is <SPAN><ICLASS="EMPHASIS">dangerous</I></SPAN>. For example, what if someone hacked your <TTCLASS="FILENAME">.kalam-ch13</TT> configuration file and set the entry <TTCLASS="LITERAL">currentStyle</TT> to <TTCLASS="LITERAL">os.rmdir('/')</TT>? If you were fool enough to run <SPANCLASS="APPLICATION">Kalam</SPAN> as root on Unix, you'd lose your system—irretrievably.</P><P>This is why I checked the existence and believability of the <TTCLASS="VARNAME">currentStyle</TT> string before <TTCLASS="FUNCTION">eval</TT>-ing it. I only used <TTCLASS="FUNCTION">eval</TT> to show you that it exists— for your own sake, don't use <TTCLASS="FUNCTION">eval</TT> trivially! We'll return to <TTCLASS="FUNCTION">eval</TT> and its friends in <A href="index.lxp@lxpwrap=c6996_252ehtm.htm">Chapter 20</A>.</P></DIV><DIVCLASS="SECT3"><H3CLASS="SECT3">Setting the viewmanager</A></H3><P>The last task we handle in this chapter is the choosing of the view manager. The available choices include tabbed windows, mini-windows, splitters, stacks — the lot. This time, we will use a dictionary that maps viewmanager names to actual classes. This is only to show you how it works - in general, it's a good rule to not mix and match approaches as we have done here, but to choose one method, and stick to it.</P><PRECLASS="PROGRAMLISTING">"""kalamconfig.py - Configuration class for the Kalam Unicode Editorcopyright: (C) 2001, Boudewijn Remptemail: boud@rempt.xs4all.nl"""import sys, os, typesfrom qt import *import tabmanager, listspace, splitspace, stackspace, workspaceworkspacesDictionary = { "tabmanager" : tabmanager.TabManager, "listspace" : listspace.ListSpace, "splitspace" : splitspace.SplitSpace, "stackspace" : stackspace.StackSpace, "workspace" : workspace.WorkSpace, }class Config:... </PRE><P>First, a dictionary (<TTCLASS="VARNAME">workspacesDictionary</TT>) is created that contains a mapping from strings to the actual classes. Of course, in order to be able to access those classes, they will have to be imported.</P><PRECLASS="PROGRAMLISTING">def getViewManager(): try: return workspacesDictionary[Config.viewmanager] except: return tabmanager.TabManagerdef setViewManager(viewmanager): Config.viewmanager = viewmanager.__class__.__name__ </PRE><P>These two functions get and set the viewmanager style. If the style given in <TTCLASS="CLASSNAME">Config</TT> doesn't exist, a <TTCLASS="VARNAME">KeyError</TT> will be raised, in which case we simply return a sensible default.</P><P>The <TTCLASS="FUNCTION">getViewManager()</TT> is called from the <TTCLASS="FUNCTION">initWorkSpace()</TT> function in <TTCLASS="FILENAME">kalamapp.py</TT>:</P><PRECLASS="PROGRAMLISTING"> ... def initWorkSpace(self): workspace = kalamconfig.getViewManager()(self) self.setCentralWidget(workspace) return workspace ... </PRE></DIV></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2">Catching the changes when the application closes</A></H2><P>The configuration should be written to a file when the app closes. There are two places where <SPANCLASS="APPLICATION">Kalam</SPAN> can end: <TTCLASS="FUNCTION">slotFileQuit()</TT>, and in the eventhandler <TTCLASS="FUNCTION">eventFilter()</TT>.</P><PRECLASS="PROGRAMLISTING"> ... # # Slot implementations # def slotFileQuit(self): try: self.docManager.closeAllDocuments() except: return kalamconfig.writeConfig() qApp.quit() ... # # Toplevel event filter # ... def eventFilter(self, object, event): if (event.type() == QEvent.Close): if (object<>self): if self.docManager.closeView(object): event.accept() else: event.ignore() else: try: self.docManager.closeAllDocuments() kalamconfig.writeConfig() event.accept() except Exception, e: event.ignore() return QWidget.eventFilter(self, object, event) ... </PRE><P>After all, it is simply a matter of calling <TTCLASS="FUNCTION">writeConfig()</TT> at the right moment.</P></DIV></DIV><DIVCLASS="NAVFOOTER"><HRALIGN="LEFT"WIDTH="100%"><TABLESUMMARY="Footer navigation table"WIDTH="100%"BORDER="0"CELLPADDING="0"CELLSPACING="0"><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top"><A accesskey="P" href="index.lxp@lxpwrap=x6053_252ehtm.htm">Prev</A></TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><A accesskey="H" href="index.lxp@lxpwrap=book1_252ehtm">Home</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top"><A accesskey="N" href="index.lxp@lxpwrap=x6300_252ehtm.htm">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">The Python way of handling configuration settings</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><A accesskey="U" href="index.lxp@lxpwrap=c6013_252ehtm.htm">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Settings in Qt 3.0</TD></TR></TABLE></DIV></BODY></HTML> </td> </tr> </table> </td> </tr> </table>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?