Set text color of QTableWidgetItem (Qt) - qt

QTableWidgetItem has a method for setting the backgroundColor of a cell in the table, but no method for setting the text color of that cell.
How do I change the text color of an arbitrary cell in a QTableWidget?
Changing the color of text in all cells is as simple as using this stylesheet.
QTableWidget::item {
color: red;
}
But because the API is on the QTableWidget level (rather than QTableWidgetItem level), I find it impossible to target individual cells.

The method is called setForeground() (not sure how I missed it). Not sure how to do it in CSS only though.
Code:
item = QTableWidgetItem('text')
item.setForeground(QBrush(QColor(0, 255, 0)))

I know it's been a while, but you could try:
QTableWidget::item:selected { color:red; }

class Spreadsheet : public QTableWidget
{
Q_OBJECT
public://
Spreadsheet(const QString &fileName = QString(),
QWidget *parent = 0);
QString currentLocation() const;
QString currentFormula() const;
void clear();
QTableWidgetSelectionRange selectedRange() const;
bool load(const QString &fileName = QString());
bool save(const QString &fileName = QString());
void printHtml(const QString &html);
public slots://
void selectCellFont();
void selectFontColour();
// etc

Related

different items in one cell QTableWidget

I am learning Qt and create a small example like this.
table
I have read some suggested questions which relate to my problem here but right now they are not easy for me to understand.
This is my code, above function is calendar interaction, below function is for showing items:
SmallExample::SmallExample(QWidget *parent)
: QWidget(parent)
{
.........
connect(ui.tableWidget, SIGNAL(itemDoubleClicked(QTableWidgetItem*)), this, SLOT(calendar_clicked(QTableWidgetItem*)));
}
void SmallExample::calendar_clicked(QTableWidgetItem* tableitem)
{
int column = tableitem->column();
SmallExample::row = tableitem->row();
if (column == 2) {
if (!calendar) {
calendar = new QCalendarWidget();
}
calendar->setWindowTitle("Calendar");
calendar->setWindowModality(Qt::WindowModal);
calendar->show();
connect(calendar, SIGNAL(activated(const QDate&)), this, SLOT(date_selected(const QDate&)));
}
}
void SmallExample::date_selected(const QDate&)
{
QTableWidgetItem *itemcalendar = new QTableWidgetItem;
QIcon icon(":/icon/calendar.jpg");
itemcalendar->setIcon(icon);
SmallExample::ui.tableWidget->setItem(SmallExample::row, 0, itemcalendar);
QString text= SmallExample::calendar->selectedDate().toString("dd.MM.yyyy");
QTableWidgetItem *datetext = new QTableWidgetItem;
datetext->setText(text);
SmallExample::ui.tableWidget->setItem(SmallExample::row, 0, datetext);
SmallExample::calendar->close();
}
I know when datetext is added, the itemcalendar will be overwritten, so it does not appear any more. I want both of which will appear, but I don't know how to solve this. Thanks in advance!
update code:
void SmallExample::date_selected(const QDate&)
{
QTableWidgetItem *itemcalendar = SmallExample::ui.tableWidget->item(SmallExample::row, 2);
QIcon icon(":/icon/calendar.jpg");
itemcalendar->setIcon(icon);
QString date = SmallExample::calendar->selectedDate().toString("dd.MM.yyyy")
itemcalendar->setText(date);
}
Maybe you should consider using a QStyledItemDelegate for the second column of your table.
See this post and the star example from Qt documentation.
Here is a code sample:
class CalendarDelegate : public QStyledItemDelegate
{
public:
CalendarDelegate (QObject *parent = 0) :
QStyledItemDelegate(parent)
{
}
void CalendarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const
{
painter->save();
QIcon icon(":/icon/calendar.jpg");
QSize iconsize = option.decorationSize;
painter->drawPixmap(0.0, 0.0, icon.pixmap(iconsize.width(), iconsize.height()));
painter->restore();
}
}
And then in the SmallExample class constructor:
SmallExample::ui.tableWidget->setItemDelegateForColumn(2, new CalendarDelegate(this));
If you set one time only icon and another time text, you can try such code, with item method:
QTableWidgetItem *itemcalendar = new QTableWidgetItem;
QIcon icon(":/icon/calendar.jpg");
itemcalendar->setIcon(icon);
SmallExample::ui.tableWidget->setItem(SmallExample::row, 2, itemcalendar);
...
QTableWidgetItem* itemcalendar = SmallExample::ui.tableWidget->item(SmallExample::row, 2);
itemcalendar->setText(date);
This is how your code should look like:
QTableWidgetItem *itemcalendar = new QTableWidgetItem;
QIcon icon(":/icon/calendar.jpg");
itemcalendar->setIcon(icon);
itemcalendar->setText(SmallExample::calendar->selectedDate().toString("dd.MM.yyyy"));
SmallExample::ui.tableWidget->setItem(SmallExample::row, 2, itemcalendar);
I have just tried this example and it works as expected (both text and icon appears in item) no matter in which order I set icon and text.
You don't have to create new item evety time you choose date in date_selected, use item as Kirill suggested:
QTableWidgetItem *itemcalendar = SmallExample::ui.tableWidget->item(SmallExample::row, 2);
QString date = SmallExample::calendar->selectedDate().toString("dd.MM.yyyy");
itemcalendar->setText(date);

QToolButton with icon + text: How to center both?

I am using multiple QToolButtons in a custom QGridLayout widget. The buttons are set to display icon + text based on an assigned default QAction. The only issue is that the content (icon + text) is always left-aligned.
The content (icon + text, marked as a red box in the screenshot), should be center in the button (indicated by the blue box).
For most cases this is just fine, given that Qt automatically tries to render that button with the minimal size. However I am stretching the button to fit nicely into my QGridLayout.
QToolButton* pButton = new QToolButton(0);
pButton->addDefaultAction(pAction);
pButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
pButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
QGridLayout *pActionAreaLayout = new QGridLayout;
pActionAreaLayout->addWidget(pSomeOtherWidget, 0, 0, 1, 2);
pActionAreaLayout->addWidget(pButton , 1, 0, 1, 1);
Is there a way to force the content to be centered in the button?
PS: I found the following comment in another forum, which however seems quite invasive and is not really clear to me yet:
You can try doing the horizontal alignment using a stylesheet, but you probably have to implement a QStyle proxy and reimplement drawControl() for QStyle::CE_ToolButtonLabel
Or derive from QToolButton, overwrite paintEvent() and call the style for everything other than the label.
As I suggest in answer to you another question. https://stackoverflow.com/a/28630318/1917249 Do not use QToolButton, just use QPushButton, and add popup menu if needed.
Then you wont have different sizes of QToolButton and QPushButton widgets. And you will have centered icon and text.
Popupmenu can be easily added to QPushButton ( only small arrow wont be shown )
QPushButton *pushButton = new QPushButton(toolAction->icon(), "PushButton", window);
// window - widget where button is placed ( to get correct QMenu position )
QObject::connect(pushButton, &QPushButton::released, [window, pushButton, action](){
QMenu menu;
menu.addAction(action);
QPoint pos = window->mapToGlobal(pushButton3->pos());
pos += QPoint(0, pushButton->height());
menu.exec(pos);
});
Or you can subclass QPushButton and add Popup menu handling there. Much better then try to center text with icon in QToolButton or have in same size of QPushButton and QToolButton
For complex example please see my answer: https://stackoverflow.com/a/28630318/1917249
The following class does the job for me:
class CenteredToolButtonStyle : public QProxyStyle
{
Q_OBJECT
public:
CenteredToolButtonStyle(QToolButton* b, const QSize& sIcon);
virtual void drawItemPixmap(QPainter *painter, const QRect &rect, int, const QPixmap &pixmap) const
override { m_pic = pixmap; m_ny = rect.y(); Draw(painter); }
virtual void drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled,
const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const override;
void Draw(QPainter *painter) const;
const QToolButton* B;
const QSize SICON;
mutable QString m_s;
mutable QPixmap m_pic;
mutable QRect m_r;
mutable int m_nf, m_ny;
mutable bool m_bEnabled;
mutable QPalette m_pal;
mutable QPalette::ColorRole m_textRole;
};
CenteredToolButtonStyle::CenteredToolButtonStyle(QToolButton* b, const QSize& sIcon)
: QProxyStyle(), B(b), SICON(sIcon), m_nf(0), m_bEnabled(true), m_ny(0)
{
b->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
setParent(b);
}
void CenteredToolButtonStyle::drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal,
bool enabled, const QString &text, QPalette::ColorRole textRole/* = QPalette::NoRole*/) const
{
m_s = text;
m_r = rect;
m_nf = flags | Qt::AlignCenter;
m_bEnabled = enabled;
m_pal = pal;
m_textRole = textRole;
Draw(painter);
}
void CenteredToolButtonStyle::Draw(QPainter *painter) const
{
if (m_ny) {
if (m_r.y() != m_ny) return;
auto r = m_r;
r.adjust(-SICON.width() - 8, m_ny = 0, -itemTextRect(B->fontMetrics(), m_r, m_nf, m_bEnabled, m_s).width(), 0);
QProxyStyle::drawItemPixmap(painter, r, Qt::AlignCenter, m_pic);
}
QProxyStyle::drawItemText(painter, m_r, m_nf, m_pal, m_bEnabled, m_s, m_textRole);
}
Sample use:
foreach(auto b, ui.mainToolBar->findChildren<QToolButton*>())
b->setStyle(new CenteredToolButtonStyle(b, ui.mainToolBar->iconSize()));

