In reimplemented paint function of QItemDelegate, setFont is not working - c++

I have reimplemented paint() function for QTreeWidget, I want to show data of second column bold, but it doesn't work.
How can i fix it?
void extendedQItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
const QString txt = index.data().toString();
painter->save();
QFont painterFont;
if (index.column() == 1) {
painterFont.setBold(true);
painterFont.setStretch(20);
}
painter->setFont(painterFont);
drawDisplay(painter, option, rect, txt);
painter->restore();
}
I attached a screen shot of the problem, second half should be bold

You forgot to add your extendedQItemDelegate to the QTreeView/QTreeWidget object via the setItemDelegate member function.
As an example:
QTreeWidget* tree_view = ...;
extendedQItemDelegate* extended_item_delegate = ...;
tree_view->setItemDelegate(extended_item_delegate);

You need to make a copy of the const QStyleOptionViewItem &option, apply your font changes to that copy, then paint using your copy instead of the original option passed to the function.
void extendedQItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
const QString txt = index.data().toString();
painter->save();
QStyleOptionViewItem optCopy = option; // make a copy to modify
if (index.column() == 1) {
optCopy.font.setBold(true); // set attributes on the copy
optCopy.font.setStretch(20);
}
drawDisplay(painter, optCopy, rect, txt); // use copy to paint with
painter->restore();
}
(Just realized this is an old question but it had popped up to the top of qt tags.)

Related

Override Text in QStyledItemDelegate for QTreeView

I'm having an issue with overriding the text displayed for a QTreeView using a QStyledItemDelegate. When some condition is met following code is executed:
void MyDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
.
.
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
QString text = opt.text;
text = text + QString("TEST");
opt.text = text;
QStyledItemDelegate::paint(painter, opt, index);
}
I confirmed in the debbugger that TEST is added to opt.text.
However, when I run my program and look at the TreeVuew it is still displaying the original text without the TEST string appended.
It seems that when I call QStyledItemDelegate::paint(painter, opt, index), it's ignoring the change I've made to the opt parameter.
The default implementation of the QStyledItemDelegate::paint() method uses it's own QStyleOptionViewItem instance initialized with data from the model.
From the Qt 5.4.0 source code:
void QStyledItemDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_ASSERT(index.isValid());
QStyleOptionViewItem opt = option;
initStyleOption(&opt, index);
const QWidget *widget = QStyledItemDelegatePrivate::widget(option);
QStyle *style = widget ? widget->style() : QApplication::style();
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
}
Solution:
Do not call the default implementation and implement your delegate's paint() method like this:
void MyDelegate::paint(QPainter* painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
QStyleOptionViewItem itemOption(option);
initStyleOption(&itemOption, index);
itemOption.text = "Test Text"; // override text
QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &itemOption, painter, nullptr);
}
The alternative solution, if you want to change the displayed text in a view, is to override displayText() method.
Example for Qt5:
mydelegate.h
virtual QString displayText(const QVariant &value,
const QLocale &locale) const override;
mydelegate.cpp
QString MyDelegate::displayText(const QVariant &value,
const QLocale &locale) const
{
Q_UNUSED(locale)
QString result = value.toString() + "TEST";
return result;
}
doc link: https://doc.qt.io/qt-5/qstyleditemdelegate.html#displayText
Depending what type of delegates it is, I would also try to override the setEditorData() method or even the createEditor() (where you can add values different from your model). It is less time consuming than doing such operation in paint.
Otherwise, you can use something like that to draw your text where you want:
painter->drawText(option.rect, Qt::AlignJustify, text + "_test");
You probably have a reason for doing so, but it seems like something is wrong in your design if you want to add extra text on the fly?
Possible QStyledItemDelegate::paint picks a text directly from index.data( Qt::DisplayRole ).toString(). That's why text is not changed. You may debug through Qt sources to be sure.
I propose you to use QIdentityProxyModel to do such things. Delegates are not designed for such solutions. You just need to override 1 method. So your code should look like this:
class MyProxyModel : public QIdentityProxyModel
{
// ...
};
QVariant MyProxyModel::data(const QModelIndex &index, int role) const override
{
if ( /*Conditions when you don't want to change source text*/ )
return QIdentityProxyModel::data( index, role );
// Extra check for editors or other roles to return original data
if ( role == Qt::EditRole || role != Qt::DisplayRole )
return QIdentityProxyModel::data( index, role );
const auto sourceIndex = mapToSource( index );
const auto originalText = sourceModel()->data( sourceIndex, Qt::DisplayRole ).toString();
const auto newText = QString( "%1 [TEST]" ).arg( originalText );
return newText;
}
// Usage
auto yourModel = YourOriginalModel( this );
auto proxy = MyProxyModel( this );
proxy->setSourceModel( yourModel );
view->setModel( proxy );

How can I set the background color of some special row in QTableView?

I read an older post however that is not work for me.
I would like to set the background color of every row whose 6th argument is true.
I tried to overwrite the Paint method in my subclass of QSqlRelationalDelegate but apparently it does not do anything.
MoviesDelegate::MoviesDelegate(QObject *parent)
: QSqlRelationalDelegate(parent)
{ }
void MoviesDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
if( index.sibling( index.row(), 6 ).data().toBool() )
{
QStyleOptionViewItemV4 optionViewItem = option;
optionViewItem.backgroundBrush = QBrush( Qt::yellow );
drawDisplay( painter, optionViewItem,
optionViewItem.rect,index.data().toString() );
drawFocus( painter, optionViewItem, optionViewItem.rect);
}
else
QSqlRelationalDelegate::paint(painter, option, index);
}
How can I fix it?
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
// Grab cell value and cast it to boolean
bool boolValue = index.model()->data(index).toBool();
// Paint cell background depending on the bool value
if(boolValue)
painter->fillRect(option.rect, QColor(179, 229, 255));
else
painter->fillRect(option.rect, Qt::red);
// Paint text
QStyledItemDelegate::paint(painter, option, index);
}

