Wie würdet ihr das machen...

Alles rund um die Programmierung mit Qt
Antworten
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Wie würdet ihr das machen...

Beitrag von AuE »

Hi @ll,

bin gerade dabei einen Settingsdialog zu schreiben(bei OK soll die Settingsdatei geschrieben werden).... Ich will aber nicht jedesmal alles schreiben-also dachte ich mir ich mache mir eine Liste mit QObjects und packe da jedes Element rein welches sich verändert hat.

Beim "Übernehmen" will ich dann die Liste mit den Objects durchgehen und die Werte schreiben.

Aber wie Ordne ich die Werte am geschicktesten den Keys zu?


Freue mich über Ideen und Kritik!
archer
Beiträge: 306
Registriert: 2. Februar 2006 09:56

Beitrag von archer »

Setz dir doch eine property in deinen Eingabefeldern.
setProperty("changed", true);
und prüf die bei click auf ok ab.
RD1978
Beiträge: 84
Registriert: 5. Juni 2007 08:00
Wohnort: Stralsund (DDR)

Beitrag von RD1978 »

Hi, also erstmal würde ich das lesen/schreiben der Einstellungen nicht von einem Widget/Dialog abhängig machen.

Da man Einstellungen ja meist an mehreren verschiedenen Orten im Programm braucht, macht sich hier ein Singleton ganz gut.

Ansatz:

Code: Alles auswählen

class GlobalConfig
{
	public:
		static GlobalConfig *getInstance();
		void setAccount( const QString &email, const QString &password );
		const QString &email() const { return m_email; }
		const QString &password() const { return m_password; }
		
	private:
		GlobalConfig();
		static GlobalConfig *s_pInstance;
		QString m_email;
		QString m_password;
};

Code: Alles auswählen

GlobalConfig *GlobalConfig::s_pInstance = 0;

GlobalConfig *GlobalConfig::getInstance()
{
	if( !s_pInstance )
	{
		s_pInstance = new GlobalConfig();
	}
	return s_pInstance;
}

