index.lxp@lxpwrap=x1408_252ehtm.htm

来自「GUI Programming with Python」· HTM 代码 · 共 1,236 行 · 第 1/2 页

HTM
1,236
字号
    <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&#153;</div>    </div>      </td></tr></table>    <div align="center" class="author">      	<a href="../products.lxp">Products</a>	&nbsp;|&nbsp;	<a href="../wheretobuy.lxp">Where to buy</a>	&nbsp;|&nbsp;	<a href="../bookstore.lxp">Retailers</a>	&nbsp;|&nbsp;	<a href="../faq.lxp">FAQ</a>	&nbsp;|&nbsp;        <a href="../writeforus.lxp">Write for Us.</a>        &nbsp;|&nbsp;        <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>Connecting with signals and slots</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="Signals and Slots in Depth"HREF="c1267.htm"><LINKREL="PREVIOUS"TITLE="Signals and Slots in Depth"HREF="c1267.htm"><LINKREL="NEXT"TITLE="Disconnecting"HREF="x1631.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=c1267_252ehtm.htm">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom">Chapter 7. Signals and Slots in Depth</TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><A accesskey="N" href="index.lxp@lxpwrap=x1631_252ehtm.htm">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="SECT1"><H1CLASS="SECT1">Connecting with signals and slots</A></H1><P>Signals and slots come in two basic      varieties: Vanilla, or C++ signals and slots (as defined in the      Qt library) and Pythonic (signals and slots defined in Python).      Any function of any object can be used as a slot in Python (you      don't even have to inherit from <TTCLASS="CLASSNAME">QObject</TT>).      This contrasts to C++, where you need to specially mark a      function as a slot in order to be able to connect it to a signal      (and have to inherit <TTCLASS="CLASSNAME">QObject</TT>).</P><P>Every class that descends from      <TTCLASS="CLASSNAME">QObject</TT> is eligible for the sending      (<SPAN><ICLASS="EMPHASIS">emitting</I></SPAN> is the technical term) and      connecting of signals to its own methods. That means that if      your Python class is to emit signals it has to ultimately      inherit <TTCLASS="CLASSNAME">QObject</TT>.</P><P>Connections are made using the      <TTCLASS="FUNCTION">connect()</TT> method. This is a class method of      <TTCLASS="CLASSNAME">QObject</TT>, and you can, according to your      preference, use the method on <TTCLASS="CLASSNAME">QObject</TT>, or      on the actual object you're working with.</P><P>You can connect signals to slots, but also      to other signals, creating a chain of notifications. If you want      to disconnect signals from slots, you can use      <TTCLASS="CLASSNAME">QObject</TT>.<TTCLASS="FUNCTION">disconnect()</TT>.       If you want to emit signals from a Python object, you can use      the <TTCLASS="CLASSNAME">QObject</TT>.<TTCLASS="FUNCTION">emit()</TT>      function.</P><P>The connect function can take the following    parameters:</P><P></P><UL><LI><P>sender &#8212; the <TTCLASS="CLASSNAME">QObject</TT> that will          send the signal.        </P></LI><LI><P>signal &#8212; the signal that must be connected        </P></LI><LI><P>receiver &#8212; the <TTCLASS="CLASSNAME">QObject</TT> that has          the slot method that will be called when the signal is          emitted.        </P></LI><LI><P>slot &#8212; the slot method that will be called when the        signal is emitted.        </P></LI></UL><P>If you're connecting your signals from within a class, you can    often omit the third parameter &#8212; the receiver.</P><P>PyQt defines three special functions that      appear to be macros (because of their all-caps spelling, as in      C++) but are in fact just functions. (In fact, there are no      macros in Python). These are <TTCLASS="FUNCTION">SLOT()</TT>,      <TTCLASS="FUNCTION">SIGNAL()</TT> and      <TTCLASS="FUNCTION">PYSIGNAL()</TT>.</P><P>Two of these functions are meant for      signals and slots defined in C++; the other is meant for signals      defined in Python. Signals and slots defined in C++ are      connected on the level of C++ (i.e., not in the sip registry)      and can be a bit faster.</P><P>The first function is      <TTCLASS="FUNCTION">SLOT()</TT>, which marks its only argument, a      string, as a slot defined in the Qt library, i.e. in C++. The      corresponding <TTCLASS="FUNCTION">SIGNAL</TT>, which also has one      string argument, marks its argument as a signal as defined in      Qt.</P><P>For instance, from the documentation of      <TTCLASS="CLASSNAME">QListview</TT> we can learn that this class      possesses the slot <TTCLASS="FUNCTION">invertSelection()</TT>. From the      documentation of <TTCLASS="CLASSNAME">QButton</TT> we learn that it      can emit a signal <TTCLASS="FUNCTION">clicked()</TT>. We can      connect a button press to this slot as follows:</P><DIVCLASS="EXAMPLE"></A><P><B>Example 7-4. Connecting a signal to a slot</B></P><PRECLASS="PROGRAMLISTING">## lsv.py - connect a button to a listview#import sysfrom qt import *class MainWindow(QMainWindow):    def __init__(self, *args):        apply(QMainWindow.__init__, (self, ) + args)        self.mainWidget=QWidget(self);                     <IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A>        self.vlayout = QVBoxLayout(self.mainWidget, 10, 5)        self.lsv = QListView(self.mainWidget)              <IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A>        self.lsv.addColumn("First column")        self.lsv.setSelectionMode(QListView.Multi)        self.lsv.insertItem(QListViewItem(self.lsv, "One"))        self.lsv.insertItem(QListViewItem(self.lsv, "Two"))        self.lsv.insertItem(QListViewItem(self.lsv, "Three"))        self.bn = QPushButton("Push Me", self.mainWidget)  <IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A>                self.vlayout.addWidget(self.lsv)        self.vlayout.addWidget(self.bn)        QObject.connect(self.bn, SIGNAL("clicked()"),      <IMGSRC="images/callouts/4.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(4)"></A>                        self.lsv, SLOT("invertSelection()"))        self.setCentralWidget(self.mainWidget)def main(args):    app=QApplication(args)    win=MainWindow()    win.show()    app.connect(app, SIGNAL("lastWindowClosed()")                , app                , SLOT("quit()")                )    app.exec_loop()  if __name__=="__main__":        main(sys.argv)      </PRE><DIVCLASS="CALLOUTLIST"><DLCOMPACT="COMPACT"><DT><A href="index.lxp@lxpwrap=x1408_252ehtm.htm#CH6MAINWIDGET"><IMGSRC="images/callouts/1.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(1)"></A></DT><DD>We want to combine a pushbutton and              a listview in a main window. So we first define a single              main widget that can be managed by the layout manager of              <TTCLASS="CLASSNAME">QMainWindow</TT>, and then add a new              layout manager to that widget. The pushbutton and the              listview then become children of the main widget,              <TTCLASS="VARNAME">self.mainWidget</TT>. </DD><DD><P>You don't need to keep              <TTCLASS="VARNAME">self</TT> references to the widgets,              because these widgets are child objects to              <TTCLASS="CLASSNAME">QMainWindow</TT>. However, if you              later want to access those widgets, it is necessary to              have a reference.</P></DD><DT><A href="index.lxp@lxpwrap=x1408_252ehtm.htm#CH6LISTVIEW"><IMGSRC="images/callouts/2.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(2)"></A></DT><DD>The              <TTCLASS="CLASSNAME">QListView</TT> is a child widget to              the <TTCLASS="VARNAME">mainWidget</TT>. It has one column and              owns three listview items. In order to give the              pushbutton some useful work to do, we allow a multiple              selection.</DD><DT><A href="index.lxp@lxpwrap=x1408_252ehtm.htm#CH6PUSHBUTTON"><IMGSRC="images/callouts/3.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(3)"></A></DT><DD>A very standard pushbutton &#8212;              nothing special, except that is is a child of the              <TTCLASS="VARNAME">mainWidget</TT>.</DD><DT><A href="index.lxp@lxpwrap=x1408_252ehtm.htm#CH6LSVCONNECT"><IMGSRC="images/callouts/4.gif"HSPACE="0"VSPACE="0"BORDER="0"ALT="(4)"></A></DT><DD>This is the actual connection              between the <TTCLASS="FUNCTION">clicked()</TT> signal of the              button and the <TTCLASS="FUNCTION">invertSelection()</TT> of              the listview. If you press the button, you'll notice the              effect.</DD></DL></DIV></DIV><P>Note that the arguments of SIGNAL and SLOT      are used as an index of the dictionary      <SPANCLASS="APPLICATION">sip</SPAN> keeps of available slots and      signals, and that you should match the definition of the signal      and slot as given in the class documentation exactly.</P><P>A more complicated signal/slot combination      can pass an integer along (or even a complete object). Let's      connect the knob of a <TTCLASS="CLASSNAME">QDial</TT> to a few      functions, creating an color dialer. A      <TTCLASS="CLASSNAME">QDial</TT> generates the      <TTCLASS="FUNCTION">valueChanged(int)</TT> signal, which passes the      current value of the dial in the form of an integer to every      slot that's connected to the signal. You need to explicitly      enter the types of the signal arguments, but not their      names.</P><DIVCLASS="EXAMPLE"></A><P><B>Example 7-5. Connection a dial to a label with signals and slots</B></P><PRECLASS="PROGRAMLISTING">## dial.py &#8212; connecting a QDial to a QLabel or two#import sysfrom qt import *class MainWindow(QMainWindow):    def __init__(self, *args):        apply(QMainWindow.__init__, (self, ) + args)        self.vlayout = QVBoxLayout(self, 10, 5)        self.hlayout = QHBoxLayout(None, 10, 5)        self.labelLayout=QHBoxLayout(None, 10, 5)        self.red = 0        self.green = 0        self.blue = 0        self.dialRed = QDial(0, 255, 1, 0, self)        self.dialRed.setBackgroundColor(QColor("red"))        self.dialRed.setNotchesVisible(1)        self.dialGreen = QDial(0, 255, 1, 0, self)        self.dialGreen.setBackgroundColor(QColor("green"))        self.dialGreen.setNotchesVisible(1)        self.dialBlue = QDial(0, 255, 1, 0, self)        self.dialBlue.setBackgroundColor(QColor("blue"))        self.dialBlue.setNotchesVisible(1)        self.hlayout.addWidget(self.dialRed)        self.hlayout.addWidget(self.dialGreen)        self.hlayout.addWidget(self.dialBlue)        self.vlayout.addLayout(self.hlayout)        self.labelRed = QLabel("Red: 0", self)        self.labelGreen = QLabel("Green: 0", self)        self.labelBlue = QLabel("Blue: 0", self)        self.labelLayout.addWidget(self.labelRed)        self.labelLayout.addWidget(self.labelGreen)        self.labelLayout.addWidget(self.labelBlue)        self.vlayout.addLayout(self.labelLayout)        QObject.connect(self.dialRed, SIGNAL("valueChanged(int)"),                        self.slotSetRed)        QObject.connect(self.dialGreen, SIGNAL("valueChanged(int)"),                        self.slotSetGreen)        QObject.connect(self.dialBlue, SIGNAL("valueChanged(int)"),                        self.slotSetBlue)        QObject.connect(self.dialRed, SIGNAL("valueChanged(int)"),                        self.slotSetColor)        QObject.connect(self.dialGreen, SIGNAL("valueChanged(int)"),                        self.slotSetColor)        QObject.connect(self.dialBlue, SIGNAL("valueChanged(int)"),                        self.slotSetColor)    def slotSetRed(self, value):        self.labelRed.setText("Red: " + str(value))        self.red = value    def slotSetGreen(self, value):        self.labelGreen.setText("Green: " + str(value))        self.green = value    def slotSetBlue(self, value):        self.labelBlue.setText("Blue: " + str(value))        self.blue = value    def slotSetColor(self, value):        self.setBackgroundColor(QColor(self.red, self.green, self.blue))        self.labelRed.setBackgroundColor(QColor(self.red, 128, 128))        self.labelGreen.setBackgroundColor(QColor(128, self.green, 128))        self.labelBlue.setBackgroundColor(QColor(128, 128, self.blue))def main(args):    app=QApplication(args)    win=MainWindow()    win.show()    app.connect(app, SIGNAL("lastWindowClosed()")                , app                , SLOT("quit()")                )    app.exec_loop()if __name__=="__main__":        main(sys.argv)      </PRE></DIV><P>Note that we connect the C++ signals      (SIGNAL), to Python functions. You simply give the function      object as the slot argument&#8212; not the result of the      function call. Consider the difference between:</P><PRECLASS="PROGRAMLISTING">      QObject.connect(self.dialBlue,                      SIGNAL("valueChange(int)"),                      self.slotSetColor())    </PRE><P>which is wrong, and:</P><PRECLASS="PROGRAMLISTING">      QObject.connect(self.dialBlue,                      SIGNAL("valueChange(int)"),                      self.slotSetColor)    </PRE><P>which is right. All that difference for two little brackets!      This is a rather frequent typo or thinko. (However, to give you a      glimpse of the dynamic nature of Python, if you have a function      that returns the correct function to connect to the signal, you      do want a function call in      <TTCLASS="FUNCTION">connect()</TT>.)</P><P>Note also that the number and type of arguments of the      signal and the slot you want to connect have to match. When      connecting C++ signals to C++ slots, there is also a bit of

⌨️ 快捷键说明

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