P
wxSkip schrieb:
1. Beim connect() steht ja, dass per Default Qt::AutoConnection benutzt wird. D.h. wenn ich das connect() vom GUI-Thread aus mache, wird eine Qt::DirectConnection benutzt. D.h. bei meinem ersten Vorschlag müsste ja im Prinzip gleich der Slot ausgeführt werden und nicht erst später im EventLoop?!
Im Prinzip ja, wenn der Signalemitter zur Zeit der Emittierung noch im selben Thread lebt wie der Signalempfänger. (kein zB QThread::moveToThread )
- Syntaktisch klappt an deinem Code nix - es fehlt zB durchgehebnd das Q_OBJECT und noch mehr - verrät dir alles der Compiler )
Ich hab (ca 3h) rumprobiert und kam auf sowas ... das kompiliert zumindest und läuft:
mw.pro
TARGET = CloseTest
TEMPLATE = app
SOURCES += main.cpp\
mw.cpp
HEADERS += mw.h
main.cpp
#include <QtGui/QApplication>
#include <QtGui>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
EventManager instance;
QApplication a(argc, argv);
QWidget w;
{
QVBoxLayout * vbl = new QVBoxLayout(&w);
MWbool * mwbool = new MWbool;
MWreal * mwreal = new MWreal;
MWint * mwint = new MWint;
mwbool->setEventManager(&instance);
mwreal->setEventManager(&instance);
mwint->setEventManager(&instance);
vbl->addWidget(mwbool);
vbl->addWidget(mwreal);
vbl->addWidget(mwint);
}
w.show();
return a.exec();
}
mw.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QWidget>
#include <QString>
class QCloseEvent;
// helper //////////////////////////////////////////////////////////
class MWbasic;
namespace Helper {
void fillWidget(MWbasic * m, const QString & txt);
}
// interface //////////////////////////////////////////////////////////
class MWsavedata {
public:
MWsavedata();
virtual ~MWsavedata();
virtual void saveData() = 0;
bool saved;
bool ignoreUnsavedData;
};
// basic //////////////////////////////////////////////////////////
class EventManager;
class MWbasic : public QWidget, public MWsavedata
{
Q_OBJECT
public:
MWbasic(QWidget * parent);
virtual ~MWbasic();
void setEventManager(EventManager * m);
protected slots:
void setSaved(bool to) { saved = to; }
void setIngnoreUnsaved(bool to) { ignoreUnsavedData = to; }
protected:
EventManager * manager;
};
// bool //////////////////////////////////////////////////////////
class MWbool : public MWbasic
{
Q_OBJECT
bool data;
public:
MWbool (QWidget *parent = 0);
virtual ~MWbool();
virtual void saveData();
signals:
void aboutToClose();
protected:
void closeEvent(QCloseEvent *event);
};
// int //////////////////////////////////////////////////////////
class MWint : public MWbasic
{
Q_OBJECT
qint16 data;
public:
MWint(QWidget *parent = 0);
virtual ~MWint();
virtual void saveData();
signals:
void aboutToClose();
protected:
void closeEvent(QCloseEvent *event);
};
// real //////////////////////////////////////////////////////////
class MWreal : public MWbasic
{
Q_OBJECT
qreal data;
public:
MWreal(QWidget *parent = 0);
virtual ~MWreal();
virtual void saveData();
signals:
void aboutToClose();
protected:
void closeEvent(QCloseEvent *event);
};
// eventManager //////////////////////////////////////////////////////////
class EventManager : public QObject
{
Q_OBJECT
public:
EventManager(QObject * parent = 0);
public slots:
void WindowCloseSlot();
};
#endif // MAINWINDOW_H
mw.cpp
#include "mainwindow.h"
#include <QtDebug>
#include <QtCore/QTime>
#include <QtGui/QCheckBox>
#include <QtGui/QCloseEvent>
#include <QtGui/QGridLayout>
#include <QtGui/QLabel>
#include <QtGui/QMessageBox>
#include <QtGui/QPushButton>
// helper ////////////////////////////////////////////////////////////////////////
void Helper::fillWidget(MWbasic *widget, const QString &txt)
{
const QFont headline = QFont("Arial",14,200,true);
QGridLayout * lay = new QGridLayout(widget);
QLabel * idLabel = new QLabel(txt + " " + QTime::currentTime().toString("hh:mm:ss (zzz)"));
idLabel->setEnabled(false);
idLabel->setFont(headline);
idLabel->setAlignment(Qt::AlignCenter);
QPushButton * savedButton = new QPushButton("SAVE");
QCheckBox * saved = new QCheckBox("Saved: ");
saved->setChecked(false);
saved->setEnabled(false);
QWidget::connect(savedButton,SIGNAL(clicked()),saved,SLOT(toggle()));
QWidget::connect(saved,SIGNAL(toggled(bool)), widget, SLOT(setSaved(bool)));
QPushButton * ignoreButton = new QPushButton("IGNORE UNSAVED");
QCheckBox * ignoreunsaved = new QCheckBox("Ignore unsaved: ");
ignoreunsaved->setChecked(false);
ignoreunsaved->setEnabled(false);
QWidget::connect(ignoreButton,SIGNAL(clicked()),ignoreunsaved,SLOT(toggle()));
QWidget::connect(ignoreunsaved,SIGNAL(toggled(bool)), widget, SLOT(setIngnoreUnsaved(bool)));
QPushButton * closeButton = new QPushButton("CLOSE");
QWidget::connect(closeButton,SIGNAL(clicked()),widget,SLOT(close()));
lay->addWidget(idLabel,0,0,1,2);
lay->addWidget(savedButton,1,0);
lay->addWidget(saved,1,1);
lay->addWidget(ignoreButton,2,0);
lay->addWidget(ignoreunsaved,2,1);
lay->addWidget(closeButton,3,0,1,2);
}
// interface ////////////////////////////////////////////////////////////////////////
MWsavedata::MWsavedata() : saved(false), ignoreUnsavedData(false) {}
MWsavedata::~MWsavedata() {}
// basis ////////////////////////////////////////////////////////////////////////
MWbasic::MWbasic(QWidget * parent) : QWidget(parent) {}
MWbasic::~MWbasic() {}
void MWbasic::setEventManager(EventManager *m)
{
manager = m;
connect(this,SIGNAL(aboutToClose()), manager, SLOT(WindowCloseSlot()));
}
// bool ////////////////////////////////////////////////////////////////////////
MWbool::MWbool (QWidget *parent) :
MWbasic(parent), data(true)
{
qDebug() << Q_FUNC_INFO;
Helper::fillWidget(this,"bool");
}
MWbool::~MWbool() {qDebug() << Q_FUNC_INFO;}
void MWbool::saveData()
{
qDebug() << Q_FUNC_INFO <<"\n\tbool saved :" << data;
}
void MWbool::closeEvent(QCloseEvent *event)
{
qDebug() << Q_FUNC_INFO;
if (! saved && ! ignoreUnsavedData)
{
emit aboutToClose(); // directly connected !
}
MWbool * newMw = new MWbool;
newMw->setEventManager(manager);
parentWidget()->layout()->addWidget(newMw);
event->accept();
}
// int ////////////////////////////////////////////////////////////////////////
MWint::MWint(QWidget *parent) :
MWbasic(parent), data(12345)
{
qDebug() << Q_FUNC_INFO;
Helper::fillWidget(this,"int");
}
MWint::~MWint()
{
qDebug() << Q_FUNC_INFO;
}
void MWint::saveData()
{
qDebug() << Q_FUNC_INFO <<"\n\tint saved :" << data;
}
void MWint::closeEvent(QCloseEvent *event)
{
qDebug() << Q_FUNC_INFO;
if (! saved && ! ignoreUnsavedData)
{
emit aboutToClose(); // directly connected !
}
MWint * newMw = new MWint;
newMw->setEventManager(manager);
parentWidget()->layout()->addWidget(newMw);
event->accept();
}
// real ////////////////////////////////////////////////////////////////////////
MWreal::MWreal(QWidget *parent) :
MWbasic(parent), data(1.618033989)
{
qDebug() << Q_FUNC_INFO;
Helper::fillWidget(this,"real");
}
MWreal::~MWreal()
{
qDebug() << Q_FUNC_INFO;
}
void MWreal::saveData()
{
qDebug() << Q_FUNC_INFO <<"\n\treal saved :" << data;
}
void MWreal::closeEvent(QCloseEvent *event)
{
qDebug() << Q_FUNC_INFO;
if (! saved && ! ignoreUnsavedData)
{
emit aboutToClose(); // directly connected !
}
MWreal * newMw = new MWreal;
newMw->setEventManager(manager);
parentWidget()->layout()->addWidget(newMw);
event->accept();
}
// eventManager //////////////////////////////////////////////////////////
EventManager::EventManager(QObject * parent) :
QObject(parent)
{
qDebug() << Q_FUNC_INFO;
}
void EventManager::WindowCloseSlot()
{
MWsavedata *savedata = dynamic_cast<MWsavedata*>(sender());
if (savedata) // cast-able
{
qDebug() << Q_FUNC_INFO;
QWidget * wid = qobject_cast<QWidget*>(sender());
const QMessageBox::StandardButtons
answer = QMessageBox::question(wid,"Save before close?", "Save before close?", // title, question
QMessageBox::Yes|QMessageBox::No, // buttons
QMessageBox::Yes); // default button
if(answer == QMessageBox::Yes) // Save
{
savedata->saveData();
}
}
}
Das Beispiel tut in etwa das was du wolltest (für DirectConnectedSignals - nicht Threadsicher) - jede Klasse die das machen will muss das Interface implementieren und es bleibt ein unschöner sender()-cast drin. Wenn du damit leben willst, ginge es so in etwa.
wxSkip schrieb:
Jetzt habe ich nur noch eine Frage, die ich so nicht in der Qt-Doku gefunden habe:
Wenn ich mehrere Slots an ein Signal connecte, werden sie dann in der umgekehrten Reihenfolge abgearbeitet, wie sie connected wurden?
Bsp.:
QObject::connect(ptr1, SIGNAL(sig()), ptr2, SLOT(slot1()));
QObject::connect(ptr1, SIGNAL(sig()), ptr2, SLOT(slot2()));
QObject::connect(ptr1, SIGNAL(sig()), ptr2, SLOT(slot3()));
emit ptr1->sig(); //wird hier zuerst slot3(), dann slot2() und dann slot1() aufgerufen?
http://doc.qt.nokia.com/latest/signalsandslots.html#advanced-signals-and-slots-usage Runterscrollen bis "SIGNALs" da steht es