Stylesheets, widgets hidden and sizes in Qt

2019-01-23 21:16发布

There is a big problem with stylesheets.

If you set the sizes through the style sheet by setting max and min values the same (fixed size) or whatever, and then you try to fetch them using size() on the widget, if the widget has never been shown the sizes you get are weird.

But you can't fetch them from the stylesheet neither, so you have to show all widgets before resizing or fetching the positions.

In my case, i start with a window. But the widgets under this window will appear later, and they have to be positioned in the correct positions before appearing. i have floating widgets, they are not integrated as children of a QMainWindow, so i move them by hand, and position them... but how can i do it, if i don't know how they are?

Do you know any other way to fetch the sizes stored in the stylesheet?.

1条回答
劫难
2楼-- · 2019-01-23 21:32

There are three solutions I know of, so far:

  1. Polish the widget: call widget->ensurePolished().

  2. Polish the widget through the style: call qApp->style()->polish(widget).

  3. Send the events posted to the widget: QCoreApplication::sendPostedEvents(widget, 0) on the widgets before it's shown. With Qt 5, you don't need the second argument as it now has a default value of 0.

Another solution to your problem would be simply not writing any synchronous code at all. To lay out a top-level widget when it's first shown:

  1. Install an event filter on the widget.

  2. When the show event arrives on the widget:

    1. Uninstall the event filter from the widget.

    2. Deliver all of the window's events until none are left:

      while (widget->d_ptr->postedEvents)
        QCoreApplication::sendPostedEvents(widget, 0);
      

      You're now guaranteed that the widget is visible and has the correct size.

    3. Use the widget's geometry and move it. If you need information from all the widgets to make that decision, store it in some data structure and process it only when all the widgets are there.

If you wish to prevent temporary visibility of widgets in wrong positions, you may wish to act on the resize event instead. The layout and styling system will resize the top-level widget suitably to fit its contents. You should uninstall the event filter and process the most recent geometry only when there are no more events to be delivered for that object upon return from the call to sendPostedEvents.

The following demonstrates the forced polishing approach, and works under both Qt 4.8.5 and 5.2.0. I've tested it on both 64 bit build on OS X, and a 32 bit build on Windows.

Note that neither l1 nor l2 is shown, yet they both report a correct size. l3 is shown, but when queried before being shown, it reports the wrong size.

screenshot

#include <QApplication>
#include <QLabel>
#include <QStyle>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString style("QLabel { min-height:100px; max-height:100px; min-width: 300px; max-width:300px }");
    a.setStyleSheet(style);
    QLabel l1, l2, l3;
    l1.ensurePolished(); // equivalent first/second methods
    QCoreApplication::sendPostedEvents(&l2, 0); // third method
    l3.setText(QString("l1: %1 x %2 l2: %3 x %4 l3: %5 x %6")
               .arg(l1.width()).arg(l1.height())
               .arg(l2.width()).arg(l2.height())
               .arg(l3.width()).arg(l3.height()));
    l3.setAlignment(Qt::AlignCenter);
    l3.show();
    return a.exec();
}
查看更多
登录 后发表回答