QListView如何设置字体删除

Posted

技术标签:

【中文标题】QListView如何设置字体删除【英文标题】:QListView how to set font strike out 【发布时间】:2021-04-06 17:57:19 【问题描述】:

无法在单独的单元格中划掉文本。事实证明,它只适用于所有人。尝试改变模型方法。也适用于所有人。我在网上找了一个例子,但是没有用。底线是让用户选择一个单元格,点击按钮,单元格中的文本就会被检出。

我的代码

import sys
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
STRIKE_ROLE = Qt.UserRole + 1
import pandas as pd

class StrikeDelegate(QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        font = QFont(option.font)
        font.setStrikeOut(index.data(STRIKE_ROLE))
        option.font = font


class MyDelegate(QItemDelegate):

    def setEditorData(self, editor, index):
            text = index.data(Qt.EditRole) or index.data(Qt.DisplayRole)
            editor.setText(text)


    # def initStyleOption(self,option,index):
    #
    #     QtWidgets.QStyledItemDelegate.initStyleOption(option,index)
    #     option.font().setStrikeOut(True)




class TableModel(QAbstractTableModel):
    def __init__(self, data):
        super(TableModel, self).__init__()
        self._data = data





    def setData(self, index, value, role):

        self._data.iloc[index.row(), index.column()] = value
        self.dataChanged.emit(index, index)
        return True

    def flags(self, index):
        return Qt.ItemIsEnabled | Qt.ItemIsEditable |Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled



    def data(self, index, role):
        if role == Qt.DisplayRole:
            value = self._data.iloc[index.row(), index.column()]
            return str(value)



    def rename_column(self, index, new_name):
        self._data.rename(index=self._data.index[index]: new_name, inplace=True)
        return True



    def rowCount(self, index):
        return self._data.shape[0]

    def columnCount(self, index):
        return self._data.shape[1]

    def headerData(self, section, orientation, role):
        # section is the index of the column/row.
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._data.columns[section])

            if orientation == Qt.Vertical:
                return str(self._data.index[section])

    def add_empty_row(self):
        self.beginResetModel()
        try:
            self._data = self._data.append(
                pd.DataFrame(columns=self._data.columns, data=([[0] * len(self._data.columns)]),
                             index=['Пусто']))
        except IndexError:
            self._data = self._data.append(
                pd.DataFrame(columns=self._data.columns, data=([[None] * len(self._data.columns)]),
                             index=[0]))
        self.layoutChanged.emit()
        self.endResetModel()
        # self.inp_.add_delete_row.emit(self.createIndex(self._data.index[-1], 0), 'add_empty_row')

    def delete_row(self, index):


        self._data.drop(self._data.index[index.row()], inplace=True)
        # self._data.reset_index(inplace=True, drop=True)
        self.layoutChanged.emit()


class TaskModel(TableModel):

    def add_empty_row(self):
        self.beginResetModel()
        try:
            self._data = self._data.append(
                pd.DataFrame(columns=self._data.columns, data=([['Новая задача'] * len(self._data.columns)]),
                             index=[self._data.index[-1] + 1]))
        except IndexError:
            self._data = self._data.append(
                pd.DataFrame(columns=self._data.columns, data=([[None] * len(self._data.columns)]),
                             index=[0]))
        self.layoutChanged.emit()
        self.endResetModel()

    def data(self, index, role):
        value = self._data.iloc[index.row(), index.column()]
        if role == Qt.DisplayRole:
            return str(value)
        if role == STRIKE_ROLE:
            font=QFont('Calibri',13)

            return font

    def setData(self, index, value, role):

            self._data.iloc[index.row(), index.column()] = value
            self.dataChanged.emit(index, index)
            return True



