⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 index.lxp@lxpwrap=x7601_252ehtm.htm

📁 GUI Programming with Python
💻 HTM
📖 第 1 页 / 共 2 页
字号:
>self.items</TT>.</P><P>If the end of a line is reached,          drawing continues on the next line.</P><P>An <SPAN><ICLASS="EMPHASIS">essential</I></SPAN>          step, and one which I tend to forget myself, is to resize          the <TTCLASS="CLASSNAME">QCanvas</TT> after having determined          what space the items take. You can place items outside the          confines of the canvas, and they won't show unless you          resize the canvas to include them.</P><P>Finally, you must          <TTCLASS="FUNCTION">update()</TT> the          <TTCLASS="CLASSNAME">QCanvas</TT> &#8212; otherwise you still          won't see anything. This method updates all          <TTCLASS="CLASSNAME">QCanvasView</TT> objects that show this          canvas.</P><P>Setting the font involves drawing the          table anew. This is more efficient than applying the font          change to each individual <TTCLASS="CLASSNAME">QCanvasText</TT>          item &#8212; even though that is perfectly possible. The          reason is that if the font metrics change, for instance          because the new font is a lot larger, you will have to check          for collisions and adjust the location of all items anyway.          That would take not only a lot of time, it would also demand          complex and unmaintainable code. Simple is good, as far as          I'm concerned.</P><P>This little table shows almost nothing          of the power of <TTCLASS="CLASSNAME">QCanvas</TT> &#8212; you          can animate the objects, determine if they overlap, and lots          more. It offers everything you need, for instance, to write          your very own <SPAN><ICLASS="EMPHASIS">Asteroids</I></SPAN> clone...</P></DIV><DIVCLASS="SECT3"><H3CLASS="SECT3">The view on the canvas</A></H3><P>Putting stuff on a canvas          is useless, unless you can also see what you've done. You          can create one or more <TTCLASS="CLASSNAME">QCanvasView</TT>          objects that show the contents of canvas. Each view can show          a different part, but every time you call          <TTCLASS="FUNCTION">update()</TT> (or          <TTCLASS="FUNCTION">advance()</TT>, which advances all animated          objects), all views are updated.</P><P>The most important work your          <TTCLASS="CLASSNAME">QCanvasView</TT> subclasses have is to          react on user input. Here, we draw a cursor rectangle round          selected glyphs and emit signals for every          mousepress.</P><PRECLASS="PROGRAMLISTING">class CharsetBrowser(QCanvasView):    def __init__(self, *args):        apply(QCanvasView.__init__,(self,)+args)    def setCursor(self, item):        self.cursorItem=QCanvasRectangle(self.canvas())        self.cursorItem.setX(item.boundingRect().x() -2)        self.cursorItem.setY(item.boundingRect().y() -2)        self.cursorItem.setSize(item.boundingRect().width() + 4,                                item.boundingRect().height() + 4)        self.cursorItem.setZ(-1.0)        self.cursorItem.setPen(QPen(QColor(Qt.gray), 2, Qt.DashLine))        self.cursorItem.show()        self.canvas().update()    def contentsMousePressEvent(self, ev):        try:            items=self.canvas().collisions(ev.pos())            self.setCursor(items[0])            self.emit(PYSIGNAL("sigMousePressedOn"), (items[0].text(),))        except IndexError:            pass    def setFont(self, font):        self.font=font        self.canvas().setFont(self.font)        </PRE><P>First, the drawing of the cursor. You          can see that you don't need to create your canvas items in          the <TTCLASS="CLASSNAME">QCanvas</TT> class or its derivatives.          Here, it is done in the <TTCLASS="FUNCTION">setCursor()</TT>          method. This method is called with the activated          <TTCLASS="CLASSNAME">QCanvasText</TT> item as its          parameter.</P><P>A new item is created, a          <TTCLASS="CLASSNAME">QCanvasRectangle</TT> called          <TTCLASS="VARNAME">self.cursorItem</TT>. It's an instance, not a          local variable, because otherwise the rectangle would          disappear once the item goes out of scope (because the function          finishes).</P><P>The location and dimensions of the          rectangle are determined. It will be a two-pixel wide, gray,          dashed line exactly outside the current glyph. Of course, it          must be shown, and the canvas must call          <TTCLASS="FUNCTION">update()</TT> in order to notify the          view(s). Note that you can retrieve a canvas shown by          <TTCLASS="CLASSNAME">QCanvasView</TT> with the          <TTCLASS="FUNCTION">canvas()</TT> function.</P><P>If you consult PyQt's documentation          (or the C++ Qt documentation) on          <TTCLASS="CLASSNAME">QCanvasView</TT>, you will notice that it          is not very well endowed with useful functions.          <TTCLASS="CLASSNAME">QCanvasView</TT> is a type of specialized          <TTCLASS="CLASSNAME">QScrollView</TT>, and this class offers          lots of useful methods (for example, event handling methods          for mouse events).</P><P>One of these methods,          <TTCLASS="FUNCTION">contentsMousePressEvent</TT>, is highly          useful. It is called whenever a user clicks somewhere on the          canvas view. You can then use the coordinates of the click          to determine which <TTCLASS="CLASSNAME">QCanvasItem</TT>          objects were hit. The coordinates of the mouse click can be          retrieved with the <TTCLASS="FUNCTION">pos()</TT> function of          the <TTCLASS="VARNAME">ev</TT>          <TTCLASS="CLASSNAME">QMouseEvent</TT>. You then check which          <TTCLASS="CLASSNAME">QCanvasItem</TT> objects were hit using          the collision detection <TTCLASS="CLASSNAME">QCanvas</TT>          provides with the <TTCLASS="FUNCTION">collisions()</TT>.</P><P>The result is a list of items. Because          we <SPAN><ICLASS="EMPHASIS">know</I></SPAN> that there are no overlapping          items on our canvas, we can simply take the first          <TTCLASS="CLASSNAME">QCanvasText</TT> item: that's          <TTCLASS="VARNAME">items[0]</TT>. Now we have the selected glyph.          The <TTCLASS="FUNCTION">setCursor()</TT> function is called to          draw a rectangle around the glyph. Then a signal is emitted,          which can be caught by other widgets. This signal is          ultimately responsible for getting the selected character in          the <SPANCLASS="APPLICATION">Kalam</SPAN> document.</P></DIV><DIVCLASS="SECT3"><H3CLASS="SECT3">Tying the canvas and view together</A></H3><P>The <TTCLASS="CLASSNAME">CharMap</TT>          widget is a specialized <TTCLASS="CLASSNAME">QWidget</TT> that          contains the three components we developed above.</P><P>A vertical layout manager contains the          selection combobox and the          <TTCLASS="CLASSNAME">CharsetBrowser</TT>          <TTCLASS="CLASSNAME">QCanvasView</TT> widget. Every time a new          script is selected, a new          <TTCLASS="CLASSNAME">CharsetCanvas</TT> is created &#8212; this          is easier than erasing the contents of the existing          canvas.</P><PRECLASS="PROGRAMLISTING">class CharMap(QWidget):    def __init__(self,                 parent,                 initialFont = "arial",                 datadir = "unidata",                 *args):        apply(QWidget.__init__, (self, parent, ) + args)        self.parent=parent        self.font=initialFont        self.box=QVBoxLayout(self)        self.comboCharset=CharsetSelector(datadir, FALSE, self)        self.box.addWidget(self.comboCharset)        self.charsetCanvas=CharsetCanvas(self, self.font, 0, 0, 0)        self.charsetBrowser=CharsetBrowser(self.charsetCanvas, self)        self.box.addWidget(self.charsetBrowser)        self.setCaption("Unicode Character Picker")        self.connect(qApp,                     PYSIGNAL("sigtextfontChanged"),                     self.setFont)        self.connect(self.comboCharset,                     PYSIGNAL("sigActivated"),                     self.slotShowCharset)        self.connect(self.charsetBrowser,                     PYSIGNAL("sigMousePressedOn"),                     self.sigCharacterSelected)        self.resize(300,300)        self.comboCharset.sigActivated(self.comboCharset.currentItem())        </PRE><P>In the constructor of          <TTCLASS="CLASSNAME">CharMap</TT> both the selector combobox          and the canvasview are created. We create an initial canvas          for the view to display. The          <TTCLASS="VARNAME">qApp.sigtextfontChanged</TT> signal is used to          redraw the character map when the application font changes.          Recall how we synthesized signals for all configuration          options in <A href="index.lxp@lxpwrap=c6013_252ehtm.htm">Chapter 18</A>, and used the          globally available <TTCLASS="VARNAME">qApp</TT> object to emit          those signals.</P><PRECLASS="PROGRAMLISTING">    def setFont(self, font):        self.font=font        self.charsetBrowser.setFont(font)    def sigCharacterSelected(self, text):        self.emit(PYSIGNAL("sigCharacterSelected"), (text,))        </PRE><P>Every time a user selects a character, the          <TTCLASS="VARNAME">sigCharacterSelected</TT> signal is emitted.          In <TTCLASS="CLASSNAME">KalamApp</TT>, this signal is connected          to the a slot function that inserts the character in the          current view or window.</P><PRECLASS="PROGRAMLISTING">    def slotShowCharset(self, begin, end):        self.setCursor(Qt.waitCursor)                self.charTable=CharsetCanvas(self,                                     self.font,                                     begin,                                     end,                                     self.width() - 40)        self.charsetBrowser.setCanvas(self.charTable)        self.setCursor(Qt.arrowCursor)                </PRE><P>Drawing a character map can take a          while, especially if you select the set of Chinese          characters, which has a few tens of thousands of entries. In          order to not disquiet the user, we set a waiting          cursor&#8212;this is a small wristwatch on most versions of          Unix/X11, and the familiar sand-timer on Windows. Then a new          canvas is created and the canvas view is told to display          it.</P><DIVCLASS="WARNING"><P></P><TABLECLASS="WARNING"BORDER="1"WIDTH="100%"><TR><TDALIGN="CENTER"><B>Saving Unicode files</B></TD></TR><TR><TDALIGN="LEFT"><P>Recall <A href="index.lxp@lxpwrap=c2029_252ehtm.htm">Chapter 8</A> on            Unicode&#8212; if you implement this character map and            want to save your carefully created Thai letter, you will            be greeted by an encoding error.</P><P>To avoid that, you need to use of the            <TTCLASS="FUNCTION">unicode</TT> function instead of            <TTCLASS="FUNCTION">str()</TT> when converting the            <TTCLASS="CLASSNAME">KalamDoc</TT>.<TTCLASS="VARNAME">text</TT>            <TTCLASS="CLASSNAME">QString</TT> variable to Python            strings.</P></TD></TR></TABLE></DIV><DIVCLASS="NOTE"><BLOCKQUOTECLASS="NOTE"><P><B>Input methods and foreign keyboards: </B>If you have played around with the            version of Kalam that belongs to this chapter, you will no            doubt have noticed that writing a letter in, say, Tibetan,            is not quite as easy as just banging on the keyboard (to            say nothing of writing Chinese, which demands advanced            hunting and picking skills).</P><P>A character map like we just made is            useful for the occasional phonetic or mathematics character,            but not a substitute for the real stuff: specific keyboard            layouts for alphabetic scripts, like Cyrillic or Thai, and            input method editors for languages like Chinese.</P><P>Properly speaking, it's the job of            the Operating System or the GUI system to provide this            functionality. Specialized keyboard layouts are fairly            easy to come by, at least in the Unix/X11 world. My KDE 2            desktop has lots of keyboard layouts &#8212; perhaps you            have to buy them in the Windows world. Still, it's not            worthwhile to create special keyboard layouts in            PyQt.</P><P>It is possible to create your own keyboard layouts in            PyQt: re-implement the            <TTCLASS="FUNCTION">keyPressEvent()</TT> of the view class and            use each pressed key as an index into a dictionary that            maps plain keyboard key definitions to, say, Tibetan            Unicode characters. This is the same technique we used in             <A href="index.lxp@lxpwrap=c5783_252ehtm.htm">Chapter 17</A> to make sure tab characters            ended up in the text</P><PRECLASS="PROGRAMLISTING">            keymap={Qt.Key_A: QString(u"\u0270")}            def keyPressEvent(self, ev):                if keymap.has_key(ev.key()):                    self.insert(keymap[ev.key()])                else:                    QMultiLineEdit.keyPressEvent(self, ev)          </PRE><P>Input method editors (IME's) are            more difficult. Installing the free Chinese or Japanese            IME's on Unix/X11 is a serious challenge. Getting your            applications to work with them is another challenge. There            are, however, special Chinese, Korean and Japanese            versions of Qt to deal with these problems. As for            Windows, I think you need a special Chinese, Korean or            Japanese version of Windows.</P><P>It can be worthwhile to implement a            Chinese IME, for instance, yourself:</P><DIVCLASS="MEDIAOBJECT"><P><DIVCLASS="CAPTION"><P>A Chinese input method editor                written in Python and PyQt.</P></DIV></P></DIV><P>You can find the code for a            stand-alone Pinyin-based Chinese IME at            http://www.valdyas.org/python/qt2.html &#8212; it's also a            nice example of using large Python dictionaries (every            Mandarin Chinese syllable is mapped to a list characters            with that pronunciation, and Emacs cannot syntax-color the            file containing the dictionary).</P></BLOCKQUOTE></DIV></DIV></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=c7391_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=x7875_252ehtm.htm">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Drawing on Painters and Canvases</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><A accesskey="U" href="index.lxp@lxpwrap=c7391_252ehtm.htm">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Conclusion</TD></TR></TABLE></DIV></BODY></HTML>      </td>      </tr>      </table>      </td>    </tr>  </table>      

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -