PyQt4: restrict stylesheet to parent - css

So, first off, I've already read this, and everything I can find online says the same thing. To restrict the scope of a stylesheet setting do this:
self.setObjectName( self._TAG )
self.setStyleSheet( "#{} {{ background-color:{}; }}".format( self._TAG, "#d5d5d5" ) )
Where self is an object derived from QFrame. The problem is that, at least in the case of objects derived from QFrame, it only excludes children that don't descend from QFrame. The buttons and checkboxes retain the default color, but the QLabels inherit from the parent.
So is there any way around this, other than explicitly specifying the stylesheet for each child?

You have to set the autoFillBackground property of the Qlabel to True, otherwise, the label won't paint its background:
myqlabel.setAutoFillBackground(True)

Related

Dynamically change QStyle at runtime?

I want to tweak the existing style at runtime, specifically QStyle::PM_ToolBarIconSize. Can this be done? As far as I can tell, you can only inherit QStyle and override pixelMetric().
Edit 1: In the specific case of QStyle::PM_ToolBarIconSize, I could use QToolBar::setIconSize, but that would set the icon size for just a single toolbar instance. I want to change the underlying style hint to affect all toolbars everywhere with one fell swoop. And QStyle::PM_ToolBarIconSize may not be the only style I want to tweak, it's just the first one I'm looking at that just so happens to have a "change this instance's icon size" function.
Edit 2: I can't just make a new style subclass because the current style is already a custom style based on style sheets. There are several styles that a user can choose from. I don't want to create a bunch of new styles just so I can tweak a couple of toolbar icon or menu height size settings.
This is the exact purpose of QProxyStyle.
Why not overriding QStyle then? Your subclass would return an icon size (via pixelMetric) which depends on a settable parameter of your QStyle.
As Qt does not have a dynamic QStyle mechanism, it is better to create a new style instance with the changed icon size, then set it to the QApplication, rather than altering the current style.

Qt childs are visible but parent not

I have some widgets, QToolButtons to be exactly, and I initialize them like this:
QFrame *frmBackground = new QFrame(ui->centralWidget);
QToolButton *btnMenueExit = new QToolButton(frmBackground);
But now my problem. When I call frmBackground->setVisible(false), the child should disappear too, but thats not the case. The children are still visible and I would have to call setVisible(false) for every child. It's not like I can't do this, but I think I miss something essential about the concept of parent and child.
All of the widgets are organized in the same QGridLayout.
What concerns me is, that if I make the child<-->parent relationship in the designer, with dropping the child into the parent widget, the child is disappearing when I call parent->setVisible(false);
Are there some other parameters I have to set to make these properties to be passed to the child, like a property binding?
QLayout takes ownership of the widget, when you add one with addWidget(). Using parent argument in widget constructor is not necessary.
Setting one widget to be direct parent of another is not a good practice, you should always use layouts.
If you want to use a QWidget to hold child widgets you will usually want to add a layout to the parent QWidget.
setVisible() propagates to all children. If it doesn't work for child widgets then the widget is not their parent (anymore).

Why is a dynamically by C++ generated QML Item not aware of other pre-existing Items?

