使用视图的委托方法(PySide/Qt/PyQt)将QMainWindow中的动作连接起来 [英] Connect action in QMainWindow with method of view's delegate (PySide/Qt/PyQt)

查看:79
本文介绍了使用视图的委托方法(PySide/Qt/PyQt)将QMainWindow中的动作连接起来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a QTreeView displaying data from a QStandardItemModel. One of the columns of the tree is displayed with a delegate that lets the user edit and display rich text. Below is a SSCCE that limits the editing to bold (with keyboard shortcut).

当用户编辑其中一项时,如何设置它,以便除了使用键盘快捷键(CTRL-B)切换粗体之外,用户还可以使用工具栏图标进行切换?

When the user is editing one of the items, how can I set it up so that in addition to toggling boldness with keyboard shortcut (CTRL-B), the user can also toggle it using the toolbar icon?

到目前为止,键盘快捷键的效果很好(您可以双击,编辑文本,并且CTRL-B将切换为粗体).但是,我还没有弄清楚如何将工具栏中的粗体按钮连接到适当的插槽:

Thus far, the keyboard shortcut works great (you can double click, edit text, and CTRL-B will toggle bold). However, I haven't figured out how to connect the bold button in the toolbar to the appropriate slot:

    self.boldTextAction.triggered.connect(self.emboldenText)

我只是坐在那里,什么都不做:

where I have this just sitting there doing nothing:

def emboldenText(self):
    print "Make selected text bold...How do I do this?"

如果主窗口的中央小部件是文本编辑器,事情将会变得容易:我可以直接调用文本编辑器的toggle bold方法.不幸的是,文本编辑器仅在用户双击开始编辑树时才由树视图的委托临时生成.

Things would be easy if the main window's central widget was the text editor: I could directly invoke the text editor's toggle bold method. Unfortunately, the text editor is only generated transiently by the tree view's delegate when the user double-clicks to start editing the tree.

也就是说,我们有这种复杂的关系:

That is, we have this complicated relationship:

QMainWindow-> QTreeView-> Delegate.CreateEditor-> QTextEdit.toggleBold()

QMainWindow -> QTreeView -> Delegate.CreateEditor -> QTextEdit.toggleBold()

如何从主窗口中访问toggleBold()以供工具栏操作使用,特别是考虑到编辑器仅在用户打开时临时创建?

How do I access toggleBold() from within the main window for use by the toolbar action, especially given that the editor is only created temporarily when opened by the user?

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

I realize this may not be a PySide/Qt question as much as a Python/OOP question, so I've included additional potentially relevant tags. Any help with improving my word choice/jargon would be appreciated too.

SSCCE

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

Note for those that want the Full Tree Experience, with the button in the toolbar, here it is you can put it in the same folder as the script (change the name to boldText.png:

推荐答案

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

I think from a design point of view the top window is a sort of global. You have already described a behaviour which is treating it in that way and (as ekhumoro has said) that pretty much requires you to provide access to that top window to the editor.

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

One very simple way to do that is to call parent.window() in the createEditor method. Maybe something like:

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

这似乎对我有用.

这篇关于使用视图的委托方法(PySide/Qt/PyQt)将QMainWindow中的动作连接起来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