Show QWidget or QWindow near QSystemTrayIcon in QT C++ - c++

I have managed to get the QSystemTrayIcon visible similar to this:
using the following line of code (with the signal slots working):
#include "dialog.h"
#include "ui_dialog.h"
#include <QMessageBox>
#include <form.h>
Dialog::Dialog(QWidget *parent)
: QDialog(parent), ui(new Ui::Dialog)
{
ui->setupUi(this);
QIcon icon("/Users/JohnnyAppleseed/IMAGE.png");
m_ptrTrayIcon = new QSystemTrayIcon(icon );
m_ptrTrayIcon->setToolTip( tr( "Bubble Message" ) );
// m_ptrTrayIcon->setContextMenu(m_trayIconMenu);
connect(m_ptrTrayIcon, SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
this, SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
}
Dialog::~Dialog()
{
delete ui;
}
However, when I try to implement code to show the QWidget/QWindow near the QSystemTrayIcon that I have created, it fails to show up near it. It also shows up and disappears quickly as well (even if I didn't want it near the QSystemTrayIcon) using this code:
void Dialog::iconActivated(QSystemTrayIcon::ActivationReason reason)
{
form fr;
fr.setWindowFlags(Qt::Popup);
fr.show();
}
For the sake of being clear, I would like to show my QWidget/QWindow just like VMWare Fusion's approach (or the clock that is found on Microsoft Windows Vista or later...)
Mac OS X / Linux
Microsoft Windows
Can some one please point out what am I doing wrong? Thanks!
To make things much simpler, download the project: http://zipshare.net/sv
UPDATE #1
Regarding the QWidget/QWindow flicking issue, vahancho advised me to move the form fr; from the void Dialog::iconActivated(QSystemTrayIcon::ActivationReason reason) function to the header of the working window. And it worked successfully all thanks to vahancho. The window now shows up, but its not near the QSystemTrayIcon yet :(

The problem is that you create you form object in the stack and it gets deleted as soon as the execution goes out of you iconActivated() slot. That is why it disappears as soon as you see it. To solve the problem you need to create your pop up in the heap.
UPDATE
In order to place you dialog near the tray icon you have to determine the tray icon position. To do that you can use QSystemTrayIcon::geometry() function. You code will look like (adjust the coordinates according to your needs):
QRect rect = m_ptrTrayIcon->geometry();
fr.move(rect.x(), rect.y());
fr.show();

Related

How does one split a QT(C++) UI into multiple widget subclasses and get it to display the same as all in the same class?

I'm learning QT (I already know C++ very well) and trying to get a UI to display well but I do not want to use the QT Designer that comes with QT Creator. I have the following class:
#include "MainPanel.h"
#include<QVBoxLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
The Main window class has a bunch of extra protected functions but the initControls method just does this:
void MainWindow::initControls()
{
QHBoxLayout *loMain = new QHBoxLayout(this);
loMain->addWidget(new MainPanel(this));
setLayout(loMain);
}
When I put all the code from MainPanel into MainWindow::initControls() or even in the constructor(either way), it works - shows a list widget with a single item "Testing". With the code in MainPanel though, it shows up as a very small rectangle that wouldn't fit the word "Testing" nor is there any semblance of text in there even partially.
I have tried to override sizeHint() in and move the code to create and return the list widget to a method getList() so I can access it from sizeHint too but that did nothing - I still get a small rectangle.
What am I doing wrong and what do I need to do or include to get the widget to paint properly? I have more controls I want to add to this UI (a button panel below the list widget and a detail panel on the right 2/3 of the window) but until I can get this to display, I can't possibly proceed with the rest.
I also want to do this entirely with code - not using the designer as I have vision issues and found it to be difficult to place things correctly on the form.
Someone please help - documentation and tutorials other than the documentation on QT's website is helpful if it points me to the right direction. I have already looked on QT's docs site under QWidget, QListWidget, QLayout, and QH(and V)BoxLayouts but see nothing and many of the tutorials talk about the designer.
Before someone tries to scold about creating a SSME or whatever small program - I have given you the smallest one that displays the issue - I know that putting the code all into the main window fixes it but one should never have everything in one class.
Okay, too unclear, what's happening there, we should have requested for more of your code =)
Here is the smallest possible sample, demonstrating what you should have been trying to achieve:
mainwindow.cpp:
#include "mainwindow.h"
#include "mainpanel.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
MainPanel* p = new MainPanel(this);
setCentralWidget(p);
}
mainpanel.h:
#include "mainpanel.h"
#include <QListWidget>
#include <QLayout>
MainPanel::MainPanel(QWidget *parent)
: QWidget(parent)
{
QLayout *lo = new QVBoxLayout(this);
QListWidget* mList = new QListWidget(this);
mList->addItem("Testing");
setLayout(lo);
lo->addWidget(mList);
lo->setSpacing(5);
}
main.cpp:
#include <QApplication>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow w;
w.resize(400, 500);
w.show();
return app.exec();
}
Seemingly, you've tried to set a layout on QMainWindow, but it already has a built-in layout, it is exactly the case when setCentralWidget should work, leave manual layout creation for QWidget & QDialog subclasses.
The code above works fine, try it and refactor the way you want.
#MasterAler is correct that the root cause of your issue is setting a layout MainWindow. The reason for using a MainWindow is to support standard VBoxLayout of menubar, central widget, and status bar. So it makes no sense to set your own layout for a QMainWindow.
Since we didn't have your entire code, I didn't assume MainWindow was a QMainWindow. I got your code to work by making MainWindow a QDialog. This may be more of what you were originally looking for, where you want to put a widget of your own making into any container. Following is in Python (I find Python a faster prototyping environment than C++), but you can easily read it and see how to host your MainPanel is any widget (not just a MainWindow):
import sys
from PySide2.QtWidgets import QApplication, QWidget, QListWidget, QDialog, QVBoxLayout, QHBoxLayout
class MainPanel(QWidget):
def __init__(self, parent):
QWidget.__init__(self, parent)
lo = QVBoxLayout(self)
lo.setSpacing(5)
self.setLayout(lo)
mList = QListWidget(self)
mList.addItem("Testing")
lo.addWidget(mList)
class MainWindow(QDialog):
def __init__(self, parent):
QDialog.__init__(self, parent)
loMain = QHBoxLayout(self)
loMain.addWidget(MainPanel(self))
self.setLayout(loMain)
if __name__ == "__main__":
app = QApplication(sys.argv)
# Show the form
window = MainWindow(None)
window.exec_()

Qt Save as File dialog show filename as untitled in Mac 10.9

In my application i want the Save as dialog as a sheet dialog ,so i make an instance of QFileDialog instead of using the static method getSaveFileName.
When i create the instance of QFileDialog i pass all the required parameters correctly, but still when the dialog is display only the first time correct file name is displayed,there after Qt only displays “Untitled” as the file name.Even though i am providing the correct file name.
I am using Qt 5.3. OS: Mac:10.9.
Has anybody faced this issue?
I already saw similar issue mentioned here : https://bugreports.qt.io/browse/QTBUG-36212 , but here again the static method is getting used.
I did some more testing by creating a project in Qt Creator (5.3.1 Clang 5.0 ( Apple ),64 bit ),this project just has QPushButton which on clicked displays the Save as dialog box.
The first time the output is correct:
Second time onwards the file name is always displayed as “Untitled”:
My code is quite straight forward:
#include “mainwindow.h”
#include “ui_mainwindow.h”
#include <QFileDialog>
#include <QPushButton>
#include <QLayout>
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QPushButton *pButton = new QPushButton( “Save As..”, this );
connect( pButton,SIGNAL),this,SLOT)); setCentralWidget( pButton );
}
MainWindow::~MainWindow()
{
}
void MainWindow::OnClicked()
{
QFileDialog *pFile = new QFileDialog ( this, “TestApplication”, “BoomBoom”, “.jpg” );
pFile->setAcceptMode( QFileDialog::AcceptSave );
pFile->setWindowModality( Qt::WindowModal ); int statusCode = pFile->exec();
}

