Resetting Qt Style Sheet - qt

I've managed to style my QLineEdit to something like this:
alt text http://www.kimag.es/share/54278758.png
void Utilities::setFormErrorStyle(QLineEdit *lineEdit)
{
lineEdit->setStyleSheet(
"background-color: #FF8A8A;"
"background-image: url(:/resources/warning.png);"
"background-position: right center;"
"background-repeat: no-repeat;"
"");
}
I called the function using
Utilities *util = new Utilities;
util->setFormErrorStyle(lineNoStaf);
The flow should be something like this:
User open form
User fill data
User submit data
Got error
Use setFormErrorStyle()
User edit the text in the QLineEdit and the style disappear
This function should be reusable over and over again, but how can I connect QLineEdit signal such as textChanged() to a function in other class that will reset the Style Sheet and then disconnect the signal so that it won't be running continuously every time the text changed ?

Qt also allows dynamic properties in its stylesheet, that means you don't need to code your own class for every widget type in your form.
From http://qt-project.org/doc/qt-4.8/stylesheet-examples.html
Customizing Using Dynamic Properties
There are many situations where we need to present a form that has mandatory fields. To indicate to the user that the field is mandatory, one effective (albeit esthetically dubious) solution is to use yellow as the background color for those fields. It turns out this is very easy to implement using Qt Style Sheets. First, we would use the following application-wide style sheet:
*[mandatoryField="true"] { background-color: yellow }
This means that every widget whose mandatoryField Qt property is set to true would have a yellow background.
Then, for each mandatory field widget, we would simply create a mandatoryField property on the fly and set it to true. For example:
QLineEdit *nameEdit = new QLineEdit(this);
nameEdit->setProperty("mandatoryField", true);
QLineEdit *emailEdit = new QLineEdit(this);
emailEdit->setProperty("mandatoryField", true);
QSpinBox *ageSpinBox = new QSpinBox(this);
ageSpinBox->setProperty("mandatoryField", true);
Works also in Qt 4.3!

Allright, this is not compile but should work in principle, you should be able to change the look by calling editWidget->setProperty('isError',true) or editWidget->setError(false)
class ErrorTextEdit : QLineEdit
{
Q_OBJECT
QPROPERTY(bool isError, READ isError, WRITE setError);
public:
ErrorTextEdit(QWidget* parent) : QLineEdit(parent), m_isError(false)
{
m_styleSheet = "" // see below
setStyleSheet(m_styleSheet);
}
void setError(bool val)
{
if (val != m_isError)
{
m_isError = val;
setStyleSheet(m_styleSheet);
}
}
bool isError() {return m_isError;}
private:
QString m_styleSheet;
bool m_isError;
}
for the stylesheet
ErrorTextEdit[isError="false"]
{
optional ...
Style for textedit that is NOT an error
}
ErrorTextEdit[isError="true"]
{
background-color: #FF8A8A;
background-image: url(:/resources/warning.png);
background-position: right center;
background-repeat: no-repeat;
}
the term
[<property>="<value>"]
restricts the application of the stylesheet to instances of the class whose <property> has the appropriate <value> the only caveat is that the style is not changed when the property changes its' value, so the stylesheet has to be reapplied for the look of the widget to actually change, see Stylesheet Documentation -> Property Selector
This construction moves the stylesheet into the widget that uses it and makes switch internal to the widget, the widget changes in accordance to its state.
In general you have a couple of ways to handle invalid inputs in your form
a) observe every change and update the style appropriately, you should be able to use QValidator for that too, but that is a separate topic, using QValidator you will probably be able to completely internalize the state of a single QTextEdit and not have to deal with its validity from the outside
b) Do it in the submit loop that you have described above, whenever the user clicks on submit change the state of the correct and incorrect fields
it all depends the structure of your app and the view

See, the other idea is you need to override the paint evet of line edit and then set the background image and color.
here the implimentation is presetn here button, follow up the same to your line edit

Related

QDockWidget change background color when floating

