繁体   English   中英

使用 QStyledItemDelegate 时 QPushButton 的绘制方法面临问题

Facing issue with paint method for QPushButton when used QStyledItemDelegate

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

由于我们使用QSortFilterProxyModel过滤表视图,因此我已经为QTableView中的列实现了PushButtonDelegate 我正在将此委托设置为列之一,如下所示...

table_->setItemDelegateForColumn(11, new PushButtonDelegate(table_));

PushButtonDelegate派生自QStyledItemDelegate ,我已经覆盖了createEditor, setEditorData, setModelData, updateEditorGeometry, and paint方法,如下所示...

PushButtonDelegate::PushButtonDelegate(QObject* parent) :QStyledItemDelegate(parent)
{
    if (const auto table_view = qobject_cast<QTableView*>(parent))
    {
        my_widget_ = table_view;
        btn_ = new QPushButton(button_text_, my_widget_);
        btn_->hide();
        //my_widget_->setMouseTracking(true);
        connect(my_widget_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(CellEntered(QModelIndex)));
        is_one_cell_in_edit_mode_ = false;
    }
}
QWidget* PushButtonDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        const auto btn = new QPushButton(parent);
        const auto value = index.data().toString();
        btn->setCheckable(true);
        btn->setChecked(value == "Yes" ? true : false);
        btn->setFocusPolicy(Qt::NoFocus);
        connect(btn, SIGNAL(clicked(bool)), this, SLOT(UpdateUseButton(bool)));

        return btn;
    }
    else
    {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

void PushButtonDelegate::UpdateUseButton(bool checked) const
{
    if (const auto selection_button = dynamic_cast<QPushButton*>(sender()))
    {
        const QString value = selection_button->text();
        selection_button->setText(value == "Yes" ? "No" : "Yes");
        selection_button->setChecked(value == "Yes" ? false : true);
        selection_button->setCheckable(true);
    }
}

void PushButtonDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        const auto value = index.model()->data(index, Qt::EditRole).toString();
        const auto pb = dynamic_cast<QPushButton*>(editor);
        pb->setChecked(value == "Yes" ? true : false);
        pb->setText(value);
        pb->setCheckable(true);
    }
    else
    {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void PushButtonDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        const auto pb = dynamic_cast<QPushButton*>(editor);
        const auto value = pb->text();
        pb->setChecked(value == "Yes" ? true : false);
        pb->setCheckable(true);
        const auto ptr = dynamic_cast<QSortFilterProxyModel*>(model);
        ptr->setData(index, value, Qt::EditRole);
    }
    else
    {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

void PushButtonDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        painter->save();
        btn_->setGeometry(option.rect);
        const auto value = index.data().toString();
        btn_->setCheckable(true);
        btn_->setText(value);
        btn_->setChecked(value == "Yes" ? true : false);

        if (value == "Yes")
            painter->fillRect(option.rect, option.palette.highlight());
        else
            painter->fillRect(option.rect, option.palette.shadow());

        const QPixmap map = btn_->grab();
        painter->drawPixmap(option.rect.x(), option.rect.y(), map);

        painter->restore();
    }
    else
    {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

void PushButtonDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    editor->setGeometry(option.rect);
}

我面临以下问题...

  1. 我必须单击按钮 3 次才能将文本从“否”更改为“是”。
  2. 如图所示,按钮的突出显示不正确(文本为yes时应突出显示按钮)...

在此处输入图像描述

需要帮忙...

1 个回复

必须单击单元格 3 次才能更改值的原因是因为您需要双击进行编辑(创建编辑器)和另一个单击将调用UpdateUseButton 您不需要这样做,您可以在创建编辑器时执行单击。 事实上,您甚至不需要UpdateUseButton ,因为您可以在setModelData中进行必要的更改。 将以下插槽添加到PushButtonDelegate

void commitAndCloseEditor();

然后像这样实现 class :

