我有QTreeView来自的显示数据QStandardItemModel。树的一列显示有一个委托,该委托使用户可以编辑和显示富文本。下面是一个SSCCE,它将编辑内容限制为粗体(使用键盘快捷键)。
QTreeView
QStandardItemModel
当用户编辑其中一项时,如何设置它,以便除了使用键盘快捷键(CTRL-B)切换粗体之外,用户还可以使用工具栏图标进行切换?
到目前为止,键盘快捷键的效果很好(您可以双击,编辑文本,并且CTRL-B将切换为粗体)。但是,我还没有弄清楚如何将工具栏中的粗体按钮连接到适当的插槽:
self.boldTextAction.triggered.connect(self.emboldenText)
我只有坐在那里什么都不做的地方:
def emboldenText(self): print "Make selected text bold...How do I do this?"
如果主窗口的中央小部件是文本编辑器,事情将会很容易:我可以直接调用文本编辑器的toggle bold方法。不幸的是,当用户双击开始编辑树时,文本编辑器仅由树视图的委托临时生成。
也就是说,我们有这种复杂的关系:
QMainWindow-> QTreeView-> Delegate.CreateEditor-> QTextEdit.toggleBold()
如何从主窗口中访问toggleBold()以供工具栏操作使用,尤其是考虑到编辑器仅在用户打开时临时创建?
我意识到这可能不像Python / OOP问题那样是PySide / Qt问题,因此我加入了其他可能相关的标签。改善我的单词选择/专业术语的任何帮助也将不胜感激。
社会科学中心
#!/usr/bin/env python import platform import sys from PySide import QtGui, QtCore class MainTree(QtGui.QMainWindow): def __init__(self, tree, parent = None): QtGui.QMainWindow.__init__(self) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setCentralWidget(tree) self.createStatusBar() self.createBoldAction() self.createToolbar() self.tree = tree #self.htmlDelegate = self.tree.itemDelegateForColumn(1) def createStatusBar(self): self.status = self.statusBar() self.status.setSizeGripEnabled(False) self.status.showMessage("In editor, keyboard to toggle bold") def createToolbar(self): self.textToolbar = self.addToolBar("Text actions") self.textToolbar.addAction(self.boldTextAction) def createBoldAction(self): self.boldTextAction = QtGui.QAction("Bold", self) self.boldTextAction.setIcon(QtGui.QIcon("boldText.png")) self.boldTextAction.triggered.connect(self.emboldenText) self.boldTextAction.setStatusTip("Make selected text bold") def emboldenText(self): print "Make selected text bold...How do I do this? It's stuck in RichTextLineEdit" class HtmlTree(QtGui.QTreeView): def __init__(self, parent = None): QtGui.QTreeView.__init__(self) model = QtGui.QStandardItemModel() model.setHorizontalHeaderLabels(['Task', 'Priority']) rootItem = model.invisibleRootItem() item0 = [QtGui.QStandardItem('Sneeze'), QtGui.QStandardItem('Low')] item00 = [QtGui.QStandardItem('Tickle nose'), QtGui.QStandardItem('Low')] item1 = [QtGui.QStandardItem('Get a job'), QtGui.QStandardItem('<b>High</b>')] item01 = [QtGui.QStandardItem('Call temp agency'), QtGui.QStandardItem('<b>Extremely</b> <i>high</i>')] rootItem.appendRow(item0) item0[0].appendRow(item00) rootItem.appendRow(item1) item1[0].appendRow(item01) self.setModel(model) self.expandAll() self.resizeColumnToContents(0) self.setToolTip("Use keyboard to toggle bold") self.setItemDelegate(HtmlPainter(self)) class HtmlPainter(QtGui.QStyledItemDelegate): def __init__(self, parent=None): QtGui.QStyledItemDelegate.__init__(self, parent) def paint(self, painter, option, index): if index.column() == 1: text = index.model().data(index) #default role is display (for edit consider fixing Valign prob) palette = QtGui.QApplication.palette() document = QtGui.QTextDocument() document.setDefaultFont(option.font) #Set text (color depends on whether selected) if option.state & QtGui.QStyle.State_Selected: displayString = "<font color={0}>{1}</font>".format(palette.highlightedText().color().name(), text) document.setHtml(displayString) else: document.setHtml(text) #Set background color bgColor = palette.highlight().color() if (option.state & QtGui.QStyle.State_Selected)\ else palette.base().color() painter.save() painter.fillRect(option.rect, bgColor) document.setTextWidth(option.rect.width()) offset_y = (option.rect.height() - document.size().height())/2 painter.translate(option.rect.x(), option.rect.y() + offset_y) document.drawContents(painter) painter.restore() else: QtGui.QStyledItemDelegate.paint(self, painter, option, index) def sizeHint(self, option, index): fm = option.fontMetrics if index.column() == 1: text = index.model().data(index) document = QtGui.QTextDocument() document.setDefaultFont(option.font) document.setHtml(text) return QtCore.QSize(document.idealWidth() + 5, fm.height()) return QtGui.QStyledItemDelegate.sizeHint(self, option, index) def createEditor(self, parent, option, index): if index.column() == 1: editor = RichTextLineEdit(parent) editor.returnPressed.connect(self.commitAndCloseEditor) return editor else: return QtGui.QStyledItemDelegate.createEditor(self, parent, option, index) def commitAndCloseEditor(self): editor = self.sender() if isinstance(editor, (QtGui.QTextEdit, QtGui.QLineEdit)): self.commitData.emit(editor) self.closeEditor.emit(editor, QtGui.QAbstractItemDelegate.NoHint) class RichTextLineEdit(QtGui.QTextEdit): returnPressed = QtCore.Signal() def __init__(self, parent=None): QtGui.QTextEdit.__init__(self, parent) self.setLineWrapMode(QtGui.QTextEdit.NoWrap) self.setTabChangesFocus(True) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) fontMetrics = QtGui.QFontMetrics(self.font()) h = int(fontMetrics.height() * (1.4 if platform.system() == "Windows" else 1.2)) self.setMinimumHeight(h) self.setMaximumHeight(int(h * 1.2)) self.setToolTip("Press <b>Ctrl+b</b> to toggle bold") def toggleBold(self): self.setFontWeight(QtGui.QFont.Normal if self.fontWeight() > QtGui.QFont.Normal else QtGui.QFont.Bold) def sizeHint(self): return QtCore.QSize(self.document().idealWidth() + 5, self.maximumHeight()) def minimumSizeHint(self): fm = QtGui.QFontMetrics(self.font()) return QtCore.QSize(fm.width("WWWW"), self.minimumHeight()) def keyPressEvent(self, event): '''This just handles all keyboard shortcuts, and stops retun from returning''' if event.modifiers() & QtCore.Qt.ControlModifier: handled = False if event.key() == QtCore.Qt.Key_B: self.toggleBold() handled = True if handled: event.accept() return if event.key() in (QtCore.Qt.Key_Enter, QtCore.Qt.Key_Return): self.returnPressed.emit() event.accept() else: QtGui.QTextEdit.keyPressEvent(self, event) def main(): app = QtGui.QApplication(sys.argv) myTree = HtmlTree() #myTree.show() myMainTree = MainTree(myTree) myMainTree.show() sys.exit(app.exec_()) if __name__ == "__main__": main()
请注意,对于那些需要“全树体验”的用户,单击工具栏中的按钮,即可将其与脚本放在同一文件夹中(将名称更改为boldText.png:
boldText.png
从设计的角度来看,我认为顶部窗口是一种全局的窗口。您已经描述了一种以这种方式对其进行处理的行为,并且(如ekhumoro所说),几乎需要您向编辑器提供对该顶部窗口的访问。
一个非常简单的方法是调用parent.window()的createEditor方法。也许像这样:
parent.window()
createEditor
parent.window().boldTextAction.triggered.connect(editor.toggleBold)
这似乎对我有用。