Qt QLayout inside QDesktopWidget - qt

I want to do universal method to set position of my widget.
All I wanna get it is set right coordinates for my widget wich must always be in right bottom corner of desktop. My widget can change his height (or maybe width) but it must have adjusted size by both ordinates... (too many words)
My idea is using QDesktopWidget as basic widget to put into my QLayout with stratch items (to align inner (my) widget to right and to bottom sides)
my code prototype is here:
QDesktopWidget * desktopWidget = QApplication::desktop();
MyWidget * myWidget = new MyWidget(desktopWidget);
QVBoxLayout * vlayout = new QVBoxLayout;
vlayout->addStretch();
vlayout->addWidget(myWidget);
QHBoxLayout * hlayout = new QHBoxLayout(desktopWidget);
hlayout->addStretch();
hlayout->addLayout(vlayout);
but it doesn't work...
Help me please implement my idea if you know how.
At this moment I know only one work way to do it - it is manually set pos of widget and handle many events (resize etc.) - but this is not good... (because i do it bad of cause ;-)
)
PS: idea with qlayout inside other widget is working for example with QTextBrowser with sandclock at certer of view, etc.

A QDesktopWidget isn't intended to be used like a typical widget (at least as far as I'm aware, I'm surprised the documentation isn't more explicit about that). So you shouldn't try to parent widgets to it or try to assign it a layout. You call its methods to obtain information about the desktop environment or connect to its signals to be informed of changes.
Using this information, you would then set the geometry of your own application widgets so that they appear on the correct screen and position you want.
This page shows some basic functionality.

Related

Qt: Correct implementation of floating widgets

I've inherited my class from QWidget. Basically no extra code, just changes with the editor.
The way I use it:
focusWidget = new FocusWidget(this); //this points to the mainWindow
focusWidget->show();
focusWidget->hide();
Now the widget appears like this (it now looks ugly because of the bad 4k scaling), at the top left corner of the mainWindow.
I intend to use my application mostly full screen.
Is this usage correct?
How can I make it a floating widget?
If I want multiple widgets like that, how can I control their position?

QT: two layouts add the same widget

