changing cell background color in qt - qt

i'm new to pyqt , and i'm still facing some newbie problems :D
i have a QTableWidget that is item delegated on a QChoice control ( hope i said it right )
i need to have the cell background color changes whenever a user change the choice control selection
briefly: how to change a cell background color in a table widget ??
i use pyqt4 and python 2.6
thanx in advance

I used something like this:
brush = QtGui.QBrush(QtGui.QColor(255, 0, 0))
brush.setStyle(QtCore.Qt.SolidPattern)
item.setBackground(brush)
Where item is QTableWidgetItem object

Use
QTableWidgetItem QTableWidget.item(row, column)
and
QTableWidgetItem setData(role, data)
with
Qt.BackgroundRole
as follows:
table.item(0, 0).setData(Qt.BackgroundRole, color).
And read about the Roles mechanism used in Qt Model/View.

if you use QTableView use this:
model.setData(model.index(0, 0), QVariant(QBrush(Qt::red)), Qt::BackgroundRole);

Here are some useful lines of code. Sorry for redundancy, I'm trying to gain some reputation.
QStandardItemModel* model = new QStandardItemModel(numRows, numColumns);
QStringList headers;
headers.append("Date");
model->setHorizontalHeaderLabels(headers);
QStandardItem* item = new QStandardItem(text);
item->setData(Qt::AlignCenter, Qt::TextAlignmentRole);
item->setData(QVariant(QBrush(Qt::green)), Qt::BackgroundRole);
model->setItem(row, column, item);
or simply:
item->setBackground(Qt::green);

Hey, you set the delegate method for the table widget. in the paint event of the delegate you handle the color changing technique..
have a look at this example,here they have done custom selection color. same way you handle the item cell painting

For supplement in C++ way, if you want to paint custom color unlike Qt::red and so on, you can do something like :
ui->tableWidget->item(i, j)->setBackground(QColor(152,234,112));

Related

How to set stylesheet for the current item in QTableView

When QTableView edit control is visible for the current item the shylesheet of the edit takes place. When there is no active edit control in the QTableView the current item is styled using the QTableView { selection-background-color: } How to set different style only for the current item?
Qt style sheets support sub-controls and pseudo states, you can use it to improve your customization. see Qt6 docs
In this case you can use the ::item sub-control and the :focus pseudo state (the "current" pseudo state doesn't exist, but the :focus does the same).
This is an example that you can use:
QTableView::item:focus
{
selection-background-color: yellow;
}
See also Qt6 documentation of customizing a qtableview
1. As it IGHOR said you can use data() method in your model and provide a color when role is Qt::BackgroundColor. But there is a stumble here because you don't know whether index is current or not. You'll ought to set a current index in the model when it changes and then make a check like this:
if (index == m_currentIndex and role==Qt::BackgroundRole) return Qt::black;
Actually it's not the best idea to tell the model about currentIndex according to Model/View pattern, because you can have two views for one model.
2. Descendants of QAbstractItemView has method setItemDelegate. A delegate is used to draw a cell.
All you need is to inherit from QStyledItemDelegate, pass a pointer to the view to the delegate and override method initStyleOption.
Then do something like this:
void MyStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const
{
QStyledItemDelegate::initStyleOption(option, index);
QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option);
if (index == view()->currentIndex())
{
v4->backgroundBrush = QBrush(Qt::grey);
}
}
3. If you really need to use css (for example you have themes) you can do it this way:
Add something like this in your css file:
QTableView
{
qproperty-currentItemBackground: #cccccc;
}
Modify initStyleOption from the previous example to use the property:
v4->backgroundBrush = view()->property("currentItemBackground").toColor();
With this approach you can set a specific style via css for a column, a row, a single cell or a group of cells.
You need to create a new delegate, that renders itself based on the data model (custom role, for example). You need to base its style on a special control created for the purpose (that can be changed via stylesheet) . I'll post some code when I find time.
One can use variadic templates, and crtp (Coplien) to good effect to layer one's delegates

How to set animated icon to QPushButton in Qt5?

