I am working on updating an application for a client.
They use Qt and currently use a QGLWidget to display a full-screen view of 1 of 4 possible cameras selected by clicking the appropriate radio button. They then use OpenGL to draw on the image being displayed. This works great, but they want to update the UI to include a quad-split view of all 4 cameras.
My first thought on how to accomplish this was to keep the one QGLWidget for the full-screen display, and have 4 small QGLWidgets for the quad-split. From the documentation I found that you can't overlap QGLWidgets or QOpenGLWidgets because they don't handle z-order appropriately, but that this can be accomplished by using QOpenGLWindows and QWidget::createWindowContainer.
So, I coded up an application that uses a QOpenGLWidget (trying to bring them up to date) for the full-screen view, and 4 smaller QOpenGLWindows using QWidget::createWindowContainer, but this isn't working either.
The widgets built from QOpenGLWindows are always on top even if I use lower() to try to get them behind the full screen QOpenGLWidget. I've also tried using hide() on the widgets built from QOpenGLWindows, however, this has had no effect.
Do this at a lower level. Keep the one QGLWidget -- in fact don't touch your Qt objects. Instead, change the lower-level rendering so that it makes 4 calls to glViewport.
After each call to glViewport, update the modelview and projection and matrices according to the camera of interest, then draw the 3D scene.
This is simple and performant, because the driver only needs to deal with a single OpenGL context. You might have some extra work to adjust mouse input, but I think it'll be worthwhile.
Related
I'm building a UI in Qt 5.9 that needs to run on an X11 display. I'm trying to add drop shadows to my dialog windows - but they don't work over X11.
The approach I'm taking is from zeFree's answer in This Question. (Put everything in the window in one widget, set the window translucent, and create a dropshadow effect on the widget).
setAttribute(Qt::WA_TranslucentBackground); //enable Window to be transparent
QGraphicsDropShadowEffect* effect = new QGraphicsDropShadowEffect();
effect->setBlurRadius(5);
ui->widget->setGraphicsEffect(effect);
It works great in my redhat vm:
RedHat Dropshadow
But when I send to the X11 display I, it looks like the transparency isn't supported, and I get the shadow on black instead:
X11 Dropshadow
My question is: Is there a way to make my Dialogs project a drop shadow onto my main window instead of onto their own (transparent) background? My application will be full screen on the X11 display so I don't need to worry about shadow effects outside of the window.
Any answer that gives me a clean way to get a drop shadow effect on this X11 display will be accepted.
If your window manage doesn't support transparency you are out of luck IMO. At least with your current approach.
There is theoretically a way to fake it, provided you can grab the pixel values from the underlying window manager composite that is under your application, then draw those pixels from your application, filling the black void, with the shadow composed over that, and finally your GUI stuff.
There is also the more viable course of giving up on native windowed dialogs and fake the dialog using a regular floating widget. This has the disadvantage that it will only be able to move within the confines of your main window, but this way you will have complete control over the drawing and not fall victim to platform limitations.
I'm working on some Qt GUI application with shiny glossy design.
I have a list view customized with my QItemDeleagte subclass. I draw items in paint virtual method. Selected items need to be drawn with glow effect on the border. Normal items must be without glow effect
That's RectangularGlow QML Type which is exactly what I need my view items border to look like. Unfortunately the app was written in Qt 4.7 and there is no way to port the app and all its dependencies to Qt 5.
QGraphicsDropShadowEffect is not sutable since shadow gradient has one direction and an offset. QLinearGradient doesn't help too or I don't know how to use it.
I consider drawing some kind of border image.
Is there any proper and elegant way to implement this using gradients or graphics effects?
EDIT:
As cmannett85 pointed out QGraphicsDropShadowEffect seems to be ok. However graphics effect may be installed on a whole paintdevice and for view item i cant just draw only selected item border rectangle with glow effect and leave other elements in a normal state. Instead all drawing on a list view affected
EDIT2:
I found a solution in an answer for another question. So I think this question may be closed
i came about this problem and knew it could be done better.
The problem:
When overlaying a QGLWidget (Qt OpenGL contextview) with Qt widgets, Qt redraws those widgets after every Qt frame.
Qt isn’t built to redraw entire windows with >60fps constantly, so that’s enormously slow.
My idea:
Make Qt use something other to draw upon: a transparent texture. Make OpenGL use this texture whenever it redraws and draw it on top of everything else. Make Qt redirect all interaction with the OpenGL context view to the widgets drawn onto the texture.
The advantage would be that Qt only has to redraw whenever it has to (e.g. a widget is hovered or clicked, or the text cursor in a text field blinks), and can do partial redraws which are faster.
My Question:
How to approach this? how can I tell Qt to draw to a texture? how can i redirect interaction with a widget to another one (e.g. if i move the mouse above the region in the context view where a checkbox sits in the drawn-to-texture widget, Qt should register this event to the checkbox and repaint to reflect itshovered state)
I separate my 2D and 3D rendering out for my CAD-like app for the very same reasons you have, although in my case my the 2D stuff are not widgets - but it shouldn't make a difference. This is how would approach the problem:
When your widget changes render it onto a QGLFramebufferObject, do this by using the FBO as the QPaintDevice for a QPainter in your QGLWidget::paintEvent(..) and calling myWidget->render( myQPainter, ...). Repeat this for however many widgets you have, but only onto the same FBO - don't create an FBO for each one... Remember to clear it first, like a 'normal' framebuffer.
When your current OpenGL background changes, render it onto another QGLFramebufferObject using standard OpenGL calls, in the same way.
Create a pass through vertex shader (the 'camera' will just be a unit cube), and a very simple fragment shader that can layer the two textures on top of each other.
At the end of the QGLWidget::paintEvent(..), activate your shader program, bind your framebuffers as textures for it (myFBO->texture() gets the handle), and render a unit quad. Because your camera is a unit square, and the viewport size defined the FBO size, it will fill the viewport pixel perfect.
However, that's the easy part... The hard part is the widget interaction. Because you are essentially rendering a 'proxy', you going to have to relay the interaction between the 'real' and 'proxy' widget, whilst keeping the 'real' widget invisible. Here's how would I start:
Some operating systems are a bit weird about rendering widgets without ever showing them, so you may have to show and then hide the widget after instantiation - because of the clever painting queue in Qt, it's unlikely to actually make it to the screen.
Catch all mouse events in the viewport, work out which 'proxy' widget the cursor is over (if any), and then offset it to get the relative position for the 'real' hidden widget - this value will depend on what parent object the 'real' widget has, if any. Then pass the event onto the 'real' widget before redrawing the widget framebuffer.
I should state that I also had to create a 'flagging' system to handle redraws nicely. You don't want every widget event to trigger a widget FBO redraw, because there could many simultaneous events (don't just think about the mouse) - but you would only want one redraw. So I created a system where if anything in the application could change anything in the viewport visually, then it would flag the viewport as 'dirty'. Then setup a QTimer for however many fps you are aiming for (in my situation the scene could get very heavy, so I also timed how long a frame took and then used that value +10% as the timer delay for the next check, this way the system isn't bombarded when rendering gets laggy). And then check the dirty status: if it's dirty, redraw; otherwise don't. I found life got easier with two dirty flags, one for the 3D stuff and one for the 2D - but if you need to maintain a constant draw rate for the OpenGL drawing there's probably no need for two.
I imagine what I did wasn't the easiest way to do it, but it provides plenty of scope for tuning and profiling - which makes life easier in the long run. All the answers are definitely not in this post, but hopefully it will get you on the way to a strategy.
I want to create my own tiny windowless GUI system, for that I am using GDI+. I cannot post code here because it got huge(c++) but bellow is the main steps I am following...
Create a bitmap of size equal to the application window.
For all mouse and keyboard events update the custom control states (eg. if mouse is currently held over a particular control e.t.c.)
For WM_PAINT event paint the background to offscreen bitmap and then paint all the updated controls on top of it and finally copy entire offscreen image to the front buffer via Graphics::DrawImage(..) call.
For WM_SIZE/WM_SIZING delete the previous offscreen bitmap and create another one with new window size.
Also there are some checks to prevent repeated drawing of controls i.e. controls are drawn only when it needs repainting in other words when the state of a control is changed only then it is painted e.t.c.
The system is working fine but only with one exception...when window is being resizing something sort of tearing effect appears. Now what I mean by tearing effect I shall try to explain ...
On the sizing edge/border there is a flickering gap as I drag the border.It is as if my DrawImage() function returns immediately and while one swap operation is half done another image drawing starts up.
Now you may think that it is common artifact that happens in many other application for the fact that resizing backbuffer is not always as fast as resizing window are but in other applications I noticed in other applications that although there is a leg between window size and client area size as window grows in size nothing flickers near the edge (its usually just white background that shows up as thin uniform strips along the border).
Also the dynamic controls which move with window resize acts jerky during sizing.
At first it seemed to me that using a constant fullscreen size offscreen surface could minimize the artifact but when I tried it results are not that satisfactory. I also tried to call Sleep() during sizing so that the flipping is done completely before another flip starts but strangely even that won't worked for me!
I have heard that GDI on vista is not hardware accelerated, could that might be the problem?
Also I wonder how frameworks such as Qt renders windowless GUI so smoothly, even if you size a complex Qt GUI window very fast negligibly little artifact appears. As far as I know Qt can use opengl for GUI rendering but that is second option.
If I use directx then real time resizing is even harder, opengl on the other hand seems to be nice for resizing without any problem but I will loose all the 2d drawing capability of GDI+.
If any of you have done anything like this before please guide me. Also if you have any pointer that I should consider for custom user interface design then provide me the links.
Thanks!
I always wished to design interfaces like windows media player 11 but can someone tell me that there is a straight forward solution for a c++ programmer (I want to know how rather than use some existing framework etc.)? Subclassing, owner drawing, custom drawing nothing seems to give you such level of control, I dont know a way to draw semitransparent control with common controls, so I think this question deserves some special attention . Thanks again.
Could it be a WM_ERASEBKGND message that's causing it?
see this question: GDI+ double buffering in C++
Also, if you need fast response from your GUI I would advise against GDI+.
I am working on a graphics game project in OpenGL and I want to make a front page of the game containing a image, few buttons and some text. Buttons on click perform different actions e.g. start button for starting the game , Can anyone please suggest me , How can I do it?
How can I do it?
Well, by implementing it. OpenGL is not a game engine, nor a scene graph, nor a UI toolkit. It's merely a drawing API providing you the means to draw nice pictures, and that's it. Anything beyond that is the task of either a 3rd party library/toolkit, or your own code, or a combination of both.
A usual approach to model this behaviour is by introducing application states. Here is a related question.
You could model your StartScreenState by drawing a plane with buttons using an orthogonal projection and not drawing (or not having initialized yet) the rest. When the player clicks on 'start', you can switch to perspective projection and display game contents.
I don't know that I would even use OpenGL for that. OpenGL is for rendering colored/textured triangles/quads so that you can do tons of stuff graphically. There's no such thing as "load an image to coordinate x,y on the screen". The equivalent would be "draw two triangles with these vertices that make up a rectangle and are textured with this image". Which is why I would probably stay away from OpenGL to do this, because you don't really need to use any of the awesome features that OpenGL has.
A very common UI framework that I believe nestles in with OpenGL well if you really want to use the two together is Qt. It should make your life easier in terms of UI stuff. See wiki and dev page.