Destruktoraufruf nach Fenster schließen

Alles rund um die Programmierung mit Qt
Antworten
t_b
Beiträge: 41
Registriert: 27. Februar 2010 14:12

Destruktoraufruf nach Fenster schließen

Beitrag von t_b »

Hallo,

da ich in C++ (und Qt) noch ein wenig neu bin, habe ich ein Problem mit den Destruktoren.

Theoretisch sollte es ja so laufen:

Hauptprogramm starten ->
Button drücken ->
neuer Dialog erscheint (wird erstellt durch Konstruktor) ->
man macht daran etwas ->
man schließt das Fenster (sei es durch den Button in der Leiste oder durch Ok/Abbrechen im Dialog) ->
Destruktor wird aufgerufen (in meinem Fall ist er (noch) leer ) ->
Objekt wird gelöscht ->

Beim erneuten Aufrufen müsste doch der Dialog wieder neu aufgebaut werden, bei mir bleibt er jedoch mit den Änderungen vorhanden. Ich kann mir nur vorstellen, das ich beim aufrufen etwas "falsch" mache.

Der QDialog fixation

Code: Alles auswählen

    // der Fixationstest
    fixation = new Fixation;
    fixation->setAttribute(Qt::WA_QuitOnClose);
Der dazugehörige Signal/Slot

Code: Alles auswählen

   connect(startFixation,SIGNAL(clicked()),fixation,SLOT(exec()));
Da ich geänderte Einstellungen haben kann, sollte im Fixations-Dialog jedesmal neu aus einer Konfigurationsdatei gelesen werden. Da das Objekt aber weiterhin besteht, werden die geänderten Daten nicht ausgelesen.
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

1. Ein Dialog muss eigentlich nicht gelöscht werden... üblicherweise wird einfach mit einem dialog->updateDate() oder sonst einer "Re-Initialisierung" die Basis-Daten neu eingelesen und der gleiche Dialog neu angezeigt (show() oder exec()).

2. Qt::WA_QuitOnClose
Makes Qt quit the application when the last widget with the attribute set has accepted closeEvent().[...] By default this attribute is set for all widgets of type Qt::Window.
Das ist nicht das, was du möchtest.. wäre folgendes nicht besser...
Makes Qt delete this widget when the widget has accepted the close event
-> http://doc.trolltech.com/4.6/qt.html#Wi ... ibute-enum

hth..
t_b
Beiträge: 41
Registriert: 27. Februar 2010 14:12

Beitrag von t_b »

Wenn ich Qt::WA_DeleteOnClose nutze, zerstöre ich das Objekt aber dauerhaft. d.h. bei einen erneuten Drücken des Knopfes passiert nichts mehr.

Ok, Folgendes Codebeispiel:

configfile.h

Code: Alles auswählen

#ifndef CONFIGFILE_H
#define CONFIGFILE_H

#include <QWidget>
#include <QSettings>

class ConfigFile : public QWidget
{
Q_OBJECT
public:
    explicit ConfigFile(QWidget *parent = 0);
    ~ConfigFile();
    QVariant readValue(const QString &key);
    void writeValue(const QString &key, QVariant value);
    void writeConfig();
private:
    QSettings *settings;
signals:

public slots:

};

#endif // CONFIGFILE_H
configfile.cpp

Code: Alles auswählen

#include "configfile.h"
#include <QSettings>
#include <QFile>

ConfigFile::ConfigFile(QWidget *parent) :
    QWidget(parent)
{
    settings = new QSettings("config.ini",QSettings::IniFormat,this);
    settings->beginGroup("config");

}

QVariant ConfigFile::readValue(const QString &key)
{
 return(settings->value(key));
}

void ConfigFile::writeValue(const QString &key, QVariant value)
{
    settings->setValue(key,value);
}

void ConfigFile::writeConfig()
{

}

ConfigFile::~ConfigFile()
{
    settings->endGroup();
}
dialog.h

Code: Alles auswählen

#ifndef DIALOG_H
#define DIALOG_H

#include "configfile.h"
#include <QDialog>
#include <QGridLayout>

class Dialog : public QDialog
Q_OBJECT
public:
    explicit Dialog();
    ~Dialog();

private:
    QGridLayout *layoutMain;

    ConfigFile *configFile;

signals:

public slots:

};


#endif // DIALOG_H
dialog.cpp

Code: Alles auswählen

#include "dialog.h"
#include "configfile.h"
#include <QGridLayout>
#include <QLabel>

Dialog::Dialog()
{
	configFile = new ConfigFile;
	QLabel *label = new QLabel(configFile->readValue("label").toString());
	layoutMain->addWidget(label);
	setLayout(layoutMain);
}

Dialog::~Dialog()
{
}
Und die Main wie gehabt....

Wenn ich also über ein Konfigurationsmenu den Wert in der Konfigurationsdatei ändere, und diesen Dialog neu Aufrufe, nachdem ich ihn geschlossen habe, dann sollte sich dieser "neu" aufbauen.

Eine "update" variante habe ich schon implementiert, aber ich finde diese "Methode" etwas unglücklich.

Hier mal das Bsp:

Code: Alles auswählen

public:
    explicit ConfigColors(QWidget *parent = 0);
    void loadValues();
    void storeValues();

Code: Alles auswählen

