簡體   English   中英

QTableView中的單選行激活列編輯

[英]Single selecting row in QTableView activates column edit

每當在表格視圖中選擇一行時,如何在編輯模式下使第二列處於活動狀態,如以下此gif所示? 我正在嘗試在python / pyside中重新創建它。

理想情況下,我想使用某種項目委托,以便可以輕松地處理column單元格中的keyPressEvents並添加自定義(X)清除按鈕。 但是我不確定在使用ItemModels時如何使用這樣的委托。 因此,感謝您為實現該任務提供任何幫助。

class ExampleDelegate(QtGui.QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        line_edit = QtGui.QLineEdit(parent)
        return line_edit

在此處輸入圖片說明

這是我的代碼和屏幕截圖:

在此處輸入圖片說明

import os, sys
from PySide import QtGui, QtCore


class HotkeyItem():
    def __init__(self, command, shortcut):
        self.command = command
        self.shortcut = shortcut


class HotkeysModel(QtCore.QAbstractTableModel):

    def __init__(self):
        super(HotkeysModel, self).__init__()
        self.items = []
        self.headers = ['Command','Hotkey']

    def clear(self):
        self.beginResetModel()
        self.items = []
        self.endResetModel()

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.items)

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal:
            if role == QtCore.Qt.DisplayRole:
                cnt = len(self.headers)
                if section < cnt:
                    return self.headers[section]
        return None

    def columnCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.headers)

    def index(self, row, column, parent=QtCore.QModelIndex()):
        return self.createIndex(row, column, parent)

    def addItem(self, item):
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        self.items.append(item)
        self.endInsertRows()

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return

        row = index.row()
        col = index.column()

        if 0 <= row < self.rowCount():
            item = self.items[row]

            if role == QtCore.Qt.DisplayRole:
                if col == 0:
                    return getattr(item, 'command', 'N/A')
                elif col == 1:
                    return getattr(item, 'shortcut', '')

            if role == QtCore.Qt.BackgroundRole:
                shortcuts = filter(None, [x.shortcut for x in self.items])
                dups = shortcuts.count(getattr(item, 'shortcut', ''))
                if dups > 1:
                    return QtGui.QBrush(QtGui.QColor(255, 50, 50, 255))

            elif role == QtCore.Qt.FontRole:
                shortcuts = filter(None, [x.shortcut for x in self.items])
                dups = shortcuts.count(getattr(item, 'shortcut', ''))
                if dups > 1:
                    fnt = QtGui.QFont()
                    fnt.setBold(True)
                    fnt.setItalic(True)
                    return fnt

        return None

    def flags(self, index):
        if not index.isValid():
            return 0
        return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable


class Example(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)
        self.resize(600, 400)

        model = HotkeysModel()

        proxyModel = QtGui.QSortFilterProxyModel()
        proxyModel.setFilterKeyColumn(0)
        proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        proxyModel.setSourceModel(model)

        self.uiView = QtGui.QTableView()
        self.uiView.setSortingEnabled(True)
        self.uiView.setModel(proxyModel)
        self.uiView.setAlternatingRowColors(True)
        self.uiView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.uiView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        self.uiView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.uiView.verticalHeader().hide()
        self.uiView.horizontalHeader().show()

        lay = QtGui.QVBoxLayout()
        lay.addWidget(self.uiView)
        self.setLayout(lay)

        self.populate()

        # connections
        selection = self.uiView.selectionModel()
        selection.currentRowChanged.connect(self.selection_changed)


# ui->tableView->setCurrentIndex(index);
# ui->tableView->edit(index);

    def selection_changed(self, index):
        if index.isValid():
            row = index.row()
            self.uiView.setCurrentIndex(index)
            self.uiView.edit(index)


    def populate(self):
        model = self.uiView.model().sourceModel()
        model.clear()

        items = [
            HotkeyItem(command='Save', shortcut='Ctrl+S'),
            HotkeyItem(command='Open', shortcut='Ctrl+O'),
            HotkeyItem(command='Close', shortcut='Ctrl+Q'),
            HotkeyItem(command='Align Top', shortcut=''),
            HotkeyItem(command='Align Bottom', shortcut=''),
            HotkeyItem(command='Align Left', shortcut=''),
            HotkeyItem(command='Align Right', shortcut=''),
            HotkeyItem(command='Align Center', shortcut='Ctrl+O')
        ]

        for x in items:
            model.addItem(x)

        self.uiView.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.uiView.resizeColumnsToContents()


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

問題的一部分是,要使某個項目可編輯,必須將其標記QtCore.Qt.ItemIsEditable激活。 另一部分是,通過selection_changed的索引可以來自第一列中的項目,而不是來自第二列,因此使用該索引應該從第二列中獲取索引。

在Qt5中,已經實現了清除按鈕,並且僅使用setClearButtonEnabled(True)激活了清除按鈕,並使用qss更改了圖標,但是對於Qt4,它不存在,因此必須使用此答案創建它。

最后,您還必須實現setData()方法。

import os
import sys
from PySide import QtGui, QtCore


class LineEdit(QtGui.QLineEdit):
    def __init__(self, parent=None):
        super(LineEdit, self).__init__(parent)
        btnSize = self.sizeHint().height() - 5
        self.clearButton = QtGui.QToolButton(self)
        icon = QtGui.QIcon("clear.png")
        self.clearButton.setIcon(icon)
        self.clearButton.setCursor(QtCore.Qt.ArrowCursor)
        self.clearButton.setStyleSheet("QToolButton { border: none; padding: 2px}")
        self.clearButton.setFixedSize(btnSize, btnSize)
        self.clearButton.hide()
        frameWidth = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
        self.setStyleSheet("QLineEdit{{ padding-right: {}px }}".format(btnSize - frameWidth))
        self.setMinimumHeight(self.sizeHint().height())
        self.clearButton.clicked.connect(self.clear)
        self.textChanged.connect(self.onTextChanged)

    def resizeEvent(self, event):
        frameWidth = self.style().pixelMetric(QtGui.QStyle.PM_DefaultFrameWidth)
        self.clearButton.move(self.width() - self.clearButton.width() - frameWidth, 0)

    def onTextChanged(self, text):
        self.clearButton.setVisible(text != "")


