Qt QCalendarWidget QSS Styling - qt

I know there's no support for QCalendarWidget QSS styling but does anyone know some workarounds for changing the color of sections 1 and 2 of the QCalendarWidget? (the light blue for section 1 and white for section 2)
Thanks!

I've examined QCalendarWidget source code and found the solution.
QCalendarWidget internally has a model and a view to display days. QCalendarModel has a formatForCell(int, int) function that returns QTextCharFormat for a given cell. Returning format is the result of merging QCalendarView palette data, a format for current day (saturday and sunday are shown in red) and a format for current date, which can be set using QCalendarWidget::setDateTextFormat function.
Actually an item's background is:
format.setBackground(pal.brush(cg, header ? QPalette::AlternateBase : QPalette::Base));
pal is a QCalendarView's palette;
cg is a color group;
header is true when the current cell is a header cell (section 1 in your example)
So, all you need is to set your custom palette to that internal QCalendarView. In the source code we can find that QCalendarView object has a name "qt_calendar_calendarview" which we can use:
QCalendarWidget *c = new QCalendarWidget;
QTableView *view = c->findChild<QTableView*>("qt_calendar_calendarview");
if (view)
{
QPalette pal = view->palette();
pal.setColor(QPalette::Base, Qt::red);
pal.setColor(QPalette::AlternateBase, Qt::green);
view->setPalette(pal);
}
In my example section 1 will be red and section 2 will be green.
Additionally you can set colors for every color group of you palette to get the widget you like when it's active, inactive etc.

Area "1" customization:
QTextCharFormat format;
format.setForeground(QBrush(Qt::blue));
format.setBackground(QBrush(Qt::red);
ui->calendarWidget->setHeaderTextFormat(format);
Area "2" QSS CSS:
QCalendarWidget QAbstractItemView
{
background-color: rgb(192,192,192); /* цвет фона текущего месяца */
selection-background-color: yellow; /* цвет фона выбранного дня */
selection-color: black; /* цвет текста выбранного дня */
}
or
#qt_calendar_calendarview
{
background-color: rgb(192,192,192); /* цвет фона текущего месяца */
selection-background-color: yellow; /* цвет фона выбранного дня */
selection-color: black; /* цвет текста выбранного дня */
}
, where #qt_calendar_calendarview - object's name from d->m_view->setObjectName(QLatin1String("qt_calendar_calendarview")); in qcalendarwidget.cpp

Related

Why does padding-left style result in QComboBox menu stretching to screen height?

Consider the following example. It creates two instances of QComboBox: one with a stylesheet, and another without. If the first one is clicked (with widget style being Fusion), the menu is sized as expected, although padding of text is inconsistent between hovered and non-hovered items. But if you click on the second one, the padding problem is now fixed, but the menu appears to have huge entries, making the menu fill the whole screen height.
#include <QComboBox>
#include <QApplication>
int main(int argc, char** argv)
{
QApplication app(argc, argv);
QComboBox box1, box2;
const QString stylesheetOrig=R"(
QComboBox::item:selected
{
background-color: #0000ff;
}
)";
box1.setStyleSheet(stylesheetOrig);
box2.setStyleSheet(stylesheetOrig+R"(
QComboBox::item
{
padding-left: 27px;
}
)");
box1.addItems({"Hello 1","Goodbye 1"});
box2.addItems({"Hello 2","Goodbye 2"});
box1.show();
box2.show();
return app.exec();
}
If I remove the padding statement, still leaving the QComboBox::item {} part, then nothing strange (and nothing useful) happens. But if I even set the padding to 1px or 0px, the stretching already happens with all its might.
Why does setting horizontal padding result in such a strange change vertically?
Wow OK, that is screwy indeed. Adding any css to a combo box makes it go into some other "retro" mode with showing icons next to the current item. I've never noticed that in many years, but I see a bunch of common threads on the issue. Seems to only affect Fusion style though, I was confused for a while on my Windows box until I figured that out.
The question is if you want the checkbox or not. Here's one way to get rid of it, the only consistent one I found after a bit of playing with it. The main trick is setting the selection colors on the ::item and not on ::item:selected (the latter makes the checkmarks appear).
QComboBox::item {
selection-background-color: #0000ff;
selection-color: palette(highlighted-text);
}
PS. Another reason for confusion and why QComboBox::item and :checked even work is that the QComboBox default item delegate (used to draw the items in the QListView which the combo box uses for the options list) "pretends" it's a QMenu: QComboMenuDelegate::paint()
So another workaround would be to use something more sane/customizable for a delegate, perhaps even a default QStyledItemDelegate.
ADDED: A version keeping the checkbox and ensuring the unchecked items have padding (w/out using padding property which appears to be FUBAR when used in a combo box item with Fusion style). The icon size seems easiest set via iconSize property -- I tried a few ways via css icon/image/element width/height but nothing affected it... probably because the iconSize property overrides it.
QComboBox { qproperty-iconSize: 12px; } /* or QComboBox::setIconSize() */
QComboBox::indicator { color: transparent; } /* to force space for the icon column */
/* Using ::item:selected vs. ::item { selection-*-color: } will apparently make the
checkbox column appear... at least with Fusion as the main style */
QComboBox::item:selected {
color: palette(highlighted-text);
background-color: #0000ff;
}
VERSION 3 (as per comments):
QComboBox { qproperty-iconSize: 12px; } /* or QComboBox::setIconSize() */
QComboBox::indicator:!checked { border: 0; } /* to force space for the icon column */
QComboBox::item { background-color: palette(base); } /* gets rid of icon|text separator */
/* Using ::item:selected vs. ::item { selection-*-color: } will apparently make the
checkbox column appear... at least with Fusion as the main style */
QComboBox::item:selected {
color: palette(highlighted-text);
background-color: #0000ff;
}
There's still a 1px frame line at the top of the unselected icon area, though it's pretty subtle. I have no idea where that comes from... tried some guesses but to no avail.

