Qt transparent QWebView: past page stay in background of new one - c++

I have a little app with a transparent QWebView displaying some HTML pages (they all have a style="background-color: transparent;" property on the body) over a QTabWidget with a font.
The transparency is working, i can see the font of my QTabWidget beside the content of my QWebView. But when i load another page in the QWebView, the old one is still visible in the background of the new one. Like if the pages were just arranged one above the other and not closed.
I dont know how to get rid of this behavior and from where it can come from!

I had similar problem recently with QtJambi. The page I load is dynamic (animations with javascript and css3) and the web view painted new rendering without clearing the old rendering each time some component was moving or changing.
I found a solution today. I wrote a class inherited from QWebView and set the background to transparent in the paintEvent method. The background is set to transparent each time the web view is repainted.
Here is my Java code
public class WebBrowserTestQWebView extends QWebView
{
#Override
public void paintEvent(QPaintEvent event)
{
QPalette palette = this.palette();
palette.setBrush(QPalette.ColorRole.Base, new QBrush(new QColor(Qt.GlobalColor.transparent)));
this.setPalette(palette);
this.setAttribute(Qt.WidgetAttribute.WA_OpaquePaintEvent, false);
super.paintEvent(event);
}
}
I guess it works with C++ too.

Related

gtkmm centering widget in Gtk::Layout

I'm trying to create a fullscreen window covered with an image and one entry widget in the middle of the window.
I already have the fullscreen window with the image, however, I'm struggling with positioning the entry box exactly in the middle of the window. I tried Gtk::Alignment, Gtk::VBox, Gtk::HBox, Gtk::Table
and many other containers, but to be honest, I don't really understand all the containers how do they behave. I am used to WIN32 API with absolute positioning and this is way different. I know I can use something like fixed positioning in Gtk/gtkmm, however, it does not seem like the cleanest solution to me.
class App : public Gtk::Window {
public:
[...]
App() {
fullscreen();
Gdk::Rectangle rec = get_screen()->get_monitor_workarea(get_screen()->get_primary_monitor());
set_default_size(rec.get_width(), rec.get_height());
show();
m_bgImage.set("image.jpg");
m_layout.add(m_bgImage);
m_entry.set_size_request(300, 30);
m_entry.set_opacity(0.5);
m_entry.set_visibility(false);
m_entry.signal_activate().connect(sigc::mem_fun(*this, &PadlockGui::onPasswordEntryReturn));
m_entry.set_icon_from_icon_name("edit-clear", Gtk::ENTRY_ICON_SECONDARY);
m_entry.signal_icon_press().connect(sigc::mem_fun(*this, &PadlockGui::clearPasswordEntry));
m_layout.add(m_entry);
add(m_layout);
show_all_children();
}
private:
Gtk::Layout m_layout;
Gtk::Image m_bgImage;
Gtk::Entry m_entry;
[...]
};
Here is a picture of my current situation:
Here is what I am trying to achieve:
I would suggest using CSS to create the background image rather than Gtk::Image. Then you can just put the entry directly in the window, and make sure its expand property is set to false and its halign and valign properties are centered.

QDockWidget::background-color not applied when docked

I have a QDockWidget:
I would like to alert the user to certain events by setting the background color of the title bar.
I have achieved this by setting the style sheet for my DockWidget:
void DockWidget::setCriticalAlert()
{
setStyleSheet("QDockWidget { background-color:red; }");
}
The result is this:
The problem is that the background-color doesn't get applied when the QDockWidget is docked:
How can I get the background color to be applied when the QDockWidget is docked?
This is a bug in Qt.
Issue 10537
Quoting from the linked issue:
The problem is that in QDockWidget::paintEvent, there is a
isFloating() condition before drawing PE_FrameDockWidget. We cannot
jsut remove this condition as it would break the other style (that
does not whish to draw frame when the dockwidget is docked) We cannot
either use PE_Widget to draw the frame as then it goes over the
dockwidget's title The solution is maybe to introduce a new
PE_FrameDockWidgetDocked primitive element. Or some
SH_DockWidget_DrawDockedFrame stylehint to draw the frame in every
cases.
a valid workaround seems to be to set the stylesheet of the parent, and use the class-and-id selector. Forgive the python formatted code but the concept is the same - in this case, 'dock' is a QDockWidget which has been given an object name using setObjectName(), and its parent, the QMainWindow, is 'self':
self.setStyleSheet("QDockWidget#"+str(dock.objectName())+"::title {background-color:red}")
In PyQt5.5, this works at runtime, i.e., can be changed on the fly.
I find a solution like this:
Firstly put a frame behind all the widgets of dockwidget's center widget, as the background.
Then set stylesheet for the frame.
By this way, we could change the background color of dockwidget.
Or you can extend the dockwidget and overwrite the function
void QDockWidget::setWidget(QWidget *widget)
using private/qdockwidget_h. and add a frame as this widget's father.

