Transparent QGraphicsWebview over QGLWidget leads to super imposed images - qt

I have a transparent QGraphicsWebview inside a QGraphicsView with the following settings:
The QGraphicsView is the high level widget, and is shown in full screen mode
The graphics view uses a QGLWidget as its view port (to use opengl-es)
Alpha channel and double buffering are enabled in this QGLWidget
Transparency is achieved by graphicsView->setStyleSheet("background:transparent")
Following attributes are set for QGraphicsView and QGraphicsWebview
WA_TranslucentBackground = true
WA_NoSystemBackground = true
WA_OpaquePaintEvent = false
The QPalette::Base and QPalette::Window brushes of webview and webview->page() are set to Qt::transparent
At the beginning, the transparency works fine. But as the screen get updated (when I scroll), it looks like the new bitmap is blended on top of the existing one to get a superimposed picture. After about 5-6 screen updates, this blending causes the colors to accumulate and form an opaque rectangle (with a corrupted image). Following images show first, second and final stages of the problem.
How do I tell qt/opengl to stop blending and just draw the new image to the frame buffer?
I tried calling fillRect(boundRect(), Qt::transparent) from overridden Webview::paint and GraphicsView::paintEvent; but it didn't work except for making the updates slower.
I am new to Qt and OpenGl, so I might be missing some basic flags or settings.

I tried all the methods mentioned above. They did not work for me. I then debugged into qtbase code and found that setting the Opacity level make the top browser layer transparent.
this->setOpacity(0.1);
this pointer points to the QGraphicsWebView object.
With this method, the whole front browser contents including background will be transparent. To separate header, paragraph and background and to specify different transparent levels for them, I will have to dig into webkit code a little further to figure out the problem. But for now, setOpacity() did the trick and is good enough for what I am doing.

It turns out the problem is graphicsView->setStyleSheet("background:transparent");. Who would have guessed?!
Yeah, the line that I thought made transparency work was actually causing troubles with transparency. The application works fine without that line (or if you change it to background:none)
In short, steps to get a transparent QGraphicsWebview using QGLWidget:
Set the Base palettes of QGraphicsWebview, QWebpage and the outer QGraphicsView to Qt::transparent
scene->setBackgroundBrush(QBrush(Qt::transparent));
You should also make sure that html body background is set to transparent values:
html, body {
background-color: rgba(127, 127, 0, 0.5);
}

Related

Qt3D transparency in offscreen renderer

I'm using Qt3D with a combination of this offscreen renderer and modified the framegraph to include a background image, like here.
Unfortunately, adding transparency to the objects drawn over the background image using QPhongAlphaMaterial only works unsatisfactorily.
This is th result:
What you can't see here is that the whole circle part is actually transparent, i.e. the renderer wrote the transparency value of the object for the whole pixel instead of adding it transparently on top of the background.
This is what the rendered object looks like wihtout transparency:
And this is the background:
The framegraph has two branches: one for the backgroun image, which is processed first, and one for the objects. I added a QRenderStateSet for the objects that contains a QBlendEquation with the blend function set to add and a QBlendEquationArguments with source RGB and alpha set to 1, and destination RGB and alpha set to 1 minus source alpha.
Any ideas how to fix this problem?
(For anyone wondering, I took the images from the T-Less dataset and wrote a program to create ground-truth data for 6D pose estimation)
Similarly to this question, the format of the texture that is being rendered to needs to be set to RGB8_UNorm and not RGBA8_UNorm, i.e. without the alpha channel.

Highlighting text in JavaFx Label

