Solved How do I ensure a QDialog's widgets fit on the screen on iOS?
-
(Qt 5.12.11)
I have a QDialog with a label and radio buttons with quite long text:#include <QApplication> #include <QButtonGroup> #include <QDebug> #include <QDialog> #include <QLabel> #include <QLayout> #include <QRadioButton> #include <QScreen> #include <QVBoxLayout> QRect screenGeometry() { QScreen *screen = QGuiApplication::primaryScreen(); return screen->geometry(); } int screenWidth() { return screenGeometry().width(); } class ModeDialog : public QDialog { Q_OBJECT public: ModeDialog(QWidget* parent) : QDialog(parent) { auto prompt = new QLabel("Here is the prompt text, quite a long description blah blah blah"); auto short_button = new QRadioButton("Short option"); auto long_button = new QRadioButton("Long option with quite a lot of words that take up more than one line"); auto mode_selector = new QButtonGroup(); mode_selector->addButton(short_button, 1); mode_selector->addButton(long_button, 2); auto mainlayout = new QVBoxLayout(); mainlayout->addWidget(prompt); mainlayout->addWidget(short_button); mainlayout->addWidget(long_button); mainlayout->setAlignment(Qt::AlignLeft | Qt::AlignTop); setLayout(mainlayout); int prompt_width = prompt->width(); int radio_width = long_button->width(); int screen_width = screenWidth(); int dialog_width = this->width(); qDebug() << "prompt width" << prompt_width << "\n" << "radio width" << radio_width << "\n" << "screen width" << screen_width << "\n" << "dialog width" << dialog_width << "\n"; } }; int main(int argc, char* argv[]){ QApplication app(argc, argv); ModeDialog dialog(nullptr); dialog.exec(); return app.exec(); } #include "main.moc"
On the desktop the dialog is much smaller than the screen so there is no wrapping.
On the iOS simulator with an iPhone in portrait orientation the text on the labels and radio buttons disappears off the screen:
It looks like the widgets widths' are 640 pixels, which doesn't seem right given the screen width is 375px.
What is the best way to ensure that the widgets wrap properly if their widths exceed that of the screen?
-
The best way is to set widget's wordWrap attribute to true.
-
@mvuori Thanks for the suggestion. There are a few problems with this approach.
First if I add the line:
prompt->setWordWrap(true);
The text now wraps but it is cropped so that the height is that of one line.
Furthermore, from what I can tell there is no equivalent to setWordWrap() on a QRadioButton.
Finally, I feel this shouldn't be necessary. I would have thought that the layout engine should be capable of arranging the widgets to fit the available width.
-
OK so if I comment out this line:
// mainlayout->setAlignment(Qt::AlignLeft | Qt::AlignTop);
I now see both lines of text on the label wrapped, but there is now way too much space between the prompt and the radio buttons:
-
Hi,
Add a stretch after your last widget, it will push them towards the top.
-
@SGaist Thanks.
mainlayout->addStretch(1);
That fixes the spacing. So now the only problem is getting the radio button labels to wrap. Is this possible?
@jsulm says in the post
https://forum.qt.io/topic/122652/how-to-enable-word-wrap-on-qradio-button/2 "Make sure the radio button is big enough? I guess you don't use a layout?" (it turned out the OP was trying to solve a different problem). -
There's another problem with calling setWordWrap(true) on all the labels. This now means that on the desktop (Ubuntu pictured, but also seen on Windows) all of the labels will wrap when they don't need to. If I make the two radio button labels short, the prompt label wraps to match their width.
I think what I want to say is: "wrap all labels and radio buttons if there is not enough screen width to display them".
-
One possibility is to do that only for iOS. You can use a
#ifdef Q_OS_IOS
for that. -
@SGaist Yes thanks I can give that a go. I guess it's only on iOS that the dialogs are always going to be fullscreen. I see that word-wrapping is not possible on QRadioButton and QCheckBox https://bugreports.qt.io/browse/QTBUG-5370 so it looks like I'll have to use a custom widget to do that.