eigener QEvent

Alles rund um die Programmierung mit Qt
Antworten
ole
Beiträge: 15
Registriert: 22. Dezember 2009 11:21

eigener QEvent

Beitrag 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
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag von upsala »

Ein QEvent::type() hat nicht die Nummer 1111, sondern QEvent::User+x. Bzw. seit Qt4.4 gibt es sogar

Code: Alles auswählen

int QEvent::registerEventType ( int hint = -1 ) 
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.
ole
Beiträge: 15
Registriert: 22. Dezember 2009 11:21

Beitrag 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?
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag 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?
upsala
Beiträge: 3946
Registriert: 5. Februar 2006 20:52
Wohnort: Landshut
Kontaktdaten:

Beitrag 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.
ole
Beiträge: 15
Registriert: 22. Dezember 2009 11:21

Beitrag 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ß
ole
Beiträge: 15
Registriert: 22. Dezember 2009 11:21

Beitrag 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?
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag 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
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
ole
Beiträge: 15
Registriert: 22. Dezember 2009 11:21

Beitrag 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
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Was spricht gegen das connect genau dann wenn sie dynamisch erzeugt werden ??
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
padreigh
Beiträge: 340
Registriert: 13. Mai 2010 10:06

Beitrag 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.
Patrick (QtCreator 1.3.1, Qt 4.6.3)
---
template = subdirs
Antworten