PDA

View Full Version : QAction signal: want to send int



vonCZ
30th June 2007, 17:13
I've a button with menus like so:


pButton2 = new QPushButton(tr("&Terrain"));
menu = new QMenu(this);
action1 = menu->addAction(tr("Topography"));
action2 = menu->addAction(tr("Landsat"));
pButton2->setMenu(menu);

connect(action1, SIGNAL(triggered()), this, SLOT(mySlot(1))); //wrong
connect(action2, SIGNAL(triggered()), this, SLOT(mySlot(2)));


I know why this doesn't work: triggered() has no parameters, mySlot(int) has one. I could fix this by making 2 separate mySlot() functions that don't take parameters, but I'm going to have alot of these and was wondering if there's another, better way to do it... a way such that I can create a single SLOT function.

Michiel
30th June 2007, 17:24
That is a common mistake. Signals and slots don't work that way. You could of course create a custom slot for each signal, as you said. But there is a better way. Check out the QSignalMapper class.

vonCZ
30th June 2007, 18:51
thanks Michiel. I'm trying out QSignalMapper now but having a problem. This is my first attempt at subclassing:

my .h file:

#ifndef TEXTUREACTION_H
#define TEXTUREACTION_H

#include <QWidget>
#include <QSignalMapper>
#include <QAction>
//class QSignalMapper;
//class QAction;

class TextureAction : public QAction
{

Q_OBJECT

public:
TextureAction(QObject *parent);

signals:
void clicked(int value);

private:
QSignalMapper *signalMapper;

};

#endif

my .cpp file:

#include "textureAction.h"

#include <QAction>

TextureAction::TextureAction(QObject *parent)
: QAction(parent)
{

signalMapper = new QSignalMapper(this);

QAction *act = new QAction; //chokes here

// connect(action, SIGNAL(triggered()), signalMapper, SLOT(map()));
// signalMapper->setMapping(action, value);


}

compilation chokes on the QAction line above (with comment). The error message is:

error C2512: 'QAction' : no appropriate default constructor available

As I said, this is my first attempt at subclassing. I looked on the web and "C++ GUI Programming with Qt4" for examples of subclassing QAction; I couldn't find any. I'm not sure why, for example, in the QSignalMapper link you provided, why they subclass from QWidget instead of QPushButton. I tried subclassing from QObject instead of QAction, but it still wouldn't compile.

Any tips?

Michiel
30th June 2007, 21:07
The error has nothing to do with your subclass. You simply forgot the parent parameter for the QAction constructor. :)

The example subclassed from a QWidget because the result is supposed to be a keypad with multiple QPushButtons. Not a single QPushButton. (The keypad IS-A widget. It's not a pushbutton.)

vonCZ
2nd July 2007, 11:17
oh yeah... my bad. Thanks.

I'm still stuck (predictably). In short, what I'm trying to do is create a class--TextureAction--that is a subclass of QAction and behaves exactly like QAction, except for two things:

1) TextureAction will have a variable, int myValue, that can be set by a member function, mySetVariable.

2) my TextureAction class will have a QSignalMapper object to take QAction's triggered() SIGNAL, pass it to my QSignalMapper SLOT, and then signal this back out as an integer. Sounds simple enough, but when I instantiate a TextureAction object, I get the following error:


error C2440: '=' : cannot convert from 'QAction *' to 'TextureAction *'
Cast from base to derived requires dynamic_cast or static_cast

textureAction.h and .cpp look like this:

#include <QSignalMapper>
#include <QAction>

//#include <QWidget>
//class QSignalMapper;
//class QAction;

class TextureAction : public QAction
{

Q_OBJECT

public:
// TextureAction(int value, QObject *parent);
TextureAction(QAction *parent);

void setValue(int x) { Value = x; }

signals:
void myClicked(int value);

private:
QSignalMapper *signalMapper;
int Value;

};

//+++ and .cpp below
#include "textureAction.h"

#include <QAction>