Strange behaviour of QCombobox::setItemData function

I was working with a simple class derived(publicly) from QComboBox and noticed a strange behaviour of setItemData function:
a simple example:
QFont font;
font.setItalic(true);
setItemData(0, font, Qt::FontRole);
I was sure that this had to change the font of the first element in combobox to italic. But it does NOTHING.
I was more surprised when this code works porperly in this combination:
setEditable(true); //setting my derived class editable changes the situation
QFont font;
font.setItalic(true);
setItemData(0, font, Qt::FontRole);
Moreover, if I run my application(which uses my custom combobox class) giving style option from terminal f.e. -style plastique then everything works properly, without setting combobox editable.
I couldn't find anything said about this in documentation.
Does anybody have idea what is the reason of all this?
Here is the source code:
.h file:
class ComboBoxWrapper : public QComboBox
{
Q_OBJECT;
public:
ComboBoxWrapper(QWidget* parent = 0);
const QString& getDefaultValue() const;
void setDefaultValue(const QString& defaultValue);
private:
QString defaultValue_;
};
And here is .cpp:
ComboBoxWrapper::ComboBoxWrapper(QWidget* parent)
: QComboBox(parent)
{
setAutoFillBackground(true);
}
const QString& ComboBoxWrapper::getDefaultValue() const
{
return defaultValue_;
}
void ComboBoxWrapper::setDefaultValue(const QString& defaultValue)
{
int index = findText(defaultValue);
if(-1 == index)
{ /// current value is invalid.
defaultValue_.clear();
Q_ASSERT(false);
}
defaultValue_ = defaultValue;
QFont font = QApplication::font();
font.setItalic(true);
setEditable(true); //setItemData doesn't work without this trick
setItemData(index, font, Qt::FontRole);
setEditable(false);
}

