6

Okay I'm using Qt Designer to build a GUI. I've managed to figure out how to make the menuBar and I've added some actions to the bar, but now I need to connect the actions to make them do something.

Specifically, on my file menu, I have the simple open action. I want this action to run a function that calls my QFileDialog and so on, but I don't know how to do this.

So, how do I connect my actionOpen to my static function?

I am using the latest Qt, 5.0.2

I'm a little frustrated here. This is obviously one of the most basic things someone might need to do, yet I cannot find any real solution to this anywhere on the web. From the lacking Qt wiki, to other people's questions, nobody really seems to have a clear answer. There are answers for older versions of Qt, yet in those old versions apparently signals couldn't connect to static functions, so those are irrelevant. And nobody seems to know how to do this through the Qt Designer. Also, nobody ever clarifies where to put what.

I have this line in my main.cpp file:

QObject::connect(actionOpen, &actionOpen::triggered, fileOpen)

I have an object called 'actionOpen' made in Qt Designer, there is a signal called triggered, and I have a function defined just below my main inside main.cpp called 'fileOpen'. This seems to follow the proper syntax, yet it throws many errors.

Also, I can repeatedly click build in Qt Creator and every single time it comes up with a different number of errors, disappearing and reappearing, without me even touching the code. I'm starting to think this IDE is sort of a POS.

EDIT:

Here are my files. Maybe this will help somewhat.

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    void fileOpen();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <iostream>
#include <fstream>

using namespace std;


int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;

    w.show();


    return a.exec();
}

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>

using namespace std;



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    QObject::connect(ui->actionOpen, &QAction::triggered, &MainWindow::fileOpen);
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;

}

void fileOpen()
{

    /*
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), QString(),
        tr("Text Files (*.txt);;C++ Files (*.cpp *.h)"));

    if (!fileName.isEmpty()) {
        QFile file(fileName);
        if (!file.open(QIODevice::ReadOnly)) {
            QMessageBox::critical(this, tr("Error"), tr("Could not open file"));
            return;
        }
        QTextStream in(&file);
        ui->textEdit->setText(in.readAll());
        file.close();
    }
    */

    cout << "Hello!";
}
krb686
  • 1,726
  • 9
  • 26
  • 46
  • 1
    This is not 'one of the most basic things'. Signals are usually connected to slots which are non-static member functions of QObject-derived classes. I recommend you to use the regular slots. Connecting to a static function should be used if it's really required. – Pavel Strakhov Jun 17 '13 at 17:18
  • @Riateche So how would I go about that? Are you saying I need to create my own class for the actionOpen object, inheriting from QObject, and give it a member function to run? That seems a little bogus, having to create a class for every object and action in Qt Designer I want to use. I can see typically signals are sent from an object to a slot of another object, but for a simple open file command, there is no receiver object. I don't understand how that model of connecting them works in that case. – krb686 Jun 17 '13 at 17:22
  • Possible duplicate?: http://stackoverflow.com/questions/9428038/is-it-possible-to-connect-a-signal-to-a-static-slot-without-a-receiver-instance – Tyler Jandreau Jun 17 '13 at 17:23
  • @TylerJandreau Nope, I've read that post, and my question still isn't answered. That post refers to the old syntax, and the top answer links to a page on the new syntax, which I've also read and am still confused about. – krb686 Jun 17 '13 at 17:25
  • Sorry dude I've never tried to do this. I wish I could help. – Tyler Jandreau Jun 17 '13 at 17:26
  • Typically top level widget is an object of your class inherited from QWidget (or QMainWindow), and most signals are connected to slots of this object. It's very convenient. You really need to take a look at Qt examples. – Pavel Strakhov Jun 17 '13 at 17:29

2 Answers2

6

The second argument is incorrect. You should specify the class name, not object name. So it should be:

QObject::connect(actionOpen, &QAction::triggered, fileOpen);