class Ui_Form(object):
    def setupUi(self, Form):
        if not Form.objectName():
            Form.setObjectName(u"Form")
        Form.resize(586, 683)
        self.Form=Form
        self.horizontalLayout_2 = QHBoxLayout(Form)
        self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
        self.dock_task_calendar = QDockWidget(Form)
        self.dock_task_calendar.setObjectName(u"dock_task_calendar")
        self.dock_task_calendar.setFeatures(QDockWidget.DockWidgetClosable|QDockWidget.DockWidgetMovable)
        self.dockWidgetContents_task = QWidget()
        self.dockWidgetContents_task.setObjectName(u"dockWidgetContents_task")
        self.verticalLayout_3 = QVBoxLayout(self.dockWidgetContents_task)
        self.verticalLayout_3.setObjectName(u"verticalLayout_3")
        self.scrollArea_task = QScrollArea(self.dockWidgetContents_task)
        self.scrollArea_task.setObjectName(u"scrollArea_task")
        self.scrollArea_task.setWidgetResizable(True)
        self.scrollAreaWidgetContents_task_2 = QWidget()
        self.scrollAreaWidgetContents_task_2.setObjectName(u"scrollAreaWidgetContents_task_2")
        self.scrollAreaWidgetContents_task_2.setGeometry(QRect(0, 0, 548, 623))
        self.horizontalLayout = QHBoxLayout(self.scrollAreaWidgetContents_task_2)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.gridLayout = QGridLayout()
        self.gridLayout.setObjectName(u"gridLayout")
        self.verticalLayout_2 = QVBoxLayout()
        self.verticalLayout_2.setObjectName(u"verticalLayout_2")

        self.gridLayout.addLayout(self.verticalLayout_2, 4, 0, 1, 1)

        self.tasklistView = QListView(self.scrollAreaWidgetContents_task_2)
        self.tasklistView.setObjectName(u"tasklistView")
        self.tasklistView.setDragEnabled(True)
        self.tasklistView.setDragDropOverwriteMode(True)
        self.tasklistView.setWordWrap(True)
        self.tasklistView.setItemAlignment(Qt.AlignLeading)

        self.gridLayout.addWidget(self.tasklistView, 4, 1, 1, 1)
        self.model=TaskModel(pd.DataFrame([],columns=['a']))
        self.delegater=MyDelegate()
        self.tasklistView.setModel(self.model)
        self.tasklistView.setItemDelegate(self.delegater)

        self.label_task = QLabel(self.scrollAreaWidgetContents_task_2)
        self.label_task.setObjectName(u"label_task")
        sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label_task.sizePolicy().hasHeightForWidth())
        self.label_task.setSizePolicy(sizePolicy)
        self.label_task.setMaximumSize(QSize(16777215, 20))
        self.label_task.setAlignment(Qt.AlignCenter)

        self.gridLayout.addWidget(self.label_task, 2, 1, 1, 1)

        self.calendar = QCalendarWidget(self.scrollAreaWidgetContents_task_2)
        self.calendar.setObjectName(u"calendar")
        sizePolicy1 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        sizePolicy1.setHorizontalStretch(0)
        sizePolicy1.setVerticalStretch(0)
        sizePolicy1.setHeightForWidth(self.calendar.sizePolicy().hasHeightForWidth())
        self.calendar.setSizePolicy(sizePolicy1)
        self.calendar.setMaximumSize(QSize(16777215, 400))

        self.gridLayout.addWidget(self.calendar, 1, 1, 1, 1)

        self.verticalLayout = QVBoxLayout()
        self.verticalLayout.setObjectName(u"verticalLayout")
        self.add_task = QPushButton(self.scrollAreaWidgetContents_task_2)
        self.add_task.setObjectName(u"add_task")
        sizePolicy2 = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
        sizePolicy2.setHorizontalStretch(0)
        sizePolicy2.setVerticalStretch(0)
        sizePolicy2.setHeightForWidth(self.add_task.sizePolicy().hasHeightForWidth())
        self.add_task.setSizePolicy(sizePolicy2)
        self.add_task.setMaximumSize(QSize(40, 40))

        self.verticalLayout.addWidget(self.add_task)

        self.del_task = QPushButton(self.scrollAreaWidgetContents_task_2)
        self.del_task.setObjectName(u"del_task")
        self.del_task.setMaximumSize(QSize(40, 40))

        self.verticalLayout.addWidget(self.del_task)

        self.check_task = QPushButton(self.scrollAreaWidgetContents_task_2)
        self.check_task.setObjectName(u"check_task")
        self.check_task.setMaximumSize(QSize(40, 40))

        self.verticalLayout.addWidget(self.check_task)

        self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)

        self.verticalLayout.addItem(self.verticalSpacer)


        self.gridLayout.addLayout(self.verticalLayout, 4, 2, 1, 1)


        self.horizontalLayout.addLayout(self.gridLayout)

        self.scrollArea_task.setWidget(self.scrollAreaWidgetContents_task_2)

        self.verticalLayout_3.addWidget(self.scrollArea_task)

        self.dock_task_calendar.setWidget(self.dockWidgetContents_task)

        self.horizontalLayout_2.addWidget(self.dock_task_calendar)

        self.add_task.pressed.connect(self.model.add_empty_row)

        self.retranslateUi(Form)
        self.Form.show()

    # setupUi

    def retranslateUi(self, Form):
        Form.setWindowTitle(QCoreApplication.translate("Form", u"Form", None))
        self.dock_task_calendar.setWindowTitle("")
        self.label_task.setText(QCoreApplication.translate("Form", u"C\u043f\u0438\u0441\u043e\u043a \u0434\u0435\u043b/\u0437\u0430\u0434\u0430\u0447", None))
        self.add_task.setText(QCoreApplication.translate("Form", u"PushButton", None))
        self.del_task.setText(QCoreApplication.translate("Form", u"PushButton", None))
        self.check_task.setText(QCoreApplication.translate("Form", u"PushButton", None))
    # retranslateUi