TextureAction::TextureAction(QAction *parent)
: QAction(parent)
{

signalMapper = new QSignalMapper(this);

QAction *myAction = new QAction(this);

// connect(myAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
// signalMapper->setMapping(myAction, Value);

// connect(signalMapper, SIGNAL(mapped(Value)), this, SIGNAL(myClicked(Value)));


}

In my Window.cpp code (my main Qt application window) I'm declaring a TextureAction object like so:


pButton2 = new QPushButton(tr("&Terrain\n Texture"));
menu = new QMenu(this);
tAction1 = menu->addAction(tr("Topography")); // TextureAction *tAction1; declared in .h file
//tAction1 = new TextureAction; //this also fails

If my TextureAction class is derived from QAction, can't I use a TextureAction object in nearly the same way as I could a QAction object? (like add it to the QMenu, as I've done above?)

jpn
2nd July 2007, 11:24
There is no need to subclass QAction for this:


QSignalMapper* mapper = new QSignalMapper(pButton2);
mapper->setMapping(action1, 1);
mapper->setMapping(action2, 2);
connect(action1, SIGNAL(triggered()), mapper, SLOT(map()));
connect(action2, SIGNAL(triggered()), mapper, SLOT(map()));
connect(mapper, SIGNAL(mapped(int)), this, SLOT(mySlot(int)));

vonCZ
2nd July 2007, 11:41
jpn: BEAUTIFUL! my apologies for being such an idiot.:o

Michiel
2nd July 2007, 11:49
Oh, so that's why you wanted a subclass. :)

For good measure, you should be able to add your QAction subclass to a QMenu, no problem. You were just doing it wrong.

QMenu::addAction(QString), as you've used, creates a new action (a QAction), places it in the menu and returns a pointer to it. It doesn't use your own class. The assignment there is what causes your error.

What causes the second error ('this also fails') is that you forgot the parent argument of the constructor again.

Back to adding it to the menu, though. There's a function for adding an action that you've already created yourself. QWidget::addAction(QAction*).

Good luck.

vonCZ
2nd July 2007, 12:16
Oh, so that's why you wanted a subclass. :)
yeah... as you've probably guessed, I'm pretty new at this stuff, so often when I find an example of how I might solve a problem, I tend to stick to it... often too closely. Trolltech's example on their QSignalMapper page uses a subclassed Widget to implement the class... so i figured, why not? :rolleyes:


QMenu::addAction(QString), as you've used, creates a new action (a QAction), places it in the menu and returns a pointer to it. It doesn't use your own class. The assignment there is what causes your error.This should've been obvious.


What causes the second error ('this also fails') is that you forgot the parent argument of the constructor again.I tried a variety of options, including:


tAction(pButton2) = new TextureAction;
tAction(menu) = new TextureAction;
tAction(this) = new TextureAction;
tAction(parent) = new TextureAction;
none of which worked.



Back to adding it to the menu, though. There's a function for adding an action that you've already created yourself. QWidget::addAction(QAction*).
Thanks. I will try this when I need to add a subclass QAction. Thanks for your help.

Michiel
2nd July 2007, 12:31
yeah... as you've probably guessed, I'm pretty new at this stuff,

Your mistakes indicate you just need some more C++ experience. I always say it's a mistake to start off with event-driven programming and/or big fat OOP libraries (so, Qt). You should first understand classes, pointers and all those other good things.


This should've been obvious.

I tried a variety of options, including:


tAction(pButton2) = new TextureAction;
tAction(menu) = new TextureAction;
tAction(this) = new TextureAction;
tAction(parent) = new TextureAction;
none of which worked.
:p

tAction = new TextureAction(this);

vonCZ
2nd July 2007, 18:52
I always say it's a mistake to start off with event-driven programming and/or big fat OOP libraries (so, Qt).
perhaps, depending on one's situation. I've been writing command-line, data-processing programs for years... compiling w/gcc, but rarely making use of even the simplest OOP functionality, because I could get by without it. No longer: Qt forces one's hand.

anyhow, thanks again for the tips. & trust me: i'm consulting my Schildt book along with Blanchette/Summerfield.:D