Seite 1 von 1
eigener QEvent
Verfasst: 6. Februar 2011 01:06
von ole
Hallo,
Folgendes Szenario:
Ich habe eine Qt Applikation, in welcher viele Klassen existieren, unter anderm auch eine Klasse "MyButton" welche abgeleitet ist von QPushButton. So ein Knopf befindet sich zum Beispiel in einem QWidget, und das in einem QWidgetStack, welches wiederrum dem Hauptfenster (also QMainWindow) gehört.
Nun möchte ich auf jeden Knopfdruck eben dieser "MyButton" Knöpfe eine Reaktion implementieren, jedoch ohne explizit jeden Knopf per Signal und Slot bis zum QMainWindow durchzuschleifen.
Also im Prinzip möchte ich irgendwie in meinem Hauptfenster rausbekommen, wenn ein "MyButton" gedrückt wurde, wobei diese Knöpfe in "Unterwidgets" sind, die wiederrum dem Hauptfenster zugehörig sind.
Bis dato habe ich Folgendes versucht:
eigener QEvent:
Code: Alles auswählen
class QMyEvent : public QEvent
{
public:
QMyEvent () : QEvent((QEvent::Type)1111) {}
};
Dann bei jedem Knopfdruck:
Code: Alles auswählen
void MyButton::onClickedSlot(void)
{
QMyEvent *eve;
eve = new QMyEvent ();
qApp->postEvent(this, eve);
}
Und in dem MainWindow in der eventFilter Funktion:
Code: Alles auswählen
bool MyMainWindow::eventFilter(QObject *object, QEvent *event)
{
if (event->type() == 1111)
{
qDebug("Beep\n");
}
return QMainWindow::eventFilter(object,event);
}
Die eventFilter Funktion wird nun schon betreten, aber er geht nie in die if Anweisung wenn ich so einen Knopf drücke...
Kann mir da vielleicht bitte jemand einen Tipp geben? War der Gedanke das so zu machen verkehrt?
Viele Grüße
Verfasst: 6. Februar 2011 01:31
von upsala
Ein QEvent::type() hat nicht die Nummer 1111, sondern QEvent::User+x. Bzw. seit Qt4.4 gibt es sogar
Dann sendest du das Event an den Button selbst. Du must es aber an den gewünschten Empfänger schicken.
Und wenn du dann das Event empfangen willst, überlade QObject::event() und nicht QObject::eventFilter(). Der eventFilter wird verwendet, um Events von anderen Objekten abzufangen.
Verfasst: 6. Februar 2011 02:06
von ole
Okay...
Also ich habe mal die MyEvent Klasse so geschrieben:
Code: Alles auswählen
class MyEvent : public QEvent
{
public:
static Type myregisteredEventType()
{
static Type myType = static_cast<QEvent::Type>(QEvent::registerEventType());
return myType;
}
MyEvent () : QEvent(myregisteredEventType()) {}
};
und gesendet wird an "qApp":
Code: Alles auswählen
void MyButton::onClickedSlot(void)
{
MyEvent *eve;
eve = new MyEvent ();
qApp->postEvent(qApp, eve);
}
und in dem QMainWindow benutze ich die "event" Funktion:
Code: Alles auswählen
bool MyMainWindow::event(QEvent *event)
{
if (event->type() == MyEvent::myregisteredEventType())
{
qDebug("Beep\n");
}
return QMainWindow::event(event);
}
Aber er springt noch immer nicht in die if Anweisung... Ist qApp vielleicht nicht der richtige Empfänger?
Verfasst: 6. Februar 2011 08:46
von franzf
Warum denn eigentlich so kompliziert? Für Kommunikation zwischen unterschiedlichen Klassen (Objekten) sind eigentlich SIGNAL/SLOT-Connections um Welten bequemer! Ein eigenes Event macht z.B. dann Sinn, wenn von deiner Klasse nochmal abgeleitet werden soll, und du spezielle Events anbietest, die dann in abgeleiteten Klassen abgearbeitet werden sollen.
Code: Alles auswählen
void MyButton::onClickedSlot(){
emit specialEvent();
}
MainWindow::MainWindow() {
myButton_ = new MyButton;
connect(myButton_, SIGNAL(specialEvent), SLOT(handleSpecialEvent));
}
Du hast im Übrigen ein dickes MemoryLeak eingebaut, in dein MyButton::onClickedSlot(). Siehst du das?
Verfasst: 6. Februar 2011 09:13
von upsala
@franzf: Nein, er hat keine Memory-Leak:
Code: Alles auswählen
The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted. It is not safe to modify or delete the event after it has been posted.
Verfasst: 6. Februar 2011 11:17
von ole
Hallo,
Nun, Signals und Slots sind in dem Fall unpraktisch, weil wir von circa 100 Knöpfen reden und diese sind in Unter-unter-unter-Widgets.
Gruß
Verfasst: 6. Februar 2011 11:49
von ole
So, hier neue Erkenntnisse...
Ich habe in meinem "MyMainWindow" im Konstruktor einen EventFilter an qApp gehangen:
Code: Alles auswählen
MyMainWindow::MyMainWindow(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
...
qApp->installEventFilter(this);
}
und der Eventfilter sieht so aus:
Code: Alles auswählen
bool MyMainWindow::eventFilter (QObject* sender, QEvent *event)
{
if (event->type() == MyEvent ::myregisteredEventType())
{
qDebug("Beep\n");
}
return QMainWindow::eventFilter(sender, event);
}
wobei der Knopf folgenden Slot hat:
Code: Alles auswählen
void MyButton::onClickedSlot(void)
{
MyEvent *eve;
eve = new MyEvent ();
QApplication::postEvent(qApp, eve);
}
Und das funktioniert jetzt auch.
Gibts da irgendetwas einzuwenden?
Verfasst: 6. Februar 2011 17:11
von padreigh
Für normale QPushButtons benutzt du doch auch Signal/Slot warum ist das dann für eine Ableitung dafür schwierig? Sind das irgendwie dynamisch generierte Buttons die in nem SubSubSubwidget stecken? Irgendwie scheint mir das Design fragwürdig das Buttons in der 10. Schachtelungstiefe einfügt und deren Aktivierung im TopLevel behandelt. Ausserdem geht es genauso mit connects:
Code: Alles auswählen
class DeinButton : public QPushButton {
DeinButton(QString title=QString(), QWidget * parent = 0) :
QPushButton(title, parent)
{
// special emit - damit bist du sicher das dieses clicked nur von deinen specialbuttons kommt
connect (this, SIGNAL(clicked(bool)), this, SLOT(emitSpecialClicked(bool)));
}
signals: // wir geben gleich den pointer zum auslösenden button mit ... ginge zwar auch über sender() aber das ist böse
void meinSpecialClicked(DeinButton *,bool);
slots:
// dank des connects löst jedes click diesen slot aus
void emitSpecialClicked(bool b) { emit meinSpecialClicked(this,b); }
};
irgendwo in der Hirarchie:
Code: Alles auswählen
// mach nen neuen specialbutton
DeinButton * db = new DeinButton("whatever", this);
// connecte das spezialsignal an dein main window
// entweder du suchst das solange über parent()->parent()->...->parent() bis du was ohne parent findest
// und hoffst das es das richtige ist und du keinen specialbutton in einen parent-losen dialog oder so gemacht has
// oder du gibts ihm nen passenden Namen (setObjectName("")) und machst das so wie ich hier
// oder du speicherst das als member
connect(db, SIGNAL(meinSpecialClicked(DeinButton*,bool), qApp->findChild<QMainWindow*>("DeinMeinWindowName"), SLOT(slotDerSpecialButtonsHandelt(bool));
// hier fehlt das reinpacken in irgendein widget/layout
Verfasst: 10. Februar 2011 23:20
von ole
Hey,
Danke für deinen Tipp.
Zunächst, ja, ein paar dieser Spezialknöpfe sind dynamisch generiert, ein Teil nicht. Es sind jedoch sehr viele und jeden Knopf per Signal und Slot zu verbinden und das über ein paar subwidgets, dass ist mir zu viel zum Schreiben.
Wenn es etwas in der Art gäbe wie:
Code: Alles auswählen
connect(<jeder_MyButton_im_Programm, SIGNAL(clicked()), MyMainwindow, SLOT(machmalwas()));
Aber das kenn ich nicht und der Umweg über den eventFilter scheint mir da doch geschickter...
Ole
Verfasst: 11. Februar 2011 06:27
von Christian81
Was spricht gegen das connect genau dann wenn sie dynamisch erzeugt werden ??
Verfasst: 11. Februar 2011 14:58
von padreigh
stellt sich mir die Frage warum du millionen Knöpfe hast die alle das selbe tun ... und daher auch alle an die selbe Methode connected werden. Irgendwie ... komisch.