我已经为QTableView
中的一个列实现了QSortFilterProxyModel
,因为我们使用QSortFilterProxyModel
来筛选表视图。我将此委托设置为如下所示的一列.
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);
}
我面临以下问题..。
我必须点击3次按钮才能将文本从“否”更改为“是”。yes
)...
需要帮助..。
发布于 2022-09-25 15:08:12
需要单击3次单元格才能更改值的原因是,您需要双击才能编辑(这将创建编辑器),并需要另一次单击才能调用UpdateUseButton
。您不需要这样做,您可以在创建编辑器时执行单击。实际上,您甚至不需要UpdateUseButton
,因为您可以在setModelData
中进行必要的更改。将下面的插槽添加到PushButtonDelegate
中
void commitAndCloseEditor();
然后像这样实现这个类:
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
信号。这确保commitAndCloseEditor
槽在createEditor
和setEditorData
退出后被调用(在每个函数的开头使用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框上)如下所示:
https://stackoverflow.com/questions/73810341
复制相似问题