White screen observed while launching the QGraphicsView application

Our application uses Qt's Graphics View framework to load the html pages. QGraphicsWebView loads local html page which is black background. But always observed the white screen while launching the application. I have tried setting black background for both QGraphicsView and QGraphicsScene. Nothing worked for me.
Here's the sample code for your reference.
MainWindow which inherited from QMainWindow class
mGraphicsScene = new QGraphicsScene(this);
mGraphicsView = new QGraphicsView(mGraphicsScene);
mGraphicsView->setViewport(new QGLWidget(this));
mGraphicsWebView = new QGraphicsWebView;
mGraphicsWebView->setUrl(QUrl("https://www.google.co.in/"));
mGraphicsScene->addItem(mGraphicsWebView);
setCentralWidget(mGraphicsView);
Is there any way to avoid white screen of the application?
Best Regards,
Pratap
Try next. Why did you see white? Because item already added, but page not loaded, so you see white(blank) item without page. Set to your scene some black pixmap, connect loadFinished signal to special slot, where you add item to your scene. In this case scene will be black, but when page will be loaded, your slot will add this on scnen and you will see only page.
mGraphicsScene = new QGraphicsScene(this);
mGraphicsScene->addItem(new QGraphicsPixmapItem(QPixmap("G:/2/qt.jpg")));
mGraphicsView = new QGraphicsView(mGraphicsScene);
mGraphicsView->setViewport(new QGLWidget(this));
mGraphicsWebView = new QGraphicsWebView;
mGraphicsWebView->setUrl(QUrl("https://www.google.co.in/"));
connect(mGraphicsWebView,SIGNAL(loadFinished(bool)),this,SLOT(slotLoaded()));
//mGraphicsScene->addItem(mGraphicsWebView);
mGraphicsView->resize(1000,700);
mGraphicsView->show();
Slot:
void MainWindow::slotLoaded()
{
mGraphicsScene->addItem(mGraphicsWebView);
}
For example black pixmap which was created by code:
QPixmap black(1000,700);
black.fill(Qt::black);
mGraphicsScene = new QGraphicsScene(this);
mGraphicsScene->addItem(new QGraphicsPixmapItem(black));
When application start:
As you can see, all is black, when page was loaded:
As you can see, it is normal page. It is not very beautiful because I use fast settings and resize window and so on, but you set graphicsview as central widget, do it will be more beautiful.
Thank you very much for the response.
I have tried your solution and also observed white screen while launching the application on Windows
I found the culprit is mGraphicsWebView->setUrl(QUrl("https://www.google.co.in/")); This is blocking all other widgets on the scene. So I have added a singleShot timer and kept this statement under that.
//QTimer::singleShot(100, this, SLOT(loadUrl())); Then it works fine.
Please let me know if you have any better idea.

How to Layer independent widgets in Qt?

