PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [QT] connect mit Methodenzeigern



Gartenzwerg
13-02-2004, 06:47
Hallo!

Ich habe folgendes Problem:
Ich habe 5 Knöpfe und möchte die in einem Array speichern und entsprechend initialisieren, dafür habe ich folgende Struktur erstellt:



struct Buttons
{
typedef void (OptionChangeWindow::*PtrToSlot)( void);
QString Name;
PtrToSlot Slot;
};
Buttons MyButtons[2] =
{
{"Hinzufügen", &OptionChangeWindow::AddOption},
{"Ändern", &OptionChangeWindow::ChangeOption},
};

Mein connect sieht wie folgt aus:


connect(mCommands[i].get(), SIGNAL(clicked()), this, SLOT( MyButtons[i].Slot ) );

Wobei mCommands ein vector von boost::shared_ptr auf die QPushButtons ist.
Das Problem liegt beim letzten Parameter und zwar wird das MyButtons[i].Slot nicht aufgelöst zu der wirklichen Memberfunktion, sondern einfach als String genommen.
Der Laufzeitfehler ist dann folgender:


QObject::connect: Parentheses expected, slot OptionChangeWindow::MyButtons[i].Slot

Kann man eventuell ein eigenes Makro schreiben, das den Zeiger vorher dereferenziert und das ganze dann in einen String umwandelt oder gibt es eine viel einfachere Lösung?

tuxipuxi
13-02-2004, 15:33
hi,

gibt es irgendeinen grund warum du sowas probierst? mir erschliesst sich gerade nicht so ganz der sinn deiner methode.

aber um deine frage teilweise zu beantworten:
als receiver muss eine funktion angegeben werden, die ausdrücklich als slot definiert wurde.
http://www.trolltech.com/products/qt/whitepaper/qt-whitepaper-3.html

gruss,
michael.

Gartenzwerg
13-02-2004, 16:17
hi,
warum ich das probiere?
Ich habe ja nun ein paar mehr Buttons mit Slots zu connecten und da empfinde ich das als reichlich ineffektiv alle einzeln zu connecten. Das sollte eine for-Schleife für mich machen.
Das Dokument hilft mir nicht wirklich, da mir das Signal-Slot-Prinzip vertraut ist. Die unter connect angegebenen Funktionen im SLOT-Bereich sind auch als public slots: in meiner Klasse definiert.
Gibt es da keine Möglichkeit?

Tschau Gartenzwerg

axeljaeger
13-02-2004, 16:20
Das was du vorhast, ist gängig, aber deine Umsetzung ist unüblich. Wenn du mehrere Buttons hast und alle sollen mit einem Slot conntected werden, nimmst du eine QButtonGroup, packst die Buttons rein und verbindest das clicked-signal der Group mit deinem Slot.

Gartenzwerg
13-02-2004, 16:41
hi,
die Buttons sollen ja nicht alle mit dem selben Slot verbunden werden. Wenn ich für jeden Slot eine Gruppe Buttons erstelle, habe ich immer noch die selbe Arbeit.

Tschau Gartenzwerg

axeljaeger
13-02-2004, 16:47
Anstatt dem connect-aufruf musst du ja jetzt den Funktionspointer in deine Struktur schreiben. Das ist eine Zeile Code. Der connect-Aufruf wäre auch eine Zeile Code. was findest du jetzt an deiner Lösung so viel eleganter?

microdigi
13-02-2004, 16:54
...die fuenf knoepfe an die jacke naehen.
das sieht dann so aus: :) :) :) :) :)
gruss mit spass - digi

tuxipuxi
13-02-2004, 17:23
Original geschrieben von axeljaeger
Anstatt dem connect-aufruf musst du ja jetzt den Funktionspointer in deine Struktur schreiben. Das ist eine Zeile Code. Der connect-Aufruf wäre auch eine Zeile Code. was findest du jetzt an deiner Lösung so viel eleganter?

zudem frage ich mich, wieviele buttons du erstellen willst, dass es dir zuviele aufrufe sind :).
20? 200? ;)

Gartenzwerg
13-02-2004, 17:34
hi,
hab mir schon Nadel und Faden besorgt ;)
Es geht ja auch ein bisschen um das Design und die Übersichtlichkeit.
Das sieht doch wohl wesentlich besser und übersichtlicher aus ...


struct Buttons
{
typedef void (OptionChangeWindow::*PtrToSlot)( void);
QString Name;
PtrToSlot Slot;
};

Buttons MyButtons[2] =
{
{"Hinzufügen", &OptionChangeWindow::AddOption},
{"Ändern", &OptionChangeWindow::ChangeOption},
};

