QScrollArea::ensureVisible() and QScrollArea::setWidget() - c++

I encountered another problem with QScrollArea, after I got help for the previous one, which was somewhat similar.
The problem now is that ensureVisible() does nothing if you create a scroll area and a label, set the label to be the scroll area's widget, and then load an image into the label - after setWidget():
This example illustrates the problem, just replace /path/to/some/image.png with some real image on your computer:
QScrollArea *scrollArea = new QScrollArea;
QLabel *label = new QLabel(scrollArea);
scrollArea->setWidgetResizable(true);
scrollArea->setWidget(label);
label->setPixmap(QPixmap("/path/to/some/image.png"));
label->setFixedSize(label->pixmap()->size());
scrollArea->ensureVisible(10000, 10000);
scrollArea->show();
If the setPixmap() is called before setWidget(), ensureVisible() will work.
Also, the problem is reproducible even though I call setWidgetResizable() and even setFixedSize().
Why does this happen, and is it possible to make ensureVisible() work without changing the order of setWidget() and setPixmap()?

When you call ensureVisible(10000, 10000); the scrollArea hasn't adjusted the widget's size yet. That is why it won't work.
If you create a slot that calls ensureVisible and use QTimer::singleShot to call that slot with the timeout set to 0 (you can also use QMetaObject::invokeMethod with queued connection), it will work, even if you set the scroll area's widget before you set the pixmap on the label.
What also works is, if you call ensureVisible after you call show. But this only works if your scrollArea is a top level window. If you embed it to a widget, it will not work.

Related

How to add a widget to a pre-existing QLayout?

I'm looking for a super simple example, and can't seem to find one. I have a MainWindow. When a button gets pressed I want to create a new window that gets opened up in the layout of MainWindow, to become a part of the mainwindow.
I have the code that sets up when a button is pushed to call this slot...when it gets called my QLabel shows up, but my QWidget does not
QWidget *test = new QWidget();
test->setGeometry(QRect(100,100,100,100));
layout->addWidget(test,0,0)
//Operation Mode
QLabel *operationalModeLabel1 = new QLabel("TEST");
layout->addWidget(operationalModeLabel1,2,1);
The reason for "lack of examples" is that you think of it wrong. What you describe is done all the time, by every single Qt example that uses layouts! I mean it. It doesn't matter when you add a widget to a layout. There's nothing magical about adding widgets "now" vs. adding them "later".
Just think of the title of the question: it makes no sense. All widgets must be added to layouts that already exist! By definition, no less. If there's no layout, how could you add a widget to it?
Your code is wrong, that's all. It's always pointless to set a geometry on a widget that is to be managed by a layout. As soon as you add it to the layout, the layout will change the geometry.
Since you're adding an empty widget into the layout, you most likely won't be able to see it. That's why the label shows up - it's not an empty widget.
If you want a widget that has a fixed size, to make it easier to notice, just set the fixed size on it. Even better, make it red so that it stands out.
QWidget * test = new QWidget();
test->setStyleSheet("QWidget { background-color: red }");
test->setFixedSize(100, 100);
layout->addWidget(test, 0, 0);

QGLWidget not receiving calls to resizeGL after initialization

I am having what appears to be the same problem as asked in this (unanswered) question: Qt resizeGL problem
I am testing a new QGLWidget for a larger application. The resizeGL method is wired up to change the glViewport and repaint the OpenGL view. My QGLWidget is not part of a layout and is simply being created displayed as follows:
boost::shared_ptr<StandardCustomWidgetBuilder>
builder(new StandardCustomWidgetBuilder());
WaterfallDirector<StandardCustomWidgetBuilder, DataSource> director(builder);
director.construct();
std::unique_ptr<CustomWidget> widget = builder->getWidget();
widget->show();
On my computer, this defaults to creating a 640x480 window and calls resizeGL upon initialization. Whenever I resize the window, resizeGL is never called.
In my attempts to remedy this I have attempted creating a separate QWidget that has a QVBoxLayout containing only the CustomWidget. This created a very small window, so I fixed my sizeHint and sizePolicy for CustomWidget, though this still had no affect on having resizeGL called. At this point I'm not sure precisely how to proceed.
I resolved my problem with some help from my co-worker. As it turns out, I had implemented the event method and forgot to call the QGLWidget::event method inside it. The widget now correctly resizes.
If you haven't done so already, I would suggest checking the size hints and size policies of all widgets concerned.
For example, the following will make sure your widget uses available space when the window grows:
widget->setSizePolcy( QSizePolicy::MinimumExpanding,
QSizePolicy::MinimumExpanding );
I don't think that the default size policy for QGLWidget makes it want to expand, so I'm thinking it's just possible that this needs changing.