QPushButton can have icon, but I need to set animated icon to it. How to do this?
I created new class implemented from QPushButton but how to replace icon from QIcon to QMovie?
This can be accomplished without subclassing QPushButton by simply using the signal / slot mechanism of Qt. Connect the frameChanged signal of QMovie to a custom slot in the class that contains this QPushButton. This function will apply the current frame of the QMovie as the icon of the QPushButton. It should look something like this:
// member function that catches the frameChanged signal of the QMovie
void MyWidget::setButtonIcon(int frame)
{
myPushButton->setIcon(QIcon(myMovie->currentPixmap()));
}
And when allocating your QMovie and QPushButton members ...
myPushButton = new QPushButton();
myMovie = new QMovie("someAnimation.gif");
connect(myMovie,SIGNAL(frameChanged(int)),this,SLOT(setButtonIcon(int)));
// if movie doesn't loop forever, force it to.
if (myMovie->loopCount() != -1)
connect(myMovie,SIGNAL(finished()),myMovie,SLOT(start()));
myMovie->start();
Since I had to solve this problem for a project of mine today, I just wanted to drop the solution I found for future people, because this question has lots of views and I considered the solution quite elegant. The solution was posted here. It sets the icon of the pushButton every time, the frame of the QMovie changes:
auto movie = new QMovie(this);
movie->setFileName(":/sample.gif");
connect(movie, &QMovie::frameChanged, [=]{
pushButton->setIcon(movie->currentPixmap());
});
movie->start();
This also has the advantage, that the icon will not appear, until the QMovie was started. Here is also the python solution, I derived for my project:
#'hide' the icon on the pushButton
pushButton.setIcon(QIcon())
animated_spinner = QtGui.QMovie(":/icons/images/loader.gif")
animated_spinner.frameChanged.connect(updateSpinnerAniamation)
def updateSpinnerAniamation(self):
#'hide' the text of the button
pushButton.setText("")
pushButton.setIcon(QtGui.QIcon(animated_spinner.currentPixmap()))
Once you want to show the spinner, just start the QMovie:
animated_spinner.start()
If the spinner should disappear again, then stop the animation and 'hide' the spinner again. Once the animation is stopped, the frameChanged slot won't update the button anymore.
animated_spinner.stop()
pushButton.setIcon(QtGui.QIcon())

How to change color of QWidget in QTableWidget

I have a QTableWidget. In its cells I need to display 3-state QSliders, that must change their color, depending form their state. -1 = red, 0 - normal, 1 - green. I tried to set QPalette to QSlider - whitout success. I tried to place QSlider into QWidget with Layout and apply palette to QWidget - whitout success.
How to do that? I need any color sign (border or full background, e.t.c) How to do that?
You can use QItemDelegate, then you'll could to rule your QSlider into QTableWidget.
Detail.
At first, you should derive from QItemDelegate. A good docs presents by doc.qt.digia example using qitemdelegate
You should substitute QSpinBox to QSlider. And after reading this document, you can do needed with setting color your QSlider.
QTableWidget *table = new QTableWidget(this);
table->setItemDelegateForColumn(index_column, delegate);
// or table->setItemDelegateForRow(index_row, delegate);
// or table->setItemDelegate(delegate);
To editor was opened always, you should use openPersistentEditor(). For example:
QTableWidgetItem *item = new QTableWidgetItem;
table->insertRow(row);
table->setItem(row, index_your_delegate, item);
table->openPersistentEditor(item);

how to add an widget into the Form In QtDesigner

in qdesigner_workbench.cpp, how can I add a widget (say QLabel) into a FormWindow by code?
Since methods like createWidget()...etc are all abstract, how do I properly use the internal mechanics to add QLabel into the active FormWindow?
EDIT:
In qdesigner_workbench.cpp, this is currently what I have:
QDesignerFormWindowManagerInterface* fwm = core()->formWindowManager();
QDesignerFormWindowInterface* fw = fwm->activeFormWindow();
QWidget* mw = fw->mainContainer();
QLabel* label = new QLabel(mw); //can be added correctly but not in the right hierarchy
label->setText("I am a good girl.");
The mw (obtained from fw->mainContainer()) is actually a MainWindow, however the real data I need is in:
mw -> children[2] (which is a QDesignerWidget) -> children
There are 9 widgets in the designer, and you can see there's 9 arrays in children mentioned above; see this link (an image) for illustration.
http://img24.imagevenue.com/img.php?image=98871_a_122_476lo.jpg
So... how can I correctly add the QLabel widget?
Tried both
QLabel* label = new QLabel(fw); // will be a sibling of MainContainer, which is the QMainWindow (mw) in this case
QLabel* label = new QLabel(mw); // will be a sibling of QDesignerWidget
and apprarently either of the works.
If you want just to display a widget on a form, you can set your QMainWindow or QDialog to be the widget parent:
QLabel *l = new QLabel(this);
l->setText("My long string");
Where this is a pointer pointing to your current QDialog or QMainWindow.
Otherwise as ufukgun pointed out, you can use setCentralWidget if you need your widget to occupy the center of the QMainWindow.
You should add any QWidget to the QLayout of the form.This will put it into the display strategy of the form when resizing it.
form->ui->layout->add(yourQWidget);
Depending of the QLayout you are using, parameters of the add function will not be the same.
create a widget and add it to your main window as it is your central widget
mainWindow->setCentralWidget(centralWidget);
if you want to add a label, you can add it to this central widget