QWidget* PushButtonDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        const auto btn = new QPushButton(parent);
        const auto value = index.data().toString();
        btn->setCheckable(true);
        btn->setChecked(value == "Yes" ? true : false);
        btn->setFocusPolicy(Qt::NoFocus);
        
        // You don't need this, you can update your data in setModelData instead
        // connect(btn, SIGNAL(clicked(bool)), this, SLOT(UpdateUseButton(bool)));
        
        // the click will commit the data and close the editor
        // we connect it with a queued connection so that the slot is called after this function exits
        connect(btn, &QPushButton::clicked, this, &PushButtonDelegate::commitAndCloseEditor, Qt::QueuedConnection);
        emit btn->clicked(false); // perform a click programatically to that the commitAndCloseEditor will be called after we exit this function 
        return btn;
    }
    else
    {
        return QStyledItemDelegate::createEditor(parent, option, index);
    }
}

void PushButtonDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        //nothing to do when you are in your delegate column
    }
    else
    {
        QStyledItemDelegate::setEditorData(editor, index);
    }
}

void PushButtonDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        // set your model data here
        model->setData(index, (index.data().toString() == "Yes") ? "No" : "Yes");
    }
    else
    {
        QStyledItemDelegate::setModelData(editor, model, index);
    }
}

void PushButtonDelegate::commitAndCloseEditor()
{
    auto* editor = qobject_cast<QWidget*>(sender());
    emit commitData(editor);
    emit closeEditor(editor);
}

请注意,我使用了Qt::QueuedConnnection来连接clicked信号。 这确保了在createEditorsetEditorData都退出后将调用commitAndCloseEditor槽(通过在每个函数的开头使用 print 语句很容易检查)。 如果您删除了排队的连接,那么commitAndCloseEditor将在createEditor返回实际编辑器之前被调用,因此该插槽将不会执行任何操作,因为编辑器尚未打开。

现在,对于paint方法......看来btn_->setChecked是没有正确显示按钮背景颜色的原因。 我不确定它为什么会这样,但一种解决方法是使用这样的样式表:

void PushButtonDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
    if (index.model()->headerData(index.column(), Qt::Horizontal, Qt::DisplayRole).toString() == constants::kUse)
    {
        painter->save();
        btn_->setGeometry(option.rect);
        const auto value = index.data().toString();
        
        btn_->setText(value);
        
        QString stylesheet = QString("background-color: %1").arg((value == "Yes") ? "green" : "red"  );
        btn_->setStyleSheet(stylesheet);

        const QPixmap map = btn_->grab();
        painter->drawPixmap(option.rect.x(), option.rect.y(), map);

        painter->restore();
    }
    else
    {
        QStyledItemDelegate::paint(painter, option, index);
    }
}

现在应该通过双击切换值,结果(在我的 Windows 框上)如下所示:

结果

1 QStyledItemDelegate & 绘制

我正在使用 QT(在 Python 中)使用QComboBox构建自定义下拉菜单。 我创建了一个自定义的QStyleItemDelegate ,其中包含了paint方法的覆盖。 我能够正确QStyleItemDelegate部件的大小,但是包含它们的窗口总是会填满整个屏幕。 此外,列表从屏幕左上角 ...

6 绘制函数中的QStyledItemDelegate问题

我有QListView和DelegateClass : QStyledItemDelegate 。 在paint函数中我想捕捉鼠标状态。 当我在Windows中测试我的代码if (oOption.state &amp; QStyle::State_MouseOver)条件工作正常但在linu ...

2019-06-14 12:38:00 1 43   c++/ qt
9 QStyledItemDelegate 绘制刷新问题

我目前正在尝试围绕模型视图方法编写一个缩略图查看器应用程序。 在这个例子中,我只是尝试绘制 20 个框,但我得到了一个随机选择,它会随着鼠标移动而更新。 滚动使事情变得更糟,有时绘图只有框等。此外,文本似乎根本没有呈现。 对我来说,它看起来像是paint方法的刷新/更新问题。 我在这里错过了什么 ...

10 使用QStyledItemDelegate paint()在表中绘制图标

我正在尝试为QStyledItemDelegate子类(QT4.8.2)实现自定义绘制功能。 我已经审查了StarItemDelegate示例,其中的示例似乎非常简单。 委托被分配给表中指示记录状态的列。 列项目是可编辑的,但用户不可编辑。 我已经实现了委托子类,并证明了它可以工作, ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM