无法让自定义 ItemDelegate 工作

发布于 2024-09-25 08:55:55 字数 2882 浏览 0 评论 0原文

首先,我是 python 和 pyqt 的新手,所以请耐心等待。

我使用 QTableView 和 QSqlTableModel 一切都按预期工作。 视图的最后一列仅包含 0 和 1 作为我想显示为复选框的值,并且该列应该是可编辑的。

我读过您应该将我所做的 QItemDelegate 子类化。不幸的是,我的表格不会将最后一列显示为复选框。

我尝试使用 setItemDelegateForColumn() 仅为最后一列设置委托(我喜欢的方式),但它不起作用。所以我修改了它并使用 setItemDelegate() 为整个 QTableView 设置它,仅对最后一列的请求做出反应。它仍然行不通。不起作用意味着没有错误消息,它只是不会执行我所说的;)似乎除了 init() 之外,我重新实现的方法都没有被调用。所以我想我错过了一些基本的东西。

我已经提取了相关的代码行,KSCheckBoxDelegate 是我的子类。这是为整个 QTableView 设置委托的版本。


-- code from applications main class --
self.taglist = QTableView()
self.tagmodel = QSqlTableModel()
self.tagmodel.setTable("data")
self.tagmodel.select()
self.taglist.setModel(self.tagmodel)
print self.taglist.itemDelegate()
myDel = KSCheckBoxDelegate(self)
myDel.colnumber = 3
self.taglist.setItemDelegate(myDel)


-- KSCheckBoxDelegate.py --
from PyQt4.QtGui import *

class KSCheckBoxDelegate(QStyledItemDelegate):

    colnumber = None

    def __init__ (self, parent = None):
        print "KSCheckBoxDelegate::init"
        QStyledItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        print "KSCheckBoxDelegate::createEditor"
        if index.column()==self.colnumber:
            return QCheckBox(self)
        else:
            return QStyledItemDelegate.createEditor(self, parent, option, index)

    def setEditorData (self, editor, index):
        print "KSCheckBoxDelegate::setEditorData"
        if index.column() == self.colnumber:
            cont = index.model().data(index, Qt.DisplayRole).toString()
            if cont == "1":
                editor.setCheckState(Qt.Checked)
            else:
                editor.setCheckState(Qt.UnChecked)
        else:
            QStyledItemDelegate.setEditorData(self,editor, index)

    def setModelData (self, editor, model, index):
        print "KSCheckBoxDelegate::setModelData"
        if index.column() == self.colnumber:
            if editor.checkBox.checkState() == Qt.Checked:
                model.setData(index, 1)
            else:
                model.setData(index, 0)
        else:
            QStyledItemDelegate.setModelData(self, editor, model, index)

关于这个问题有什么提示吗?

此外,我对 QTableViews 选择模型的 currentChanged() 信号有困难。我正在打印所选内容的右上角坐标。单击鼠标左键时,我不断收到错误的索引(不是无效的)。使用光标键可以获得正确的索引。使用selectionChanged()具有相同的行为。我实际上获取了 QTableView 的倒数第二个选定单元格的坐标。例如我点击坐标<1,1> <2,1>第二次单击将显示坐标<1,1>。


selInd = self.taglist.selectionModel().selectedIndexes()
if(len(selInd) > 0):
    self.xPosData=selInd[0].column()
    self.yPosData=selInd[0].row()

我自己修复了这个问题,使用QTableView.currentIndex()而不是selectionModel.selectedIndexes():)

最后使用OnManualSubmit作为editStrategy在调用submitAll()时不会抛出错误(返回false),但不会抛出错误保存数据。它适用于选择 OnFieldChange 作为 editStrategy。我可以忍受,但不是我打算做的。

感谢您抽出时间。

霍斯特

first off, im new to python and pyqt so please bear with me.

Im using a QTableView with a QSqlTableModel everything works as intended.
The last column of the view contains only 0 and 1 as value which i want to display as checkbox and this column should be editable.

Ive read that you should subclass QItemDelegate which i did. Unluckily my table wont show the last column as a checkbox.

