Qt connect itemDoubleClicked to self-defined slot - c++

I have the following class that extends QListWidget, but I can't seem to connect the doubleClicked signal to the slot I desire. Here's the code implemented - in VS2012. The idea is to be able to double click a item and edit it. I connect the signal to the slot in the constructor, but the slot is never called when I run it through the debugger.
# .h file
class DisplayFeed :
public QListWidget
{
Q_OBJECT
public:
DisplayFeed(QWidget *parent, Logic *logic, int xpos, int ypos, int width, int height, std::string color);
~DisplayFeed(void);
void setColor(std::string color);
void refresh(std::vector<Event*> *thingsToInclude);
private:
Logic* logic;
private slots:
void editItem(QEventStore *item);
};
Below is the .cpp file. QEventStore extends QListWidgetItem. I placed the MessageBox to test the system as well, in case it was my other code that didn't work.
# .cpp file, only relevant methods included
DisplayFeed::DisplayFeed(QWidget *parent, Logic *logic, int xpos, int ypos, int width, int height, std::string color)
: QListWidget(parent)
{
this->logic = logic;
setGeometry(xpos, ypos, width, height);
setColor(color);
QObject::connect(this, SIGNAL(itemClicked(QEventStore*)), this, SLOT(editItem(QEventStore*)));
show();
}
void DisplayFeed::editItem(QEventStore *item){
QMessageBox::information(this,"Hello!","You clicked \""+item->text()+"\"");
QEventEditor *editor = new QEventEditor(item->getEvent());
}

You forgot the Q_OBJECT macro in your DisplayFeed class. It should be like :
# .h file
class DisplayFeed :
public QListWidget
{
Q_OBJECT
public:
DisplayFeed(QWidget *parent, Logic *logic, int xpos, int ypos, int width, int height, std::string color);
~DisplayFeed(void);
void setColor(std::string color);
void refresh(std::vector<Event*> *thingsToInclude);
private:
Logic* logic;
private slots:
void editItem(QEventStore *item);
};
That's the first thing I noticed and may solve your problem. If not I'll look deeper.
EDIT: Read the first answer here

There are several changes to do:
Add Q_OBJECT in the .h of displayFeed class
class DisplayFeed : public QListWidget
{
Q_OBJECT
...
};
Change your slot with a public slot and a QListWidgetItem* parameter
public slots:
void editItem(QListWidgetItem *item);
Connect with the good SIGNAL which have the same parameter that your SLOT
connect(this,SIGNAL(itemDoubleClicked(QListWidgetItem*)), this,SLOT(editItem(QListWidgetItem*)));
This works fine for me, hope it helps you.

I have found the answer. The problem is that the default signal for itemDoubleClicked emits the QListWidgetItem* and emitting a subclass of that doesn't work. So what I had to do was to go to editItem and get it to dynamic_cast the QListWidgetItem* to a QEventStore*

Related

Qt/C++ - Call of overriden method from derived class