JavaFX - Set different hover colors on toggle button based on toggle state

I have a toggle button in my program that starts/stops a script. I would like for this button to be green and say "START" when the button is not selected, and red and say "STOP" when it is selected. More importantly, I would like the unselected hover color to be a slightly darker version of the original green, and the selected hover color to be a slightly darker version of the red color. My current CSS for this button looks like this:
#startStopButton {
-fx-border-color:#d4d4d4;
-fx-background-color:#85eca5;
-fx-background-image: url("startButton.png");
-fx-background-size: 50px;
-fx-background-repeat: no-repeat;
-fx-background-position: 80% 50%;
-fx-alignment: CENTER_LEFT;
-fx-effect: dropshadow(three-pass-box, #e7e7e7, 15, 0, 0, 0);
}
#startStopButton:hover {
-fx-background-color:#80dc9c;
}
#startStopButton:selected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
#startStopButton:selected:focused{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
Currently, this will work fine, except for when the button turns red. In this case, there is no hover effect. Within my FXML controller, there is a function that is activated every time this button is clicked:
private void startStopClick()
{
if(startStopButton.isSelected())
{
startStopButton.setText(" STOP");
// startStopButton.setStyle()
}
else {
startStopButton.setText(" START");
}
}
Is there any way to 1) set the button text within CSS so that I can leave that out of my controller?
2) Get the current toggle button state in CSS, so that I can have multiple hover effects. For example, something like this:
#startStopButton:unselected{
-fx-background-color: #ff6060;
-fx-text:"STOP";
}
If there is no way to do this in CSS, can I set the hover styles in the Java code in the FXML controller?
CSS properties are only available for the look of nodes. With a few exceptions the basic JavaFX nodes don't allow you to specify content via CSS. The text property of buttons is no exception; it cannot be set using CSS.
As for the colors: The rules occuring last override values assigned by rules with the same precedence occuring before them. This means the background color assigned by the rules for #startStopButton:selected and #startStopButton:selected:focused always override the color #startStopButton:hover assigns.
Since in both cases you want a darker color when hovering, the derive function and a lookedup color may work for you.
Example
#Override
public void start(Stage primaryStage) {
ToggleButton btn = new ToggleButton();
btn.getStyleClass().add("start-stop");
btn.textProperty().bind(Bindings.when(btn.selectedProperty()).then(" STOP").otherwise(" START"));
Pane p = new Pane(btn);
Scene scene = new Scene(p);
scene.getStylesheets().add("style.css");
primaryStage.setScene(scene);
primaryStage.show();
}
style.css
.start-stop.toggle-button {
base-color: #85eca5;
-fx-background-color: base-color;
}
.start-stop.toggle-button:selected {
base-color: #ff6060;
}
.start-stop.toggle-button:hover {
-fx-background-color: derive(base-color, -20%);
}
If you cannot use derive since you need to specify different colors for all 4 states you could still rely on looked-up colors to avoid relying on the rule ordering:
.start-stop.toggle-button {
unselected-color: blue;
selected-color: yellow;
-fx-background-color: unselected-color;
}
.start-stop.toggle-button:hover {
unselected-color: red;
selected-color: green;
}
.start-stop.toggle-button:selected {
-fx-background-color: selected-color;
}

JavaFX TableView change selected cell colour

