الفئة QSettings
أحيانا عدة في البرمجة تحتاج إلى حفظ خصائص برنامجك أو إعداداته كحجم النافذة ومكان البرنامج وخصائصه المفعلة وغير المفعلة، لتقوم بتفعليها مباشرة عند تشغيل البرنامج،

يجب حفظ هذه البيانات في القرص الصلب على شكل ملف، يمكن إستعمال الفئة QFile لكن كيوت توفر فئة أخرى جاهزة لهذا الغرض إسمها QSettings هي موضوع درسنا.
طريقة العمل:
تتمثل طريقة عمل هذه الفئة بشكل أساسي في حفظ البيانات على شكل مفتاح تقابله قيمة معينة نوع المفتاح يمكن أن يأخذ جميع أنواع الفئة QVariant مثل QString و QRect و QImage وغيره كما يمكن إضافة مفاتيح فرعية لهيكلة البيانات بشكل منظم
هناك ثلاث أنواع لحفظ البيانات يمكن إختيارها:
- Native Format: وهو ترك العمل على الفئة لتقوم بحفظ البيانات حسب نوع نظام تشغيل، في ويندوز على شكل مدخلة في الرجيستري، في ماك على شكل ملف .plist في مجلد إعدادات النظام، وفي يونكس على شكل ملف نصي .conf
- Ini Format: حفظ البيانات في ملف .ini بالنسبة لجميع أنظمة التشغيل
- Invalid Format: تخصيص جميع الإعدادات يدويا
البداية:
لفهم الأمور لابد من تطبيق عملي، سنقوم بكتابة برنامج صغير للتجربة ثم نحاول حفظ خصائصه بـ QSettings
قم بفتح بيئة التطوير أو محرر النصوص المفضل لديك وانشئ مشروعا جديدا يتضمن مايلي في ملف main.cpp الخاص به:
#include <Qwidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
return a.exec();
}
لنلق نظرة على Constructor الخاص بالفئة Qsettings:
كما هو ظاهر يجب تحديد إسم الفريق والبرنامج في المعاملين الأول والثاني، أما الثالث فيتكفل بإفراع الذاكرة إن قمت بحجز يدوي لأحدى الفئات عند الإستدعاء
إسم الملف سيأخذ إسم البرنامج وينشَؤ داخل مجلد يأخذ إسم الفريق، هكذا للتفرقة بين كل برنامج وملف إعداداته ولتنظيم المجلدات
لنقم بإضافته لبرنامجنا:
#include <Qwidget>
#include <QSettings>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
QSettings settings("qt-ar", "MySoft");
return a.exec();
}
بعد التصنيف ستظهر شاشة فارغة، لكن سيقوم البرنامج بإنشاء الملف MySoft.conf أو MySoft.plist أو إضافة المدخلة في الرجيستري حسب نوع نظام التشغيل (هناك من الأنظمة من لا تنشئه حتى تكون له قيمة أي يحتوي على خصائص)، ويكون فارغا في البداية
كتابة البيانات:
لكتابة البيانات في الملف نستعمل الدالة التالية:
تأخذ معاملين المفتاح والقيمة، هذه الأخيرة نوعها QVariant أي ممكن تأخذ العديد من الأنواع كما أشرنا سابقا ويكفي وضع القيمة كما هي وستقوم المكتبة بتحويلها آليا، لنقم بتجربة ذلك:
#include <Qwidget>
#include <QSettings>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
QSettings settings("qt-ar", "MySoft");
settings.setValue("test", true);
return a.exec();
}
سيتم كتابة القيمة true مقابل المفتاح test، مثلا على لينوكس محتويات الملف تكون كتالي:

نلاحظ كتابة المفتاح والقيمة ضمن القسم العام ([General]) إفتراضيا لأننا لم نحدد القسم، يمكن تحديده بإضافة / على شكل مسار، مثلا:
#include <Qwidget>
#include <QSettings>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
QSettings settings("qt-ar", "MySoft");
settings.setValue("test", "false");
settings.setValue("User/name", "mohamed");
settings.setValue("User/age", 19);
return a.exec();
}
لتعديل قيمة ما قم بتغييرها من خلال المفتاح مع قيمة أخرى، كما في مثالنا test أخذت false وسيتم تعديلها في الملف مباشرة.