I tried to set the delegate only for the last column (the way i would prefer) using setItemDelegateForColumn(), it didnt work. So i modified it and set it for the entire QTableView using setItemDelegate() reacting only to requests to the last column. It still wont work. Wont work means there are no error messages it just wont do what i say ;) It seems that none of the methods i reimplemented gets ever called except init(). So i guess im missing something fundamental.

Ive extracted the relevant lines of code, KSCheckBoxDelegate is my subclass. This is the version where the delegate is set up for the entire QTableView.


-- code from applications main class --
self.taglist = QTableView()
self.tagmodel = QSqlTableModel()
self.tagmodel.setTable("data")
self.tagmodel.select()
self.taglist.setModel(self.tagmodel)
print self.taglist.itemDelegate()
myDel = KSCheckBoxDelegate(self)
myDel.colnumber = 3
self.taglist.setItemDelegate(myDel)


-- KSCheckBoxDelegate.py --
from PyQt4.QtGui import *

class KSCheckBoxDelegate(QStyledItemDelegate):

    colnumber = None

    def __init__ (self, parent = None):
        print "KSCheckBoxDelegate::init"
        QStyledItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        print "KSCheckBoxDelegate::createEditor"
        if index.column()==self.colnumber:
            return QCheckBox(self)
        else:
            return QStyledItemDelegate.createEditor(self, parent, option, index)

    def setEditorData (self, editor, index):
        print "KSCheckBoxDelegate::setEditorData"
        if index.column() == self.colnumber:
            cont = index.model().data(index, Qt.DisplayRole).toString()
            if cont == "1":
                editor.setCheckState(Qt.Checked)
            else:
                editor.setCheckState(Qt.UnChecked)
        else:
            QStyledItemDelegate.setEditorData(self,editor, index)

    def setModelData (self, editor, model, index):
        print "KSCheckBoxDelegate::setModelData"
        if index.column() == self.colnumber:
            if editor.checkBox.checkState() == Qt.Checked:
                model.setData(index, 1)
            else:
                model.setData(index, 0)
        else:
            QStyledItemDelegate.setModelData(self, editor, model, index)

Any hints for me on that issue?

Furthermore i have difficulties with the currentChanged() signal of the QTableViews selectionModel. Im printing the top right coordinates of the selection. I keep getting wrong indexes (not invalid) when clicking with the left mouse button. Using the cursor keys gets me the right indexes. Using selectionChanged() has the same behaviour. Im actually getting the coordinates of the second last selected cell of the QTableView. For instance im clicking on the coordinates <1,1> <2,1> the second click would show me the coordinates <1,1>.


selInd = self.taglist.selectionModel().selectedIndexes()
if(len(selInd) > 0):
    self.xPosData=selInd[0].column()
    self.yPosData=selInd[0].row()

Fixed that by myself, with using QTableView.currentIndex() instead of selectionModel.selectedIndexes() :)

And last off using OnManualSubmit as editStrategy doesnt throw an error (return false) when calling submitAll() but doesnt save the data either. It works with choosing OnFieldChange as editStrategy. Which i can live with but is not was i have intended to do.

Thanks for your time.

Horst

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海拔太高太耀眼 2024-10-02 08:55:55

我认为基于 QSqlTableModel 创建自己的模型会更简单,并且对于 0/1 列,为 QDisplayRole 返回 QVariant() ,并根据值返回 Qt::Checked/Qt::Unchecked 为 Qt::CheckStateRole 。对于所有其他情况返回 QSqlTableModel::data

class MySqlTableModel: public QSqlTableModel
{
public:
// contructors
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole)
    {
        if(index.column() == 3 /* your 0/1 column */)
        {
            if(role == Qt::DisplayRole)
            {
                return QVariant();
            }
            else if(role == Qt::CheckStateRole)
            {
                QString value = QSqlTableModel::data(index, Qt::DisplayRole).toString();
                return value == "1" ? Qt::Checked : Qt::Unchecked;
            }
        }

        return QSqlTableModel::data(index, role);
    }
};

我知道它是 C++ 代码,但逻辑仍然相同,因此只需针对 Python 重新调整它

