如何使QTreeWidget拖动半透明并保持itemWidgets

2024-09-28 21:51:21 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个在列上设置了itemWidget的treeWidget,但是在拖动之后,这些小部件就消失了,并且放置指示器是不透明的

  1. 如何在删除后使小部件保持不变
  2. 如何使滴落指示器透明?(我在centos 6.5上,合成管理器没有运行)

dropping indicator not transparent

item widgets gone after dropping

可执行示例

#!/usr/bin/env python2
import os
import sys
import re

from PyQt4 import QtGui, QtCore
from PyQt4.QtCore import Qt, QString


class MyTreeWidget(QtGui.QTreeWidget):
    def __init__(self, parent=None):
        super(MyTreeWidget, self).__init__(parent)

class CommandWidget(QtGui.QDialog):

    def __init__(self, parent=None, level=0,script='echo /path/to/script'):
        super(CommandWidget, self).__init__()
        self.layout = QtGui.QHBoxLayout(self)

        browseBtn = QtGui.QPushButton(parent)

        browseBtn.setMinimumSize(QtCore.QSize(0, 25))
        # level, path = val

        # levelNum = re.search('(?<=level).+', level).group()
        browseBtn.setText('%s : %s' % (level, script))
        self._level = int(level)
        self._script = script
        browseBtn.setStyleSheet("text-align: left")

        self.layout.addWidget(browseBtn)

        # self.updateGeometry()
        self.browseBtn = browseBtn
        # self.layout.addWidget(browseBtn)
        self.browseBtn.clicked.connect(self.browseCommandScript)
        self.browseBtn.setIconSize(QtCore.QSize(64, 64))

    def browseCommandScript(self):
        script = QtGui.QFileDialog.getOpenFileName(
            self, 'Select Script file', '/home/xxx/python', ".py Files (*.py);;Executable Files (*)")
        if script:
            self._script = script
            button_label = re.search('[^\\/]*$',script).group()
            self.browseBtn.setText(('%s : %s' % (self._level, button_label)))

    @property
    def level(self):
        return self._level

    @level.setter
    def level(self, value):
        self._level = value

    @property
    def script(self):
        return self._script

    @script.setter
    def script(self, value):
        self._script = value


class MyLineEdit(QtGui.QWidget):
    def __init__(self,value=None,parent=None):
        super(MyLineEdit,self).__init__(parent)
        self.layout = QtGui.QHBoxLayout(self)
        self.layout.setSpacing(0)
        self.layout.setMargin(3)

        self.lineEdit = QtGui.QLineEdit(value)
        spacer1 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
        spacer2 = QtGui.QSpacerItem(20, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)

        self.lineEdit.setContentsMargins(2,2,2,2)
        self.lineEdit.setAlignment(Qt.AlignHCenter)

        self.layout.addItem(spacer1)
        self.layout.addWidget(self.lineEdit)
        self.layout.addItem(spacer2)

        self.lineEdit.setMaximumSize(QtCore.QSize(70, 25))
        self.lineEdit.textEdited.connect(self._update_item_widget_data)

    def text(self):
        return self.lineEdit.text()

    def setText(self,text):
        return self.lineEdit.setText(text)   


    def _update_item_widget_data(self,text):
        # print 'update',text
        self.treeWidgetItem.setData(1,Qt.UserRole,text)