I'm creating an application using Qt which consists of a widget that is used as the background of the application, and a user control interface that is floating above.
A similar example is google maps, where the map is on the background and the controls are on top of the background.
But the thing is that the background widget can be changed to a different widget (there's a widget that displays a map, another widget that displays video feed, ...)
And the same thing happens for the buttons in the user control interface, they are not directly related to the current background and can be change dinamically.
I've tried using a QStackedLayout, using two layers, the background widget and the user control interface. But you cannot interact with the background layer because all the clicks are blocked by the widget in the front.
Any suggestions?
You could place a filter on the event stream to your interface widgets using the QObject::installEventFilter() function, and intercept all the incoming mouse-click events. Once you have captured these events, use the filter function to delegate them to either the background widget, or deliver them to the front interface buttons. You would most likely have to use the (x,y) coordinates of the mouse-click to determine if an event should go to the background widget, or one of the foreground button widgets.
Another option is to create a derived class from QAbstractButton (or whatever QWidget you're using for your buttons), and re-implement the event functions for mouse-clicks on that widget (i.e., QAbstractButton::mousePressEvent(), etc.). When a mouse-click arrives, check to see if the mouse was over the button, and if it wasn't, send the event to the background widget via a signal or QCoreApplication::sendEvent().
Your question is too generic to give you a especific answer, but the most obvious solution is to implement classes that inherits from QWidget for each possible component of you system. In your example I can visualize 2 distinct components: Background and Controls. Background would store all the image data, like maps and videos, while the Controls would have the buttons to interact with the system. You can even break the Background into different classes to manage image or video. I recommend using a central GUIController class that inherits from QObject to manage all the interface interactions, like connecting the signals/slots or implementing any animations, this way you can add/manage multiple widgets without going trough different .cpp's.
EDIT: With your comment, seems that your main problem is that your mouse events are not propagating to your widgets as you expected. Probably the reason for this is that you are not setting the parent/children relationships between the components. Make sure that you are calling the default QWidget constructor in your custom widgets classes like above:
CustoWidget(QWidget *parent = 0, Qt::WFlags flags = 0) : QWidget(parent, flags)
{
//your code here
}
When creating the Controller class, sets the right relationships between the components. In the context of your system, seens to me that all components will be added as Background children, so it would looks like below:
class Controller : public QObject
{
public:
Controller(QObject *parent = 0, Qt::WFlags flags = 0) : QObject(parent, flags)
{
wdg_back_= new BackWidget(this);
wdg_control_ = new Controls(wdg_back);
wdg_1_ = new GenericWidget(wdg_back);
//connect your signals/slots, etc
}
private:
BackWidget *wdg_back_;
Controls *wdg_control_;
GenericWidget *wdg_1_;
}
Ok I've finally found a solution for my issue.
My approach of using QStackedWidget was wrong, widget on the background are not meant to be clickable, and even though it might be done, it's not what I was looking for.
In the end, this is what I've done:
QWidget *centralWidget = new QWidget(this);
setCentralWidget(centralWidget);
MapView *backgroundWidget = new MapView(centralWidget);
backgroundWidget->setMinimumSize(1024,600);
QGridLayout *controlsLayout = new QGridLayout(centralWidget);
MyControlWidget *control1 = new MyControlWidget(centralWidget);
control1->setMinimumSize(140,140);
control1->show();
controlsLayout->addWidget(control1,2,0);
So I create a QWidget, centralWidget which will be the parent of the background and the foreground. Set the background to full screen, and organize the controls in a QGridLayout, which doesn't affect the backgroundWidget.
If I click on a control, the event is processed by this control, but clicking on an empty space will trigger a mouse event on the backgroundWidget, which is what I needed.
I'll test this for some time and if it works fine I'll close the question.

Making a window a desktop in XLib/Qt

I am trying to write a simple program to act as my desktop background in Qt, I have made it all work fine apart from making it a Desktop Widget. I have no idea on how to do this, I don't mind using XLib or Qt for doing this, but if anyone has some suggestions I would be very happy.
I have created a simple example that will fill the desktop background white. It is easy to make it draw an image.
class DesktopWidget : public QWidget
{
Q_OBJECT
public:
DesktopWidget()
{
setAttribute(Qt::WA_X11NetWmWindowTypeDesktop);
resize(QApplication::desktop()->size());
}
protected:
void paintEvent(QPaintEvent*)
{
QPainter painter(this);
painter.fillRect(geometry(), Qt::white);
}
};
The problem with this solution is that it completely paints over everything that your desktop environment draws in the background (including icons, plasmoids,...).
If you just want to set a new background image programmatically, I would check if your DE has an API for that.