I have a JavaFX TableView and a ListView and they both use custom cell factories. In particular I have overridden updateItem method in order to bind a particular CSS class based on cell value.
This is part of my CSS file:
.tissueCell {
-fx-text-fill: #F5AD11;
}
.tissueCell:selected {
-fx-background-color: #F5AD11;
-fx-text-fill: white;
}
.significantDataCell {
-fx-background-color: yellow;
-fx-text-fill: black;
}
.significantDataCell:selected {
-fx-background-color: white;
-fx-text-fill: black;
}
For the ListView everything work flawlessly: text is displayed with the proper colour and when the cell is selected the text becomes white and the background is filled with proper colour.
I am experiencing problems with the TableView instead. When unselected the text in the cell is displayed with the chosen colour, but when the cell is selected the background is filled with default JavaFX colour for selected table cells background and the text colour remains #F5AD11 (it does not become white).
The same happens with TableCells that use .significantDataCell class. Cells are displayed properly with yellow background and black text, but when selected nothing changes, not event the background this time.
Any ideas? I did a lot of research but couldn't find any working solution.
By default, TableViews do not allow selection of individual cells, but allow selection of rows. Thus the selector .table-cell:selected never matches any cell in the default selection mode. In this case, you would need
.table-row-cell:selected .table-cell {
/* style definitions */
}
or in your scenario
.table-row-cell:selected .tissue-cell {
-fx-background-color: #F5AD11;
-fx-text-fill: white;
}
etc.
If you allow the table to use cell selection, by calling
myTableView.setCellSelectionEnabled(true);
then individual cells become selected on mouse click (etc), and so your original CSS will work.

Style QProgressBar when the value is 16

It is possible to style the QProgressBar using only QSS when the value is 16 example?
ui->progresso->setValue(16);
Using a QSS like this:
QProgressBar {
//Default QSS
...
}
QProgressBar:value(16) {
background-color: #fc0;
}
My goal is:
- When the QProgressBar is 0: It will use background-color: transparent
- When the QProgressBar is greater than 0: show a gray bar and the "chunk" will be blue
- When the QProgressBar is greater than 89: shows the "chunk" in red.
I can do this with QT + C++, but would like to know is it is possible to do this only with QSS?
Like this (this code does not exist, is just one example):
QProgressBar {
background-color: gray;
}
QProgressBar:value(0) {
background-color: transparent;
}
QProgressBar::chunk {
background-color: blue;
}
QProgressBar::chunk:minValue(90) {
background-color: red;
}
I think it is possible with help of Property Selector but only for exect values i.e.:
QProgressBar[value = 16]::chunk{
background-color: red;
}
but you can generate such stilesheet in code for each value
QString styleSheet;
for(int i = 0; i < 101; i++)
{
styleSheet.append(QString("QProgressBar[value = \"%1\"]::chunk{background-color: %2;}").arg(QString::number(i), (i < 17 ? "red" :"blue")));
}
myProgressBar->setStyleSheet(styleSheet);
I don't try it. It's just a theory based on documentation.
Update 1
Warning: If the value of the Qt property changes after the style sheet has been set, it might be necessary to force a style sheet recomputation. One way to achieve this is to unset the style sheet and set it again.
This is not possible.
The only valid extensions are in the documentation and too long to post here.
However you could handle the valueChanged( int ) signal of the QProgressBar
and set the stylesheet accordingly using setStyleSheet( ) but I figure you already know that.

How do you remove the border from a QPushButton?

I have some QPushButtons in the rows of a QTreeView, and they're showing up with these black borders around them that I can't seem to modify. Currently I can grey out the buttons with this code:
for (int i = 0; i < QPalette::NColorRoles; i++){
QPalette::ColorRole thisRole = static_cast<QPalette::ColorRole>(i);
QColor newColor = commitPalette.color(QPalette::Disabled,thisRole);
int grayColor = qGray(newColor.rgb());
newColor.setRgb(grayColor,grayColor,grayColor,50);
commitPalette.setColor(QPalette::Disabled, thisRole, newColor);
}
But it doesn't do anything to the border. I'd prefer to avoid using stylesheets, as I like the automatic color generation provided by QPalette's constructor
If you are using Qt creator, right click the QPushButton and setStyleSheet as border: none; Thats it.
If you set the QButton property isFlat = true it should disable the border unless it's being clicked.
I suggest using a stylesheet. From the code you can make it to a function:
void setFlatStyle(QPushButton *btn)
{
btn->setStyleSheet(QString("QPushButton {border: 0px;}"));
}
Just pass the button in there and get your result.
button.setStyleSheet("QPushButton { border: none; }")
As said #RajaRaviVarma

Resources