أما لحذف قيمة ما نستعمل الدالة التالية:
ستقوم بحذف المفتاح مع قيمته، بالإضافة للمفاتيح التابعة له إن كان عبارة عن قسم مثل User في مثالنا السابق سيحذف الإسم مع العمر
إذا كان هنالك أقسام كثيرة في برنامجك فليس عمليا أن نقوم بكتابة إسم القسم و / مع كل مدخلة
لذا يمكن إستعمال الدالة beginGroup و endGroup:
#include <Qwidget>
#include <QSettings>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
QSettings settings("qt-ar", "MySoft");
settings.beginGroup("User");
settings.setValue("name", "mohamed");
settings.setValue("age", 19);
settings.endGroup();
return a.exec();
}
البرنامج يقوم بكتابة البيانات بشكل جيد كما لاحظنا، ولم يتبق سوى قراءتها
قراءة البيانات:
لقراءة البيانات نستعمل الدالة التالية:
نعطي الدالة المفتاح المراد قراءة قيمته وترجعه لنا على شكل QVariant دائما، لذا وجب علينا تحويل الناتج إلى نوعه المناسب، شاهد المثال:
#include <Qwidget>
#include <Qsettings>
#include <QLineEdit>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QLineEdit lineEdit;
lineEdit.show();
QSettings settings("qt-ar", "MySoft");
lineEdit.setText(settings.value("User/name").toString());
return a.exec();
}
كود بسيط يقوم بقراءة الإسم المحفوظ (من مثال السابق) ويعرضه في QLineEdit، الملاحظ هو إضافة toString لأن القيمة المرجعة عبارة عن QVariant و lineEdit يستقبل QString من خلال setText لذا وجب التحويل للتتناسب الأنواع.

إذا صادف وكانت القيمة غير متوفرة بعد في الملف، يمكن المعامل الثاني من الدالة من إعطاء قيمة إفتراضية للقيمة، كمايلي:
إن لم تتوفر قيمة للمفتاح name في ملف الإعدادات فستقوم الدالة بإعطاء القيمة amine إلى ذلك المفتاح وبالتالي إظهار amine في lineEdit
الدالة allKeys() تقوم بإرجاع قائمة من نوع QStringList تحتوي على جميع مفاتيح المجموعة الحالية والمجموعات الفرعية:
settings.setValue("fridge/size", Qsize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList keys = settings.allKeys();
// keys: ["fridge/color", "fridge/size", "sofa", "tv"]
الدالة childKeys() تقوم بإرجاع قائمة من نوع QStringList تحتوي على جميع مفاتيح المجموعة الحالية فقط:
settings.setValue("fridge/size", Qsize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList keys = settings.childKeys();
// keys: ["sofa", "tv"]
الدالة childGroups() تقوم بإرجاع قائمة من نوع QStringList تحتوي على جميع مفاتيح القسم الذي يحتوي أبناءً بالنسبة للمجموعة الحالية :
settings.setValue("fridge/size", Qsize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList keys = settings.childGroups();
// keys: ["fridge"]
الدالة contains(QString key) تقوم بإرجاع صح إن كان هناك مفتاح يحمل الإسم key وإلا فخطأ:
settings.setValue("fridge/size", Qsize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
bool exists = settings.contains("name");
// exists = false
تطبيق عملي:
طبعا الأوامر السابقة تبقى كمدخل فقط، التطبيق العملي لهذه الخاصية (حفظ واسترجاع البيانات) يكون عادة عند إيقاف وتشغيل البرنامج، هنا تقوم المكتبة Qt بتوفير فئة QEvent تحتوي على عدة أحداث منها حدث إغلاق البرنامج، يتم عبر الدالة التالية:
يتم توريث هذه الدالة من الفئة QWidget. نقوم بإعادة كتابة محتواها هكذا مثلا:
{
writeSettings();
event->accept();
}
void MainWindow::writeSettings()
{
QSettings settings("Qt Soft", "Prog");
settings.beginGroup("MainWindow");
settings.setValue("size", size());
settings.setValue("pos", pos());
settings.endGroup();
}
قمنا بفصل أوامر الحفظ في الدالة writeSettings تحتوي على أوامر عادية سبق وشرحناها، أما السطر الثاني فهو مهم لقبول حدث الإغلاق وإلا فلن يغلق البرنامج.
عملية قراءة البيانات تتم عادة عند تشغيل البرنامج، وفي الـ constructor تحديدا، ويفضل فصلها في دالة أخرى لتنظيم الكود، ثم لحفظ الخصائص التي تم قراءتها طوال تشغيل البرنامج وبدلا من أن نستدعي دالة القراءة كل مرة، نقوم بحفظ الخصائص في متغيرات، مثال يوضح العملية:
{
...
readSettings();
}
void MainWindow::readSettings()
{
QSettings settings("Qt Soft", "Prog");
settings.beginGroup("MainWindow");
size = settings.value("size", QSize(400, 400)).toSize();
pos = settings.value("pos", QPoint(400, 130)).toPoint();
settings.endGroup();
resize(size);
move(mov);
}
بالتأكيد يمكنك تخصيص الدوال إلى ماتريد وفق متطلبات برنامجك، راجع التوثيق فستجد مايسرك من الخصائص لحفظها.
هذا كل شيء، بالتوفيق وبرمجة ممتعة.

![[del.icio.us]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/delicious.png)
![[Digg]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/digg.png)
![[Facebook]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/facebook.png)
![[Google]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/google.png)
![[Mixx]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/mixx.png)
![[Sphinn]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/sphinn.png)
![[StumbleUpon]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/stumbleupon.png)
![[Technorati]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/technorati.png)
![[Windows Live]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/windowslive.png)
![[Yahoo!]](http://amine27.zici.fr/wp-content/plugins/bookmarkify/yahoo.png)
ياااه أخيراً يا عم أمين رجعت تنشط المدونة وتنفض التراب عنها
مُبارك علينا يا سيدي