void ConfigColors::loadValues()
{
    BackgroundColor = configFile->readValue("BackgroundColor").value<QColor>();
    ArrowFillColor = configFile->readValue("ArrowFillColor").value<QColor>();
    ArrowFrameColor = configFile->readValue("ArrowFrameColor").value<QColor>();

    pixmapBackgroundColor.fill(BackgroundColor);
    pushbuttonBackgroundColor->setIcon(pixmapBackgroundColor);
    pixmapArrowFillColor.fill(ArrowFillColor);
    pushbuttonArrowFillColor->setIcon(pixmapArrowFillColor);
    pixmapArrowFrameColor.fill(ArrowFrameColor);
    pushbuttonArrowFrameColor->setIcon(pixmapArrowFrameColor);
}

void ConfigColors::storeValues()
{
    configFile->writeValue("BackgroundColor",BackgroundColor);
    configFile->writeValue("ArrowFillColor",ArrowFillColor);
    configFile->writeValue("ArrowFrameColor",ArrowFrameColor);
}
Sowie die im darüberliegenden Widget entspechende Abfragen.

Code: Alles auswählen

void ConfigDialog::acceptConfig()
{
    configColors->storeValues();

}

void ConfigDialog::rejectConfig()
{
    configColors->loadValues();
}
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Destruktoraufruf nach Fenster schließen

Beitrag von Christian81 »

t_b hat geschrieben: Destruktor wird aufgerufen (in meinem Fall ist er (noch) leer ) ->
Objekt wird gelöscht ->
und
t_b hat geschrieben: Wenn ich Qt::WA_DeleteOnClose nutze, zerstöre ich das Objekt aber dauerhaft. d.h. bei einen erneuten Drücken des Knopfes passiert nichts mehr.
Na was denn nun???
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
t_b
Beiträge: 41
Registriert: 27. Februar 2010 14:12

Beitrag von t_b »

Mhhh, es scheint, als verstehe ich den Destruktor falsch . Ich dachte, mit dem Schließen des Fensters wird der Speicher freigegeben und beim nächsten öffnen des Fensters wieder initialisiert. :(
solarix
Beiträge: 1133
Registriert: 7. Juni 2007 19:25

Beitrag von solarix »

Das kann man auch so machen... verzeih uns wenn wir verwirrt sind, denn du hast im Wesentlichen gefragt "wie lösch ich den Dialog" .. wir haben dir ne Lösung gezeigt und nun sagst du "aber dann lösch ich den Dialog ja!" :?

Du hast doch folgende Varianten:

1. Der Dialog lebt solange wie der Parent und wird auf Klick "Re-Initialisiert"

Code: Alles auswählen

Parent::Parent()
{
   mConfigFile     = new ConfigFile; 
   mConfigDialog = new ConfigDialog(configFile);
}

Parent::~Parent()
{
   delete mConfigFile;
   delete mConfigDialog;
}

void Parent::on_btn_clicked()
{
  mConfigDialog->loadValues();
  mConfigDialog->exec();
}
2. Der Dialog lebt nur temporaer:

Code: Alles auswählen

Parent::Parent()
{
   mConfigFile     = new ConfigFile; 
}

Parent::~Parent()
{
   delete mConfigFile;
}

void Parent::on_btn_clicked()
{
  configDialog  ConfigDialog(mConfigFile);
  configDialog.exec();
}
Dann gibt es noch Varianten mit WA_DeleteOnClose oder deleteLater().. aber seien wir ehrlich: zwei Varianten reichen doch... :?:

hth...


PS.

Code: Alles auswählen

Dialog::Dialog()
{
   configFile = new ConfigFile;
   QLabel *label = new QLabel(configFile->readValue("label").toString());
   layoutMain->addWidget(label);
   setLayout(layoutMain);
} 
layoutMain zeigt ins Nirvana...

PPS.
Wenn die ConfigFile-Instanz genau so lange lebt wie der Parent, kannst du auch auf die Pointer verzichten und "configFile" als normalen, privaten Member deklarieren.. schon wieder zwei Zeilen gesparrt.. :wink:
t_b
Beiträge: 41
Registriert: 27. Februar 2010 14:12

Beitrag von t_b »

Ich habe jetzt mal ein Demoprojekt geschrieben, um zu zeigen wie ich es bisher gelöst habe (in dem Fall config.[h/cpp]). Diese Variante ist aber "höchst" unbefriedigend, da ich alle Werte in die Label und Slider etc. beim Reject neu hinschreiben muss.
Vom Prinzip kann ich das auch machen, sobald ein CloseEvent für das Dialog Fenster (dialog.[h/cpp]) im Parent (widget.[h/cpp]) erkannt wird, aber wie gesagt, dafür dachte ich wäre ja das reinstanziieren gedacht.

@solarix beim 1. Beispiel hast du ein loadValues genutzt, welches aber wieder wie bei mir in der Config vorraussetzt, dass ich die Variablen als Privat dekaltieren muss, um Sie wieder zu aktualisieren. Was ich aber suche ist die Variante, eben dieses nicht zu tun.
Im 2. Beispiel verstehe ich nicht, warum die die ConfigFile übergibst (<= sorry, vielleicht bin ich auch zu blöde)
Dateianhänge
DestructorDemo.zip
(3.49 KiB) 148-mal heruntergeladen
Antworten