I have a QQuickView that displays a QML file which itself consists of several QML Items (in separate files). I'd like to add Items dynamically using C++ code. The dynamically added item should resize with the parent one, i.e. width and height properties reference parent.
For example, my target Item in QML looks like this:
// TargetContainer.qml
Grid {
id: fillMeWithItemsContainer
objectName: "fillMeWithItemsContainer"
}
The Item I want to add dynamically (maybe multiple times) looks like this:
// DynamicItem.qml
Rectangle {
color: "white"
height: fillMeWithItemsContainer.height
width: height * 4/3
}
Note that the rectangle references the container it is intended to reside in regarding height.
quickView is populated with TargetContainer:
QQuickView *quickView = new QQuickView();
quickView->setSource(QUrl("qrc:/foo/bar/TargetContainer.qml"));
So I load a component
QQmlComponent dynamicallyLoadedComponent(
quickView->engine(),
QUrl("qrc:/foo/bar/DynamicItem.qml")
);
And I create an Object out of it.
QObject *dynamicallyLoadedObject = dynamicallyLoadedComponent.create();
Here I get an error (in application output view):
DynamicItem.qml:4: ReferenceError: fillMeWithItemsContainer is not defined
quickView should be aware of the existence of fillMeWithItemsContainer, because it has been created before. However, fillMeWithItemsContainer is not a parent of dynamicallyLoadedObject (yet) and this could be the problem.
So I find the target Item by
QQuickItem *targetItem = quickView->rootObject()->findChild<QQuickItem*>("fillMeWithItemsContainer");
And reparent the previously created object
dynamicallyLoadedObject->setProperty("parent", QVariant::fromValue<QObject*>(targetItem ));
Note: I tried dynamicallyLoadedObject->setParent() before, but this seems to be a different kind of parent (QObject vs. parent property).
However, the width and height properties of dynamicallyLoadedObject are set to 0 (because of the reference error, I assume) and won't change. Even if I set them again programatically
dynamicallyLoadedObject->setProperty("height", "fillMeWithItemsContainer.height;");
dynamicallyLoadedObject->setProperty("width", "height * 4/3");
nothing changes.
If I define DynamicItem directly in QML it works:
Grid {
id: fillMeWithItemsContainer
objectName: "fillMeWithItemsContainer"
DynamicItem {}
}
How do I make sure that dynamically added items can access Items that have been in the QML view before? Alternatively: What am I doing wrong?
dynamicallyLoadedObject->setProperty("height", "fillMeWithItemsContainer.height;");
dynamicallyLoadedObject->setProperty("width", "height * 4/3");
This will not actually set a JavaScript binding on the properties. Instead, it will try to assign e.g. the string "fillMeWithItemsContainer.height;" to the property, which will fail since the property is of type int, not of type QString.
Assigning bindings to properties is actually not possible from within C++ (with some exceptions like QQmlBinding).
dynamicallyLoadedObject->setProperty("parent", QVariant::fromValue<QObject*>(targetItem ));
As Sergei mentioned, you need to call QQuickItem::setParentItem instead of setting the parent property. That is also a bit more typesafe than the general string-based setProperty API. Without a parent item, a QQuickItem will not be visible.
Reparenting will only change the parent item, which will affect layouting and a few other things. It will not change the context of the object. A context defines which objects/IDs are in the scope. The context can not be changed after an item has been created. Even if changing the parent would change the context, it is too late - the object has been created, and IDs/object are only looked up in the creation phase.
The solution is to pass the correct context to QQmlComponent::create(), which actually has an optional argument. You need to create your item in the context of fillMeWithItemsContainer, so you need to get a pointer to it (you did that already with findChild) and then retrieve its context, which is possible with QQmlEngine::contextForObject(). That should give you enough to figure out how to make it work.
I agree with Sergei though, you should prefer to dynamically create objects in JavaScript instead. Changing QML from within C++ is a layering violation, you should never access QML from C++, only the other way around, to have a nicer separation between UI and program logic.
I believe, QML engine treats DynamicItem instance as a non-graphical item since it is casted to QObject*. Thus it is not rendered. It has to be at least QQuickItem* to be rendered.
I believe you experience same problem with setParent() since parent property refers to parent QQuickItem and might no be the same as QObject parent.
Two questions:
Why wouldn't you create dynamic objects in JS?
Is it possible to use relative parent instead of absolute fillMeWithItemsContainer?
p.s. I assume you understand this is rather irregular way of using QML and have strong reasons for such hacky approach.

Limiting the effects of a stylesheet to the parent widget?

I am setting the background color of a QWidget subclass. When I do this using a stylesheet, the styles of the other components in the QWidget change (eg, the color of a PushButton, and its look changes).
How do I make sure only the background color of the container widget changes and the rest of the child components remain unchanged?
One way is to specify an ID selector. Make sure to set the objectName of your container widget (with setObjectName()) and use that name in the CSS selector. Assuming a widget named MyContainer, you would use something like this:
QWidget#MyContainer {...}
Try !imporant qualifier on child els background color property.

Accessing padding from stylesheet in QT

I have a custom QWidget subclass that lays out a number of children. In my stylesheet I define a background, which works fine. I also define padding, which doesn't work. I clearly need to provide support for this myself.
To do that, I need to be able to find out what padding is set in the stylesheet for my widget. I do not wish to parse the stylesheet myself, that would not make much sense. How can I access the top, left, bottom and right padding set in the stylesheet?
Thanks in advance,
Your custom widget has to inherit from a widget that supports the "box model" (you can find which widgets do on that page), and then you can use QWidget::contentsRect() to get the... content rectangle :

Resources