Triggering PaintEvent in a "hidden" QGLWidget without a layout? - c++

I have a QGLWidget that shares context with 5 other widgets that can change layouts and locations dynamically. This shared widget is something that I dont want to be shown because it doesnt fit in anywhere. The only way I can use it, however, is by doing a "static" one time VBO generation in its initializeGL().
How do I use its paintEvent as normal with this shared widget not being attached to a layout or visible in any way?

To make it appear seamless you attach the shared QGLWidget only onto the QMainWindow, then show() the QMainwindow so the initializeGL() gets called. Basically you show the QMainwindow earlier than normal.

Related

How to draw a QQuickItem on a QQuickItem

I have two QQuickItems and I would like to draw one on top of the other in C++ before it is exposed to QML. I would like to do this because I want the second QQuickItem (which I would refer to as background QQuickItem from here on) to act as the background of the first QQuickItem (which I would refer to as parent QQuickItem from here on) and then draw a QPixmap (which has been painted on using QPainter) on top of both items. I would also prefer to pass in the second "background" QQuickItem as a property to the first QQuickItem so that it can be set dynamically from QML. Does anyone have any idea on how to do this?
I would like to mention that both QQuickItems have implementations of QQuickItem::updatePaintNode(). Is there a way to make them work together?
To do that, you have to use the visual parent property (note that in c++ you access it with setParentItem() and parentItem(), not parent() which is for the QObject parent).
If you want to have a background property, I guess you don't want to have your background as the parent of your item, so you could instead set yourself as the parent of the background and set the background's z to -1 so it paints behind your item.
Alternatively, and that's what Qt Quick Controls 2 do, you could have a QQuickItem painting nothing and just be a parent for your background and your content item (QQC2 controls expose their contentItem as a property but you don't have to).
For some inspiration you can check the source code of QQC2's Control here : https://code.woboq.org/qt5/qtquickcontrols2/src/quicktemplates2/qquickcontrol.cpp.html
Don't forget to handle the resizing of your background to the size of your item.

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 to paint with QPainter only after a specific event?

I have a main window with some widgets on it, each needs its own graphic. I would like to use QPainter to draw shapes, lines, etc. on them, but only after a specific event, like the press of a button.
The problem is, if I just create a QPainter in any function, it won't work:
QPainter::setPen: Painter not active
The QPainter methods can only be called inside a paintEvent(QPaintEvent *) function! This raises the following problems:
I have to derive my custom classes for all the widgets I would like to paint on, so I can't use the Designer to place my widgets. This can get frustrating with a large number of widgets.
The widgets redraw themselves after each paint event of the window, like moving it around, or moving other windows in front of it. I do a lot of drawing in those widgets, so they will visibly blink in these cases.
Is there a better and simpler way to solve this? I started to think about just displaying images, and re-manufacturing those images only when the specific buttons are pressed. I doubt that it's the most elegant solution...
You can use custom widgets in the designer: Creating Custom Widgets for Qt Designer.
Qt Designer's plugin-based architecture allows user-defined and third party custom widgets to be edited just like you do with standard Qt widgets.
For your second question, one of the approaches is to create a QPixmap for each of your widgets. When your widget's appearance needs to be changed, you draw in that pixmap (using QPainter's constructor that takes a QPaintDevice - QPixmap is a QPaintDevice).
In your widget's paintEvent function, you simply fill your widget with that "cache" pixmap. This way, you only do the (potentially expensive) painting when it's actually necessary.

Is it possible force Qt to call paintEvent after other Qt components are drawn?

I've a class that extends QWidget and contains a QLabel (lblBackground). I've overriden paintEvent function too.
I want to draw something on top of lblBackground however paintEvent method is called before the QLabel is drawn. Thus my custom drawings are overwritten.
Is there a way to change drawing order?
Painting the children on top of their parent is the common thing to do. That being said you could try one of the following options:
extend QLabel itself to paint whatever you want
try to set the Qt::WA_TranslucentBackground flag on the QLabel and having an alpha channel, so that the underlying parent (QWidget) would shine through
if you are only using the QLabel to paint some background, maybe you can get rid of it and paint the desired background first thing in the QWidget's paintEvent()?
If you want to use label as a background then just create your custom widget as a child of your label. May be split some window frame related tasks if any (to be implemented as a parent of the label) and drawing/controls/etc (to be child of the label).

How do i cause a qtabwidget instance to automatically resize when child tabs are added to it?

I am trying to get the QTabWidget automatically resized to fit the child tab when the child is added but have been unable to do so. I have created a form using Qt Designer and have inherited this using the single inheritance approach as follows.
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0);
private:
Ui::MyForm ui;
};
I have a QTabWidget and I am adding the instance of the object to my QTabWidget using the addTab(). When I display the QTabWidget, I notice that it hasn't resized to fit the MyWidget instance. What do I need to do to ensure that the QTabWidget instance gets automatically resized?
In designer, make sure you add a layout to your widget. Click on the widget's background so that way when you apply a layout, it applies to the whole widget. The trick is that the base (parent) widget that your form is built on needs a layout, and not just the items in the form.
Grid's are generally pretty easy to use. But sometimes the other ones are better. Designer can be tricky to use and takes a while to get used to. Basically every widget should probably have a layout applied to it. Strange things can happen when you don't.
I believe this is a bug of the Creator (at least for V4.7.4 opensource).
My solution is as following.
Do not create the QTabWidget object in the main project.
Create it independently (by creating Qt-> Form-class).
Then, copy the 3 files (.h, ,cpp, .ui) into the project, and add them to the project.
The result is: it resizes as the mainwindow resizing.
To fit any widget into its parent widget, you need to use a particular layout (grid, horizontal, vertical etc).