class TheUI(QtGui.QDialog):

    def __init__(self, args=None, parent=None):
        super(TheUI, self).__init__(parent)
        self.layout = QtGui.QVBoxLayout(self)
        treeWidget = MyTreeWidget()

        button = QtGui.QPushButton('Add')
        self.layout.addWidget(treeWidget)
        self.cssEditTE = QtGui.QPlainTextEdit()

        self.layout.addWidget(button)
        self.layout.addWidget(self.cssEditTE)

        self.cssEditTE.textChanged.connect(self._update_css)

        treeWidget.setHeaderHidden(True)
        treeWidget.setRootIsDecorated(False)

        layout = QtGui.QHBoxLayout(self)
        rootDecorationCB = QtGui.QCheckBox('RootIsDecorated')
        layout.addWidget(rootDecorationCB)
        self.layout.addLayout(layout)
        rootDecorationCB.stateChanged.connect(self._update_root_decorated)

        indentationSlider = QtGui.QSlider()
        indentationSlider.setOrientation(Qt.Horizontal)
        indentationSlider.setRange(0,100)
        indentationSlider.setValue(20)
        indentationSlider.valueChanged.connect(self._alter_indentation)
        layout.addWidget(indentationSlider)


        self.layout.setStretchFactor(treeWidget,1)

        self.treeWidget = treeWidget
        self.button = button
        self.button.clicked.connect(lambda *x: self.addCmd())

        HEADERS = ( "script", "chunksize", "mem" )
        self.treeWidget.setHeaderLabels(HEADERS)
        self.treeWidget.setColumnCount( len(HEADERS) )

        self.treeWidget.setColumnWidth(0,200)
        self.treeWidget.header().show()

        for i in range(len(HEADERS)):
            self.treeWidget.headerItem().setTextAlignment(i,Qt.AlignHCenter)


        self.treeWidget.setDragDropMode(QtGui.QAbstractItemView.InternalMove)

        self.treeWidget.setIndentation(60)

        self.resize(500,700)

        for i in xrange(2):
            self.addCmd()

        item = self.addCmd()
        self.addCmd(parent = item)
        self.addCmd(parent = item)
        item = self.addCmd()

        item=self.addCmd(parent = item)
        self.addCmd(parent = item)
        self.addCmd()

        self.treeWidget.setColumnWidth(0,200)

    def addCmd(self, level=0, script='echo /path/to/script',parent=None):
        'add a level to tree widget'

        root = self.treeWidget.invisibleRootItem()

        if parent is None:
            parent = root
        item = QtGui.QTreeWidgetItem(parent)
        # item = QtGui.QTreeWidgetItem(self.treeWidget.invisibleRootItem())
        item.setFlags(item.flags() | QtCore.Qt.ItemIsDropEnabled)

        existingLevels = self.treeWidget.topLevelItemCount()
        # level, path = val
        # level = level % existingLevels

        cmdWidget = CommandWidget(self.treeWidget, existingLevels, script)
        self.treeWidget.setItemWidget(item, 0, cmdWidget)

        line_edit_1 = MyLineEdit('1')
        line_edit_2 = MyLineEdit('200')

        self.treeWidget.setItemWidget(item, 1, line_edit_1)
        self.treeWidget.setItemWidget(item, 2, line_edit_2)

        item.setExpanded(True)
        return item

    def _update_css(self):
        self.treeWidget.setStyleSheet(self.cssEditTE.toPlainText())

    def _update_root_decorated(self,state):
        if state == Qt.Checked:
            self.treeWidget.setRootIsDecorated(True)
        else:
            self.treeWidget.setRootIsDecorated(False)
        self.treeWidget.updateGeometries()

    def _alter_indentation(self,value):
        print value
        self.treeWidget.setIndentation(value)
        self.treeWidget.updateGeometries()



if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    gui = TheUI()
    gui.show()
    app.exec_()

Tags: textselfnoneinitvaluedefscriptitem
1条回答
网友
1楼 · 发布于 2024-09-28 21:51:21

1) How can i make the widget persist after dropping ?

请使用此工具了解如何使用QItemDelegate(运行在Windows 7、Python 2.7、pyqt4中):

import sys
import os
from PyQt4 import QtCore, QtGui
from functools import partial