“text-overflow” for a QLabel’s text rendering in QT

I have got a QLabel element in a widget which can be resized. The text can overflow boundaries, so I need, for the application to look more elegant, some way to make the text generate an ellipsis (...) after the last totally visible word in the text.
Making layouts in HTML/CSS I used to use text-overflow: ellipsis; for this, but for QT classes I have not found any information on this.
It looks like on your label resize event you can create elided text using the new width of the widget and reset the text. Use QFontMetrics::elidedText method to get the elided version of the string.
QString text("some long text without elipsis");
QFontMetrics metrics(label->font());
QString elidedText = metrics.elidedText(text, Qt::ElideRight, label->width());
label->setText(elidedText);
hope this helps, regards
I've modified solution described above and created a function:
static void SetTextToLabel(QLabel *label, QString text)
{
QFontMetrics metrix(label->font());
int width = label->width() - 2;
QString clippedText = metrix.elidedText(text, Qt::ElideRight, width);
label->setText(clippedText);
}
Hope it will be useful.
Qt-5 includes an example of an elided label class which may be a useful reference when implementing your own.
From the example:
elidedlabel.h:
class ElidedLabel : public QFrame
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText)
Q_PROPERTY(bool isElided READ isElided)
public:
explicit ElidedLabel(const QString &text, QWidget *parent = 0);
void setText(const QString &text);
const QString & text() const { return content; }
bool isElided() const { return elided; }
protected:
void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;
signals:
void elisionChanged(bool elided);
private:
bool elided;
QString content;
};
elidedlabel.cpp:
ElidedLabel::ElidedLabel(const QString &text, QWidget *parent)
: QFrame(parent)
, elided(false)
, content(text)
{
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
}
void ElidedLabel::setText(const QString &newText)
{
content = newText;
update();
}
void ElidedLabel::paintEvent(QPaintEvent *event)
{
QFrame::paintEvent(event);
QPainter painter(this);
QFontMetrics fontMetrics = painter.fontMetrics();
bool didElide = false;
int lineSpacing = fontMetrics.lineSpacing();
int y = 0;
QTextLayout textLayout(content, painter.font());
textLayout.beginLayout();
forever {
QTextLine line = textLayout.createLine();
if (!line.isValid())
break;
line.setLineWidth(width());
int nextLineY = y + lineSpacing;
if (height() >= nextLineY + lineSpacing) {
line.draw(&painter, QPoint(0, y));
y = nextLineY;
//! [2]
//! [3]
} else {
QString lastLine = content.mid(line.textStart());
QString elidedLastLine = fontMetrics.elidedText(lastLine, Qt::ElideRight, width());
painter.drawText(QPoint(0, y + fontMetrics.ascent()), elidedLastLine);
line = textLayout.createLine();
didElide = line.isValid();
break;
}
}
textLayout.endLayout();
if (didElide != elided) {
elided = didElide;
emit elisionChanged(didElide);
}
}
This is how I achive. Behave just like regular QLabel yet with ellipsis.
class EllipsisLabel : public QLabel
{
Q_OBJECT
public:
explicit EllipsisLabel(QWidget *parent = nullptr);
explicit EllipsisLabel(QString text, QWidget *parent = nullptr);
void setText(QString);
protected:
void resizeEvent(QResizeEvent *);
private:
void updateText();
QString m_text;
};
EllipsisLabel::EllipsisLabel(QWidget *parent)
: EllipsisLabel("", parent)
{
}
EllipsisLabel::EllipsisLabel(QString text, QWidget *parent)
: QLabel(parent)
{
setText(text);
}
void EllipsisLabel::setText(QString text)
{
m_text = text;
updateText();
}
void EllipsisLabel::resizeEvent(QResizeEvent *event)
{
QLabel::resizeEvent(event);
updateText();
}
void EllipsisLabel::updateText()
{
QFontMetrics metrics(font());
QString elided = metrics.elidedText(m_text, Qt::ElideRight, width());
QLabel::setText(elided);
}