I have a QDockWidget with a transparent background, but I would like to change the background color or background image when it is floating. It doesn't look like the qt style sheets have a pseudo state to tell you whether or not they are floating, so I'd like to know: is this possible to do?
Found the solution. Add the following connection in the code:
connect(knobDock, &QDockWidget::topLevelChanged, [&] (bool isFloating)
{
if (isFloating)
{
setAttribute(Qt::WA_TranslucentBackground, false);
setAttribute(Qt::WA_NoSystemBackground, false);
}
});
This will cause the dock widgetto use whatever background is specified in the stylesheet when the dock is floating, but it will be transparent (i.e. show the mainwindow background) when it's docked.
You can use custom properties to do this.
Thanks #phyatt for link to Dynamic Properties and Stylesheets.
To declare custom property in your custom class you can write in .cpp:
setProperty("customPropertyName", 1);
or in .h (don't forget to define and implement used get/set access methods too):
Q_PROPERTY( int customPropertyName, READ getCustomPropertyName, WRITE setCustomPropertyName);
And in your global stylesheet file you can use the state of your custom property as following:
.YourClass[customPropertyName="1"] {
background-color: transparent;
}
.YourClass[customPropertyName="2"] {
background-color: black;
}
Also it's needed to reload stylesheet of the object instance after your set new property value, because stylesheets are not recalculated automatically:
object->style()->unpolish(tstFrame);
object->style()->polish(tstFrame);
object->update();
or:
object->setStyleSheet("/* */");

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

Qt Style Sheet - Different styles for same type widgets

I need to assign different styles for the same typed widget instances. Specially for QActions. Following style sheet sets QActions' background images, actualy tool buttons'.
QToolButton
{
background-image: url(bg.png);
}
But I need to assign different backgrounds for tool buttons like this.
QToolButton::actClose
{
background-image: url(close.png);
}
QToolButton::actOpen
{
background-image: url(open.png);
}
Is there any easy way like this or is it not possible?
You can set object name for instances of QToolButton
QToolButton *button = new QToolButton;
button->setObjectName("firstButton");
button = new QToolButton;
button->setObjectName("secondButton");
and next use them in Style Sheet
QToolButton#firstButton
{
background-color: gray
}
QToolButton#secondButton
{
background-color: red
}
It helps if you can post c++ code that creates the QToolButton and associates with QActions.
Cite from QToolBar's reference "Toolbar buttons are added by adding actions, using addAction() or insertAction(). " and "QWidget * QToolBar widgetForAction (QAction *action )const
Returns the widget associated with the specified action."
So if you are creating QToolBar and call QToolBar::addAction(QAction*) to fill it, it is possible to get pointer to the tool buttons. Try QToolBar::widgetForAction(), and call setObjectName("") and Blueman's method can be applied.
while applying Style Sheet to widgets, "#" is used after class name to specify object name, ":" is used after className of objectName indicating the object's status such like "enabled", "::" is used to specify the subcontrols such as "ListView::Item", unfortunately QAction is neither of QToolBar.

Removing border of QLineEdit

I have a bunch of QLineEdit boxes that I want to remove the borders from. Ideally I want to just do this with one line of code, rather than having to set no border for each QLineEdit box. I am trying to use QLineEdit::setFrame(false); but this returns illegal call of non-static member function. Suggestions?
You can set the style sheet for the application, or for the parent of those line edits:
window()->setStyleSheet("QLineEdit { border: none }");
or
window()->setStyleSheet("QLineEdit { qproperty-frame: false }");
The latter is equivalent to executing the following code:
for(auto ed : window()->findChildren<QLineEdit*>())
ed->setFrame(false);
The window() refers to QWidget * QWidget::window() const.
Since you want to do it application-wide, you can simply set the style sheet on the application:
qApp->setStyleSheet("QLineEdit { qproperty-frame: false }");
You can further use CSS selectors to override the frame on certain objects. You've got the power of CSS at your disposal.
Use QLineEdit::setFrame() for that. But yes, it isn't a static method. So, you have to call it on an object : myLineEdit->setFrame( false );

Property selectors in QT CSS

I have a tree widget that I'm using for a user/room concept. How can I style the rooms independently from the users in the rooms? I'm assuming it has something to do with QT's property selector in CSS? I would like to be able to do this:
QTreeView::item[isUser="true"] { background: blue; }
QTreeView::item[isRoom="true"] { background: red; }
Since the items in a model are not QObjects (nor QWidgets), you will not be able to add a property to the item, or style them with stylesheets.
I have two suggestions for doing what you want to do :
1) (C++ only) Attach your QTreeView to a QStandardItemModel, and when you add items as QStandardItem objects, you can call QStandardItem::setBackground() with either Qt::blue or Qt::red depending of whether the item is a room or a user.
2) (C++ and CSS) Define a QStyledItemDelegate that you attach to your QTreeView. In your reimplementation of QStyledItemDelegate::paint() method, use a QLabel to display the content of the item, then set a property on that QLabel. You will then be able to use a stylesheet to customize the look of the label :
QLabel[isUser="true"] { background: blue; }
QLabel[isRoom="true"] { background: red; }
I was able to accomplish what I needed by creating a label, using the setProperty method on that label, and then using the setItemWidget function to attach that QLabel to the appropriate QTreeWidgetItem. So I wouldn't be "styling the QTreeWidgetItem", but rather styling the QLabel that was overlayed on top of the QTreeWidgetItem. The following example sets my topLevelItem in the QTreeWidget to be ready to be styled as a room:
QTreeWidgetItem *topItem = ui->treeWidget->topLevelItem(0);
currentLabel = new QLabel;
currentLabel->setProperty("room",true);
currentLabel->setText(QString("Room Lobby"));
ui->treeWidget->setItemWidget(topItem,0,currentLabel);`
I can then select it in the stylesheet with
QLabel[room="true"] { background: red; }

Resources