I have the following code:
void AppMPhase::closeEvent(QCloseEvent *closeEvent) {
QMessageBox* dialog = new QMessageBox(this);
dialog->setText("Warning: Initial configuration changed\nDo you want to restore it ?");
dialog->setIcon(QMessageBox::Warning);
dialog->addButton(QMessageBox::Yes);
dialog->addButton(QMessageBox::No);
connect(dialog, SIGNAL(buttonClicked(QAbstractButton*)), this, SLOT(restoreInitialConfig(QAbstractButton*)));
dialog->exec();
}
void AppMPhase::restoreInitialConfig(QAbstractButton *button) {
if(!button->text().compare(QString("Yes"))) {
// restore Config
}
else {
// don't restore
}
MainWindow::closeEvent(closeEvent);
}
with AppMPhase the derived class of MainWindow
I would like to call the method closeEvent of the base class MainWindow in the "restoreInitialConfig" method, to close the window after we restore the config.
Is it possible ? it's different from the other questions I have seen because the method closeEvent is overriden in the AppMPhase class.
the AppMPhase class:
class AppMPhase : public QtUi::MainWindow
{
Q_OBJECT
public:
AppMPhase(QWidget *const parent = Q_NULLPTR, const Qt::WindowFlags flags = 0);
~AppMPhase();
int readConfigFromExternFile(QString path);
int readCalibrationDate(QString path);
QSize sizeHint() const Q_DECL_OVERRIDE;
QtWrapperTestManager * testManager;
public Q_SLOTS:
void show();
public slots:
void currentTestFinished();
void createTest(unsigned int,QString);
void restoreInitialConfig(QAbstractButton* button);
signals:
void notifyPageTestCurrentTestFinished();
private:
enum AppPage
{
PAGE_START,
PAGE_ABOUT
};
bool isTestMangaerCreated;
std::map<QString, std::map<std::string, std::string> > conversion_Table_Cable_Ref_sensorParamMap;
Pages::GenericAppPage * appPage(const int index) const;
QToolButton * appPageButton(const int index) const;
virtual void closeEvent(QCloseEvent *closeEvent) Q_DECL_OVERRIDE;
The MainWindow class:
class SHARED_EXPORT_LIB_QT_UI MainWindow : public QMainWindow
{
Q_OBJECT
signals:
void aboutToClose();
public slots:
virtual void show();
private slots:
void changeLanguage(const QString &language);
public:
MainWindow(QWidget *const parent = Q_NULLPTR, const Qt::WindowFlags flags = 0);
virtual ~MainWindow();
protected:
void showCopyright(const QString &copyRightHeader);
void showLanguageSelector(const QStringList &languages);
void setupUi(const MainPageList &pageList);
void setupUi(QWidget *centerWidget = Q_NULLPTR);
virtual void closeEvent(QCloseEvent *closeEvent) Q_DECL_OVERRIDE;
const Ui::MainWindow *const _ui;
MainPageItemList _mainPageItemList;
};
Thanks in advance.
Flo
There is a far easier way to achieve what you're wanting to do, without having to use signals and slots, and call base class functions from your slot.
It is possible to do the restoration directly from within your closeEvent handler.
This is made possible by the fact that QMessageBox::exec returns an integer code which matches one of the values in the StandardButton enum, depending on what button was pressed.
That then allows you to call restoreInitialConfig directly from within your closeEvent handler, as you know which button was pressed.
void AppMPhase::closeEvent(QCloseEvent* ev)
{
int res = QMessageBox(
QMessageBox::Icon::Warning,
"Restore configuration?",
"Warning: Initial configuration changed\nDo you want to restore it?",
QMessageBox::Yes | QMessageBox::No,
this).exec();
if (res == QMessageBox::Yes)
restoreInitialConfig();
MainWindow::closeEvent(ev);
}
Note that this also simplifies your restoreInitialConfig function, as there is no need to check button text, you know the answer was yes.
Note also I made use of this QMessageBox constructor which makes it very easy to create simple message boxes.

QT extend MainWindow to other class or diffrent way

I have class printrectangle
class PrintRectangle : public QWidget
{
Q_OBJECT
public:
explicit PrintRectangle(QWidget *parent = 0);
private:
void resetClickedIndex();
void updateIndexFromPoint( const QPoint& point);
public:
int mXIndex;
int mYIndex;
QVector<QPoint> points;
bool clicked[5][5] = {};
teacher tech;
perceptron p[5][5];
double techconst = 0.1;
signals:
public slots:
protected:
void paintEvent(QPaintEvent *);
void mousePressEvent(QMouseEvent *eventPress);
};
and MainWindow
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_learn_clicked();
void on_classify_clicked();
private:
Ui::MainWindow *ui;
};
When I click button I call to on_learn_clicked() function. I would like to transfer clicked[5][5] array into on_learn_clicked becasue I send this array to other object when user click button. How to do this?
It is not clear what is exactly the relation between MainWindow and the PrintRectangle widget. I suppose the button signal and PrintRectangle slot are connected somewhere in the MainWindow implementation.
One way to solve the problem would be to use to use the QSignalMapper as #Noidea stated.
Another way would be to use a lambda as a slot when connecting. This way you could capture the sender/receiver or other objects in scope and use their members.
You can find some information about the connect syntax in New Signal Slot Syntax
But basically you could write something like:
connect(button, &QPushButton::clicked, this, [this, printRectangle]()
{
// do smth with clicked[5][5] from printRectangle or just
// retrieve it and call another method like:
// this->processClicked(printRectangle->clicked);
// or pass it to another object
}
This way you could modify your on_classify_clicked slot to a regular method with bool[5][5] argument to do the processing.

Qt, using OpenGL, QGLWidget is private

I'm quite new to Qt. I wanted to create a simple application where there's triangle generated using OpenGL and three push buttons changing that triangle colour. Unfortunately I get an error:
E:\Programy\Qt\5.3\mingw482_32\include\QtOpenGL\qgl.h:457: error: 'QGLWidget::QGLWidget(const QGLWidget&)' is private
Q_DISABLE_COPY(QGLWidget)
I don't know what to do. Here's my code:
MainWindow.h
class MainWindow : public QMainWindow
{
Q_OBJECT
QVBoxLayout *layout;
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QPushButton *redButton;
QPushButton *greenButton;
QPushButton *blueButton;
public slots:
void redSlot(Widget w);
void greenSlot(Widget w);
void blueSlot(Widget w);
};
Slots in MainWindow.cpp look like this:
void MainWindow::redSlot(Widget w)
{
w.setColor(red);
}
Widget.h
class Widget : public QGLWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
QSize minimumSizeHint() const;
QSize sizeHint() const;
enum color c;
void setColor(enum color color1);
protected:
void initializeGL();
void paintGL();
void resizeGL(int width, int height);
};
enum color is just an enum declared ina another header file
enum color
{
red,
green,
blue
};
Your Slots
void redSlot(Widget w);
void greenSlot(Widget w);
void blueSlot(Widget w);
all take a Parameter of Type Widget. This tries to create a copy of the object when called. Your Widget is a subclass of QGLWidget which has a private copy constructor and therefore can't be called from a subclassed object.
As you want to change the color of an existing object and not a copy of it you should change the functions to take a pointer of that object:
void redSlot(Widget*);
void greenSlot(Widget*);
void blueSlot(Widget*);
void MainWindow::redSlot(Widget* w)
{
w->setColor(red);
}