Set QTableWidget cell's borders to 0px

How can I set the cell borders in a QTableWidget to 0px? Preferably I can choose which sides of a cell's border to set to 0, but I can live with setting them all to 0 as well.
EDIT: Either setting the border to 0px or setting the color to white would be good as well.
You can disable all the borders with QTableWidget::setShowGrid, and re-enable some of them with a style sheet (for instance: "QTableView::item { border-left: 1px solid black; }")
The latter are cell interior borders, so they might not be as well aligned as the grid.
If you want to change the borders individually for each cell, you need to write a delegate (like in that answer).
check if QTableWidget's setShowGrid would work for you, smth like this:
tableWidget->setShowGrid(false);
hope this helps, regards
The easiest way to do it for me without affecting widget's focus policy and using qss is to create the following custom delegate and install it for table:
*.h:
class FocusControlDelegate : public QStyledItemDelegate {
public:
FocusControlDelegate(QObject *parent = 0);
virtual void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const;
void setFocusBorderEnabled(bool enabled);
protected:
bool f_focus_border_enabled;
};
*.cpp:
FocusControlDelegate::FocusControlDelegate(QObject *parent) : QStyledItemDelegate(parent) {
f_focus_border_enabled = false;
}
void FocusControlDelegate::setFocusBorderEnabled(bool enabled) {
f_focus_border_enabled = enabled;
}
void FocusControlDelegate::initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const {
QStyledItemDelegate::initStyleOption(option, index);
if(!f_focus_border_enabled && option->state & QStyle::State_HasFocus)
option->state = option->state & ~QStyle::State_HasFocus;
}

Resources