📄 index.lxp@lxpwrap=x6734_252ehtm.htm
字号:
>QRegExp</TT> here (though it is a little underpowered in its Qt 2.3 incarnation compared to <TTCLASS="FILENAME">re</TT> and Qt 3.0's <TTCLASS="CLASSNAME">QRegExp</TT>).</P><P>A <TTCLASS="CLASSNAME">QRegExp</TT> is constructed from a string that contains the patterns that should be matched, and two options. The first option determines whether the search should be case sensitive; the second determines whether or not the search is a wildcard search. Wildcard searches work like the filename expansion on a Unix command line, and are not terribly useful for searching in a text.</P><P><TTCLASS="CLASSNAME">QRegExp</TT> has two tools for searching: <TTCLASS="FUNCTION">match()</TT> and <TTCLASS="FUNCTION">find()</TT>. Both take as parameters the <TTCLASS="CLASSNAME">QString</TT> to be searched and the position from which searching should start. However, <TTCLASS="FUNCTION">match()</TT> also returns the length of the string that is found, and can take an optional parameter that indicates whether the start position should match the regular expression character "^" (start of input). You don't want this for searching in editable text, so we make it FALSE by default.</P><P>Literal searching is a simple matter of applying the <TTCLASS="FUNCTION">find()</TT> method of <TTCLASS="CLASSNAME">QString</TT> from the current position.</P><P>Looking for an occurrence returns either -1, if nothing was found, or the begin and end positions of the string that was found. Note that <TTCLASS="CLASSNAME">QString</TT>.<TTCLASS="FUNCTION">find()</TT> doesn't return the length of the found string; we take the <TTCLASS="FUNCTION">length()</TT> of the search string to determine the end position.</P><PRECLASS="PROGRAMLISTING"> def previousOccurrence(self): findText = self.cmbFind.currentText() caseSensitive = self.chkCaseSensitive.isChecked() pos = self.view.text().findRev(findText, self.currentPosition, caseSensitive) return (pos, pos + findText.length()) </PRE><P>Qt 2.3 doesn't yet support backwards searching with regular expressions, so the function <TTCLASS="FUNCTION">previousOccurrence</TT> is quite a bit simpler. Instead of <TTCLASS="CLASSNAME">QString</TT>.<TTCLASS="FUNCTION">find()</TT>, <TTCLASS="CLASSNAME">QString</TT>.<TTCLASS="FUNCTION">findRev()</TT> is used - this searches backwards.</P><PRECLASS="PROGRAMLISTING"> def slotFindNext(self): if self.radioForward.isChecked(): begin, end = self.nextOccurrence() if begin > -1: self.view.setSelection(begin, end) self.currentPosition = end return (begin, end) else: if (self.chkSelection.isChecked() == FALSE and self.chkWholeText.isChecked() == FALSE): self.wrapExtentForward() return (self.currentPosition, self.currentPosition) else: begin, end = self.previousOccurrence() if begin > -1: self.view.setSelection(begin, end) self.currentPosition = begin -1 return (begin, end) else: if (self.chkSelection.isChecked() == FALSE and self.chkWholeText.isChecked() == FALSE): self.wrapExtentBackward() return (self.currentPosition, self.currentPosition) </PRE><P>The <TTCLASS="FUNCTION">slotFindNext</TT> slot is the central bit of intelligence in this class. Depending upon the selected direction, the next or previous occurrence of the search string is searched. If an occurrence is found (when <TTCLASS="VARNAME">begin</TT> is greater than -1), it is selected, and the current position is moved. If there are no more matches, the user is asked whether he or she wants to go on with the rest of the document. </P><PRECLASS="PROGRAMLISTING"> def slotReplaceNext(self): begin, end = self.slotFindNext() if self.view.hasSelection(): self.view.replaceSelection(self.cmbReplace.currentText()) return begin, end else: return -1, -1 def slotReplaceAll(self): begin, end = self.slotReplaceNext() while begin > -1: begin, end = self.slotReplaceNext() print begin, end </PRE><P>Replacing is one part finding, one part replacing. The <TTCLASS="FUNCTION">slotFindNext()</TT> code is reused, which is one good reason for creating a dialog that has both a find and a find and replace mode. <TTCLASS="FUNCTION">slotFindNext()</TT> already selects the match, so replacing is a simple matter of deleting the match and inserting the replacement string. This is done with a new function in <TTCLASS="CLASSNAME">KalamView</TT>:</P><PRECLASS="PROGRAMLISTING">...class KalamView(QWidget):... def replaceSelection(self, text): self.editor.deleteChar() self.editor.insert(text) self.editor.emit(SIGNAL("textChanged()"),()) </PRE><P>Messing about with the text in a <TTCLASS="CLASSNAME">QMultiLineEdit</TT> widget has a few tricky points. You should avoid trying to directly change the <TTCLASS="CLASSNAME">QString</TT> that you retrieve with <TTCLASS="CLASSNAME">QMultiLineEdit</TT>.<TTCLASS="FUNCTION">text()</TT>— changing this string behind the editor's back is a sure recipe for a beautiful crash. <TTCLASS="CLASSNAME">QMultiLineEdit</TT> has several functions, such as <TTCLASS="FUNCTION">deleteChar()</TT> (which not only deletes characters, but also the selection, if there is one), to alter the contents. However, these functions don't emit the <TTCLASS="FUNCTION">textChanged()</TT> signal— you will have to do that yourself. If we do not emit <TTCLASS="FUNCTION">textChanged()</TT>, other views on the same document won't know of the changes, nor will the document itself know it has been changed.</P><P>Another interesting complication occurs because <TTCLASS="CLASSNAME">QMultiLineEdit</TT>, the editor widget used in <TTCLASS="CLASSNAME">KalamView</TT>, works with line and column positioning, not with a position within the string that represents the text. This makes it necessary to create conversion functions between string index and editor line / column position in <TTCLASS="CLASSNAME">KalamView</TT>, which is potentially very costly business for long files:</P><PRECLASS="PROGRAMLISTING">...class KalamView(QWidget):... def getLineCol(self, p): i=p for line in range(self.editor.numLines()): if i < self.editor.textLine(line).length(): return (line, i) else: # + 1 to compensate for \n i-=(self.editor.textLine(line).length() + 1) # fallback return (0,0) def setCursorPosition(self, p): """Sets the cursor of the editor at position p in the text.""" l, c = self.getLineCol(p) self.editor.setCursorPosition(l, c) def getPosition(self, startline, startcol): if startline = 0: return startcol if startline > self.editor.numLines(): return self.editor.text().length() i=0 for line in range(self.editor.numLines()): if line < startline: i += self.editor.textLine(line).length() else: return i + startcol def getCursorPosition(self): """Get the position of the cursor in the text""" if self.editor.atBeginning(): return 0 if self.editor.atEnd(): return self.editor.text().length() l, c = self.editor.getCursorPosition() return self.getPosition(l, c) </PRE><P>The function <TTCLASS="FUNCTION">getLineCol()</TT> takes a single index position as argument. It then loops through the lines of the editor, subtracting the length of each line from a temporary variable, until the length of the current line is greater than the remaining number of characters. Then we have linenumber and column.</P><P>The same, but in reverse is necessary in <TTCLASS="FUNCTION">getPosition</TT> to find out how far into a string the a certain line number and column position is. There are a few safeguards and optimizations, but not quite enough.</P><P>Qt 3 offers the <TTCLASS="CLASSNAME">QTextEdit</TT> class, which is vastly more powerful than <TTCLASS="CLASSNAME">QMultiLineEdit</TT>. For instance, <TTCLASS="CLASSNAME">QTextEdit</TT> sports a built-in find function. Internally, <TTCLASS="CLASSNAME">QTextEdit</TT> is associated with <TTCLASS="CLASSNAME">QTextDocument</TT>, which is comparable to our <TTCLASS="FUNCTION">KalamDocument</TT>. But you can't get at <TTCLASS="CLASSNAME">QTextDocument</TT> (it's not even documented, you need to read the Qt source code to find out about it), so it's not a complete replacement for our document-view architecture. The external rich text representation of <TTCLASS="CLASSNAME">QTextEdit</TT> is a subset of html, which makes it less suitable for a programmer's editor. You have to choose: either colorized, fontified text, and filter the html codes out yourself, or a plain text editor. Fortunately, Qt 3 still includes <TTCLASS="CLASSNAME">QMultiLineEdit</TT> for compatibility reasons.</P></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=c6351_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=x6992_252ehtm.htm">Next</A></TD></TR><TR><TDWIDTH="33%"ALIGN="left"VALIGN="top">Using Dialog Windows</TD><TDWIDTH="34%"ALIGN="center"VALIGN="top"><A accesskey="U" href="index.lxp@lxpwrap=c6351_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 + -