GlobalConfig::GlobalConfig()
{
	#ifdef Q_OS_WIN32
		QSettings settings( QSettings::IniFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
	#else
		QSettings settings( QSettings::NativeFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
	#endif
	
	settings.beginGroup( "account" );
	m_email = settings.value( "email", QString() ).toString();
	m_password = settings.value( "password", QString() ).toString();
	settings.endGroup();
}

void GlobalConfig::setAccount( const QString &email, const QString &password )
{
	m_email = email;
	m_password = password;
	
	#ifdef Q_OS_WIN32
		QSettings settings( QSettings::IniFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
	#else
		QSettings settings( QSettings::NativeFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
	#endif
	
	settings.beginGroup( "account" );
	settings.setValue( "email", m_email );
	settings.setValue( "password", m_password );
	settings.endGroup();
}
Damit schreibst Du dann über die Setter die Werte wieder zurück. Wie und wo Du das dann in der GUI verbaust bleibt Dir überlassen... ;-)
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Beitrag von AuE »

Genauso habe ich das schon.... also ein property mit hasChanged, und im nächsten noch den Key für das Settingsfile...

Bleibt nur noch die Frage wie man das dann mit dem Wert macht....

Code: Alles auswählen

 foreach (QObject *obj, this->findChildren<QObject *>())
	    if (obj->property("hasChanged").toBool())
{
IniFile::getInstance().writeValue("Settings", obj->property(KeyName), "???");
}

Wie kann man gescheit den Key speichern - ich weiß ja nicht was ich bekomme!
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Wie würdet ihr das machen...

Beitrag von franzf »

AuE hat geschrieben:bin gerade dabei einen Settingsdialog zu schreiben(bei OK soll die Settingsdatei geschrieben werden).... Ich will aber nicht jedesmal alles schreiben
Fail ;)
Eine Datei wird sowieso immer komplett geschrieben. Da kannst du nix dran drehen. Eine Datei ist eine Bytefolge auf der Platte. Wenn du da einzelne Sachen neuschreibst, und die Länge nicht passt hast du Löcher oder überschreibst Bereiche die nicht zu deiner Datei gehören.
Das Einzige was du machen könntest, ist das Schreiben mit nem Timer zu steuern. Gib dir nen bool changed und nen Timer configWriteTimer. setz den Timer auf (von mir aus) 10 Minuten. wenn sich die Settings ändern (changed == true) wirst du bei Ablauf des Timers die Datei schreiben, ansonsten auf den nächsten Timer warten.
Aber nur wenn du ein bisschen die Schreibintervalle auf deine Platte zügeln willst.
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Beitrag von AuE »

??? wie jetzt du willst mir sagen das wenn ich nen QSettings Objekt habe das auf ein File zugreift .... das wenn ich dann nicht jeden wert mit setValue setze das dann Löcher entstehen??

Ich möchte dich nur die Werte setzen via QSettings.setValue oder auch andere routinen/libs die dann die geg. Werte schreiben.

Das heisst ich muss irgendwie an den Objekttypen rankommen....das heisst entweder casten oder als property speichern
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

AuE hat geschrieben:??? wie jetzt du willst mir sagen das wenn ich nen QSettings Objekt habe das auf ein File zugreift .... das wenn ich dann nicht jeden wert mit setValue setze das dann Löcher entstehen??
Nein. Aus deiner Beschreibung ging für mich eindeutig hervor, dass du den jeweiligen Status einer Settings-Variable auf "changed" überprüfen können willst, um diesen dann einzeln in die Datei zu schreiben ("Ich will aber nicht jedesmal alles schreiben").
Und das geht einfach nicht! Entweder wird die ganze Datei geschrieben, oder eben nicht ;) Mehr Aussage steckt da nicht dahinter.
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Beitrag von AuE »

Nein.... sry das es falsch rüberkam....

Ich habe nen Einstellungsfenster.... wenn der Nutzer dann mit OK rausgeht will ich jedes QObject fragen ob es ein Property hat das hasChanged heisst. Wenn dieses auf true ist so möchte ich via QSettings das ins Settingsfile übernehmen!

Nur fehlt mir halt noch die Idee wie ich aus dem qobject was ich habe herausbekomme wie ich an die Daten komme....
N&#164;X
Beiträge: 77
Registriert: 21. September 2009 12:24

Re: Wie würdet ihr das machen...

Beitrag von N&#164;X »

franzf hat geschrieben:Eine Datei wird sowieso immer komplett geschrieben. Da kannst du nix dran drehen. Eine Datei ist eine Bytefolge auf der Platte. Wenn du da einzelne Sachen neuschreibst, und die Länge nicht passt hast du Löcher oder überschreibst Bereiche die nicht zu deiner Datei gehören.
Naja, QSettings schreibt ja nicht immer in ne Datei, unter Windows wird z.B. standardmäßig in die Registry im RAM geschrieben, und auch sonst wird der Schreibzugriff gepuffert, das Schreiben sollte also keine größeren Probleme machen.

Zum eigentlichen Problem: Mach doch ne QMap oder nen QHash aus QString und QVariant, in den du einfach alles was sich ändert schreibst. sprich ändert sich "lala" auf den Wert 5 machst du einfach ein myHash.insert("lala", 5) und wenn dann geschrieben werden soll kannst du einfach den ganzen Hash mit Iterators durchgehen, abarbeiten und leeren. Somit hättest du deinen eigenen kleinen Cache, aber da QSettings, wie bereits gesagt, nen eigenen Cache verwendet weiß ich nicht ob dir das wirklich was bringt...
mfg N¤X
pfid
Beiträge: 535
Registriert: 22. Februar 2008 16:59

Beitrag von pfid »

AuE hat geschrieben:Nein.... sry das es falsch rüberkam....

Ich habe nen Einstellungsfenster.... wenn der Nutzer dann mit OK rausgeht will ich jedes QObject fragen ob es ein Property hat das hasChanged heisst. Wenn dieses auf true ist so möchte ich via QSettings das ins Settingsfile übernehmen!

Nur fehlt mir halt noch die Idee wie ich aus dem qobject was ich habe herausbekomme wie ich an die Daten komme....

Code: Alles auswählen

  for (...)
   {
      QComboBox* box = qobject_cast<QComboBox*>(obj);

      if (box)
      {
         ...
         continue;
      }

      QLineEdit* line = qobject_cast<QLineEdit*>(obj);

      if (line)
      {
         ...
         continue;
      }

      QSpinBox* spin = qobject_cast<QSpinBox*>(obj);

      if (spin)
      {
         ...
         continue;
      }

      QDateTimeEdit* date = qobject_cast<QDateTimeEdit*>(obj);

      if (date)
      {
         ...
         continue;
      }

      QTextEdit* text = qobject_cast<QTextEdit*>(obj);

      if (text)
      {
         ...
         continue;
      }

      QCheckBox* check = qobject_cast<QCheckBox*>(obj);

      if (check)
      {
         ...
         continue;
      }

      QDoubleSpinBox* doubleSpin = qobject_cast<QDoubleSpinBox*>(obj);

      if (doubleSpin)
      {
         ...
         continue;
      }
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Re: Wie würdet ihr das machen...

Beitrag von franzf »

N¤X hat geschrieben:Naja, QSettings schreibt ja nicht immer in ne Datei, unter Windows wird z.B. standardmäßig in die Registry im RAM geschrieben, und auch sonst wird der Schreibzugriff gepuffert, das Schreiben sollte also keine größeren Probleme machen.
Er hat ja explizit "Settingsdatei" geschrieben, drum bin ich davon ausgegangen ist ist tatsächlich eine Datei und hab nicht weiter über die Existenz anderer komischer Betriebssysteme nachgedacht ;)
wenn der Nutzer dann mit OK rausgeht will ich jedes QObject fragen ob es ein Property hat das hasChanged heisst. Wenn dieses auf true ist so möchte ich via QSettings das ins Settingsfile übernehmen!
Um welches Property geht es dir denn dann genau? Z.B. den "text" in nem LineEdit? "value" in ner SpinBox?
Du kannst einfach bei jedem Objekt die üblichen Verdächtigen abfragen. Ob ein Property existiert bekommst du über

Code: Alles auswählen

obj->metaObject()->indexOfProperty(propertyName) != -1
Du kannst dann bspw. den index nehmen und dir direkt das QMetaProperty holen - liegt dann an dir.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

#ifdef Q_OS_WIN32
QSettings settings( QSettings::IniFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
#else
QSettings settings( QSettings::NativeFormat, QSettings::UserScope, __COMPANY__, __APPLICATION__ );
#endif
Was macht das unterscheiden nach der Plattform an der Stelle fuern Sinn ?
Schreibt der Mac ned auch "nativ" in inni-files ?
also ein
QSettings settings(QSettings::IniFormat,QSettings::UserScope,_COMPANY__, __APPLICATION__ );
ohne die compiler schalter haette die selbe Wirkung, zumindest bei Windows, Linux, MacOS ?
Und warum sollten andere BS Ihre nativ formate verwenden dürfen und das arme windows ned ? ^^
Also wennscho dann konsequent ! ^^

Aber zurueck zum Topic:
Ich hab scho mehrere Strategien implementiert (implementieren müssen). Ich denk so pauschal kann man das ned beantworten, was gut iss und was ned.
Vorher solltest fuer Dich folgene fragen klaeren:
- wann koennen/sollen die Settings geholt werden, schon bei Start der App, oder erst wenn der zugehörige wert abgefragt wird/bearbeitet wird
- schreiben andere Apps auch auf die Settings und wenn ja, musst du die aenderungen die die machen mitbekommen ?
- wie schnell brauchst du die settings bei bedarf ... kannst dir ne fileoperation beim ersten aufrufen erlauben oder nich ?
- wenn deine App crasht, isses dann tragisch wenn gecashte aenderungen an den settings ned zurueckgeschrieben wurden ?
- Sind deine controls die Du verwendest, in der Lage den resultierenden Wert fuer die Settings zu halten, oder brauchst du soweiso ne Schicht zwischen die dir dieSettings fuer die anzeige / Bearbeitung aufbereitet ....

Denk aus den Antworten die Dir gibts, solltes Deine Strategie ableiten ... denk nich das es eine generelle tolle gibt, die bei alllen Fällen einsetzbar iss.

Ciao ...
AuE
Beiträge: 918
Registriert: 5. August 2008 10:58

Beitrag von AuE »

Hi,

thx so far!

Also es handlet sich <aktueller Ansatz> um die Standard Qt Elemente wie Combobox, lineEdit, Slider, etc pp.


Mein jetziger Ansatz sieht wie folgt aus:

- hinzufügen der Propertys für (Changed, KeyName, Type)
- beim verlassen die Liste der Objects holen
- aus der Liste wie franzf gesagt hat schauen ob es das property "value" [..] gibt
- dieses dann via einer lib in das Settings-File eintragen

Andere Programmme schreiben die Settings nicht. Wer die Werte von Hand ändert - gut das kann passieren - aber der muss dann mit leben.

Die Settings werden zum ersten mal beim App Start geholt ( während der SplashScreen angezeigt wird)- danach nicht nochmal.

Der Dialog bleibt dann mit der Anwendung bestehen (kein löschen). Wenn die Anwendung crasht ist klar das dann nicht alles übernommen wurde.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Naja, klingt als waeren die Anforderungen ned besonders kompliziert. Dann kannst dich auf ne ressourcenschonde (in bezug auf entwicklerressourcen ^^) Lösung konzentrieren.

Ob ich fuer jedes control so eigenschaften einpflegen wuerd ... hmmm
Ich hab mal MFC programmiert, daher hab ich sicher ne Affinitaet zu Austauschvariablen (DDX) :-)
ich wuerd die controls mit den variablen kommunizieren lassen und mirn flag speichern, ob sich ueberhaupt was geaendert hat. Und wenn dann alles zurueckschreiben oder nix ^^
Fuer kleine und einmalige dialoge sicher ausreichend.

Mit deinem Ansatz koennte man hingegen wiederum ne Art framework bauen. Also wenn man die Properties vorgibt, die man braucht, einer von QDIalog abgeleiteten Framework-klasse nen QSettings Object gibt, und die Klasse sich dann komplett ums serialisieren von den aufgepeppten controls in nen QSetting kuemmert.
Würde sich sicher lohnen wenn man oft so kleine settingsdialogs bauen muss ....

Ciao ..
Antworten