c6351.htm
来自「GUI Programming with Python」· HTM 代码 · 共 1,422 行 · 第 1/3 页
HTM
1,422 行
<HTML><HEAD><TITLE>Using Dialog Windows</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="Creating real applications with PyQt"HREF="p4627.htm"><LINKREL="PREVIOUS"TITLE="Conclusion"HREF="x6342.htm"><LINKREL="NEXT"TITLE="Non-modal: Search and replace"HREF="x6734.htm"></HEAD><BODYCLASS="CHAPTER"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"><AHREF="x6342.htm"ACCESSKEY="P">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><AHREF="x6734.htm"ACCESSKEY="N">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1><ANAME="CH14">Chapter 19. Using Dialog Windows</A></H1><DIVCLASS="TOC"><DL><DT><B>Table of Contents</B></DT><DT><AHREF="c6351.htm#AEN6357">Modal: a preferences dialog</A></DT><DT><AHREF="x6734.htm">Non-modal: Search and replace</A></DT><DT><AHREF="x6992.htm">Conclusion</A></DT></DL></DIV><P>In this chapter we add a few dialog windows to the <SPANCLASS="APPLICATION">Kalam</SPAN> program. Dialog windows come in two basic flavors: modal and non-modal. Modal dialog windows block the interface of you application. Settings dialog, file dialogs and such are typically modal. Non-modal dialogs can stay open while the user continues working in the application. Search and replace or style dialogs are typical examples of non-modal dialogs.</P><DIVCLASS="SECT1"><H1CLASS="SECT1"><ANAME="AEN6357">Modal: a preferences dialog</A></H1><P>We will start with a preferences dialog. Nowadays, the taste is for dialogs with a strip of icons to the left that somehow indicates what section should be shown. But we will start out with a simple tabbed dialog that PyQt supports out of the box, and for which we don't have to draw icons (that's always the difficult bit, creating the artwork).</P><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN6360">Designing the dialog</A></H2><P>So: time to fire up the designer module of BlackAdder or Qt Designer!</P><DIVCLASS="MEDIAOBJECT"><P><DIVCLASS="CAPTION"><P>The settings dialog - editor tab</P></DIV></P></DIV><P>I like to show a sample of what the user selects in the dialog. In this tab, the user can select font, text and background color for the editor windows. These changes are reflected in the little label with the "Lorem ipsum" text. There are two more options: a combobox for selecting the wrapping mode (either no wrapping, wrap to the maximum line width, or wrap to the width of the window), and a spin box to set the maximum line width.</P><DIVCLASS="MEDIAOBJECT"><P><DIVCLASS="CAPTION"><P>The settings dialog - interface tab</P></DIV></P></DIV><P>Most users will not immediately get what we mean with "Window view" - in the interface tab w show an example of what we mean, too. I propose to make the "Look and Feel" selection automatically active, so that doesn't need a preview.</P><P>To fill in the preview I've snapshotted <SPANCLASS="APPLICATION">Kalam</SPAN> in all its variations and scaled the pictures down a lot. Adding these pictures as inline-image data to the dialog would make loading very slow, since Python is not so quick in reading bytecode files. It is better to create a <TTCLASS="FILENAME">pixmaps</TT> directory and store the pictures there.</P><DIVCLASS="MEDIAOBJECT"><P><DIVCLASS="CAPTION"><P>The settings dialog - document tab</P></DIV></P></DIV><P>As for the document, we need two settings: the first is the document encoding. While <SPANCLASS="APPLICATION">Kalam</SPAN> is meant to be a Unicode editor for standard <SPAN><ICLASS="EMPHASIS">utf8</I></SPAN> files, people might prefer things like iso-8859-1. This is mere window-dressing—actually loading and saving in encodings other than utf-8 will not be implemented for now. The second option is about document endings. A text file should end with a newline character, and we added code to make sure it does in <AHREF="c5783.htm">Chapter 17</A>—ultimately, this should be a configuration option.</P><P>Of course, during the course of development we will expand the contents of these pages, adding items when we need them. Someone once remarked that a configuration dialog presents the history of design decisions that were avoided during development—and it often feels that way indeed.</P></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2"><ANAME="AEN6398">Creating the settings dialog window</A></H2><P>The first part of the drill is well known: compile the <TTCLASS="FILENAME">frmsettings.ui</TT> file to Python using <BCLASS="COMMAND">pyuic</B>. </P><PRECLASS="SCREEN">pyuic -x frmsettings.ui > frmsettings.py </PRE><P>You can either call this generated dialog directly from <TTCLASS="CLASSNAME">KalamApp</TT>, or you can subclass it and add some intelligence. Since intelligence is what is needed to synchronize the switches between interface paradigm, we will go ahead and add subclass the design and add some. </P><PRECLASS="PROGRAMLISTING">"""dlgsettings.py - Settings dialog for Kalam.See: frmsettings.uicopyright: (C) 2001, Boudewijn Remptemail: boud@rempt.xs4all.nl"""import os, sysfrom qt import *import kalamconfigfrom frmsettings import FrmSettingsclass DlgSettings(FrmSettings): def __init__(self, parent = None, name = None, modal = 0, fl = 0): FrmSettings.__init__(self, parent, name, modal, fl) self.textFont = kalamconfig.get("textfont") self.textBackgroundColor = kalamconfig.get("textbackground") self.textForegroundColor = kalamconfig.get("textforeground") self.MDIBackgroundColor = kalamconfig.get("mdibackground") self.initEditorTab() self.initInterfaceTab() self.initDocumentTab() </PRE><P>The <TTCLASS="CLASSNAME">DlgSettings</TT> dialog is a subclass of <TTCLASS="CLASSNAME">FrmSettings</TT>, which we created with Designer. In the constructor we create four objects for housekeeping purposes, to store changed settings until the user chooses to apply them by pressing OK, or to cancel.</P><P>These objects represent the editor font, the editor text color, the editor background color and the background color of the MDI workspace. As you can see from the calls to <TTCLASS="FILENAME">kalamconfig</TT>, actually implementing this dialog necessitated quite a few changes to the <TTCLASS="FILENAME">kalamconfig</TT> module.</P><P>The full source of <TTCLASS="FILENAME">kalamconfig</TT> is not so interesting for this chapter, but it is available with the rest of the code. To summarize the development: all settings are now retrieved and set through a single pair of get/set functions. There are a lot more settings, too. If a setting requires special handling, then the relevant get/set function is retrieved from a dictionary (you can just as easily store references to functions or classes in a dictionary as in strings, since everything is considered an object) and executed with <TTCLASS="FUNCTION">apply()</TT>. If a setting is changed, a signal is emitted from the <TTCLASS="CLASSNAME">QApplication</TT> instance, which can be reached with the global variable <TTCLASS="VARNAME">qApp</TT>. Note how the actual signal identifier is constructed dynamically:</P><PRECLASS="PROGRAMLISTING">## kalamconfig.py# Get and set - set emits a signal via Config.notifier#customGetSetDictionary = { "style" : (getStyle, setStyle), "workspace" : (getWorkspace, setWorkspace), "textfont" : (getTextFont, setTextFont), "textforeground" : (getTextForegroundColor, setTextForegroundColor), "textbackground" : (getTextBackgroundColor, setTextBackgroundColor), "mdibackground" : (getMDIBackgroundColor, setMDIBackgroundColor),}def set(attribute, value): if customGetSetDictionary.has_key(attribute): apply(customGetSetDictionary[attribute][1], (value,)) else: setattr(Config, attribute, value) qApp.emit(PYSIGNAL("sig" + str(attribute) + "Changed"), (value,))def get(attribute): if customGetSetDictionary.has_key(attribute): value = apply(customGetSetDictionary[attribute][0]) else: value = getattr(Config, attribute) return value </PRE><P>But, let us continue with <TTCLASS="FILENAME">dlgsettings.py</TT>. There are three tab pages, and every tab pages has its own initialization function.</P><PRECLASS="PROGRAMLISTING"> def initEditorTab(self): self.txtEditorPreview.setFont(self.textFont) pl = self.txtEditorPreview.palette() pl.setColor(QColorGroup.Base, self.textBackgroundColor) pl.setColor(QColorGroup.Text, self.textForegroundColor) self.cmbLineWrapping.setCurrentItem(kalamconfig.get("wrapmode")) self.spinLineWidth.setValue(kalamconfig.get("linewidth")) self.connect(self.bnBackgroundColor, SIGNAL("clicked()"), self.slotBackgroundColor) self.connect(self.bnForegroundColor, SIGNAL("clicked()"), self.slotForegroundColor) self.connect(self.bnFont, SIGNAL("clicked()"), self.slotFont) </PRE><P>The editor tab shows a nice preview of the font and color combination the user has chosen. Setting these colors, however, is not as straightforward as you might think. Qt widget colors are governed by a complex system based around palettes. A palette (<TTCLASS="CLASSNAME">QPalette</TT>) contains three color groups (<TTCLASS="CLASSNAME">QColorGroup</TT>), one that is used if the widget is active, one that is used if the widget is disabled, and one that is used if the widget is inactive.</P><P>A <TTCLASS="CLASSNAME">QColorGroup</TT> in its turn, is a set of colors with certain roles:</P><P></P><UL><LI><P>Background - general background color.</P></LI><LI><P>Foreground - general foreground color.</P></LI><LI><P>Base - background color text entry widgets </P></LI><LI><P>Text - the foreground color used with Base.</P></LI><LI><P>Button - general button background color</P></LI><LI><P>ButtonText - for button texts</P></LI><LI><P>Light - lighter than Button color. </P></LI><LI
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?