QGLWidget crashes when added to layout

I am trying to adapt the opengl Es example "Hello GL" featured here - http://qt-project.org/doc/qt-4.8/opengl-hellogl-es.html. I am basically looking for a simple way to get a 3D graphics rendering window into a form made in Qt creator.
The first thing I tried:
Grid layout is a layout I created in Qt Creator.
#include <QProcess>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QTimer>
#include "glwidget.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
GLWidget *glwidget = new GLWidget(); // This is mandatory. No problems here.
QTimer *timer = new QTimer(this); // Need this for the example to work.
timer->setInterval(10); // Also necessary.
ui->gridLayout->addWidget(glwidget);
Which compiles, but then promptly crashes with a segmentation fault.
ui->gridLayout->addWidget(new GLWidget);
Segfaults the same way.
The debugger points me toward line 104 of qgridlayout.h:
inline void addWidget(QWidget *w) { QLayout::addWidget(w); }
Not sure what to make of that. Perhaps the QGLWidget wants to do something before I call ui->setupUi(this)? Perhaps it can't add the widget to the layout for some reason?
Of course if I comment out the line where I am added the widget, the program works flawlessly.
Any ideas for what's going on here?
Edit: I have fixed this. It was problem with order of operations - I called updateui too quickly.
The setupUi function in the generated form class initializes all variables of the form class, so using the variables before the form is initialized is undefined behaviour, since the variables contain garbage.
So the solution is to call:
ui->setupUi(this)
Before any call that uses variables in the ui object.
I'm not sure, but I think the problem is with the following line:
ui->gridLayout->addWidget(GLWidget);
I think, you should write it as follows:
ui->gridLayout->addWidget(glwidget);
// declare glwidget as member of your class
GLWidget *glwidget;
//in constructor use
glwidget = new GLWidget();