for(unsigned int i = 0; i < sizeof(MyButtons) / sizeof(Buttons); ++i)
{
//Einen neuen Button erzeugen mit entsprechendem Namen
mCommands.push_back(boost::shared_ptr<QPushButton>(new QPushButton(this, MyButtons[i].Name)));
mCommands[i]->setGeometry(130, 20+40*i, 70, 30);
mCommands[i]->show();
mCommands[i]->setText(MyButtons[i].Name);
connect(mCommands[i].get(), SIGNAL(clicked()), this, SLOT( MyButtons[i].Slot ) );
// Verursacht: "QObject::connect: Parentheses expected, slot OptionChangeWindow::MyButtons[i].Slot"
}

als das:


struct Buttons
{
typedef void (OptionChangeWindow::*PtrToSlot)( void);
QString Name;
PtrToSlot Slot;
};

Buttons MyButtons[2] =
{
{"Hinzufügen", &OptionChangeWindow::AddOption},
{"Ändern", &OptionChangeWindow::ChangeOption},
};

for(unsigned int i = 0; i < sizeof(MyButtons) / sizeof(Buttons); ++i)
{
//Einen neuen Button erzeugen mit entsprechendem Namen
mCommands.push_back(boost::shared_ptr<QPushButton>(new QPushButton(this, MyButtons[i].Name)));
mCommands[i]->setGeometry(130, 20+40*i, 70, 30);
mCommands[i]->show();
mCommands[i]->setText(MyButtons[i].Name);
//TODO klappt noch nicht so ganz!
//connect(mCommands[i].get(), SIGNAL(clicked()), this, SLOT( MyButtons[i].Slot ) );
}
//Ich geb mich erstmal geschlagen und connecte sie manuell
connect(mCommands[0].get(), SIGNAL(clicked()), this, SLOT(AddOption()));
connect(mCommands[1].get(), SIGNAL(clicked()), this, SLOT(ChangeOption()));

oder etwa nicht?
Des Weiteren ist es einfacher zu warten, das spielt auch eine gewisse Rolle.
Außerdem habe ich das jetzt solange ausprobiert, dass es mich brennend interessiert, wie das funktionieren könnte, ob es etwas nutzt oder nicht. Ich würde es gerne wissen.

Tschau Gartenzwerg

axeljaeger
13-02-2004, 18:29
Ein Slot ist kein Funktionspointer, sondern ein String. Das du deine eine gebastelte Lösung eleganter findest, als die andere gebastelte Lösung, ist nachzuvollziehen, warum du aber überhaupt den QPushButton nochmal in eine Struct kapselst, wo doch Struct in einem C++Programm sowieso fragwürdig ist, nicht.

Gartenzwerg
13-02-2004, 18:38
hi,
ich könnte den QPushButton auch in einer Klasse kapseln. Das ist unwichtig.
Das SLOT-Makro sieht wie folgt aus:


#define SLOT(a) "1"#a

oder nicht?

Könnte man das denn irgendwie umschreiben?

Tschau Gartenzwerg

axeljaeger
13-02-2004, 18:54
Warum willst du den überhaupt in eine Klasse kapseln? Ist dir QPushButton noch nicht genug gekapselt?

Gartenzwerg
13-02-2004, 18:56
hi,
ich habe doch gesagt, ich könnte! Ich habe nicht gesagt, dass ich das will. Ich würde gern ein Methodenzeiger an SLOT übergeben. Dafür hätte ich gerne einen Lösungsvorschlag oder eine Makroveränderung.

Tschau Gartenzwerg

axeljaeger
13-02-2004, 19:03
du könntest einen Slot in einem String speichern, einfach den Returnvalue von SLOT in einen String schreiben und dann bei connect wieder übergeben. Ich möchte dir aber davon abraten, das perfekt aufeinander abgestimmte System von Signal/Slot/Connect auseinanderzunehmen. Da hast du wirklich nichts davon. Sinn der Sache ist es, keine Funktionspointer mehr zu verwenden. Wenn du das doch machen willst, siehst du dir vielleicht besser GTK an. Wenn du wirklich verstehen willst, was innerhalb von Qt abgeht und wie das mit Signals und Slots funktioniert, schau dir nochmal an, was der MOC so an Ausgaben erzeugt.

anda_skoa
14-02-2004, 14:23
Du brauchst ansich nur den Namen des Slots in einem QCString in des Struct zu speichern.
Dann kannst du das so aufrufen



connect(myCommands[i], SIGNAL(clicked()), this, SLOT(myButtons[i].slot));


Da die Buttons offensichtlich nicht dynamisch erzeugt werden, sondern feststehen, frage ich mich ob es nicht sinnvoller wäre sie direkt im Designer anzulegen und zu connecten. Die Slots dabei als virtual protected oder virtual public im Hauptwidget und dann mit ihrer Implementation überschreiben.

Cheers,
_