Inheriting from Custom Widget

I have one abstract class, TableWidget, which inherits from QWidget. It implements paintEvent.
class TableWidget : public QWidget
{
Q_OBJECT
private:
int width;
int height;
public:
explicit TableWidget(QWidget *parent = 0);
virtual int getWidthInCells() = 0;
virtual int getHeightInCells() = 0;
virtual QString getCellText(byte x, byte y) = 0;
virtual QString getColumnLabel(byte a) = 0;
virtual QString getRowLabel(byte a) = 0;
byte getCellHighlight(byte x, byte y);
void setCellHighlight(byte x, byte y, bool highlighted);
void setHeight(int h);
void setWidth(int w);
protected:
void paintEvent(QPaintEvent *e);
signals:
public slots:
};
I tried testing TableWidget out with a dummy class with next to no functionality.
class DummyTable : public TableWidget {
public:
explicit DummyTable(QWidget *parent = 0) {}
int getWidthInCells() {return 2;}
int getHeightInCells() {return 2;}
QString getCellText(byte x, byte y) {return "0";}
QString getColumnLabel(byte a) {return QString(a);}
QString getRowLabel(byte a) {return QString(a);}
};
The problem is that paintEvent (implemented in TableWidget.cpp), is never called. The first mistake I noticed was the absence of the Q_OBJECT macro in DummyTable. I added it in and tested it, but this resulted in a failure to terminate correctly. I had to completely exit out of QT to kill the process. I looked into QPushButton and it seemed to do things the same as me, except for the inclusion of Q_OBJECT.
So, how can I get paintEvent to be called properly?
How have you added your DummyTable instance to the parent window?
You could try calling on the parent window the debug method dumpObjectTree ( http://qt-project.org/doc/qt-4.8/qobject.html#dumpObjectTree ) to check that your instance is correctly parented.
Also you could try implementing showEvent(...) and instrumenting that to check the widget is actually being displayed.
Have you looked at QTableWidget? Does it not do what you need? http://qt-project.org/doc/qt-4.8/qtablewidget.html
Regarding the QObject macro you only need that in classes where you're creating signal and slot connections, or using some of the other meta-programming features of Qt (such as properties). Its not likely to be the root cause of your issues.
You may need to give your widget a proper width and height. If it has no size, paintEvent will not be called.
It turned out to be a pretty stupid mistake. I wasn't calling the parent class's constructor.

How can I change the application size in other classes not mainwindow class?

I need to change the mainwindow or the native app size width x height in other class not in the mainwindow class. How can I do this?
void OptionsDialog::resetWindowLayoutClicked(QResizeEvent* event) {
QMainWindow::resize(640, 483);
}
This is my first try but with no happiness.
I would make a signal and connect it to a slot in the main window.
For example:
class OptionsDialog : public QDialog
{
Q_OBJECT
signals:
void resize(int w, int h);
};
class MainWindow : public QMainWindow
{
Q_OBJECT
private slots:
void resizeRequest(int w, int h);
};
void OptionsDialog::resetWindowLayoutClicked(QResizeEvent* event)
{
emit resize(640, 483);
}
When you create the OptionsDialog, connect the signal like this:
OptionsDialog* d = new OptionsDialog(this);
connect(d, SIGNAL(resize(int,int)), this, SLOT(resizeRequest(int,int)));
And implement the slot:
void MainWindow::resizeRequest(int w, int h)
{
resize(w, h);
}
You need to get pointer to main window class i assume and change it from that, try passing pointer to it in new class constructor.
public OptionsDialog(const QMainWindow * mainWindow) { // class constructor
m_qWinPtr = mainWindow // this is some class member
}
void OptionsDialog::resetWindowLayoutClicked(QResizeEvent* event) {
m_qWinPtr->resize(640, 483);
}