Fullscreen for QDialog from within MainWindow only working sometimes

(Testing with C++ on Qt 4.8 and Ubuntu 12.10 unity)
I've got a main window which displays a QDialog. When I put the Dialog window full-screen it does not seem to always work even though it seems to be a proper window.
Meaning, the window can appear full-screen, though only sometimes.
Anyone got an idea? I know Qt states it might not work for all X environments, but it can't be that bad, can it?
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QDialog* d = new QDialog();
d->setModal(false);
d->show();
qDebug() << d->isWindow();
// works most of the times, though not always:
// d->showFullScreen();
// sometimes works, sometimes it doesn't:
QTimer::singleShot(2000, d, SLOT(showFullScreen()));
}
DomTomCat here at stackoverflow showed a way to detect Ubuntu and the QDialog problem is related to a bug in Metacity (Ubuntu's default window manager).
Metacity doesn't manage the same way dialogs and main windows and it has to be tricked making it think that a QDialog is a normal window. In order to do so using QDialog class it's window flags have to be changed.
Instead of doing all the steps DomTomCat says, you can detect the session and then just
//example inside the QDialog
this->setWindowFlags(Qt::Window);
this->showFullScreen();
The bug was reported (and ignored) before but as far as I know this is the first simple workaround.
https://bugreports.qt.io/browse/QTBUG-16034
https://git.gnome.org/browse/metacity/tree/src/core/window.c#n6326
Ubuntu can also use compiz. This can be seen at:
grep DefaultProvider-windowmanager /usr/share/gnome-session/sessions/*
Best regards,
Iker De Echaniz.
I came to a method, which works. I don't know why it works compared to just calling showFullScreen(). I guess this is not the perfect and clean solution. This can surely be adapted to other environmental variables and X sessions.
QDialog* d = new QDialog();
d->setModal(false);
d->show();
const QString session = QString(getenv("DESKTOP_SESSION")).toLower();
QByteArray geometry;
if (session == "ubuntu") {
geometry = _d->saveGeometry();
d->setFixedSize(qApp->desktop()->size());
d->setWindowFlags(Qt::FramelessWindowHint);
d->setWindowState( d->windowState() | Qt::WindowFullScreen);
d->show();
d->activateWindow();
} else {
d->showFullScreen();
}
For restoring from the fullscreen state, this has worked
if (session == "ubuntu") {
d->setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
d->setMinimumSize(0,0);
d->restoreGeometry(geometry);
d->setWindowFlags(Qt::Dialog);
d->show();
d->activateWindow();
} else {
d->showNormal();
}

setCentralWidget() causing the QMainWindow to crash.. Why?

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
this->setupUi(this);
this->setupActions();
this->setWindowTitle(tr("CuteEdit"));
label = new QLabel(tr("No Open Files"));
this->setCentralWidget(label);
label->setAlignment(Qt::AlignCenter);
}
By above code, I get a GUI like this(Its a screenshot of whole screen, Only observe the window displayed in middle of page of ebook). (I used QT Designer)
Now, i want user to select File->Open.. A Dialog appears and file gets selected.. Its contents are to be displayed in *textEdit widget..
Function for that is below..
void MainWindow::loadFile()
{
QString filename = QFileDialog::getOpenFileName(this);
QFile file(filename);
if (file.open(QIODevice::ReadOnly|QIODevice::Text))
{
label->hide();
textEdit->setPlainText(file.readAll());
mFilePath = filename;
QMainWindow::statusBar()->showMessage(tr("File successfully loaded."), 3000);
}
}
The window crashes at line:-
textEdit->setPlainText(file.readAll());
But if i comment the line:-
this->setCentralWidget(label);
i mean i remove label as being the central widget, the program runs as expected.. Why?
And also, I am not clear about the concept of CentralWidget. Pls guide.
JimDaniel is right in his last edit. Take a look at the source code of setCentralWidget():
void QMainWindow::setCentralWidget(QWidget *widget)
{
Q_D(QMainWindow);
if (d->layout->centralWidget() && d->layout->centralWidget() != widget) {
d->layout->centralWidget()->hide();
d->layout->centralWidget()->deleteLater();
}
d->layout->setCentralWidget(widget);
}
Do you see that if your MainWindow already had centralWidget() Qt schedules this object for deletion by deleteLater()?
And centralWidget() is the root widget for all layouts and other widgets in QMainWindow. Not the widget which is centered on window. So each QMainWindow produced by master in Qt Creator already has this root widget. (Take a look at your ui_mainwindow.h as JimDaniel proposed and you will see).
And you schedule this root widget for deletion in your window constructor! Nonsense! =)
I think for you it's a good idea to start new year by reading some book on Qt. =)
Happy New Year!
Are you sure it's not label->hide() that's crashing the app? Perhaps Qt doesn't like you hiding the central widget. I use Qt but I don't mess with QMainWindow that often.
EDIT: I compiled your code. I can help you a bit. Not sure what the ultimate reason is as I don't use the form generator, but you probably shouldn't be resetting the central widget to your label, as it's also set by the designer, if you open the ui_mainwindow.h file and look in setupGui() you can see that it has a widget called centralWidget that's already set. Since you have used the designer for your GUI, I would use it all the way and put the label widget in there as well. That will likely fix your problems. Maybe someone else can be of more help...
I'm not sure I understood your problem, neither what the guys above said (which I guess are valid information) and it seems to be an old topic.
However, I think I had a problem that looks like this and solved it, so I want to contribute my solution in case it helps anyone.
I was trying to "reset" central widget using QLabels. I had three different ones, switch from first to second, then to third and failed to switch back to the first one.
This is my solution that worked:
Header file
QLabel *imageLabel;
Constructor
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Reset
imageLabel = NULL;
imageLabel = new QLabel("<img src='/folder/etc.jpg' />");
this->setCentralWidget(imageLabel);
Hope that helps
Aris