In Qt: I create a widget-ui class, and I want to make the widget appear in two different layouts in two separate base widget(or window). So I want to:
widget_based_class* inside = new widget_based_class(base_widget1);
QHBoxLayout *lay1=new QHBoxLayout(base_widget1);
base_widget->setLayout(lay1);
lay1->addWidget(inside);
base_widget1.show();
-------------------------------
base_widget1.hide();
QHBoxLayout *lay2=new QHBoxLayout(base_widget2);
base_widget->setLayout(lay2);
lay2->addWidget(inside);
base_widget2.show();
How cound I achieve this? (My program is more complicated, and I didn't see the code work.)
Tank you.
A QWidget has only one parent widget and only one geometry (position and size) in that parent. Every call of QLayout::addWidget() will reparent that widget to the widget, the layout is installed on.
Your second call of setLayout won't work as expected, because you have to delete the the existing layout manager before setting the new one:
delete base_widget->layout();
base_widget->setLayout(lay2);
If base_widget hasn't already got a layout manager, the layout manager lay2 would simply be reparented.
If the widget will never be displayed twice on the screen, I don't see why you can't reparent it by addWidget/removeWidget.
In the OP, the parent widget/window is always hidden before the other one is shown. addWidget is called on the fly. We should also call removeWidget on the fly. It should be possible to move the widget around.
widget_based_class* inside = new widget_based_class(base_widget1);
QHBoxLayout *lay1=new QHBoxLayout(base_widget1);
base_widget->setLayout(lay1);
lay2->removeWidget(inside); // remove widget from other layout
lay1->addWidget(inside); // add widget to this layout
base_widget1.show();
-------------------------------
base_widget1.hide();
QHBoxLayout *lay2=new QHBoxLayout(base_widget2);
base_widget->setLayout(lay2);
lay1->removeWidget(inside); //remove widget from other layout
lay2->addWidget(inside); // add widget to this layout
base_widget2.show();
Make one widget and use a pointer in each layout?

QScrollArea: auto-scroll to newly added widget

it's not the first time that I want a scroll area which behaves like the following (imagine a log or chat window, but too complex to use a simple QTextBrowser):
I want to add multiple widgets, which appear one below the other (like when placed in a QVBoxLayout)
Each widget within this layout should have a fixed size or a height-for-width (like a simple label)
The scroll area should auto-scroll to the most recently added one
(optional) When there is space left (scroll bar not yet enabled), the contents should be aligned to bottom
Using QScrollArea:
My attempt in the past was using a QScrollArea using a QVBoxLayout inside. But this seems to be not as simple as I thought: Whenever I add a widget to the layout, the layout doesn't resize the scroll area content widget immediately, resulting in a delayed adjustment of the contents. For one short moment, the widgets contained in the layout are resized so that the total size equals the total size before the add operation, resulting in a too small size per widget. Also, scrolling to the newly added widget is thus not possible until the layout corrected its size to the new total size of widgets, so even a QTimer::singleShot(0, ...) doesn't help here. Even with a timeout of 20 or so, there are situations in which the layout needs more time to resize. It's not deterministic, and thus far away from a nice solution.
In order to get the bottom alignment behaviour, I initially place a spacer item in the layout. It won't require any space as soon as there is no space left and scrolling gets enabled.
Using QListView:
As my items are too complex, they need to be QWidgets. They can't have the focus, aren't selectable, so an item-based solution seems to be just "the wrong way". Also, this solution sounds too "heavy".
I just can't believe that there is no easy way, so I think I just haven't seen it yet!
QListView should be fine. You claim that your items are static, there's no interaction with them: no focus, no selection. It'd seem that a QWidget is an overkill for such items. You only need something that has a fixed size and can draw itself. That is precisely what delegates in the Qt's model-view system are for. Just implement one or more QAbstractItemDelegates for your items, and provide an implementation of a model for the data they will be rendering. The QAbstractItemView is is already a QAbstractScrollArea!
If you want to paint HTML within a delegate, it's easy to do -- again, QWidget is an overkill for a static display! There is a very food reason why it's "hard" to use QWidget for this -- the API guides you to the correct solution. Assuming your model contains html for each item, here's how you can paint it. You can go fancy with the sizeHint, of course, and should be caching the text document, ideally storing it in the model I'd think.
void MyDelegate::paint(QPainter* p, const QStyleOptionViewItem & opt, const QModelIndex & index) const
{
QTextDocument doc;
doc.setHtml(index.data().toString());
doc.drawContents(p, QRect(QPoint(0,0), sizeHint(opt, index)));
}
QSize MyDelegate::sizeHint(const QStyleOptionViewItem &, const QModelIndex &) const
{
return QSize(100, 200);
}

Resizing QT's QTextEdit to Match Text Height: maximumViewportSize()

I am trying to use a QTextEdit widget inside of a form containing several QT widgets. The form itself sits inside a QScrollArea that is the central widget for a window. My intent is that any necessary scrolling will take place in the main QScrollArea (rather than inside any widgets), and any widgets inside will automatically resize their height to hold their contents.
I have tried to implement the automatic resizing of height with a QTextEdit, but have run into an odd issue. I created a sub-class of QTextEdit and reimplemented sizeHint() like this:
QSize OperationEditor::sizeHint() const {
QSize sizehint = QTextBrowser::sizeHint();
sizehint.setHeight(this->fitted_height);
return sizehint;
}
this->fitted_height is kept up-to-date via this slot that is wired to the QTextEdit's "contentsChanged()" signal:
void OperationEditor::fitHeightToDocument() {
this->document()->setTextWidth(this->viewport()->width());
QSize document_size(this->document()->size().toSize());
this->fitted_height = document_size.height();
this->updateGeometry();
}
The size policy of the QTextEdit sub-class is:
this->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred);
I took this approach after reading this post.
Here is my problem:
As the QTextEdit gradually resizes to fill the window, it stops getting larger and starts scrolling within the QTextEdit, no matter what height is returned from sizeHint(). If I initially have sizeHint() return some large constant number, then the QTextEdit is very big and is contained nicely within the outer QScrollArea, as one would expect. However, if sizeHint gradually adjusts the size of the QTextEdit rather than just making it really big to start, then it tops out when it fills the current window and starts scrolling instead of growing.
I have traced this problem to be that, no matter what my sizeHint() returns, it will never resize the QTextEdit larger than the value returned from maximumViewportSize(), which is inherited from QAbstractScrollArea. Note that this is not the same number as viewport()->maximumSize(). I am unable to figure out how to set that value.
Looking at QT's source code, maximumViewportSize() is returning "the size of the viewport as if the scroll bars had no valid scrolling range." This value is basically computed as the current size of the widget minus (2 * frameWidth + margins) plus any scrollbar widths/heights. This does not make a lot of sense to me, and it's not clear to me why that number would be used anywhere in a way that supercede's the sub-class's sizeHint() implementation. Also, it does seem odd that the single "frameWidth" integer is used in computing both the width and the height.
Can anyone please shed some light on this? I suspect that my poor understanding of QT's layout engine is to blame here.
Edit: after initially posting this, I had the idea to reimplement maximumViewportSize() to return the same thing as sizeHint(). Unfortunately, this did not work as I still have the same problem.
I have solved this issue. There were 2 things that I had to do to get it to work:
Walk up the widget hierarchy and make sure all the size policies made sense to ensure that if any child widget wanted to be big/small, then the parent widget would want to be the same thing.
This is the main source of the fix. It turns out that since the QTextEdit is inside a QFrame that is the main widget in a QScrollArea, the QScrollArea has a constraint that it will not resize the internal widget unless the "widgetResizable" property is true. The documentation for that is here: http://doc.qt.io/qt-4.8/qscrollarea.html#widgetResizable-prop. The documentation was not clear to me until I played around with this setting and got it to work. From the docs, it seems that this property only deals with times where the main scroll area wants to resize a widget (i.e. from parent to child). It actually means that if the main widget in the scroll area wants to ever resize (i.e. child to parent), then this setting has to be set to true.
So, the moral of the story is that the QTextEdit code was correct in overriding sizeHint, but the QScrollArea was ignoring the value returned from the main frame's sizeHint.
Yay! It Works!
You may try setting minimumSize property of the QTextEdit to see if that force the layout to grow.
I don't understand most of Qt's layout scheme but setting minimum and maximum size pretty much does what I want it to do. Well, most of the time anyways.