Qt: Paint function of custom LineEditDelegate

I have implemented ComboBoxDelegate. It is derived from QStyledItemDelegate. Paint function is used to show the content of cell when it is not editing node.
void ComboBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QStyleOptionComboBox comboBoxOption;
comboBoxOption.rect = option.rect;
comboBoxOption.state = QStyle::State_Active | QStyle::State_Enabled;
comboBoxOption.frame = true;
comboBoxOption.currentText = index.model()->data(index).toString();
QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &comboBoxOption, painter);
QApplication::style()->drawControl(QStyle::CE_ComboBoxLabel, &comboBoxOption, painter);
}
Now I am trying to implement LineEditDelegate. I don't know how to write its paint function. Is there QStyleOptionComboBox like class for QLineEdit? Can you please share your code if anyone have done it?
Try this answer.
It uses QStyle::drawPrimitive with QStyle::PE_PanelLineEdit element.

Correct highlighting with qt custom delegates

I am making a table control that displays some additional text data apart from those in DisplayRole of its model. In all other respects text and cell display should be identical. What i am having trouble with is correct display of highlighted cell.
I am currently using the following code:
void MatchDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if (option.state & QStyle::State_Selected)
painter->fillRect(option.rect, option.palette.highlight());
painter->save();
QString str = qvariant_cast<QString>(index.data())+ "\n";
str += QString::number(qvariant_cast<float>(index.data(Qt::UserRole)));
if (option.state & QStyle::State_Selected)
painter->setBrush(option.palette.highlightedText());
else
painter->setBrush(qvariant_cast<QBrush>(index.data(Qt::ForegroundRole)));
painter->drawText(option.rect, qvariant_cast<int>(index.data(Qt::TextAlignmentRole)), str);
painter->restore();
}
However, the result looks like this:
Text color is wrong, there is no dashing line around the cell, and when the control loses focus, the cell remains blue instead of becoming light gray like drawn by default cells do.
How should painting code be changed to fix those issues?
Please try below code, It will work.
Set drawControl with take care to draw dashed line( Let Qt take care it internally ) when selected.
Fixed( Dashed line, Text color and multiline ) while selecting cell.
void MatchDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyleOptionViewItemV4 opt = option;
initStyleOption(&opt, index);
const QWidget *widget = option.widget;
QString str = qvariant_cast<QString>(index.data())+ "\n";
str += QString::number(qvariant_cast<float>(index.data(Qt::UserRole)));
opt.text = "";
//option
QStyle *style = widget ? widget->style() : QApplication::style();
if (option.state & QStyle::State_Selected)
{
// Whitee pen while selection
painter->setPen(Qt::white);
painter->setBrush(option.palette.highlightedText());
// This call will take care to draw, dashed line while selecting
style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget);
}
else
{
painter->setPen(QPen(option.palette.foreground(), 0));
painter->setBrush(qvariant_cast<QBrush>(index.data(Qt::ForegroundRole)));
}
painter->drawText(option.rect, qvariant_cast<int>(index.data(Qt::TextAlignmentRole)), str);
}

Mystery: In Qt, why would editorEvent be called, but not createEditor?

I'm subclassing QAbstractItemDelegate. This is my code. Suggestions are welcome:
QWidget *ParmDelegate::createWidget(Parm *p, const QModelIndex &index) const {
QWidget *w;
if (index.column() == 0) {
w = new QLabel(p->getName().c_str());
} else {
if (p->isSection())
return NULL;
w = p->createControl();
}
return w;
}
QWidget *ParmDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
cout << "createEditor called" << endl;
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
QWidget *retval = createWidget(p, index);
retval->setFocusPolicy(Qt::StrongFocus);
retval->setParent(parent);
return retval;
}
void ParmDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const {
QRect rect(option.rect);
editor->setGeometry(QRect(QPoint(0,0), rect.size()));
}
void ParmDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
scoped_ptr<QWidget> w(createWidget(p, index));
if (!w)
return;
QRect rect(option.rect);
w->setGeometry(QRect(QPoint(0,0), rect.size()));
w->render(painter, rect.topLeft());
}
QSize ParmDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
Parm *p = reinterpret_cast<Parm*>(index.internalPointer());
scoped_ptr<QWidget> w(createWidget(p, index));
if (!w)
return QSize(0,0);
return w->sizeHint();
}
bool ParmDelegate::editorEvent(QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ) {
cout << "editorEvent called" << endl;
return false;
}
When this is run, I only see that editorEvent gets called twice for every edit event -- no createEditor!
From Qt's AbstractItemDelegate documentation:
To provide custom editing, there are two approaches that can be used. The first approach is to create an editor widget and display it directly on top of the item. To do this you must reimplement createEditor() to provide an editor widget, setEditorData() to populate the editor with the data from the model, and setModelData() so that the delegate can update the model with data from the editor.
The second approach is to handle user events directly by reimplementing editorEvent().
This appears to say that you are missing something to trigger the first approach. My guess is that your model's data() function isn't returning the proper value for the Qt::EditRole option.
I had implemented a TableView which i had inhertied from QItemDelegate. Then i had similar problem. I tracked it down to not calling 'return QItemDelegate::editorEvent(event, model, option, index);' in the editorEvent(...) method.
You can try this. Maybe it helps.