Dynamic theme changing in PyQt application - pyqt5

I need to develop a dynamic theme changing in PyQt application, I have different components, and depending on the theme I need to change styles. I need to change the theme from some specific component and all components should change their styles. I do not use global styles, I need to write styles for each component separately in its class.
At the moment I came up with such an implementation:
I grab GlobalObject class from this article - https://stackoverflow.com/a/55554690/15709458.
And for each component, I put a listener for the "themeChanged" event. And by dispatching this event, I notify all components which listen to this event that the theme of the application has changed.
Dispatching event example:
def set_dark_theme(app: QApplication):
app.setProperty("theme", "dark")
GlobalObject().dispatchEvent("themeChanged")
Component example:
class CheckBox(QCheckBox):
def __init__(self, parent=None):
super().__init__(parent)
self.update_stylesheet()
GlobalObject().addEventListener("themeChanged", self.update_stylesheet)
def update_stylesheet(self):
theme = QApplication.instance().property("theme")
if theme == "dark":
text_color = __colors__["gray"][200]
else:
text_color = __colors__["gray"][700]
self.setStyleSheet(
f"QCheckBox {{ spacing: 8px; font-size: 14px; font-weight: 500; color: {text_color}; }}"
)
Will such an implementation adversely affect performance due to the fact that all components in the application of which there can be a lot will be subscribed to the event? Is it possible to somehow improve this solution, for example using some built-in methods?

