index.lxp@lxpwrap=x5388_252ehtm.htm
来自「GUI Programming with Python」· HTM 代码 · 共 576 行 · 第 1/2 页
HTM
576 行
closed! If this view is the first, then it it will be maximized. This is one area where the docmanager still assumes a traditional MDI paradigm — we'll massage this out in the next chapter. Note also that we keep count of the number of views in each document, and then set the caption accordingly.</P><P>Note also that we ‘install' the event filter of the parent object — that is, the application — in the view. This overrides the default event handling of the view object, and makes it possible to use the document manager object.</P><PRECLASS="PROGRAMLISTING"> def createDocument(self, documentClass, viewClass): document = documentClass() view = self._createView(document, viewClass) if self._docToViewMap.has_key(document): self._docToViewMap[document].append(view) else: self._docToViewMap[document] = [view] self._viewToDocMap[view] = document self.emit(PYSIGNAL("sigNumberOfDocsChanged"),()) return document </PRE><P>The <TTCLASS="FUNCTION">createDocument(self, documentClass, viewClass)</TT> command actually instantiates the document. When that's done, a view is created and mapped to the document. Note the signal we emit here: it can be useful for the application object to know that the number of documents has been changed. For instance, the "save" menu option must be enabled when the first document is created.</P><PRECLASS="PROGRAMLISTING"> def addView(self, document, viewClass): if self._docToViewMap.has_key(document): view = self._createView(document, viewClass) self._docToViewMap[document].append(view) self._viewToDocMap[view] = document return view else: raise DocManagerError(document) </PRE><P>Adding a new view to an existing document is fairly simple: just create the view and map it to a document, and vice versa. Note that if the document does not exist, we raise a <TTCLASS="CLASSNAME">DocManagerError</TT> — the document object apparently doesn't belong to this manager.</P><PRECLASS="PROGRAMLISTING"> def addDocument(self, document, viewClass): view = self._createView(document, viewClass) if self._docToViewMap.has_key(document): self._docToViewMap[document].append(view) else: self._docToViewMap[document] = [view] self._viewToDocMap[view] = document self.emit(PYSIGNAL("sigNumberOfDocsChanged"),()) return view </PRE><P>Of course, it must be possible to add an existing document to the document manager. This is used when the user opens a document.</P><PRECLASS="PROGRAMLISTING"> def activeDocument(self): if self._viewManager.activeWindow() is not None: return self._viewToDocMap[self._viewManager.activeWindow()] else: return None </PRE><P>Since the <TTCLASS="CLASSNAME">QWorkSpace</TT> class, which is the model for the view manager, knows which window is active, we can use that to determine which document is active.</P><PRECLASS="PROGRAMLISTING"> def _saveDocument(self, document): if document.pathName() == None: document.setPathName(self._parent.queryFileName(document)) try: document.save() except Exception, e: QMessageBox.critical(self, "Error", "Could not save the current document: " + e) raise e </PRE><P>The things that can go wrong when trying to save a document are manifold — however, we assume that the document knows when to shout "Exception". If that happens, the user is informed, and the exception re-raised.</P><PRECLASS="PROGRAMLISTING"> def _queryCloseDocument(self, document): if self._parent.queryCloseDocument(document) == QMessageBox.No: return FALSE if document.modified(): save = self._parent.querySaveDocument(document) if save == QMessageBox.Yes: try: self._saveDocument(document) return TRUE except Exception, e: if self._parent.queryDiscardDocument(document) <> \ QMessageBox.Yes: return FALSE else: return TRUE elif save == QMessageBox.No: return TRUE elif save == QMessageBox.Cancel: return FALSE return TRUE </PRE><P>The aim of <TTCLASS="FUNCTION">_queryCloseDocument</TT> is to determine what the user really wants when he closes a document—an action that can throw quite a few wobblies. At every step the function asks the user what he wants. Does he want to save the data? And in case saving doesn't succeed, does he want to discard the document? Or would he prefer to keep the document open, and go on throwing foul looks at an application that contains his precious data, which he cannot save? </P><PRECLASS="PROGRAMLISTING"> def _removeView(self, view, document): try: self._docToViewMap[document].remove(view) del self._viewToDocMap[view] except ValueError, e: pass # apparently already deleted def closeView(self, view): document=self._viewToDocMap[view] if len(self._docToViewMap[document])==1: if self._queryCloseDocument(document): self._removeView(view, document) del self._docToViewMap[document] return TRUE else: return FALSE else: self._removeView(view, document) return TRUE def closeDocument(self, document): l=self._docToViewMap[document][:] for view in l: if view.close(TRUE) == FALSE: return FALSE self.emit(PYSIGNAL("sigNumberOfDocsChanged"),()) return TRUE def closeAllDocuments(self): for document in self._docToViewMap.keys(): if not self.closeDocument(document): raise DocumentsRemainingError() </PRE><P>Getting rid of documents and views can become quite complicated if you take into consideration all the various methods available: a user can click on the close button in the titlebar of the application, or in the view, or activate the "close" <TTCLASS="CLASSNAME">QAction</TT>. In order to catch the first possibility, we need to use event filters. Clicking on the close button does not generate a signal we can connect to. That being so, we should only call <TTCLASS="FUNCTION">close()</TT> on the view, if we know that the closing has <SPAN><ICLASS="EMPHASIS">not</I></SPAN> been initiated through the event filter (otherwise we would fire the event filter again).</P><P>However, when the user selects "close document" or "close all documents" from the menu or the toolbar, <TTCLASS="FUNCTION">close()</TT> will not be automatically called on the view — we have to do this ourselves. By looping through all views in the document, and closing them, we will generate an event: the event will be handled by the event filter, which will call <TTCLASS="FUNCTION">closeView()</TT> for us. And <TTCLASS="FUNCTION">closeView()</TT> will ask the user whether it really wants to close the document if the view is the last one.</P><P>It's an interesting exercise to follow this happening with the BlackAdder debugger.</P></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=x5339_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=x5451_252ehtm.htm">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Document/View Manager</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><A accesskey="U" href="index.lxp@lxpwrap=c5288_252ehtm.htm">Up</A></TD><TDWIDTH="33%"ALIGN="right"VALIGN="top">Document</TD></TR></TABLE></DIV></BODY></HTML> </td> </tr> </table> </td> </tr> </table>
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?