I am trying to set the text background of the JavaFx label text as green using the following CSS
label.setStyle("-fx-background-color:rgba(85, 255, 68,0.7););
And the unhighlight using the following
label.setStyle("-fx-background-color:rgba(0,0,255,0);");
However these does not work most of the times when it has to be done back to back.
Is there any way to set the style without using CSS i.e. using JavaFx API itself. I found label.textFill(Paint p) for text color but nothing for background colour i.e. the color of the label itself.
Is there any way to set the style without using CSS i.e. using JavaFx API itself.
For some styles (such as the text fill) yes. For background colors, background images, borders, etc API methods will not be available until JavaFX 8 is released (see Public API for Region backgrounds and borders in the JavaFX issue tracker for more information - anybody can sign up for access).
these does not work most of the times when it has to be done back to back.
If you just highlight a label and then unhighlight it again without using something like a PauseTransition to give the user some time to see the highlighted label, then, from the user's perspective nothing is going to happen as all the user will see is an unhighlighted label.
Not sure of your use case, but if you only want to highlight part of the text in a label or let the user highlight the text with a mouse, then you can use a TextField with editable set to false.
Possible Workaround
If the Java 8 preview does not work for you and you are experiencing errors due do bugs in the JavaFX CSS processing, then try placing a Pane then a label inside a StackPane. Set the background color of the Pane to label.setStyle("-fx-background-color:rgba(85, 255, 68,0.7);); Bind the Pane's preferred width and height to the Label's width and height and toggle setVisible on the Pane as appropriate.
Finally I found the workarround. I had to give a PauseTransition to give the system some time between unhighlight and highlight. CSS showed effect only after the pausetransaction if the labels were already highlighted. I think it may be a bug. I will file a jira. The duration of paustransition may be as low as 1 milisecond so that there is not lag from the user's point of view.

Semi-transparent QWidget over QGLWidget: Strange results

I have a full size QGLWidget which paints the application background using QPainter (might change to native openGL commands in the future).
On top of this QGLWidget I use QWidgets (non-GL) for the user interface elements. These are, for example, QLineEdits and QPushButtons. I put them into a custom painted QWidget which uses semi-transparent background painting. The paintEvents of the QLineEdit and QPushButton are overwritten and use semi-transparent backgrounds, too.
The whole UI should look like the following (This is a screenshot where I disabled OpenGL and used QWidget instead of QGLWidget for the background. Note the semi-transparent top bar which also draws a shadow (within its own region)):
When the QLineEdit has the focus, it should have a higher opacity but still not fully opaque:
So now, with OpenGL enabled (The background then is a QGLWidget), the semi-transparent widgets above don't paint on top of the background but on (it seems to be) uninitialized data. The image shining through the top bar is sometimes the whole window itself and sometimes other windows currently being on my desktop.
This currently looks like the following (In this screenshot, the data on which the semi-transparent painting operations are painted on seems to be an image of the widget itself, having an offset.):
When I wrote text into the line edit (here: "This is some text which has been there before!"), removed it and set the focus back to the background widget (so the magnifier icon and the placeholder text appear), the previously painted things still shine through (Note that the visible border should not be visible anymore, but also still shines through):
So the problem is: Instead of being painted on top of the underlying widgets, the semi-transparent widget is painted on top of the old results, initially being something like "uninitialized memory".
Why does this happen? How can I solve the problem?
Things you should know before answering:
The background scene is a composition of tiles which are rendered off-screen. So it can be painted very fast and repainting of the background for every little change of the overlay isn't problematic.
The top bar is a custom QWidget with manual painting and arrangement of the contained two widgets (the button and line edit).
The two widgets overwrite the paintEvent, only draw their own (semi-transparent) background when they have focus and don't use frames already provided by Qt. So the white border in the second screenshot is drawn in my custom paintEvent.
I want the background and the composition of overlay widgets to be separately implementable. The background is an AbstractMapView which has some concrete map view classes. The whole window is an AbstractView (there are multiple concrete views, too), which contains both a concrete map view and the overlay widgets, composed in a way itself decides. Therefore, I don't want the logic of the overlay widgets to be part of the underlying map view. (I hope you understood this, as it is a bit complicated.)
This sounds like an issue where the GL content (i.e. your background aka the QGLWidget) is not in the Qt context. While I'm not a pro on GL painting with Qt, you may want to look at this discussion regarding GL painting and a QLabel for some direction/potential hints.
http://www.qtcentre.org/threads/40335-QLabel-on-top-of-a-QGLWidget-background-issue
In short, we here at the office use OpenGL painting and offscreen rendering of maps and it's very important to make sure Qt is aware of the pixels so your foreground widgets can have the semi-transparency applied to their backgrounds.
The particular product we use also renders the map in tiles and supports providing the GL output in a buffer (i.e. it's call a snapshot and is provided as a bitmap) at which point we use the paintEvent of a regular QWidget to paint the buffer so that the painted pixels are in Qt context.
You can define a Qframe with Qt::SplashScreen flag as the search box and set its opacity. Put your widgets inside it such as the search textbox and positon it where it should appear on the mainwindow. It will also be a good idea to reposition it as the mainwindow is moved or resized overriding its moveEvent.

How to make Widgets background transparent in Qt

I am building an App in which I had given background to my mainWindow only and all other widgets are used without any background, but when I run the app they are not 100% transparent they are somewhat translucent, is there any way to make them 100 % transparent so that only foreground can appear with no background hint.
Could you post the code you are using to get transparancy at the moment? If you say that you get "something translucent" I think that you created a tool window which is not what you really want.
A really transparent main window could be achieved by removing the title bar (give the QWidget constructor Qt::FramelessWindowHint as second parameter - WindowFlags), draw everything in the widget that should be transparent in a uncommon color (like 255,0,255) and then cut it off.
A very primitive example of cutting off parts of a QWidget:
QBitmap b(100, 100);
b.fill(Qt::black);
setMask(b);
QBitmap must be black on that pixels that shall be visible and white on that are not. In this example just the 100,100 area starting at 0,0 will be visible, the rest of your window will be invisible.

GDI+ DrawImage of a JPG with white background is not white

I am displaying a JPG in a C++ CWnd window using GDI+. The JPG has a pure white background, 0xffffff, but when displayed using graphics.DrawImage, the background is off-white with a mix of pixel colors such as 0xfff7f7, 0xf7fff7, 0xf7f7f7. Below is the code, I have tried various settings such as CompositingMode, SmoothingMode, etc. The image is not scaled.
The weird thing is that the background color is different depending on other non-white content in the image. If I make a simple all white JPG, then it works, or even a mostly white with just some black text. Comparison of images are shown below.
CClientDC dc(this);
Gdiplus::Graphics graphics(dc);
Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromFile( L"c:\\test.jpg" );
graphics.SetInterpolationMode(Gdiplus::InterpolationModeHighQuality);
//graphics.SetCompositingQuality(Gdiplus::CompositingQualityHighQuality);
graphics.SetCompositingQuality(Gdiplus::CompositingQualityDefault);
graphics.SetCompositingMode(Gdiplus::CompositingModeSourceCopy);
//graphics.SetSmoothingMode( Gdiplus::SmoothingMode::SmoothingModeDefault );
graphics.DrawImage(bmp, 0, 0, bmp->GetWidth(), bmp->GetHeight() );
Here I have text and some blending only on the left side of the image (no alphas, this is JPG) . Everything to the right is pure white. You can see the background is all grey.
Here I started removing the internal content (only on the left side). After a certain point the entire background starts displaying white. ???
It doesn't really matter which part of the image area I remove before it starts displaying white, as long as I remove a large portion of it. The same occurs for pngs.
Here is the original test.jpg image...
I am answering my question with the solution that I found. It seems that using graphics.DrawImage directly on the passed HDC has some issues in my case. If I use a memory DC for the initial drawing, then BitBlt it on the HDC, then it works.
I also had some problems with PNG and transparency. Using the solution below, I was able to solve this problem as well. My PNG was loaded from a stream using Bitmap::FromStream. The alpha channel was lost and I was trying different attempts using LockBits and re-creating the bitmap with PixelFormat32bppARGB, as well as Cloning. I was able to get something to work (after a lot of effort and extra code), but it still had the grey background problem that I asked here.
In my case, I have a known solid background color for the transparent areas. I used Bitmap.GetHBITMAP and passed the background color. The bitmap was then drawn on the memory DC first. Here I was able to solve both of my problems!
Gdiplus::Bitmap* bmp = Gdiplus::Bitmap::FromFile( L"c:\test.jpg" )
Gdiplus::Color backColor( 0xff, 0xff, 0xff );
HBITMAP hBmp;
bmp->GetHBITMAP( backColor, &hBmp );
CDC bitmapDC;
bitmapDC.CreateCompatibleDC(hdc); // pass original HDC for drawing
HBITMAP oldBmp = bitmapDC.SelectBitmap(hBitmap);
::BitBlt( hdc, x, y, cx, cy, bitmapDC.m_hDC, 0, 0, SRCCOPY );
bitmapDC.SelectBitmap(oldBmp);
DeleteObject( hBmp );
If anyone knows, I would be interested why this fixes the problem.
How did you confirm the JPG background is truly white? JPG implements compression that can vary the color of pixels. If there are mixed colors, then there can be certain types of blending and mixing that are part of that compression.
Can you show us the original image?

Resources