I think it would be simpler to create your own model basing QSqlTableModel, and for your 0/1 column return QVariant() for QDisplayRole and return Qt::Checked/Qt::Unchecked for Qt::CheckStateRole depending on value. For all other cases return QSqlTableModel::data

class MySqlTableModel: public QSqlTableModel
{
public:
// contructors
    QVariant data(const QModelIndex & index, int role = Qt::DisplayRole)
    {
        if(index.column() == 3 /* your 0/1 column */)
        {
            if(role == Qt::DisplayRole)
            {
                return QVariant();
            }
            else if(role == Qt::CheckStateRole)
            {
                QString value = QSqlTableModel::data(index, Qt::DisplayRole).toString();
                return value == "1" ? Qt::Checked : Qt::Unchecked;
            }
        }

        return QSqlTableModel::data(index, role);
    }
};

I know it's C++ code, but logic is still same, so just readjust it for Python

我只土不豪 2024-10-02 08:55:55

至少我设法让我的代表在显示和编辑模式下显示具有正确状态的复选框。因为我找不到关于如何做到这一点的完整描述,所以我分享它。也许其他人在以前没有使用过 qt 的情况下尝试做类似的事情。

只有一件事丢失了,那就是可编辑的项目,我想它与我在开篇文章中提出的标志问题有关。

-- KSCheckBoxDelegate.py --


class KSCheckBoxDelegate(QStyledItemDelegate):
    def __init__ (self, parent = None):
        print "KSCheckBoxDelegate::init"
        QStyledItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        print "KSCheckBoxDelegate::createEditor"
        return QCheckBox(parent)

    def setEditorData (self, editor, index):
        print "KSCheckBoxDelegate::setEditorData"
        cont = index.model().data(index, Qt.DisplayRole).toString()
        if cont == "1":
            editor.setCheckState(Qt.Checked)
        else:
            editor.setCheckState(Qt.Unchecked)

    def setModelData (self, editor, model, index):
        print "KSCheckBoxDelegate::setModelData"
        if editor.checkState() == Qt.Checked:
            model.setData(index, 1)
        else:
            model.setData(index, 0)

    def paint (self, painter, option, index):
        myopt = QStyleOptionViewItemV4(option)
        newopt = QStyleOptionButton()
        newopt.rect = myopt.rect
        newopt.palette = myopt.palette
        if index.data().toBool():
            newopt.state |= QStyle.State_On
        QApplication.style().drawControl(QStyle.CE_CheckBox, newopt, painter)

    def sizeHint (self, option, index):
        return 18

at least i managed to have my delegate show checkboxes with the correct state in display and edit mode. Because i couldnt find a complete description on how to do it ill share it. Maybe other ppl trying to do something similar without having worked with qt ever before.

Only one thing is missing, thats the items being editable, i guess its related to the flags question i asked in my opening post.

-- KSCheckBoxDelegate.py --


class KSCheckBoxDelegate(QStyledItemDelegate):
    def __init__ (self, parent = None):
        print "KSCheckBoxDelegate::init"
        QStyledItemDelegate.__init__(self, parent)

    def createEditor(self, parent, option, index):
        print "KSCheckBoxDelegate::createEditor"
        return QCheckBox(parent)

    def setEditorData (self, editor, index):
        print "KSCheckBoxDelegate::setEditorData"
        cont = index.model().data(index, Qt.DisplayRole).toString()
        if cont == "1":
            editor.setCheckState(Qt.Checked)
        else:
            editor.setCheckState(Qt.Unchecked)

    def setModelData (self, editor, model, index):
        print "KSCheckBoxDelegate::setModelData"
        if editor.checkState() == Qt.Checked:
            model.setData(index, 1)
        else:
            model.setData(index, 0)

    def paint (self, painter, option, index):
        myopt = QStyleOptionViewItemV4(option)
        newopt = QStyleOptionButton()
        newopt.rect = myopt.rect
        newopt.palette = myopt.palette
        if index.data().toBool():
            newopt.state |= QStyle.State_On
        QApplication.style().drawControl(QStyle.CE_CheckBox, newopt, painter)

    def sizeHint (self, option, index):
        return 18
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文