class Delegate(QtGui.QStyledItemDelegate):
    def createEditor(self, parent, option, index):
        editor = LineEdit(parent)
        font = index.data(QtCore.Qt.FontRole)
        editor.setFont(font)
        return editor

    def setEditorData(self, editor, index):
        text = index.data()
        editor.setText(text)

    def setModelData(self, editor, model, index):
        model.setData(index, editor.text())

class HotkeyItem():
    def __init__(self, command, shortcut):
        self.command = command
        self.shortcut = shortcut


class HotkeysModel(QtCore.QAbstractTableModel):
    def __init__(self):
        super(HotkeysModel, self).__init__()
        self.items = []
        self.headers = ['Command','Hotkey']

    def clear(self):
        self.beginResetModel()
        self.items = []
        self.endResetModel()

    def rowCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.items)

    def headerData(self, section, orientation, role=QtCore.Qt.DisplayRole):
        if orientation == QtCore.Qt.Horizontal:
            if role == QtCore.Qt.DisplayRole:
                cnt = len(self.headers)
                if section < cnt:
                    return self.headers[section]
        return None

    def columnCount(self, parent=QtCore.QModelIndex()):
        if parent.isValid():
            return 0
        return len(self.headers)

    def addItem(self, item):
        self.beginInsertRows(QtCore.QModelIndex(), self.rowCount(), self.rowCount())
        self.items.append(item)
        self.endInsertRows()

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if not index.isValid():
            return 

        row = index.row()
        col = index.column()

        if 0 <= row < self.rowCount():
            item = self.items[row]

            if role == QtCore.Qt.DisplayRole:
                if col == 0:
                    return getattr(item, 'command', 'N/A')
                elif col == 1:
                    return getattr(item, 'shortcut', '')

            if role == QtCore.Qt.BackgroundRole:
                shortcuts = filter(None, [x.shortcut for x in self.items])
                dups = shortcuts.count(getattr(item, 'shortcut', ''))
                if dups > 1:
                    return QtGui.QBrush(QtGui.QColor(255, 50, 50, 255))

            elif role == QtCore.Qt.FontRole:
                shortcuts = filter(None, [x.shortcut for x in self.items])
                dups = shortcuts.count(getattr(item, 'shortcut', ''))
                if dups > 1:
                    fnt = QtGui.QFont()
                    fnt.setBold(True)
                    fnt.setItalic(True)
                    return fnt

    def setData(self, index, value, role=QtCore.Qt.EditRole):
        if index.isValid():
            row = index.row()
            col = index.column()
            if 0 <= row < self.rowCount() and 0 <= col < self.columnCount():
                it = self.items[row]
                if col == 0:
                    it.command = value
                elif col == 1:
                    it.shortcut = value
                return True
        return False

    def flags(self, index):
        fl = QtCore.Qt.NoItemFlags
        if index.isValid():
            fl |= QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
            if index.column() == 1:
                fl |= QtCore.Qt.ItemIsEditable
        return fl


class Example(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Example, self).__init__(parent)
        self.resize(600, 400)

        model = HotkeysModel()

        proxyModel = QtGui.QSortFilterProxyModel()
        proxyModel.setFilterKeyColumn(0)
        proxyModel.setSortCaseSensitivity(QtCore.Qt.CaseInsensitive)
        proxyModel.setSourceModel(model)

        self.uiView = QtGui.QTableView()
        self.uiView.setSortingEnabled(True)
        self.uiView.setModel(proxyModel)
        self.uiView.setAlternatingRowColors(True)
        delegate = Delegate(self)
        self.uiView.setItemDelegateForColumn(1, delegate)
        self.uiView.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.uiView.setSelectionMode(QtGui.QAbstractItemView.SingleSelection)
        self.uiView.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.uiView.verticalHeader().hide()
        self.uiView.horizontalHeader().show()

        lay = QtGui.QVBoxLayout()
        lay.addWidget(self.uiView)
        self.setLayout(lay)
        self.populate()

        # connections
        selection = self.uiView.selectionModel()
        selection.currentChanged.connect(self.openEditor)
        self.uiView.clicked.connect(self.openEditor)

    def openEditor(self, index):
        if index.isValid():
            ix = index.sibling(index.row(), 1)
            self.uiView.setCurrentIndex(ix)
            self.uiView.edit(ix)

    def populate(self):
        model = self.uiView.model().sourceModel()
        model.clear()

        items = [
            HotkeyItem(command='Save', shortcut='Ctrl+S'),
            HotkeyItem(command='Open', shortcut='Ctrl+O'),
            HotkeyItem(command='Close', shortcut='Ctrl+Q'),
            HotkeyItem(command='Align Top', shortcut=''),
            HotkeyItem(command='Align Bottom', shortcut=''),
            HotkeyItem(command='Align Left', shortcut=''),
            HotkeyItem(command='Align Right', shortcut=''),
            HotkeyItem(command='Align Center', shortcut='Ctrl+O')
        ]

        for x in items:
            model.addItem(x)

        self.uiView.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.uiView.resizeColumnsToContents()


def main():
    app = QtGui.QApplication(sys.argv)
    ex = Example()
    ex.show()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM