My problem is that when I click on an item in a QMenuBar, the corresponding slot gets called twice. I'm using Qt 4.8.1. I'm not using Qt Designer nor the "auto-connection" feature. Here is my code snippet :
#include <iostream>
#include <QWidget>
#include <QMenuBar>
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget *parent = 0) : QWidget(parent)
{
QMenuBar *menu = new QMenuBar(this);
menu->addAction("Click here");
menu->addAction("Or here");
connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(handleAction(QAction*)));
}
public slots:
void handleAction(QAction *action)
{
std::cout << "Triggered" << std::endl;
}
};
And the main function :
#include "main.h"
#include <QApplication>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyWidget w;
w.show();
return app.exec();
}
If you compile this (with the MOC file), you'll see that clicking on "Click here" will print "Triggered" once, and "Or here" twice. I don't understand why.
What am I doing wrong ?
Use Qt::UniqueConnection to solve:
connect(menu, SIGNAL(triggered(QAction*)), this, SLOT(handleAction(QAction*)), Qt::UniqueConnection);
http://doc.qt.io/qt-4.8/qt.html#ConnectionType-enum
I get the same incorrect result as you on Windows 7 x64 using Qt 4.8.1. This certainly seems like a bug.
There was a bug reported and fixed for what appears to be the same behavior on Mac OS X. Although it has been closed, there is a single comment on it that they observed this problem on Windows 7.
I think filing a new bug report would be a good idea.
Related
I'm a beginner in Qt, currently reading this : https://zetcode.com/gui/qt5/menusandtoolbars/
When I declare QActions in a QToolBar, the QPixmap objects (turned into QIcons) are not showing :
No icons, only text
However, the QPixmap images are actually showing when I declare a QMenu without the toolbar.
I am using Qt6 ; working on Fedora ; no warning shown on my compiler.
simple_menu.hpp
#ifndef SIMPLE_MENU_HPP
#define SIMPLE_MENU_HPP
#include <QMainWindow>
#include <QApplication>
class SimpleMenu : public QMainWindow
{
public:
SimpleMenu(QWidget *parent = nullptr);
};
#endif
simple_menu.cpp
#include "simple_menu.hpp"
#include <QMenu>
#include <QMenuBar>
#include <QToolBar>
#include <QIcon>
#include <QAction>
SimpleMenu::SimpleMenu(QWidget *parent)
: QMainWindow(parent)
{
QPixmap newpix("new.png");
QPixmap openpix("open.png");
QToolBar *toolbar = addToolBar("main toolbar");
toolbar->addAction(QIcon(newpix), "New File");
toolbar->addAction(QIcon(openpix), "Open File");
}
main.cpp
#include "simple_menu.hpp"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
SimpleMenu window;
window.resize(350, 250);
window.setWindowTitle("Tuto Toolbar");
window.show();
return app.exec();
}
Maybe the system cannot find your pictures. Please try to put the full file path (like :).
QPixmap newpix("c:\mydoc\pictures\new.png");
To check if the pictures are loaded, you can do something a bit different :
QPixmap newpix;
qDebug() << newpix.load("c:\mydoc\pictures\new.png");
the load method returns true or false in case of loading fail.
Anyway, if you want to embed your icons in the final EXE file, check the Qt resource system
It's a convenient system to achieve what you want to do, and to avoid dealing with storage paths on your local drives.
Good luck !
The following code snippet opens two windows, w1 and w2. How can one force w2 to close when w1 is closed by the user? As in the comment, the connect function is not working that way.
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w1;
w1.setWindowTitle("w1");
w1.show();
QWidget w2;
w2.setWindowTitle("w2");
w2.show();
// when w1 is closed by the user, I would like w2 to close, too.
// However, it won't happen, even though the code compiles fine.
QObject::connect(&w1, &QObject::destroyed, &w2, &QWidget::close);
return a.exec();
}
Edit In my case, those two widgets are designed in two separate libraries, so they cannot communicate with each other. Thus, the close event is not applicable.
Edit Eventually my solution to my problem is based on the answer by #JeremyFriesner: emit a closed signal in closeEvent of w1, and connect this (instead of QObject::destroyed) to w2.
This modified version of your program shows how you could do it by overriding the closeEvent(QCloseEvent *) method on your w1 widget:
#include <QApplication>
#include <QtGui>
#include <QtCore>
#include <QtWidgets>
class MyWidget : public QWidget
{
public:
MyWidget(QWidget * closeHim) : _closeHim(closeHim)
{
// empty
}
virtual void closeEvent(QCloseEvent * e)
{
QWidget::closeEvent(e);
if (_closeHim) _closeHim->close();
}
private:
QWidget * _closeHim;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w2;
w2.setWindowTitle("w2");
w2.show();
MyWidget w1(&w2);
w1.setWindowTitle("w1");
w1.show();
return a.exec();
}
If you wanted to do it more elegantly, you could have your closeEvent() method-override emit a signal instead of calling a method on a pointer; that way you wouldn't have a direct dependency between the two classes, which would give you more flexibility in the future.
I am working on a simple project where I want to know the available printers, then connect to one of them and see if there are errors or not.
I have used QPrinterInfo class in order to know the available printer names, then in order to work with one of the available printers, I set its name using "printer.setPrinterName("desired printer name")".
In order to know if there are some errors related to this printer (named as desired printer name), I searched and find out I have to use QPrinter::Error and then handle the errors.
My question is that what kinds of error can occur when using QPrinter::Error inside my if statement(in the following code)? If no papers exists inside the printer, will using QPrinter::Error throw an error? In general, how can I know what kinds of error I can handle and how to handle them?
code:
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtPrintSupport/QPrinter>
#include <QtPrintSupport/QPrinterInfo>
#include <QtPrintSupport/QPrintDialog>
#include <QList>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
QPrinter printer;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
QPrinterInfo PrinterInfo;
qDebug() << QStringList(QPrinterInfo::availablePrinterNames());
if (QPrinterInfo::availablePrinterNames().isEmpty())
{
qDebug() << " printer not found ";
}
printer.setPrinterName("desired printer name");
if (printer.printerState() == QPrinter::Error)
{
qDebug() << "there is an error";
}
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp:
#include "mainwindow.h"
include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
Followings are my experience with QPrinter in Linux which built on CUPS. So if you are planning to use it on Windows it might be a totally difference experience than mine. But I think error checking in Linux contains a lot of uncertainties.
I tried QPrinter::printerState() with HP 107w, it was always returning Idle even when printer is not plugged in. Same was happening with Xerox WorkCentre 3025 too. So I recommend you to not rely on QPrinter::PrinterState. Also documentation states that QPrinter::printerState
Returns the current state of the printer. This may not always be accurate (for example if the printer doesn't have the capability of reporting its state to the operating system).
I was printing to via QPainter.begin(printer). It only fails if printer does not connected when OS started. But once the printer available after a boot, it behaves like everything is going to be okay forever. It just queues up prints and when printer becomes available, fed up with paper, just prints everything it received before. I thought return value of QPrinter::newPage() would be good place to check if there is no paper and ask user to insert papers to continue. But nah, it never returns false neither.
I would like to ask if you could help me with my app.
I have an application in C++ using Qt (and Qwt) in MCVS 2010. I want to open QDialog window with QwtPlot on button click from Main Window (QMainWindow). Here is some code:
MainWindow.cpp
void MainWindow::on_pushButton_1_clicked ()
{
Dialog_plot dp;
dp.setModal(true);
dp.exec();
}
Dialog_plot.cpp:
#include <qwt_plot.h>
#include <qwt_plot_canvas.h>
#include <qwt_plot_curve.h>
#include "Dialog_plot.h"
Dialog_plot::Dialog_plot(QWidget *parent)
{
plot = new QwtPlot();
//more code...
main.cpp:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
This code is compiling, but when I click on that pushbutton_1 in my application I'm getting error:
Must construct a QApplication before a QPaintDevice
I know that such error was discussed many times and I was reading a lot about it but I can't see solution for my problem.
One more thing I would like to mention - I have similar application with Qwt plot written by somebody else and his application compiles and works without any problems in my MCVS. I was trying to compare Linker/libraries included but it seems to be the same. So I guess there is a problem with my application, I just can't solve it. I really need some help!
I am very new to Qt so that some Qt issues I can't figure out. I will really appreciate if somebody can help me.
I am trying to get rid of application window's frame and create an exit button in qml in order to exit the application. Hence, I make a program as following:
main.cpp
#include <QtGui/QApplication>
#include <QDeclarativeContext>
#include <QObject>
#include "qmlapplicationviewer.h"
#include "myclass.h"
#include "mainwindow.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MyClass myClass;
MainWindow window;
window.rootContext()->setContextProperty("myObject", &myClass);
window.show();
return app.exec();
}
mainwindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QDeclarativeView(parent)
{
// No window decorations
setWindowFlags(Qt::FramelessWindowHint);
// Set QML file
setSource(QUrl::fromLocalFile("qml/Test2/main.qml"));
}
// Destructor.
MainWindow::~MainWindow()
{
}
myclass.cpp
#include <QDeclarativeEngine>
#include <QDeclarativeComponent>
#include <QDeclarativeContext>
#include <stdio.h>
#include "myclass.h"
MyClass::MyClass()
{
click_count = 0;
}
int MyClass::click_function(void)
{
click_count++;
fprintf(stderr, "CLICK COUNT in CPP: %d\n", click_count);
return click_count;
}
qml
MouseArea {
id: mouse_exit
anchors.fill: parent
onClicked: {
console.log("Click on exit button: ")
console.log("click count: ", myObject.click_function())
Qt.quit();
}
}
It compiles successfully, however, whenever I click on the exit button, the Qt error "Signal QDeclarativeEngine::quit() emitted, but no receivers connected to handle it" occurs. Based on my searching online for this issue, it seems like I have to connect the QDeclarativeEngine::quit() signal to the QApplication::quit() slot. But there isn't too much information for using connect() function. I tried many ways to use connect(), but I still couldn't know how to use it for this case.
Can anybody help me solve this problem? I will really really appreciate!
The syntax is:
connect(sender, SIGNAL(signalName(args)), receiver, SLOT(slotName(args)));
You can put it in your MyClass constructor:
connect(this, SIGNAL(quit()), qApp, SLOT(quit()));
Or in the main function, since connect() is a static function, as Slavic81 pointed out in the comment below.
Note that qApp is a macro for the global application.