How does a Qt custom widget notify ScrollArea parent about change of view

I'm writing an image viewer as a custom Qt widget (see: https://github.com/dov/Qviv) and I now got stuck on the question of how to make my widget notify a parent QScrollArea of changes in the view port, and thus to tell it to move the scrollbars. E.g. if the image viewer changes the zoom factor as the result of a keypress then the scrollbars need to change their page size.
One way of doing it would be to have the widget explicitly check if the parent is a QScrollArea and then make an explicit call to its methods to notify it on any changes.
Of course I also need to connect the changes of the ScrollArea to the internal view of the image, but that is a different question. And I need to cut the infinite recursion where the widget reports changes to the scrollbar that report changes to the widget etc.
Edit 20:15 Wednesday (GMT/UTC) trying to clarify to Vjo and myself what I need.
What I am trying to achieve is the equivalent of a Gtk widget that has been assigned a pair of GtkAdjustment's that are connected to a horizontal and vertical scrollbar. In my widget GtkImageViewer, that QvivImageViewer is based on, whenever I change the view due to some internal event (e.g. a keypress) I update the GtkAdjustment's. The scrollbars are connected to such changes and are update accordingly. GtkImageViewer also listens to the GtkAdjustment changes, and thus if the user scrolls the scrollbars, the GtkImageViewer is updated with this information and can change its view. My question is whether there is anything similar to GtkAdjustment in Qt that you can connect to for changes, and update in which case the update will be propagated to all the listeners?
Thus I don't expect the ScrollArea to be part of QvivImageViewer, but if the user has placed QvivImageViewer within a ScrollArea, I want bidirectional communication with it so that the scrollbars reflect the internal state of the widget.
The simplest is to send the QResizeEvent event from your widget object to the QScrollArea object.
I finally downloaded the Qt sources and investigated how QTextEdit does it. What I found is that QTextEdit inherits the QAbstractScrollArea on its own, and thus the scroll area and the scrollbars are part of the widget. This is different from Gtk, which uses a higher level of abstraction, through its GtkAdjustment's that are used to signal changes between the scrollbars and the widget. The Qt model is simpler and this is the way that I will implement it in my widget.
It's been a while, but I ran across this same issue.
You can inherit QAbstractScrollArea if you'd like, but QScrollArea will work as well.
Your custom inner widget (i.e. the one that you are scrolling), should do the following when its size changes:
void MyCustomControl::resize_me() {
// recompute internal data such that sizeHint() returns the new size
...
updateGeometry();
adjustSize();
}
QSize MyCustomControl::sizeHint() {
return ... ; // Return my internally computed size.
}
I was missing the adjustSize() call, and without it the QScrollArea will ignore size changes of the internal widget.

IVideoWindow update problem

I want to render the video from my webcam into QWidget. I've set QWidget, as a parent to IVideoWindow. Here is the code:
m_iVideoWindow->put_Owner((OAHWND)widget_->winId());
m_iVideoWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);
m_iVideoWindow->put_Left(0);
m_iVideoWindow->put_Top(0);
widget_->setChild(m_iVideoWindow);
Also i've reimplemented QWidget's resize event, and so when it's resizing it also resizes the IVideoWindow. Everything works good, when the widget is not set to the QLayout. When is - it becomes blank. That is the problem.
I think when Qt draws its widgets, it doesn't redraw them unless it knows they need to be updated. I'm also unsure as to whether it passes on whatever redraw stuff windows requires, to the window you've assigned as a child of the widget.
When I embed my own windows in a Qt widget, I use http://qt.nokia.com/products/appdev/add-on-products/catalog/4/Windows/qtwinmigrate/, but that may not solve your problem, as I still have to use a QTimer to force an update of my window.

Qt: Dragging a widget to scroll the widget's parent QScrollArea?

I've got a long horizontal QLabel displaying a png (the image shows a signal/time graph). Under that, I've got a QTableWidget. Both of these are in a QScrollArea because I want them to stay vertically aligned (the cells in the table correspond with the signal seen directly above them). I'm trying to add a handler to the QLabel such that the user can use the picture itself to scroll the scrollarea, rather than having to use the scrollbar. Is there a tried-and-tested way to do this? Directly setting the scrollarea's sliderPosition inside the QLabel's dragMoveEvent doesn't seem smart, because when the scrollarea scrolls it also leads to another dragMoveEvent on the (moving) QLabel.
I would suggest wrapping the combination (including the scroll area) in their own widget, and overriding the dragMoveEvent() on that widget. The dragMoveEvent() shouldn't be triggered when you change the scroll position if you are doing it this way, I wouldn't think, although I haven't actually tested it.