class QCustomDelegate (QtGui.QItemDelegate):
    def createEditor (self, parentQWidget, optionQStyleOptionViewItem, indexQModelIndex):
        column = indexQModelIndex.column()
        if column == 0:
            editorQWidget = QtGui.QPushButton(parentQWidget)
            self.connect(editorQWidget, QtCore.SIGNAL('released()'), partial(self.requestNewPath, indexQModelIndex))
            return editorQWidget            
        elif column in [1, 2]:
            editorQWidget = QtGui.QSpinBox(parentQWidget)
            editorQWidget.setAlignment(QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter)
            editorQWidget.setMinimum(0)
            editorQWidget.setMaximum(2 ** 16)
            return editorQWidget
        else:
            return QtGui.QItemDelegate.createEditor(self, parentQWidget, optionQStyleOptionViewItem, indexQModelIndex)

    def setEditorData (self, editorQWidget, indexQModelIndex):
        column = indexQModelIndex.column()
        if column == 0:
            textQString = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toString()
            editorQWidget.setText(textQString)
        elif column in [1, 2]:
            value, _ = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toInt()
            editorQWidget.setValue(value)
        else:
            QtGui.QItemDelegate.setEditorData(self, editorQWidget, indexQModelIndex)

    def setModelData (self, editorQWidget, modelQAbstractItemModel, indexQModelIndex):
        column = indexQModelIndex.column()
        if column == 0:
            textQString = editorQWidget.text()
            modelQAbstractItemModel.setData(indexQModelIndex, textQString, QtCore.Qt.EditRole)
        elif column in [1, 2]:
            value = editorQWidget.value()
            modelQAbstractItemModel.setData(indexQModelIndex, value, QtCore.Qt.EditRole)
        else:
            QtGui.QItemDelegate.setModelData(self, editorQWidget, modelQAbstractItemModel, indexQModelIndex)

    def updateEditorGeometry(self, editorQWidget, optionQStyleOptionViewItem, indexQModelIndex):
        column = indexQModelIndex.column()
        if column in [0, 1, 2]:
            editorQWidget.setGeometry(optionQStyleOptionViewItem.rect)
        else:
            QtGui.QItemDelegate.updateEditorGeometry(self, editorQWidget, optionQStyleOptionViewItem, indexQModelIndex)

    def requestNewPath (self, indexQModelIndex):
        self.emit(QtCore.SIGNAL('requestNewPath'), indexQModelIndex)

    def paint (self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex):
        column = indexQModelIndex.column()
        if column == 0:
            textQString = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toString()
            foundIndexQModelIndex = indexQModelIndex
            while foundIndexQModelIndex.parent() != QtCore.QModelIndex():
                foundIndexQModelIndex = foundIndexQModelIndex.parent()
            buttonQStyleOptionButton = QtGui.QStyleOptionButton()
            buttonQStyleOptionButton.rect = QtCore.QRect(optionQStyleOptionViewItem.rect)
            buttonQStyleOptionButton.text = str(foundIndexQModelIndex.row() + 1) + ' : ' + os.path.basename(str(textQString))
            buttonQStyleOptionButton.state = QtGui.QStyle.State_Active
            QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_PushButton, buttonQStyleOptionButton, painterQPainter)
        elif column in [1, 2]:
            value, _ = indexQModelIndex.model().data(indexQModelIndex, QtCore.Qt.EditRole).toInt()
            textQStyleOptionViewItem = optionQStyleOptionViewItem
            textQStyleOptionViewItem.displayAlignment = QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter
            currentQRect = QtCore.QRect(optionQStyleOptionViewItem.rect)
            currentQRect.setWidth(currentQRect.width() - 22)
            self.drawDisplay(painterQPainter, textQStyleOptionViewItem, currentQRect, QtCore.QString(str(value)));
            spinBoxQStyleOptionSpinBox = QtGui.QStyleOptionSpinBox()
            spinBoxQStyleOptionSpinBox.rect = QtCore.QRect(optionQStyleOptionViewItem.rect)
            QtGui.QApplication.style().drawComplexControl(QtGui.QStyle.CC_SpinBox, spinBoxQStyleOptionSpinBox, painterQPainter)
        else:
            QtGui.QItemDelegate.paint(self, painterQPainter, optionQStyleOptionViewItem, indexQModelIndex)

class QCustomTreeWidget (QtGui.QTreeWidget):
    def __init__(self, parent = None):
        super(QCustomTreeWidget, self).__init__(parent)
        self.setDragEnabled(True)
        self.setDragDropMode(QtGui.QAbstractItemView.InternalMove)
        self.setColumnCount(3)
        self.setHeaderLabels(('script', 'chunksize', 'mem'))
        for i in range(self.columnCount()):
            self.headerItem().setTextAlignment(i, QtCore.Qt.AlignHCenter)
        self.header().setStretchLastSection(False)
        self.header().setResizeMode(0, QtGui.QHeaderView.Stretch)
        self.setIndentation(60)
        self.setColumnWidth(0, 200)
        myQCustomDelegate = QCustomDelegate()
        self.setItemDelegate(myQCustomDelegate)
        self.connect(myQCustomDelegate, QtCore.SIGNAL('requestNewPath'), self.getNewPath)

    def addMenu (self, script = 'echo path_to_script', chunksize = 1, mem = 200, parentQTreeWidgetItem = None):
        if parentQTreeWidgetItem == None:
            parentQTreeWidgetItem = self.invisibleRootItem()
        currentQTreeWidgetItem = QtGui.QTreeWidgetItem(parentQTreeWidgetItem)
        currentQTreeWidgetItem.setData(0, QtCore.Qt.EditRole, script)
        currentQTreeWidgetItem.setData(1, QtCore.Qt.EditRole, chunksize)
        currentQTreeWidgetItem.setData(2, QtCore.Qt.EditRole, mem)
        currentQTreeWidgetItem.setFlags(currentQTreeWidgetItem.flags() | QtCore.Qt.ItemIsEditable)
        for i in range(self.columnCount()):
            currentQSize = currentQTreeWidgetItem.sizeHint(i)
            currentQTreeWidgetItem.setSizeHint(i, QtCore.QSize(currentQSize.width(), currentQSize.height() + 30))
        currentQTreeWidgetItem.setExpanded(True)
        return currentQTreeWidgetItem

    def getNewPath (self, indexQModelIndex):
        currentQTreeWidgetItem = self.itemFromIndex(indexQModelIndex)
        pathQString = QtGui.QFileDialog.getOpenFileName (
            self, 'Select Script file', '', '.py Files (*.py);;Executable Files (*)')
        if not pathQString.isEmpty():
            currentQTreeWidgetItem.setData(indexQModelIndex.column(), QtCore.Qt.EditRole, pathQString)