How does QWidget size when used as a window?

Several examples on trolltech use QWidget rather than a QMainWindow as the main window for simple Qt applications.
Now I need just a simple window with a single content widget (QGlWidget) that covers the entire client area.
However, when I show a QWidget window with a single content window it automatically resizes itself to be tiny.
If I create the QWidget parent window without a child It is a nice large default size.
I don't want to resort to using Layouts for a single child window :/
What I understand is that you use a QWidget to display your QGIWidget. Try calling the show method of your QGIWidget directly (if your QGIWidget class inherits QWidget), Qt will create the window decoration for you.
Otherwise if you really need your widget to be inside one another, and fit its size, you'll have to use a layout.
Either follow gregseth's advice or you can simply resize the widget yourself.
(though this way you'll loose nice auto-resizing which is provided by Qt when you use layouts)
In your case you can basically do something like:
QGlWidget* myWidget = new QGlWidget;
myWidget->resize(QApplication::desktopWidget()->availableGeometry().size());
// or maybe instead of resizing show it in fullscreen:
myWidget->showFullScreen();
(actually I don't remember if showFullScreen() will do resizing for you, maybe you'll need both resize+showFullScreen :))
Cheers :)
P.S. Using layout is actually an option. It's not expensive and it's flexible. All it gets: "layout = new QVBoxLayout(myWidget); layout->addWidget(myWidget);" and you're done :)
Not always.
I've found that a QMainWindow will not work as the parent widget when using the QVBoxLayout and QHBoxLayout to arrange child widgets.
If you create a QWidget and use that in place of the QMainWindow then the layouts will work correctly.
QWidget* centralWidget = new QWidget( MainWindow );
MainWindow->setCentralWidget( centralWidget );
If you use QtCreator and look at the code it creates you can see it creating a 'hidden' widget if you try to use the layouts directly at the top level.
It's not obvious, intuitive, or documented anywhere that I've found.

Resources