if __name__ == '__main__':

        app = QApplication(sys.argv)
        translator = QTranslator()
        if len(sys.argv) > 1:
            locale = sys.argv[1]
        else:
            locale = QLocale.system().name()
        translator.load('qt_%s' % locale,
                        QLibraryInfo.location(QLibraryInfo.TranslationsPath))
        app.installTranslator(translator)
        form=Ui_Form()
        form.setupUi(QWidget())
        app.exec_()

【问题讨论】:

请提供minimal reproducible example 从您的代码来看,它适用于所有项目是正确的:对删除的唯一检查是self.strike,这是实例的一个属性(又名:模型,如 整个模型)。如果要为特定单元格指定特定数据/变量/属性(在本例中为字体删除线),则必须使用引用。例如,创建一个列表,其中包含删除项的坐标(以行/列元组的形式)。 @it 用于待办事项列表,谁被淘汰,不知道下一个是谁) 【参考方案1】:

由于 OP 没有提供 MRE,所以我的解决方案只会限制一般逻辑,即:

如果应用罢工,则为存储布尔值(或任何其他变量)的每个项目创建一个新角色。 使用委托设置字体中的罢工。 通过单击的信号更改存储在选定行的角色罢工中的值。
from functools import cached_property

from PyQt5 import QtCore, QtGui, QtWidgets

STRIKE_ROLE = QtCore.Qt.UserRole + 1


class StrikeDelegate(QtWidgets.QStyledItemDelegate):
    def initStyleOption(self, option, index):
        super().initStyleOption(option, index)
        font = QtGui.QFont(option.font)
        font.setStrikeOut(index.data(STRIKE_ROLE))
        option.font = font

    def createEditor(self, parent, option, index):
        editor = super().createEditor(parent, option, index)
        font = QtGui.QFont(editor.font())
        font.setStrikeOut(index.data(STRIKE_ROLE))
        editor.setFont(font)
        return editor


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        hlay = QtWidgets.QHBoxLayout(central_widget)

        vlay = QtWidgets.QVBoxLayout()
        vlay.addWidget(self.add_button)
        vlay.addWidget(self.remove_button)
        vlay.addWidget(self.strike_button)
        vlay.addStretch()

        hlay.addWidget(self.view)
        hlay.addLayout(vlay)

        self.add_button.clicked.connect(self.add)
        self.remove_button.clicked.connect(self.remove)
        self.strike_button.clicked.connect(self.strike)

    @cached_property
    def model(self):
        return QtGui.QStandardItemModel()

    @cached_property
    def view(self):
        view = QtWidgets.QListView()
        delegate = StrikeDelegate()
        view.setItemDelegate(delegate)
        view.setModel(self.model)
        return view

    @cached_property
    def add_button(self):
        return QtWidgets.QPushButton("Add")

    @cached_property
    def remove_button(self):
        return QtWidgets.QPushButton("Remove")

    @cached_property
    def strike_button(self):
        return QtWidgets.QPushButton("Strike")

    def add(self):
        text, ok = QtWidgets.QInputDialog.getText(self, "Title", "Text:")
        if not ok:
            return
        item = QtGui.QStandardItem(text)
        item.setData(True, STRIKE_ROLE)
        self.model.appendRow(item)

    def remove(self):
        rows = [index.row() for index in self.view.selectedIndexes()]
        for row in sorted(rows, reverse=True):
            self.model.takeRow(row)

    def strike(self):
        for index in self.view.selectedIndexes():
            strike = self.model.data(index, STRIKE_ROLE)
            self.model.setData(index, not strike, STRIKE_ROLE)


def main():
    import sys

    app = QtWidgets.QApplication(sys.argv)

    w = MainWindow()
    w.resize(640, 480)
    w.show()

    sys.exit(app.exec_())


if __name__ == "__main__":
    main()

【讨论】:

您的回答既快又好!但是对于每个被委托人的每个项目 - 它并不多?)许多创建对象并且它们在 python 中的破坏不会很快。 我只是在一个锐化设备中,它只使用使用此代码的该死的连接器。尽可能简单。否则,为了让一个单独的单元格被划掉,你需要重写很多方法。 我知道,你知道这个例子的最佳解决方案。 已经有一个委托来更改双击行为。现在我需要这个。那我该如何组合它们呢? 我认为这是Qlistwiew的标准实现,因为当你双击不选择代理时,文本变为空,而当你选择代理时,文本保持不变。和新的 MRE

以上是关于QListView如何设置字体删除的主要内容,如果未能解决你的问题,请参考以下文章

Qt C++ QListView 或 QListWidget 中的字体列表并将它们表示为复选框

在 qListView 中,已删除的项目不会在视图中更新

如何从 QListView 取消设置所有自定义 QStyledItemDelegates?

Qt - 如何将 QListView 项目转移到另一个 QListView?

如何将 QModelIndex 设置为 QListView

如何在 QListView 中修改 drop 事件