class QCustomQDialog (QtGui.QDialog):
    def __init__ (self, parent = None):
        super(QCustomQDialog, self).__init__(parent)
        self.myQCustomTreeWidget = QCustomTreeWidget(self)
        self.addQPushButton = QtGui.QPushButton('Add', self)
        self.connect(self.addQPushButton, QtCore.SIGNAL('released()'), self.myQCustomTreeWidget.addMenu)
        self.cssQPlainTextEdit = QtGui.QPlainTextEdit(self)
        self.connect(self.cssQPlainTextEdit, QtCore.SIGNAL('textChanged()'), self.updateCss)
        self.rootDecorationCBQCheckBox = QtGui.QCheckBox('Root is decorated')
        self.connect(self.rootDecorationCBQCheckBox, QtCore.SIGNAL('stateChanged(int)'), self.updateRootDecorated)
        self.updateRootDecorated(self.rootDecorationCBQCheckBox.checkState())
        self.indentationQSlider = QtGui.QSlider(self)
        self.indentationQSlider.setOrientation(QtCore.Qt.Horizontal)
        self.indentationQSlider.setRange(0, 100)
        self.indentationQSlider.setValue(20)
        self.connect(self.indentationQSlider, QtCore.SIGNAL('valueChanged(int)'), self.alterIndentation)
        self.alterIndentation(self.indentationQSlider.value())
        self.layoutQVBoxLayout = QtGui.QVBoxLayout()
        self.layoutQVBoxLayout.addWidget(self.myQCustomTreeWidget)
        self.layoutQVBoxLayout.addWidget(self.addQPushButton)
        self.layoutQVBoxLayout.addWidget(self.cssQPlainTextEdit)
        self.downMenuQHBoxLayout = QtGui.QHBoxLayout()
        self.downMenuQHBoxLayout.addWidget(self.rootDecorationCBQCheckBox)
        self.downMenuQHBoxLayout.addWidget(self.indentationQSlider)
        self.layoutQVBoxLayout.addLayout(self.downMenuQHBoxLayout)
        self.layoutQVBoxLayout.setStretchFactor(self.myQCustomTreeWidget, 1)
        self.setLayout(self.layoutQVBoxLayout)
        self.resize(480, 640)
        _ = self.myQCustomTreeWidget.addMenu()
        _ = self.myQCustomTreeWidget.addMenu()
        currentQTreeWidgetItem = self.myQCustomTreeWidget.addMenu()
        self.myQCustomTreeWidget.addMenu(parentQTreeWidgetItem = currentQTreeWidgetItem)
        self.myQCustomTreeWidget.addMenu(parentQTreeWidgetItem = currentQTreeWidgetItem)
        currentQTreeWidgetItem = self.myQCustomTreeWidget.addMenu()
        currentQTreeWidgetItem = self.myQCustomTreeWidget.addMenu(parentQTreeWidgetItem = currentQTreeWidgetItem)
        currentQTreeWidgetItem = self.myQCustomTreeWidget.addMenu(parentQTreeWidgetItem = currentQTreeWidgetItem)
        _ = self.myQCustomTreeWidget.addMenu()

    def updateCss (self):
        self.myQCustomTreeWidget.setStyleSheet(self.cssQPlainTextEdit.toPlainText())

    def alterIndentation (self, value):
        self.myQCustomTreeWidget.setIndentation(value)
        self.myQCustomTreeWidget.updateGeometries()

    def updateRootDecorated (self, state):
        if state == QtCore.Qt.Checked:
            self.myQCustomTreeWidget.setRootIsDecorated(True)
        else:
            self.myQCustomTreeWidget.setRootIsDecorated(False)
        self.myQCustomTreeWidget.updateGeometries()

app = QtGui.QApplication([])
myQCustomQDialog = QCustomQDialog()
myQCustomQDialog.show()
sys.exit(app.exec_())

你不是唯一经历过这个问题的人。我强烈建议使用QItemDelegate。在

文件上说:

If you want to display custom dynamic content or implement a custom editor widget, use QTreeView and subclass QItemDelegate instead.

和(用户?或者)您希望“编辑器”始终可见。它可以在QItemDelegate中完成。但是在类QItemDelegate中,实现了QItemDelegate.paint (self, QPainter painter, QStyleOptionViewItem option, QModelIndex index)(后面的引用)。以及其他属性“createEditor”、“setEditorData”等

实现此类的示例:

^{pr2}$

Spin Box Delegate Example (C++)

^{}

相关问题 更多 >