cleanlook style for message box pyqt4 - pyqt4

I have an PYQT4 application. I try to display a lot of differnt messages based on user interaction. The problem I have is the displayed message using QMessageBox doest come up in clean look style, whereas the other part of the application works well with Clean look style.
I try to use the following code but it doenst work for the message.
# set messagebox properties
msgbox=QMessageBox()
font = QFont()
font.setFamily(_fromUtf8("Levenim MT"))
font.setPointSize(15)
msgbox.setFont(font)
msgbox.setStyle(QStyleFactory.create('Cleanlooks'))
msgbox.information(self,"Download Message", "donuts")
can someone tell me how to make this in clean look style as well

To change the style of your application, you should use QApplication.setSyle, then you have a consistent style in your whole GUI.
Setting a QWidgets's style only sets the style for the widget itself.
QWidget.setStyle:
Sets the widget's GUI style to style. The ownership of the style object is not transferred.
If no style is set, the widget uses the application's style, QApplication.style() instead.
Setting a widget's style has no effect on existing or future child widgets.
Warning: This function is particularly useful for demonstration purposes, where you want to show Qt's styling capabilities. Real applications should avoid it and use one consistent GUI style instead.
That means if you want to change the style of a widget and all it's children, you need to explicitly set it for all children by iterating through them:
cleanlooks = QStyleFactory.create('cleanlooks')
msgbox.setStyle(cleanlooks)
for child in msgbox.findChildren(QWidget):
child.setStyle(cleanlooks)

Related

How to get the color of a widget text, and set it as the color of another widget

