I have QDialog, which is modal and takes the whole screen, meaning it spans itself across all the monitors and I want to make it transparent. Initially I went setWindowOpacity() and it worked, but after that everything else I would draw on the dialog using QPainter it would draw opaquely, which was understandable. Because this wasn't the solution I was looking for I ended up doing setAttribute(Qt::WA_TranslucentBackground) and to my surprise the background ended up being black. The same thing happens when I do setStyleSheet("QDialog {background-color: transparent;}"). Has anyone else seen this issue and how do I fix it?
Some code snippets:
SnipAreaDialog::SnipAreaDialog(QWidget *parent) : QDialog(parent) {
setAttribute(Qt::WA_TranslucentBackground);
setCursor(Qt::CrossCursor);
}
void SnipAreaDialog::showEvent(QShowEvent *event) {
auto desktopRect = qApp->desktop()->geometry();
setGeometry(desktopRect);
QDialog::showEvent(event);
}
Also, I am showing the dialog with QDialog::exec() and I tried setting its parent to 0, as well as to the main window of my app, it's the same behavior.
Yes, I also had a situation, try like this, it helped me...
example below
#include <QApplication>
#include <QDialog>
class Dialog : public QDialog
{
public:
Dialog() : QDialog(0, Qt::FramelessWindowHint)
{
setAttribute(Qt::WA_TranslucentBackground);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog d;
d.showFullScreen();
return a.exec();
}
if there isn't a parent, you may consider using
Qt::WindowStaysOnTopHint as well. If the window system supports it, a
tool window can be decorated with a somewhat lighter frame. It can
also be combined with Qt::FramelessWindowHint .
Related
I'm trying to remove the default Windows titlebar from my Qt window (QT version 5.12.2 and using C++) while still keeping the window borders. I've more or less achieved this using the flag Qt::CustomizeWindowHint. However, this changes the window borders to white lines instead of the default borders.
Example of how the borders look AFTER I've applied the Qt::CustomizeWindowHint flag:
As you can see, these are not the normal Windows window borders.
How can I change/edit these boders (i.e. change their color) or how am I able to keep the default Windows window borders while removing the titlebar?
Here's a minimal reproducible example:
main.cpp:
int main(int argc, char* argv[]) {
QApplication application(argc, argv);
launcher mainWindow;
//debugChecks();
mainWindow.setWindowFlags(Qt::Window | Qt::CustomizeWindowHint | Qt::MSWindowsFixedSizeDialogHint);
mainWindow.setWindowTitle("Test");
mainWindow.show();
return application.exec();
}
launcher.h
#pragma once
#include <QtWidgets/QMainWindow>
#include <QMouseEvent>
#include <QPoint>
#include "ui_launcher.h"
class launcher : public QMainWindow {
Q_OBJECT
public:
launcher(QWidget* parent = Q_NULLPTR);
private:
Ui::launcherClass ui;
void mousePressEvent(QMouseEvent* eventVar);
void mouseMoveEvent(QMouseEvent* eventVar);
int mouseClickX = 0;
int mouseClickY = 0;
};
launcher.cpp
#include "launcher.h"
launcher::launcher(QWidget* parent) : QMainWindow(parent) {
ui.setupUi(this);
}
void launcher::mousePressEvent(QMouseEvent* eventVar) {
mouseClickX = eventVar->x();
mouseClickY = eventVar->y();
}
void launcher::mouseMoveEvent(QMouseEvent* eventVar) {
move(eventVar->globalX() - mouseClickX, eventVar->globalY() - mouseClickY);
}
Your description isn't really clear. One should not be using a QMainWindow for a logon/in dialog. Having said that I created an application on Ubuntu 20.04 (should build fine for you as I used qmake). You can download the project zip here. When the application starts it looks like this:
After clicking on "golden" it looks like this:
After Green it looks like this:
After clicking on Freaky it looks like this:
Please note that FramelessWindowHint not only removes the title bar and system menu along with window frame, it also removes your ability to resize/drag/move the window.
My apologies for not taking out the StackOver1.pro.user file. Didn't think about it until just now. You will need to delete that or it could hose your build.
QPalette and QStyle for Border
Palette Can Change window styles and colors of the Application. and for Reference
https://doc.qt.io/archives/qt-5.7/qtwidgets-widgets-styles-example.html
You can do something like this
self.setWindowTitle("") # Python
mainWindow.setWindowTitle(""); # C/C++
but instead of passing an empty string, pass an empty character. This one worked for me: https://emptycharacter.com/
I am working on stylesheet of a QWizard and I would like to remove the horizontal line just above the push button.
I've already posted a minimal example here, the question was solved by scopchanov from the minimal example, but I have some lines of code in my project that avoids the solution to work, so I post another question here.
Here is my code (the complete buildable example can be downloaded from the gist here):
licensewizard.h
#include <QWizard>
class LicenseWizard : public QWizard {
Q_OBJECT
public:
LicenseWizard(QWidget *parent = 0);
};
licensewizard.cpp
#include <QApplication>
#include <QtWidgets>
#include "licensewizard.h"
LicenseWizard::LicenseWizard(QWidget *parent) : QWizard(parent) {
setWizardStyle(ModernStyle);
// solution from #scopchanov https://stackoverflow.com/a/52541248/8570451
QPalette p(palette());
p.setColor(QPalette::Mid, p.color(QPalette::Base));
setPalette(p);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
// this line breaks #scopchanov solution.
// replace QLabel by QPushButton, or anything else... still broken.
qApp->setStyleSheet("QLabel { color:black; }");
LicenseWizard wizard;
wizard.show();
return app.exec();
}
As scopchanov said, I used the QPalette trick. But I have a big style sheet defined on the qApp and this is the cause of my problem. Using a very small style give the same problem.
The step to reproduce is to add this line after the declaration of the QApplication:
qApp->setStyleSheet("QLabel { color:black; }");
I hope someone could help me.
To fix this, set the palette of the whole application, instead of just the LicenseWizard class, like this:
LicenseWizard::LicenseWizard(QWidget *parent) : QWizard(parent) {
setWizardStyle(ModernStyle);
}
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPalette p(qApp->palette());
p.setColor(QPalette::Mid, p.color(QPalette::Base));
qApp->setPalette(p);
qApp->setStyleSheet("QLabel { color:black; }");
LicenseWizard wizard;
wizard.show();
return app.exec();
}
Note: As mentioned in my answer to the linked question, if this color role is used by any other item, its color would be affected as well.
I have a problem that on Linux with Xorg (Ubuntu 14.04) and Qt 5.5.1 QSplashScreen isn't painted until I get to the event loop. Even if I call QApplication::processEvents() multiple times, it still isn't painted, even after 1000 calls, although the window is already on the screen, retaining the original pixels which were there before the app launched, thus being effectively invisible*. From this answer I got an idea of using a timed loop of calling QApplication::processEvents(), like here:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
int main(int argc, char** argv)
{
QApplication a(argc,argv);
QSplashScreen splash;
splash.show();
splash.showMessage("Loading...");
// The hack to try to ensure that splash screen is repainted
for(int i=0;i<30;++i)
{
QThread::usleep(1e3);
a.processEvents();
}
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
The above code actively sleeps for 30 ms in an attempt to make QSplashScreen repaint. This works for me, but I'm not sure that it'll always work e.g. on a busy/slow CPU or in whatever other conditions (the magic value of 30 iterations was found empirically).
Another, quite intrusive in general, way would be to do all the necessary loading in another thread, only to make sure that QSplashScreen in the main thread does have an active message queue. Due to the need to considerably redo the main program, this looks not too good of a solution.
So, is there any way to make sure that QSplashScreen has been repainted, so that its window doesn't contain garbage, and only then to proceed with long blocking loading process?
* I discovered this when I moved a window behind the splash screen
One way to avoid the unknowable a priori magic timeout is to wait for an exact event: the paint event. On X11 it appears to come with a delay. To do this waiting we'll have to subclass QSplashScreen and override QSplashScreen::paintEvent(), like here:
#include <QThread>
#include <QApplication>
#include <QSplashScreen>
class MySplashScreen : public QSplashScreen
{
bool painted=false;
void paintEvent(QPaintEvent* e) override
{
QSplashScreen::paintEvent(e);
painted=true;
}
public:
void ensureFirstPaint() const
{
while(!painted)
{
QThread::usleep(1e3);
qApp->processEvents();
}
}
};
int main(int argc, char** argv)
{
QApplication a(argc,argv);
MySplashScreen splash;
splash.show();
splash.showMessage("Loading...");
splash.ensureFirstPaint();
QThread::usleep(5e6); // simulate slow loading process
splash.showMessage("Finished");
return a.exec();
}
The solution is rather simple: keep the event loop running until the window is repainted. This should be done without any spinning, i.e. you shouldn't be using any explicit timeouts.
#include <QtWidgets>
class EventSignaler : public QObject {
Q_OBJECT
QEvent::Type m_type;
protected:
bool eventFilter(QObject *src, QEvent *ev) override {
if (ev->type() == m_type)
emit hasEvent(src);
return false;
}
public:
EventSignaler(QEvent::Type type, QObject *object) :
QObject(object), m_type(type) {
object->installEventFilter(this);
}
Q_SIGNAL void hasEvent(QObject *);
};
int execUntilPainted(QWidget *widget) {
EventSignaler painted{QEvent::paint, widget};
QObject::connect(&painted, &EventSignaler::hasEvent, qApp, &QCoreApplication::quit);
return qApp->exec();
}
int main(int argc, char **argv) {
QApplication app{argc, argv};
MySplashScreen splash;
EventSignaler painted{QEvent::Paint, &splash};
splash.show();
splash.showMessage("Loading...");
execUntilPainted(&splash);
QThread::sleep(5); // simulate slow loading process
splash.showMessage("Finished");
return app.exec();
}
#include "main.moc"
Getting right to it I have a MainWindow and a dialog window which is executed if a condition is met but the problem is I can't get the app to quit if the cancel button from the dialog window is clicked. I've tried putting qApp->quit() in the slot function for the cancel button. I've tried connecting the cancel button slot to the predefined close slot for the MainWindow object via a clickme() signal from the dialog class. (as shown below)
qt application does not quit I read the answer to this question which I think got me close because it made me realize that I can't quit the app before showing the MainWindow but making that change didn't solve the problem. I even tried to explicitly emit the clickme() signal from cancel button slot but that actually caused the OS to throw a signal which threw an error at me saying "the inferior stopped because it received a signal from the operating system signal name: SIGSEGV
signal meaning: segmentation fault"
Here's my code:
Notice warning; // this is the object for the dialog window also all of this code is in main.cpp
warning.setModal(true);
QObject::connect(&warning, SIGNAL(clickme()), &warning, SLOT(on_Cancel_button_clicked()));
QObject::connect(&warning, SIGNAL(clickme()), &w, SLOT(close()));
warning.exec();
Also before that code is
MainWindow w;
w.show();
Also while writing this question I tried this
QObject::connect(&warning, SIGNAL(clickme()), qApp, SLOT(quit()));
But that still didn't work. If you need more info just let me know.
Update: I'm starting to think that the reason I'm having so much trouble with this connect signal/slot function is because it's not designed to connect two windows of two different classes and I should rework my app to do everything from the MainWindow class which is a shame because when I picture a GUI program I picture multiple windows connected to each other regardless of whether or not the object representing each window is from the same class as the others yet I have such a hard time trying do that with the QT framework when it comes to trying to connect objects of different classes.
Update: please forgive me. I assume that the code that I originally thought was the answer would work and took a break from working on the program before actually testing out that code. Going back to it now I discovered that it doesn't work. The code I'm referring to is the following
QMessageBox msg;
msg.setText("Continue?");
msg.addButton(QMessageBox::Yes);
msg.addButton(QMessageBox::No);
QObject::connect(&msg, &QMessageBox::rejected,
&app, &QApplication::quit); // this line doesn't work for me and I don't know why
QObject::connect(&msg, &QMessageBox::accepted, [&dlg]{
(new QLabel("I'm running")).show();
});
QApp->quit(); should work. Remove warning.setModal(true); The dialog becomes modal when you call exec(). SetModal(true) should be used with show() according to Qt docs. So this may be causing your problem.
I think I've found the problem.
Probably, you're calling exec() twice:
To enter the QApplicationevent loop
To execute the dialog.
Use show() instead of exec() for the dialog. You have an example below where you can check the signal/slot works well. In your application, you need the slot to close the window, but:
With the line of code dialog.exec();, the app keeps running. This is your issue.
With the line of code dialog.show();, the app stops.
By the way, I saw your last question update, but it is not correct. In fact, of course you can connect two different classes.
window.h
#ifndef WINDOW_H
#define WINDOW_H
#include <QApplication>
#include <QMainWindow>
#include <QAbstractButton>
#include <QDebug>
#include "dialog.h"
class Window : public QMainWindow
{
Q_OBJECT
public:
Window()
{
dialog = new Dialog();
dialog->setText("Continue?");
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
auto onClick = [this]() {
auto role = dialog->buttonRole(dialog->clickedButton());
if (role == QMessageBox::NoRole) {
qDebug() << "QMessageBox::NoRole";
QApplication::quit();
}
if (role == QMessageBox::YesRole) {
qDebug() << "QMessageBox::YesRole";
}
};
QObject::connect(dialog, &QMessageBox::buttonClicked, onClick);
dialog->show(); // this must be show(), not exec()
}
virtual ~Window() { delete dialog; }
private:
Dialog *dialog;
public slots:
void windowSlot() { qDebug() << Q_FUNC_INFO;
close();
}
};
#endif // WINDOW_H
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QMessageBox>
class Dialog : public QMessageBox
{
Q_OBJECT
public:
Dialog() {}
virtual ~Dialog() {}
};
#endif // DIALOG_H
main.cpp
#include <QApplication>
#include <QtGui>
#include "window.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
Window window;
window.setWindowTitle("window");
window.show();
return app.exec();
}
Update #1: a very interesting post.
I am making a desktop carousel app. There I need to show image widgets, which might contain other sub-widgets as well. For that I am using a QFrame with the required image as background. Here is the image I am trying to use: image link. What I want is that only the image shows up, no background image or anything shows up as well, so to the user it looks like just the image. Here is my code:
setGeometry(QRect(100, 20, 325,400));
setFrameStyle(QFrame::StyledPanel);
setStyleSheet("QFrame#ImageFrame { background-color: transparent; background: url(:icon/ipad-skin); }");
setAutoFillBackground(false);
However, I am getting this as a result:
I tried this as well (obtained from here) (and removing the stylesheet):
void MyWidget::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
pPainter->drawPixmap(rect(), QPixmap(":icon/newskin.png"));
delete pPainter;
QWidget::paintEvent(p);
}
Nothing different, the exact same result. The greyness of the background still shows.
How do I make the grey background of the QFrame go and display only the image (the dimensions I am setting are the same as the image)?
P.S I am aware that similar questions hve been answered here: QWidget transparent background (but not the children), and here: Frameless and transparent window qt5 but these doesn't solve my problem. The last solution makes my QFrame look like this:
The QFrame now comes with a title bar which is anything but what I wanted in the first place.
Edit - This solution works, but in my use-case, I need to display an image that is rendered via GL inside the QFrame (specifically, in the viewport within the iPad image we can see here). In Windows, setting the Qt::WA_TranslucentBackground property makes that GL-rendered image invisible. It works fine in Mac, though. So I am looking for a solution which will work in Windows as well.
This code works for me (tested under MacOS/X 10.10.3, using Qt 5.5.0-beta; I'd expect it to work under any Qt version 4.5.0 or higher though):
main.h:
#ifndef main_h
#define main_h
#include <QFrame>
#include <QPixmap>
class MyFrame : public QFrame
{
public:
MyFrame(QWidget * parent);
virtual void paintEvent(QPaintEvent * e);
private:
QPixmap _pixmap;
};
#endif
main.cpp:
#include <QApplication>
#include <QPainter>
#include "main.h"
MyFrame :: MyFrame(QWidget * parent) : QFrame(parent, Qt::Window|Qt::FramelessWindowHint)
{
setAttribute(Qt::WA_TranslucentBackground);
_pixmap.load("/Users/jaf/iPad_Vector.png");
resize(_pixmap.size());
}
void MyFrame :: paintEvent(QPaintEvent * /*e*/)
{
QPainter p(this);
p.drawPixmap(0,0,width(),height(), _pixmap);
}
int main(int argc, char ** argv)
{
QApplication app(argc, argv);
MyFrame f(NULL);
f.show();
return app.exec();
}
Screenshot (showing the app's window in front of my desktop background):
Can you try this light modification to your code ?
In case it doesn't work can you publish your compilable code on a public repository ? This would help reproduce in your exact context.
void MyWidget::paintEvent(QPaintEvent *p)
{
QPainter* pPainter = new QPainter(this);
pPainter->setBackgroundMode(Qt::TransparentMode);
pPainter->drawPixmap(rect(), QPixmap(":icon/newskin.png"));
delete pPainter;
QWidget::paintEvent(p);
}