In a QTableWidget, changing the text color of the selected row

I'm using a QTableWidget to display several rows. Some of these rows should reflect an error and their text color is changed :
Rows reflecting that there is no error are displayed with a default color (black text on white background on my computer).
Rows reflecting that there is an error are displayed with a red text color (which is red text on white background on my computer).
This is all fine as long as there is no selection. As soon as a row is selected, no matter of the unselected text color, the text color becomes always white (on my computer) over a blue background.
This is something I would like to change to get the following :
When a row is selected, if the row is reflecting there is no error, I would like it to be displayed with white text on blue background (default behavior).
If the row is reflecting an error and is selected, I would like it to be displayed with red text on blue background.
So far I have only been able to change the selection color for the whole QTableWidget, which is not what I want !
Answering myself, here is what I ended up doing : a delegate.
This delegate will check the foreground color role of the item. If this foreground color is not the default WindowText color of the palette, that means a specific color is set and this specific color is used for the highlighted text color.
I'm not sure if this is very robust, but at least it is working fine on Windows.
class MyItemDelegate: public QItemDelegate
{
public:
MyItemDelegate(QObject* pParent = 0) : QItemDelegate(pParent)
{
}
void paint(QPainter* pPainter, const QStyleOptionViewItem& rOption, const QModelIndex& rIndex) const
{
QStyleOptionViewItem ViewOption(rOption);
QColor ItemForegroundColor = rIndex.data(Qt::ForegroundRole).value<QColor>();
if (ItemForegroundColor.isValid())
{
if (ItemForegroundColor != rOption.palette.color(QPalette::WindowText))
{
ViewOption.palette.setColor(QPalette::HighlightedText, ItemForegroundColor);
}
}
QItemDelegate::paint(pPainter, ViewOption, rIndex);
}
};
Here is how to use it :
QTableWidget* pTable = new QTableWidget(...);
pTable->setItemDelegate(new MyItemDelegate(this));
What you'll want to do is connect the selectionChanged() signal emitted by the QTableWidget's QItemSelectionModel to a slot, say OnTableSelectionChanged(). In your slot, you could then use QStyleSheets to set the selection colours as follows:
if (noError)
{
pTable->setStyleSheet("QTableView {selection-background-color: #000000; selection-color: #FFFFFF;}");
}
else
{
pTable->setStyleSheet("QTableView {selection-background-color: #FF0000; selection-color: #0000FF;}");
}
It looks ok, but you might want to look at the documentation of QStyleOption it can tell you wether the item drawn is selected or not, you don't have to look at the draw color to do that. I would probably give the model class a user role that returns whether the data is valid or not and then make the color decision based on that. I.e. rIndex.data(ValidRole) would return wether the data at this index is valid or not.
I don't know if you tried overriding data for the BackgroundRole and returning a custom color, Qt might do the right thing if you change the color there
You could, of course, inherit from the table widget and override the paint event, but I don't think that is what you want to do.
Instead, should use the QAbstractItemDelegate functionality. You could either create one to always be used for error rows, and set the error rows to use that delegate, or make a general one that knows how to draw both types of rows. The second method is what I would recommend. Then, your delegate draws the rows appropriately, even for the selected row.
You could use e.g. a proxy model for this where you return a different color if you have an error for the specific modelindex;
QVariant MySortFilterProxyModel::data(const QModelIndex & index, int role = Qt::DisplayRole) {
// assuming error state and modelindex row match
if (role==Qt::BackgroundRole)
return Qt::red;
}

Resources