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          &#8216;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 &#8216;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(" ") &#62; 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&#8212;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&#8212;          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 &#8212; 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&#60;&#62;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 + -
显示快捷键?