I want to have "flying" info above my interface (like informationnal text).
I have subclassed QWidget, set the FramelessWindowHint and TranslucentBackground flags.
So I create it with my interface's widget as ctor parameter, and style (style is in a ressource QSS file and set to qApp in main) does apply to my custom widget except for background (I can put a borderbut no background-color).
But when I make my custom widget it's own parent (I leave ctor parameters empty), then I can have my background changed.
I used this technique with the exact same flyingwidget class in another project and it worked just fine. QGLWidget may be in cause (creating widget before or after QGLWidget are created causes style to be applied or not).
here's the code where I create my widget.
Form_coupeHighlighterInfo *highlightCoupeInfo = new Form_coupeHighlighterInfo(this); //ctor parameter that changes
highlightCoupeInfo->setObjectName(QStringLiteral("highlightCoupeInfo"));
highlightCoupeInfo->attachToRight();
highlightCoupeInfo->setFixedWidth(400);
highlightCoupeInfo->setFixedHeight(400);
highlightCoupeInfo->setRelativePos(QPoint(-10, 0));
connect(this, SIGNAL(alignToInterface(QPointF&)), highlightCoupeInfo, SLOT(alignToInterface(QPointF&)));
I must add that background property doesn't work like the others but I don't get what the hell is going on with him, QSS looks like magic to me on a lot of points.
I use Qt 5.2.1 / msvc2012opengl / windows 7
Related
I use a QWidgetAction to add a header to a context menu (that will also show up on Windows, no matter what style is used, in contrast to addSection(), which does not always actually display the title).
The action's widget is a QLabel. It's text is changed by each invocation of the context menu. The menu is setup in the constructor of my class, and the QWidgetAction is added like so (all m_ variables are member variables declared in the header):
m_contextMenu = new QMenu(this);
m_menuTitle = new QLabel;
m_menuTitle->setAlignment(Qt::AlignCenter);
m_menuTitle->setMargin(4);
QWidgetAction *titleAction = new QWidgetAction(m_contextMenu);
titleAction->setDefaultWidget(m_menuTitle);
m_contextMenu->addAction(titleAction);
m_contextMenu->addSeparator();
When the menu is requested, the text of the label is changed and the menu is displayed like so:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
m_contextMenu->exec(place_to_display);
When the label's text is set for the first time (with a short text the label's text is set to), everything is fine:
but when it's set to some longer text, the size remains the same and the text is cropped:
I tried to fix this, but the only working solution I found was to define the QActions displayed in the menu in the constructor, owned by this, setting the label's text, clearing the menu and adding the actions again, like so:
m_contextMenu->clear();
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
m_contextMenu->addAction(m_menuTitleAction);
m_contextMenu->addSeparator();
m_contextMenu->addAction(m_editAction);
m_contextMenu->addAction(m_deleteAction);
m_contextMenu->exec(place_to_display);
Is there a way to resize the title without rebuilding the menu each time?
The solution is to send a resize event instead:
m_menuTitle->setText(tr("%1 „%2“").arg(some_variable, some_other_variable));
...
QResizeEvent re(new_size, m_contextMenu->size());
qApp->sendEvent(m_contextMenu, &re);
This will set the QMenu's internal itemsDirty flag and will force geometry recalculation when the menu is shown. Note that the new size in the event does not matter, as the menu will aways resize based on its sizeHint()!
The QResizeEvent solution didn't really work for me (with a more complex widget), I found the generic solution by reading the QMenu and QAction source code.
m_widget->installEventFilter(this);
// and in my case m_widget->layout()->setSizeConstraint(QLayout::SetFixedSize);
bool SomeClass::eventFilter(QObject* watched, QEvent* event)
{
if (watched == m_widget && event->type() == QEvent::Resize) {
// Force QMenu to recalculate the geometry of this item
QActionEvent e(QEvent::ActionChanged, this);
qApp->sendEvent(m_contextMenu, &e);
}
...
}
QActionEvent triggers everything we need in QMenu: recalculating geometries, resizing the menu to its new size (if it's visible), etc.
This answer extends user362515's answer.
There is little more effort required if you change the size of a hidden widget action (e.g., because of its menu is currently collapsed).
Create a new class ActionWidget which derives publicly from QWidget.
Then override the showEvent method and implement it like this:
void ActionWidget::showEvent(QShowEvent* event)
{
QResizeEvent resize_event(QSize(), parentWidget()->size());
parentWidget()->adjustSize();
qApp->sendEvent(parentWidget(), &resize_event);
QWidget::showEvent(event);
}
Notice that adjustSize must be called on the parent widget of the action widget and the event must be sent to the parent widget.
Of course, you must also reimplement QWidgetAction::createWidget such that it returns an instance of the ActionWidget-class and make sure that ActionWidget reports a proper (updated) size hint.
I'm creating my custom push button class by subclassing QPushButton. However for some reason setting that class's CSS in its constructor has no effect; I have to do it in for example paintEvent, then everything is fine. I could just have a global .qss file and set it for the entire application, but I want the class to manage its own styles. Why doesn't my approach work?
The code:
custompushbutton.h
class CustomPushButton: public QPushButton
{
Q_OBJECT
public:
explicit CustomPushButton(QWidget *parent = 0);
~CustomPushButton() = default;
};
custompushbutton.cpp
CustomPushButton::CustomPushButton(QWidget *parent)
: QPushButton(parent)
{
setStyleSheet("background-color: black;"); // this does not work
}
EDIT: For future readers, if you're having a similar issue (i.e. Qt seems to ignore your CSS you set in code), see if you haven't edited the object's styleSheet property in Qt Creator - scroll down in the properties list and make sure styleSheet is empty and NOT BOLD - that was the issue in my case. If it is bold, it means Qt is still using that empty field as the object's CSS, thereby overriding your styles. To clear it either hit the little arrow next to the field in Qt Creator or open up the .ui file and delete the <styleSheet> XML property.
Thanks to JMik for pointing me in the right direction.
The performance cost of setting a stylesheet is surprisingly high, especially if you're developing for an embedded system.
I'd suggest, like you said, using a global stylesheet and specify the class name, like this:
CustomPushButton { background-color: black; }
this way all CustomPushButton will have the same style, and the object will take less time to create.
As for the reason why it doesn't work in your case, I'd guess maybe your accidentally changing the stylesheet again after the creation of the CustomPushButton.
I tested your code on my side and it worked, so it probably has something to do with code your not showing
The application that I'm building is supposed to create, destroy, and manipluate widgets that I've created
The problem is I'm not making a simple program with nice buttons where everything is symmetrical and needs to be evenly spaced and handled via a layout that will automatically move everything around and space it.
And yet, the only way I know of is to manually instance a layout and add the widgets to it, but then I can't set the coordinates of them
How can I simply instance my widget, and add it to the project generated frame?
This is how I'm instantiating my class, in which case I then set my own parameters:
Tile *tile = new Tile;
tile->setImg("://Images/placeholderTile.png");
tile->setCol(true);
tile->setGeometry(retX(line),retY(line),50,50);
To reiterate, I want to add my own widgets to a frame outside of the editor (only by code), and be able to manually move them around the frame by code.
I don't see an ".addWidget() as a method accessible from the QFrame, and yet they can be children within the designer, why can't I do this by code? Whenever I try to do it manually and add them to any layout, any attempt I make to manually set the widgets location doesn't do anything. I haven't overridden the setGeometry
I fixed my problem
After 2 hours of continual searching I finally came across my answer
I never thought that you could set the parent of a widget by code, as I thought you strictly had to add it in as a child of something else, not the reverse and declare that it should have a parent
So, by simply adding the line:
tile->setParent(ui->frame);
completely fixed my problem.
I will change this post back and submit the answer tomorrow when I'm allowed to by this site.
Thank you to those who actually came though. I'm just glad I managed to fix it before that.
All you need is to pass the parent to the widget's constructor:
Tile *tile = new Tile(ui->frame); // <-- here
tile->setImg("://Images/placeholderTile.png");
tile->setCol(true);
tile->setGeometry(retX(line),retY(line),50,50);
Since Tile is your own class, you should definitely have a Qt-style, parent-taking explicit constructor for it:
class Tile : public QWidget {
...
public:
explicit Tile(QWidget * parent = 0) : QWidget(parent) { ... }
};
Another approach is to write your own layout that would know about the relationships that are to be held between your objects. After you do it once, writing custom layouts isn't that hard.
This is a general question, which I will illustrate with two examples.
First example: Suppose I have a widget and a Layout associated with it:
QWidget myWidget;
QVBoxLayout* mainLayout = new QVBoxLayout(&myWidget);
Note that I have specified my widget as the parent of my layout. Question is, is this sufficient to associate the layout with my widget or do I have to additionally explicitly set the layout as in:
myWidget.setLayout(mainLayout);
If I do have to explicitly set the layout, then AFAIK setting will also make myWidget the parent of my layout, so what is the point of specifying the parent in the constructor?
Second example:
Suppose I have a line edit and a validator for it.
QLineEdit* lineEdit = new QLineEdit(whatever);
QIntValidator* validator = new QIntValidator(0, 100, lineEdit);
Note that I have set the parent for my validator. In order for the validator to "work", i.e. listen to lineEdit's value change events, do I also have to explicitly set the validator as in
lineEdit->setValidator(validator);
If so, will the setValidator function itself set the parent, and if so, why should I bother specifying the parent in the Validator's constructor?
Hopefully my questions are clear.
WRT the first question:
I think QWidget::setLayout() function call and setting the parent widget to a layout are equivalent operations. This pretty much fits to the Qt documentation, that states for QWidget::setLayout():
An alternative to calling this function is to pass this widget to the layout's constructor.
Thus, you do need to call QWidget::setLayout() if the parent widget is already set for the layout.
WRT the second question:
When you construct the validator with line edit as a parent you do not set validator to the line edit - this is just defines the QObjects hierarchy and objects ownership. I think you do not need to mix hierarchical and functional concepts here.
I currently have 3 Vertical Layouts in my form. I want to provide the user the option of resizing them to their liking by stretching them. Can this be achieved with Vertical layouts ?
You can use QSplitter as said before. Even being not possible to add it by Designer, there is a way to solve. Create those frames in your widget (which have no layout), and in your cpp and h file you will do that:
in header, write
class YourClass : public QSplitter
instead
class YourClass : public QWidget
and replace in your cpp these declaration on constructor
QWidget(parent)
for
QSplitter(parent)
I guess it does (or almost, perhaps some other changes will be necessary, as add include files).
EDIT: at this time usin code in a QMainWindow class:
QSpliter *splitter = new QSplitter(this) //or declare 'splitter' in .h file.
splitter->setOrientation(Qt::Vertical);
splitter->addWidget(widget1);
splitter->addWidget(widget2);
splitter->addWidget(widget3);
setCentralWidget(splitter);
As of 4.8.6, it's possible to add a QSplitter in Qt Designer by using the Lay out [horizontally/vertically] in splitter layout option. It's somewhat surprising that it's not listed in the widget box, but you can use it.