I have two widgets
first, a QLineEdit that has a stylesheet (assume not accessible or changeable) that sets the color of the text to some color (e.g., red).
second, QLabel that has a default text color (e.g., black)
How can I get the color of the text in the QLineEdit, and set it as the color in the QLabel
l1 = QLineEdit()
color_to_be_set= l1.palette().highlight().color().name() # this approach is giving the wrong color
q1 = QLabel()
q1.setText("the text")
# then set the new color
"Trial#1 (Not working at all, not changing the color)"
palette = q1.palette()
palette.setColor(QPalette.WindowText,QColor(color_to_be_set))
q1.setPalette.....
"Trial#2, gives the wrong color"
q1.setStyleSheet("color:{}".format(color_to_be_set))
As already explained in comments, there's no public API to access properties set by stylesheets, and I sincerely doubt there could be any (at least, with the current implementation, including Qt6).
That said, there is some level of access to those properties, but it only works for the following:
background and background-color (which are the same);
color;
selection-background-color;
selection-color;
alternate-background-color;
Whenever any of the properties above is set, the palette of the widget is altered with the following palette color roles:
QSS property
QPalette role(s)
background, background-color
Base, Button, Window, backgroundRole()*
color
Text, ButtonText, WindowText, foregroundRole()*
selection-background-color
Highlight
selection-color
HighlightedText
alternate-background-color
AlternateBase
The * values are references to the widget class definitions (for instance, QPushButton normally uses Button as foreground role). They may be overridden by their respective setter functions.
Also, those properties only support the QSS Brush types: plain colors, gradients or palette(<role>). No pixmaps here!
Remember that in order to get proper access to those properties, the widget must be polished, which means that, if the widget has not been ever shown yet, calling ensurePolished() is mandatory:
Ensures that the widget and its children have been polished by QStyle (i.e., have a proper font and palette).
This means that any new Qt widget created without any already polished parent will use the system palette.
Consider the following:
from PyQt5.QtWidgets import *
app = QApplication([])
app.setStyleSheet('* {color: green;}')
source = QWidget()
# source.ensurePolished() # leave this commented for now
color = source.palette().windowText().color()
target = QWidget(styleSheet='background: {}'.format(color.name()))
target.show()
app.exec()
Then uncomment the fifth line, and see the result.
Now, there are a few catches.
When a stylesheet is set, any widget affected by it gets it's style() overridden by a private QStyleSheetStyle. That style is not exposed by the API and completely takes control over the style set for each affected widget.
But not always.
Take this snippet:
from PyQt5.QtWidgets import *
app = QApplication([])
app.setStyleSheet('* {background-color: black;}')
topLevel = QTextEdit()
topLevel.show()
parent = QWidget()
layout = QVBoxLayout(parent)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(QTextEdit())
parent.show()
app.exec()
With my current style (oxygen), the two backgrounds are slightly different:
On the left there's the topLevel widget, on the right the parent. As you can see, the underlying style still has some level of control.
This is an important aspect that has to be kept in mind, and trying to override it with a QProxyStyle won't be enough: the QStyleSheetStyle will "take control" and completely ignore the overridden functions, except for a very few like drawItemText(). Any other function will be called on "the C++ side" implementation, for which there's no useful override in the python bindings.
Also, whenever the underlying style is still used internally by the QSS, the result is that the color properties will be used just like any QPalette: they are reference colors, not the actual ones. Any widget will use the style implementation, which might use different color roles, or completely alter the color depending on the situation.
Whenever the default style is used (even through QStyleSheetStyle modifications), the palette is just a reference, not unlike a physical palette: give the same basic color palette to two styled painters, and they will use its colors in different ways. The actual color shown to the user might be slightly or even completely different and possibly ignored.
Concluding, the following aspects are of utmost importance:
just created widgets will use the default palette;
there is no access to border properties, nor margins and paddings (with the last two also depending on the inherited style);
top level widgets might behave differently;
the style might not completely adhere to the colors set (and even ignore them);
palette colors are references: the style might use a role for an unexpected purpose, or completely ignore it; some common styles use the Button role for item view headers, other use the Window role;
while normally respected, the above color properties might be altered by the style, just like any palette;
basic QSS color properties can be properly accessed only after the widget has been polished: ensurePolished() has to be called, which normally happens after the first visibility change and any setStyleSheet() call that affects the widget (see QStyle.unpolish() and QStyle.polish());
QPalette uses QBrush for any of its roles and groups, which could be any of the following: a QColor, a QGradient or a QPixmap; this means that if a palette role uses a gradient or pixmap, the returned color() will be invalid, etc.;
background-image does not update the palette (in fact, it's not listed in the table above); the same goes for border-image (as said above, there is no access to border properties);
the fusion style is (usually) the most reliable style to be used for extended stylesheet implementation; when unsure or getting unexpected behavior, use QApplication.setStyle('fusion') or widget.setStyle(QStyleFactory.create('fusion'));
OS styles potentially override drawing with private pixmaps in order to respect the standard OS appearance;
complex widgets require full and explicit values for their properties; never set generic properties (aka, no selectors) for parent widgets or the application[1], including QComboBox, QScrollBar and all QAbstractScrollArea subclasses (including item views);
So, considering all this, as long as a standard QStyle is used and the widget is polished, the roles explained in the above table should return the colors set in the supported properties of any stylesheet, including inherited ones.
But you can never be sure about that, and you always have to be aware of it.
[1] in the code examples above I did use generic stylesheets, but that was on purpose and for simplicity; that practice is usually highly discouraged for normal usage. Always use selectors when setting stylesheets for parents and complex widgets (see above).

How to force Godot to recalculate control nodes size/position?

Building UI in Godot 3.2.1. Of course I use anchors so UI elements are arranged within the screen automatically according to specified layout. I have UI scale system - nothing fancy - simply change font size (DynamicFont.size). If font size is large enough then some UI nodes may be pushed out of the screen. However, nodes don't return to normal sizes/positions with font size decreasing. The way to fix a mess is to resize game window which is not always an option and doesn't seem like a correct way to handle the issue. So how can I force Godot to recalculate control nodes size/position?
Changing the parent control's minimum size to Vector2(0, 0) after changing the font size might do the trick:
$Control.rect_min_size = Vector2(0, 0)
If it's already set to Vector2(0, 0), you may have to change it twice using call_deferred() for it to work.
In your scene tree, find the top level container that contains all of the elements that you want to recalculate. This would be the lowest common ancestor in the scene tree, in computer science terminology. Now, hide the container, by setting it's 'visible' property to false. Then, add a deferred call to change it's 'visible' property back to true.
var your_container = $".".find_node("your-container")
your_container.visible = false
your_container.call_deferred("set_visible", true)
This seems to cause Godot to recalculate the layout of 'your_container'.
It looks like only CanvasItem derived classes have a 'visible' property, so you would not be able to simply set the 'visible' property on a CanvasLayer, for example.
Fortunately, Containers and Controls both derive from CannvasItem, so this methodology should work fine if your lowest common ancestor node is either a Container or a Control or other CanvasItem derived class instance.
I got this working by emitting a signal from a parent element, which appears to force a refresh:
canvas_item.emit_signal("item_rect_changed")
The problem child got refreshed, and unlike the visibility method, focus was retained.

Tootip and signal of Gio.MenuItem

Below are two questions on the same component:
Which signal is triggered when the mouse passes over a Gio.MenuItem?
How to implement a tooltip for Gio.MenuItem?
Gio.MenuItem is a direct descendent from GObject.GObject (See https://lazka.github.io/pgi-docs/Gio-2.0/classes/MenuItem.html). It does not have any signals itself, and only receives a notify signal via its descent from GObject.
As Gio.MenuItem is not a widget, it does not receive any signals from the GUI. It only represents data (opaque data at that).
I suspect you want Gtk.MenuItem, which is the visual component.
EDIT It seems the widget you are after is Gtk.PopoverMenu. Just to be clear, Gio.MenuItem is not a visible item, which is why I replied as above. Gtk.PopoverMenu is a widget (widget = a visible item).
PopoverMenu is the visible widget, and you can see how it fits together with other widgets. It inherits from Popover, which inherits from Gtk.Bin, Gtk.Container and finally from Gtk.Widget.
So, you have all the signals from those widgets, but those are for the 'complete' Gtk.PopoverMenu, not for the individual items.
According to this definition, the individual items are Gtk.ModelButtons, so you might be able to access them that way.
The solution to get this was much further than I thought. I always suspected that the Devhelp's menu could not be built using GtkPopoverMenu because my OS uses gtk 3.14. The solution involves a totally new concept of running an application, proposed by Gtk.Application interface and the Gtk.Action features. These "new" concepts can be studied in the following places.
http://python-gtk-3-tutorial.readthedocs.io/en/latest/application.html?highlight=Gtk.Application
https://wiki.gnome.org/HowDoI/GtkApplication
https://github.com/Programmica/python-gtk3-tutorial/blob/master/_examples/application.py
Apparently tooltip features are not available for this menu type.

QT5: What is the Significance of a Layout's Parent?

I am attempting to write my first program using Qt5. I found a tutorial (zetcode.com/gui/qt5) with a number of examples, which all used dynamic layout creation. I'm trying to create a nested layout configuration, but I'm having a problem with specifying the parent parameter of the layout constructor. When I use the main window as the parent for the main layout and its sub-layouts, I get an error message, apparently telling me that QWidget can have only one QLayout. The window looks OK, but I haven't implemented all my functionality yet (slots and other code), so I don't know what, if anything, is broken. If I omit the parent parameter from the sub-layouts, I get no error messages and the window looks OK as well, but again I'm wondering whether this would affect my subsequent code additions.
Can anyone explain to me the significance of a layout's parent? I've noted that specification of the parent window in the layout's constructor is apparently not sufficient, because all of the examples I've seen call setLayout() at the end of the window's constructor. In particular, will my omission of a parent ever cause problems?
The "rules" are that there can be at most one top level layout on a given widget, and that widgets can be only children of other widgets, not of layouts. So what happens is that:
when you set a layout on a widget, the widget will take ownership of that layout;
when you add widgets on a layout, these widgets will be reparented to the widget the layout is/gets installed upon;
when you add a layout inside another layout, the inner layout becomes a child of the outer layout.
What you're probably seeing is a side-effect of creating a layout with a widget as parent, as in
QLayout *layout = new SomeLayout(widget);
This will try to install the layout on widget, and fail in case there's already one. The good news is, you can pretty much ignore passing parents around and rely on the system to do "the right thing". For instance:
MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
QHBoxLayout *mainLayout = new QHBoxLayout; // top level layout
QVBoxLayout *subLayout1 = new QVBoxLayout; // sub layout 1 stuff
QPushButton *button = new QPushButton("button");
subLayout1->addWidget(button);
// create more widgets...
mainLayout->addLayout(subLayout1);
QVBoxLayout *subLayout2 = new QVBoxLayout; // sub layout 2 stuff
QLineEdit *edit = new QLineEdit;
subLayout2->addWidget(edit);
mainLayout->addLayout(subLayout2);
setLayout(mainLayout);
}
This will correctly create a layout hierarchy and a parent/child relation so that nothing will get leaked.

Redraw widgets with update

Let's say I have a button. In it's constructor I use variables to feed the values(before running I set some default values to these variables), so later they can be changed and within the program the look of the GUI can be modified. What I need is to update the widgets whenever I change these values.
For example I have some options to change a certain color, I press the button it calls a certain command defined in the constructor, changes the color variable and after that, it needs to be updated. Here it says the update() redraws widgets as needed. How do I tell it I need the widgets to be redrawn ?
http://effbot.org/tkinterbook/widget.htm
I might be mistaken on what the redrawing actually means. In any case I need it to update with the new values. I have a quite dumb solution for this, that is destroying everything and rebuilding it. I feel like there is a smarter way of doing things.
All widgets have a configure method which can be called to change any of its attributes. All you have to do is keep a reference to the widget(s), and call the method:
def update_the_widgets():
the_label.configure(background="red")
a_button = tk.Button(..., command=update_the_widgets)
the_label = tk.Label(..., background="green")
This is much easier if you use an object oriented style of coding. Otherwise these references need to be global variables.
When your GUI is properly coded you should almost never need to call update.

Resources