Complete working example (tested):

void fileOpen() {
  qDebug() << "ok";
}

int main(int argc, char *argv[]) {
  QApplication a(argc, argv);
  QMenu menu;
  QAction* actionOpen = menu.addAction("test");
  QObject::connect(actionOpen, &QAction::triggered, fileOpen);
  menu.show();
  return a.exec();
}
Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
  • Okay this makes sense. Now I've managed to remove all of the errors except one. Now I'm getting "actionOpen" : undeclared identifier. I'm guessing this is because actionOpen isn't declared anywhere in the code. I created it in the ui file so it only exists in the 'mainwindow.ui' xml type file. So how do I reference something in that file? Or do I need to declare it in code separately? – krb686 Jun 18 '13 at 14:43
  • I moved the connect call to the mainwindow.cpp file instead of main.cpp, that seems to be the only place I can access fileOpen, using ui->fileOpen, then I get the error MainWindow::fileOpen 'function call missing argument list, use &MainWindow::fileOpen to create a pointer, I try using that, and it gives 'void QtPrivate::FunctionPointer::call...cannot convert parameter 2 from QObject* to mainwindow. I have no clue what's going on. I'm a noob at c++ and this is way too confusing to me. All I want to do is connect to the simple function called fileOpen, why can't this be simple. – krb686 Jun 18 '13 at 15:06
  • Did you wrote `MainWindow::fileOpen`? It's incorrect. Or what is your exact code you're trying to compile? – Pavel Strakhov Jun 18 '13 at 15:08
  • I've tried it both ways, with the function declared just with 'void fileOpen', and also 'void MainWindow::fileOpen', neither of them work. – krb686 Jun 18 '13 at 15:10
  • I edited my original post and pasted the code from my files. Maybe you can spot the error now. – krb686 Jun 18 '13 at 15:14
  • Now you're trying to use the same syntax for connecting to a non-static function. You can't do that! You need to use 4 arguments now. 3rd is a pointer to MainWindow object, and 4th is a pointer to the method. Please read `connect` documentation. You're using [this](http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#connect-5) method, and you need to use [this](http://qt-project.org/doc/qt-5.0/qtcore/qobject.html#connect-4). – Pavel Strakhov Jun 18 '13 at 15:41
  • Okay that's true, but that wasn't the final error. I messed around with it and figured it out. Earlier I was trying to use the old syntax by making fileOpen a slot, under public slots: in mainwindow.h Because of that, the connect function thought I was referring to that declared function, not the fileOpen declared in the very same file. So I deleted the entire public slots portion and changed it to just fileOpen in the connect call and it works great. Thanks for the help. – krb686 Jun 18 '13 at 15:53
-1

1.) Create regular slot and call the static function.

OR

2.) I suppose you could create a singleton Q_OBJECT class and connect to it - of course like option 1 you'd then make the call to whatever static/global function.

/**
 * Pseudo-code!, the singleton should be in its own header file 
 * not in the global main.cpp file.
 */
class Singleton : public QObject
{
Q_OBJECT
public:
  Singleton() : QObject() {}
  static Singleton* getInstance() {
    if(!_instance) _instance = new Singleton();
    return _instance;
  }
public slots:
  void mySlot() { qDebug() << __FILE__ << " " << __FUNCTION__ << __LINE__;
  }
private:
  static Singleton* _instance;
};

Singleton* Singleton::_instance = NULL;

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  MainWindow w;
  w.show();

  Singleton* instance = Singleton::getInstance();
  QObject::connect(&w, SIGNAL(destroyed()), instance, SLOT(mySlot()));

  return a.exec();
}

I'm just trying my best to answer the question, but like many of the comments above - this isn't something that I've needed ever needed to do. I can say that QtCreator/Designer is a really amazing tool and as you overcome some of the learning curves it'll be less frustrating.

Son-Huy Pham
  • 1,899
  • 18
  • 19