使用视图的委托方法(PySide / Qt / PyQt)将QMainWindow中的动作连接起来

埃里克

我有QTreeView来自的显示数据QStandardItemModel将显示树的一列,其中包含一个委托,该委托使用户可以编辑和显示富文本格式。下面是一个SSCCE,它将编辑内容限制为粗体(使用键盘快捷键)。

当用户编辑其中一项时,如何设置它,以便除了使用键盘快捷键(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()以供工具栏操作使用,特别是考虑到编辑器仅在用户打开时临时创建?

我意识到这可能不是PySide / Qt问题,而是Python / OOP问题,因此我加入了其他可能相关的标签。改善我的单词选择/专业术语的任何帮助也将不胜感激。

社会科学中心

#!/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

在此处输入图片说明

挣扎地

我认为从设计的角度来看,顶部窗口是一种全局的窗口。您已经描述了一种以这种方式对其进行处理的行为,并且(如ekhumoro所说),几乎需要您向编辑器提供对该顶部窗口的访问权限。

一个非常简单的方法是调用parent.window()createEditor方法。也许像这样:

parent.window().boldTextAction.triggered.connect(editor.toggleBold)

这似乎对我有用。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

Qt使用函数将多个信号与插槽连接起来

QT - 将 QPushButtons 与 QCheckBoxes 连接起来

将列名称与R中的列数据连接起来(使用data.table)

Vue.js 如何将字符串与 img src 中的方法连接起来

使用 jmespath 将复杂数据结构中的多个数组连接起来

使用精确匹配和模糊匹配将R中的两个大型数据集连接起来

如何使用 Azure SDK 将私有 vnet 或子网与 Java 中的容器实例连接起来?

如何将“使用”关键字与解构方法连接起来

使用箭头将一个项目内但跨组的点连接起来

使用rbind将具有零值的数据帧列表连接起来

尝试使用 ffmpeg 将多个视频与多个音频流连接起来

如何使用css将椭圆或圆与线连接起来

使用Play Framework和JPA将两个表连接起来

使用CodeIginter将两个带有where子句的表连接起来

使用&&运算符将折叠/可变表达式的输出连接起来

使用over(),R将SpatialPointsDataFrame和SpatialLinesDataFrame连接起来

使用geom_line()将选定的NA之间的点连接起来

拆分功能的反函数:使用分号将字符串连接起来

在R中使用ggplot将移位图与另一图的点连接起来

使用ggplot将分组的点图中的所有点连接起来

使用 Python Flask 将 HTML 页面与 Elasticsearch 连接起来

使用条件条件LINQ将2个数据表连接起来

如何使用 ggplot 将图中的点与一条线连接起来?

SQL:使用CASE将一个表中的记录与另一个表中的计数连接起来

如何使用聚合和查找将 mongodb 中的两个表连接起来,我在第二个表中作为数组?

将一个视图与另一个视图性能连接起来

有没有一种pythonic的方法来将矩阵中沿第一轴的列组连接起来?

寻找一种方法将集合中的值与(B 列)连接起来,当它们的对应值(a 列)相同时,谷歌。床单

将2个div与一个具有透视图的框连接起来