📄 index.lxp@lxpwrap=c1267_252ehtm.htm
字号:
<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™</div> </div> </td></tr></table> <div align="center" class="author"> <a href="../products.lxp">Products</a> | <a href="../wheretobuy.lxp">Where to buy</a> | <a href="../bookstore.lxp">Retailers</a> | <a href="../faq.lxp">FAQ</a> | <a href="../writeforus.lxp">Write for Us.</a> | <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>Signals and Slots in Depth</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="PyQt fundamentals"HREF="p1032.htm"><LINKREL="PREVIOUS"TITLE="Conclusion"HREF="x1263.htm"><LINKREL="NEXT"TITLE="Connecting with signals and slots"HREF="x1408.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"><A accesskey="P" href="index.lxp@lxpwrap=x1263_252ehtm.htm">Prev</A></TD><TDWIDTH="80%"ALIGN="center"VALIGN="bottom"></TD><TDWIDTH="10%"ALIGN="right"VALIGN="bottom"><A accesskey="N" href="index.lxp@lxpwrap=x1408_252ehtm.htm">Next</A></TD></TR></TABLE><HRALIGN="LEFT"WIDTH="100%"></DIV><DIVCLASS="CHAPTER"><H1>Chapter 7. Signals and Slots in Depth</A></H1><DIVCLASS="TOC"><DL><DT><B>Table of Contents</B></DT><DT><A href="index.lxp@lxpwrap=c1267_252ehtm.htm#AEN1273">The concept of signals and slots</A></DT><DT><A href="index.lxp@lxpwrap=x1408_252ehtm.htm">Connecting with signals and slots</A></DT><DT><A href="index.lxp@lxpwrap=x1631_252ehtm.htm">Disconnecting</A></DT><DT><A href="index.lxp@lxpwrap=x1807_252ehtm.htm">A parser-formatter using signals and slots</A></DT><DT><A href="index.lxp@lxpwrap=x2026_252ehtm.htm">Conclusion</A></DT></DL></DIV><P>The concept of signals and slots is possibly the most interesting innovation in the Qt library. Good widgets and a clean API are rare, but not unique. But until Qt appeared on the horizon, connecting your widgets with your application and your data was a nasty and error-prone endeavor — even in Python. I will first discuss the problem that is solved by signals and slots in some detail; then I will introduce the actual mechanics of the signal/slot mechanism, and finish with an application of the technique outside the GUI domain.</P><DIVCLASS="SECT1"><H1CLASS="SECT1">The concept of signals and slots</A></H1><P>The problem in a nutshell: imagine you have an application, and the application shows a button on screen. Whenever the button is pressed, you want a function in your application to execute. Of course, you'd prefer that the button doesn't know much about the application, or you would have to write a different button for each application. In the next example, the button has been coded to work only with an application that has the <TTCLASS="FUNCTION">doSomeApplicationSpecificFunction</TT> function. </P><DIVCLASS="EXAMPLE"></A><P><B>Example 7-1. A stupid button which is not reusable</B></P><PRECLASS="PROGRAMLISTING">## stupid_button.py — this button is not reusable#class Button: def __init__(self, application): self.application = application def clicked(self): self.application.doSomeApplicationSpecificFunction()class Application: def __init__(self): self.button=Button(self) def doSomeApplicationSpecificFunction(self): print "Function called"app=Application()app.button.clicked() # simulate a user button press </PRE></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2">Callbacks</A></H2><P>This is no solution— the button code isn't reusable at all. A better solution would be to pass the <SPAN><ICLASS="EMPHASIS">function</I></SPAN> object to the button. Remember that in Python functions are objects just like everything else. In a language like C or C++ you would pass a <SPAN><ICLASS="EMPHASIS">function pointer</I></SPAN>, the actual memory address of the function being called. This is quite nasty, because there is no way the compiler can check what arguments are passed to the function represented by the function pointer. In Python, passing functions around is really easy.</P><DIVCLASS="EXAMPLE"></A><P><B>Example 7-2. A simple callback system</B></P><PRECLASS="PROGRAMLISTING">## callback.py — handing the function over the the app#class Button: def __init__(self, function): self.callbackFunction = function def clicked(self): apply(self.callbackFunction)class Application: def __init__(self): self.button=Button(self.doSomeApplicationSpecificFunction) def doSomeApplicationSpecificFunction(self): print "Function called"app=Application()app.button.clicked() # simulate a user button press </PRE></DIV><DIVCLASS="NOTE"><BLOCKQUOTECLASS="NOTE"></A><P><B>Using <TTCLASS="FUNCTION">apply()</TT> to execute function objects.: </B>Note the usage of the <TTCLASS="FUNCTION">apply()</TT> function in the <TTCLASS="FUNCTION">clicked()</TT> function — this Python built-in function executes the function object you pass as the first argument argument. You can also hand it parameters, as a tuple in the second argument to <TTCLASS="FUNCTION">apply()</TT>. You'll see that idiom quite often when we subclass Qt classes:</P><PRECLASS="PROGRAMLISTING">class MyWidget(QWidget): def __init__(self, *args): apply(QWidget.__init__, (self,) + args) </PRE><P>This is useful because <TTCLASS="CLASSNAME">QWidget</TT> and the other Qt classes often have a lot of optional parameters, such as the object name or certain widget flags. If we discount the possibility that someone wants to use those optional parameters, we would write:</P><PRECLASS="PROGRAMLISTING">class MyWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) </PRE><P>This is far less flexible. In the previous example, we created an argument tuple to be passed to the <TTCLASS="FUNCTION">__init__()</TT> by first creating a tuple containing our own object reference - <TTCLASS="VARNAME">self</TT>, and then adding the arguments from the variable positional argument list to that tuple. Remember from the discussion of positional arguments in <A href="index.lxp@lxpwrap=x719_252ehtm.htm#CH24POSITIONALARGUMENTS">the Section called <I>Methods and functions</I> in Chapter 4</A> that the arguments in *args <SPAN><ICLASS="EMPHASIS">are</I></SPAN> a tuple, and you can create a new tuple by adding two tuples.</P><P>In more recent versions of Python, you don't need to use <TTCLASS="FUNCTION">apply()</TT> anymore to call the constructor of a superclass with a variable number of arguments. That is, from version 2.0 of Python you can also use the following construction:</P><PRECLASS="SCREEN">>>> class O(QObject):... def __init__(self, *args):... QObject.__init__(self, *args)... >>> a=O()>>> b=O(a, "bla")>>> b<__main__.O instance at 0x82b5c3c>>>> b.name()'bla'>>> b.parent()<__main__.O instance at 0x8106cb4>>>> </PRE><P>That is, when calling the constructor of the superclass, you can pass <TTCLASS="VARNAME">self</TT> as the first argument, and then the argument list, with asterisks and all.</P></BLOCKQUOTE></DIV></DIV><DIVCLASS="SECT2"><H2CLASS="SECT2">Action registry</A></H2><P>Unfortunately, this callback system is not quite generic enough. For example, what if you wanted to activate two functions when the button is pressed? While this is not likely in the simple example, under more complex situations it often occurs. Think of a text editor where editing the text should change the internal representation of the document, the word count in the statusbar, and the edited-indicator in the titlebar. You wouldn't want to put all this functionality in one function, but it is a natural fit for signals and slots. You could have one signal, <TTCLASS="FUNCTION">textChanged</TT>, that is connected to three functions: <TTCLASS="FUNCTION">changeText()</TT>, <TTCLASS="FUNCTION">setWordCount()</TT>, <TTCLASS="FUNCTION">setEdited()</TT>.</P><P>Wouldn't it be extremely comfortable to simply have a central registry where interested parties could come together? Something like:</P><DIVCLASS="EXAMPLE"></A><P><B
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -