Qt Removing a QGraphicsItem from QGraphicsScene with singleShot Timer? - c++

While it is possible to automatically remove a QGraphicsTextItem from a scene using a timer and Qt's signal-slot mechanism like
QTimer::singleShot(1000, QGraphicsTextItem*, SLOT(deleteLater()));
other graphical objects (QGraphicsItem, QGraphicsEllipseItem) seem to not inherit QObject and as such cause an error when compiling:
error: C2664: 'QTimer::singleShot': Konvertierung des Parameters 2 von
'QGraphicsEllipseItem *' in 'QObject *' nicht m”glich
(conversion / cast of parameter 2 ... not possible)
Since I would like text and some graphics shown together for a limited time, my question is:
How I can achieve automatic, timed removal of the above-mentioned 'other' objects?

QGraphicsItems don't inherit QObject normally. You would need to subclass QGraphicsEllipseItem like so:
class AutoHidingItem : public QObject, public QGraphicsEllipseItem
{
Q_OBJECT
// ...
}
Or you would simply have to have your scene keep track of the items to hide, and then hide it when it needs to. (Make a slot in your subclassed scene or view that hides or deletes the item.)
EDIT: #thuga pointed out that QGraphicsEllipseItem doesn't inherit QObject, while QGraphicsTextItem does already. Edited answer to show this.
Hope that helps.

Related

QObject::sender() doesn't work properly in a slot

I want to make a button to stay pushed after a click. So I made a slot make_pushed which I try to use for that purpose. The button which was clicked on is identified by QObject::sender() method. But something goes wrong since it doesn't work.
QPushButton * size=new QPushButton("size",this);
connect(size, SIGNAL(clicked()), this, SLOT(make_pushed()));
void Window4::make_pushed()
{
QObject* sender = this->sender();
QPushButton* button = qobject_cast<QPushButton*>(sender);
button->setDown(true);
button->setText("Yep");
}
class Window4 : public QWidget
{
public:
Window4(QWidget * parent=0);
private slots:
void make_pushed();
};
There's a mistake in application output "QObject::connect: No such slot QWidget::make_pushed() in" , although everything compiles and the window appears. The problem is the slot is apparently not found, although it is in the same cpp file and in the header. And therefore when clicked, the botton neigher changes its text nor stays pushed.
You just forgot Q_OBJECT macro in class declaration http://doc.qt.io/qt-5/qobject.html:
Notice that the Q_OBJECT macro is mandatory for any object that implements signals, slots or properties. You also need to run the Meta Object Compiler on the source file. We strongly recommend the use of this macro in all subclasses of QObject regardless of whether or not they actually use signals, slots and properties, since failure to do so may lead certain functions to exhibit strange behavior.
http://doc.qt.io/qt-5/qobject.html#Q_OBJECT:
The Q_OBJECT macro must appear in the private section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.
Note: This macro requires the class to be a subclass of QObject. Use Q_GADGET instead of Q_OBJECT to enable the meta object system's support for enums in a class that is not a QObject subclass.
Just use it like this every time you subclass QObject/QWidget/...:
#include <QObject>
class Counter : public QObject
{
Q_OBJECT
// ...
}

error C2664: 'App *const' to 'QWidget *'

I'm trying to put an animated gif into my program.
However, when I follow the proper syntax
QMovie *hit1=new QMovie("BadExplosion.gif");
QLabel *processLabel=new QLabel(this);
processLabel->setMovie(hit1);
hit1->start();
in the
void TestApp::draw()
{
//this code and other drawing code here
}
I run into the error
error C2664: 'QLabel::QLabel(QWidget *, Qt::WindowFlags)' : Cannot convert parameter 1 from 'TestApp *const' to 'QWidget *' on the line
QLabel *processLabel=new QLabel(this);
Any ideas? Thanks!
EDIT: TestApp is a custom class.
If TestApp is a custom class, then it's perfectly normal that this code doesn't work.
Every UI element of Qt may take a parameter at construction, which is the QWidget that will act as a parent. This parent will notably have the responsibility for handling its children deletion. You should read more about this in the Qt Documentation (esp. the doc for QWidget constructor).
In your case, you shouldn't pass this to the QLabel constructor. You must pass another widget that'll become this QLabel parent.
The compiler shows clearly this problem with the message you got. It waits for a QWidget, but got your class instead (which doesn't inherit QWidget at any point).

C++ Qt Derived Classes

I'm trying to learn Qt and C++ and having some trouble understanding the C++ this keywork. I've seen examples where a class is derived from QMainWindow and then within the class member functions, a QMenu is added. One example is the "Simple menu" program described on this page:
http://www.zetcode.com/gui/qt4/menusandtoolbars/
In that example, a quit action is created with
QAction *quit = new QAction("&Quit", this);
However, imagine I want to also derive a class from QMenu and use that to create my menu.
mymenu.h
class MainWindow; // forward declaration
class MyMenu : QMenuBar
{
public:
MyMenu(MainWindow *main_window);
};
mymenu.cpp
#include "mymenu.hpp"
MyMenu::MyMenu(MainWindow *main_window) : QMenuBar()
{
QAction *quit = new QAction("&Quit", main_window); // Notice here I replaced
// 'this' with 'main_window'
QMenu = *file;
file = menuBar()->addMenu("&File");
file->addAction(quit);
connect(quit, SIGNAL(triggered()), qApp, SLOT(quit()));
}
Unfortunately this doesn't work because QAction expects a QObject as a parent. All that being said, there are a couple things that don't make sense to me:
If the class MainWindow inherits from QMainWindow, doesn't that make 'MainWindow' a QObject?
What is the difference between passing 'this' to QAction from within the class MainWindow, as opposed to passing 'main_window' which is (as far as I can tell) also a pointer to the instance from within the MyMenu class?
I apologize for such a long winded question, but if any of you have made it to the end with me, I would love any suggestions as to what I am missing here. The end goal here is just to create a derived class of QMenu (MyMenu here) and add it to the QMainWindow derived class (MainWindow here) existing in a separate class. Thank you for your time.
If the class MainWindow inherits from QMainWindow, doesn't that make 'MainWindow' a QObject?
Yes, MainWindow is a QMainWindow which is a QObject (you can see this by browsing the inheritance tree on the API docs).
You have only forward declared MainWindow. Since the compiler does not have a definition for the class MainWindow it can only do miminal things with a pointer to MainWindow. In order for the compiler to "know" that MainWindow is a QMainWindow which is a QObject, you must provide a class definition for MainWindow. You can solve your compiler error with:
#include "MainWindow.h"
No dynamic cast is needed
Also, in Qt land to make something "really" a QObject you should put the Q_OBJECT macro on the object:
class MyMenu : QMenuBar
{
Q_OBJECT
public:
MyMenu(MainWindow *main_window);
};
It might save you a few headaches later on if you ever plan to use the object for signal/slots or other Qt stuff.
What is the difference between passing 'this' to QAction from within the class MainWindow, as opposed to passing 'main_window' which
is (as far as I can tell) also a pointer to the instance from within
the MyMenu class?
this is a pointer to your custom MyMenu class which is also a QMenuBar. main_window is a pointer to your custom MainMenu class which is also a a QMainMenu. So, two different objects in memory. The second argument of the QAction constructor takes a pointer to a parent widget. The parent widget is responsible for managing the memory of its children. Since it takes a QObject its reasonable to pass in either this or main_menu.
Also you should probably pass a parent to the QMenu constructor.
MyMenu::MyMenu(MainWindow *main_window) : QMenuBar(main_window)
This way MyMenu is correctly deleted when the MainWindow is deleted.
The usual Qt paradigm is:
MyMenu::MyMenu(<arg1>, <arg2>, ... QObject * parent) : QMenuBar(parent)
But in this case forwarding along main_window is good enough.

Menu action connection does not find slot

I am creating a QSystemTrayIcon traymenu. Its contextmenu has several actions which I need to identify.
public slots:
void s_showNote();
void Traymenu::createMainContextMenu(){
...
std::string noteTitle = m_noteList[i]->getTitle();
QString menuEntryName = QString::fromStdString(noteTitle);
QAction *openNote = m_mainContextMenu.addAction(menuEntryName);
QObject::connect(openNote,SIGNAL(triggered() ),this,SLOT(s_showNote()) );
QVariant noteID;
noteID.setValue(m_noteList[i]->getID());
openNote->setData(noteID);
The error is
QObject::connect: No such slot QSystemTrayIcon::s_showNote()
All of the code above is a part of my class definition that inherits from QSystemTrayIcon. How can I call the SLOT?
You seem to have at least two issues ongoing:
Use Q_OBJECT for QObject derived classes.
You will need to re-run qmake correspondingly.
As for the first point, please use C++11 and at least Qt 5.2 in the future because in cases like this, you will get a static compiler time error which comes handy for avoiding these tedious issues.

Why do we pass "this" pointer to setupUi function?

I'm fairly new in QT. Taking below fairly simply explain from qt docs :
class CalculatorForm : public QWidget
{
Q_OBJECT
public:
CalculatorForm(QWidget *parent = 0);
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
private:
Ui::CalculatorForm ui;
};
and implementation of constructor
CalculatorForm::CalculatorForm(QWidget *parent)
: QWidget(parent) {
ui.setupUi(this); // <-- Question below
}
Q: I was wondering why do we pass this pointer to setupUi function?, what does it do ?
So that the dialog will have the caller as parent, so that eg when the parent is closed the dialog can be closed automatically. Generally all gui elements have a pointer to their parent.
private slots:
void on_inputSpinBox1_valueChanged(int value); //why is that slots are private?
These are auto generated slots which exactly match the naming of the gui elments in QtDesigner. They are only meant to do the direct hookup to those gui elements and so should be dealt with in this class. If these signals were extended to other classes then any change in the gui would require changing a lot of other code which doesn't need to know details of the gui.
In the handler slot for the specific gui element you can then emit another more general signal to the rest of the app.
The only widget that setupUi doesn't create is the widget at the top of the hierarchy in the ui file, and as the Ui::CalculatorForm class instance doesn't know the widget it has to fill, it (this) has to be passed explicitly to the class at some point.
this or any other widget you would pass to it, is used as the parent to all other subwidgets. For example, you could fill a widget without inheritance like this:
QWidget *widget = new QWidget;
Ui::CalculatorForm *ui = new Ui::CalculatorForm;
ui->setupUi(widget);
widget->show();
But really, it would be easier to understand if you read the content of the uic generated file (probably named ui_calculatorform.h).
setupUi creates the instances of widgets (QLabel, QTextEdit and so on). The [user interface compiler] (http://qt-project.org/doc/qt-4.8/uic.html) gets information for you from the .UI form and generates widget-creation code in the generated moc source files.
The manual way of creating widgets without using the Qt Designer or a UI file would be like so:
QWidget* pWidget = new QWidget(this);
I think it is to add the caller widget to the layout of this UI.
This widget will be the toplevel widget.
Martin Beckett answer might be correct as well, as what he described is a common behavior in Qt (cf the 'parent' argument in most of widget's derived class constructor)
Note that you have alternative ways how designer can auto-generate code.
In this case you have a separate 'UI' class for this code which is not QObject so it also is not a QWidget.
Auto generated code needs information about parent widget and to make auto-conections of slots and signals so this is why you have to pass this.
This pater is less intrusive then other pasterns (that is why it is default). You can also try alternative patters (check Qt Creator Designer options), but I recommend you to see what is generated by designer tools in default settings.