You do not have to use events at all!
You can simply have a QWidget as main class which holds all the other widgets. Then you can use setStyleSheet() once and the appearance will change for all widgets as long as they are in the stylesheet or inherit from a class in the stylesheet.
If you set a style for QWidget for example, the properties will be set for almost all widgets as they all inherit from QWidget.
You can see the minimal example below for reference. Click the CheckBox and the style will change to dark.
import sys
from PyQt5 import QtWidgets, QtGui
class Window(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.checkbox = QtWidgets.QCheckBox(self)
self.checkbox.toggled.connect(self.change_theme)
def change_theme(self):
if theme == "dark":
text_color = __colors__["gray"][200]
else:
text_color = __colors__["gray"][700]
self.setStyleSheet("QWidget { background-color: black; color: white; } QCheckBox { spacing: 8px; font-size: 14px; font-weight: 500; color: {text_color}; background-color: grey; }")
app = QtWidgets.QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
Edit: I added the theme color variables

Related

How to style Grid cell/row background without using classname generator

I searched a lot, but every solution was to include some constant CSS class names into the page, and use the Column's ClassNameGenerator to set the proper classname on the cell/row.
Now this might be a good solution when the developer can decide on formatting a cell, however when a user can decide (especially with a script written as cell renderer) how a cell will look like, it is not possible to use the ClassNameGenerator.
So question is, how can I format the cell/row background programmatically, not using any CSS? I can provide custom component as cell value. So it's fine to render a label with icon, or just icon, or a checkbox, however coloring this rendered component is not enough, since this is smaller than the cell itself, making it look really ugly. I need to access the root element of the cell, and color it using getStyle().set("background", "xxxx"). How to achieve this?
Thanks!
You can use a TemplateRenderer.
For example:
Grid<Person> grid = new Grid<>();
grid.setItems(people);
grid.addColumn(TemplateRenderer
.<Person>of("<b>[[item.name]]</b>")
.withProperty("name", Person::getName)
).setHeader("Name");
Checkout this tutorial for more information: https://vaadin.com/docs/v14/flow/components/tutorial-flow-grid
OK, finally I solved. I use a template renderer with a proper template structure. I modified the cell style in a way, that my renderer DIV fills the entire cell (removed any padding/margin from the original cells)
<dom-module id="grid-style" theme-for="vaadin-grid">
<template>
<style>
[part~='cell'] ::slotted(vaadin-grid-cell-content) {
padding: 0px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
--cellopa: 255;
}
[part~='cell'][aria-selected~="true"] ::slotted(vaadin-grid-cell-content) {
--cellopa: 0;
}
</style>
</template>
</dom-module>
I also added some simple CSS declarations to one of the main CSS:
vaadin-grid-tree-toggle flow-component-renderer {
width: 100%;
height: 100%;
}
vaadin-grid-cell-content flow-component-renderer {
width: 100%;
height: 100%;
flex-grow: 1;
}
This way the rendered DIV fills the whole cell and I can color it's background.
Now the problem comes with the selection, since the selection is not visible any more. For this you find the --cellopa variable set to 255 normally and set to 0 for selected cells.
Now when I define a background-color on the div, I use rgba and I set the alpha to the var(--cellopa) variable, like this for example rgba(255, 0, 0, var(--cellopa))
Now when the row is not selected, the cellopa is 255, so the background is visible, when I select the row the cellopa is set to 0, so the background of the DIV gets transparent, and the row selection color on the row is visible. This is super fast, and changing the selection does not cause any glitch, and also the previous coloring state is restored properly.
I also managed to get around with the treegrid and managed to color even the hierarchy column fully using a special template for the hierarchy column with some padding taking the level into account.

how to change the vue-intro.js css in nuxt.js

I'm trying to change the CSS feature vue-intro tutorial for my web app. I'm having trouble with how to change the tooltip button color, themes in vue-intro.js.
I want to change Next button color. so, how to change CSS in nuxt.js project.
I added the below code as a plugin. but I can't change the CSS
import Vue from 'vue'
import VueIntro from 'vue-introjs'
import 'intro.js/introjs.css'
Vue.use(VueIntro)
Here's an SCSS utility to generate the CSS for it:
$btn-color: #f50;
$text-color: white;
a.introjs-nextbutton {
background-color: $btn-color;
border-color: darken($btn-color, 4.2%);
text-shadow: none;
color: $text-color;
&:hover {
background-color: lighten($btn-color, 4.2%);
border-color: $btn-color;
color: $text-color;
}
&:focus {
box-shadow: 0 0 0 0.2rem transparentize($btn-color, .42);
background-color: $btn-color;
border-color: darken($btn-color, 4.2%);
color: $text-color;
}
}
I have done something similar before. I think the only way to do it is to overwrite the className or not import the intro.css (make your own). You need to "inspect element" to find out the introJS className from the library. Basically their className start with prefix introjs-something.
I can even do things like display none for previous button or change its color. See picture below.
Click this to see My Inspect Element to find introjs classes

Change headers default font on Vuetify

I've just upgraded to Vuetify 2.0 and my fonts are totally broken.
I've managed to change the font on the project by:
.v-application {
font-family: 'Montserrat', sans-serif!important;
}
But the headings that have applied classes like .display-1, .display-2 are still taking the Vuetify default (Roboto) because it has an !important in the Vuetify default styles.
How could I change the font for the entire project, overriding Vuetify's default?
You can change the default font for a specific type of typography like h1 and h2 and specifically the font-family property in the following manner in a global css file for example:
$headings: (
'h1': (
'font-family': 'Calibri',
'size': 60px,
'line-height': 60px,
'weight': 400
),
'h2': (
'font': 'Ariel',
'size': 48px,
'line-height': 48px,
'weight': 400
),
)
And than you can give these utility classes in the Vuetify way like so class="text-h1" or class="text-h2"
You could do the same in Vuetify to override the following built in(and exposed via API for modifications) utility classes:
h3
h4
h5
h6
body-1
body-2
subtitle-1
subtitle-2
button
caption
overline
If you need any further utility classes, for example that are derived from your internal design system you can add them in that global scss/css file and I recommend doing so while keeping the Vuetify naming convention.
For example if you need a body-3 or subtitle-3 you could add them like so
.text-body-3 {
// your custom style
}
.text-subtitle-3 {
// your custom style
}
In Vuetify 2.x you can customize scss variables in your variables.scss file. You probably need to set the $body-font-family and $heading-font-family variables.
There are a lot of variables documented here and many changed around Vuetify 2.3.
An example:
$font-size-root: 18px;
$body-font-family: 'Roboto', sans-serif;
$heading-font-family: 'Libre Caslon Text', serif;
$btn-text-transform: none;
Additional information for overriding specific styles:
You can further override individual styles such as text-h1 by adding a $headings to the same file.
$headings: (
'h1': (
'size': 4.0rem,
'weight': 400,
'line-height': 4.444rem,
'letter-spacing': 1em,
'text-transform': false
)
)
The valid values you can customize are listed on the typography doc. Those currently include:
h1
h2
h3
h4
h5
h6
subtitle-1
subtitle-2
body-1
body-2
button
caption
overline
These all generate text-X classes. ex: text-body-2
Also its important to note that even if you override these styles it will not change the type settings for elements of the same name (like h1). Instead you need to apply that style with class="text-h1". This is easy to miss in the docs.
Right:
<h1 class="text-h1">my header</h1>
Wrong:
<h1>my header</h1>
Also if you're not yet on 2.3 the names are different. If you follow github issues there have been a lot of changes around typography leading to this current system.

Changing chartist text color and size

The font size on the charts are to small and hard to read on certain colors. Is there a way to change these attributes?
I can do this do make the whole pie red but setting color or font-size doesn't make a change:
.ct-series-x .ct-slice-pie {
fill: #f05b4f
}
<div class="ct-chart ct-golden-section ct-series-x ct-slice-pie" id="chart2"></div>
For anyone who comes across this - override ct-label in your css file:
.ct-label {
font-size: 15px;
}

Dojo - Tree in accordion is broken (while outside is ok) , Why?

I've made simple application with dojo.
I took the exact same combo tree (cbtree) and put it once inside accordion and once first on page.
I don't understand why inside the accordion I get different cbTree (it looks really bad)
Here is online example of the problem :
http://77.235.53.170/cbTree/cbTree.htm
The problem is at your main.css, you have
#leftCol img {
width: 100%;
}
Which overwrites
.dijitFolderOpened, .dijitIconFolderOpen, .dijitIconError {
background-image: url("../../icons/images/commonIconsObjActEnabled.png");
width: 16px;
height: 16px;
}
You need resolve this in main.css by either removing your style, or changing it to a more specific rule; i.e. instead of #leftCol img, use #leftCol .yourClass.