Russian Qt Forum
Июнь 08, 2024, 10:27 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: Динамически определить тип объекта?  (Прочитано 14060 раз)
alex_beginner
Гость
« : Январь 14, 2012, 20:35 »

Есть функция, принимающая, ну, скажем, QWidget.
Как внутри функции определить, Widget какого типа я в неё передал?

Ну т.е. как бы например в object Pascal я написал бы:
....................................
if (Widget is QLineEdit) then //Определение типа
   (Widget as QLineEdit).Делать_то_то()  //Преобразование типа.вызов()
else if (Widget is QDateEdit) then
   (Widget as QDateEdit).Делать_что_то_другое();
.....................................

А что здесь писать? Есть тут такое?
Записан
mutineer
Гость
« Ответ #1 : Январь 14, 2012, 20:58 »

Можно сделать Widget.metaObject().className()

Но это фиговое проектирование, так делать не стоит
Записан
popper
Гость
« Ответ #2 : Январь 14, 2012, 21:16 »

qobject_cast
Записан
alex_beginner
Гость
« Ответ #3 : Январь 14, 2012, 21:17 »

Хорошо - научите, как стоит делать.

Задача такая: я хочу сохранить значения кучи виджетов, а потом их восстановить. Но не хочу для каждой формы делать это линейно, на 2 страницы исходников.
Вместо этого я хочу написать функцию, которая бы в цикле (пока ещё не решил, в каком) обойдёт все виджеты, и нужные мне (тоже пока не решил, как определить нужные. Динамическое свойство? В Delphi я использовал свойство контрола Tag) .
Но дело в том, что где-то придётся делать setText(), где-то setDate() и т.д.

Как мне грамотно написать такую функцию средствами QT?
Записан
stima
Гость
« Ответ #4 : Январь 14, 2012, 23:19 »

Зачем определять тип виджета?, определи тип значения:

Код:
pseudo code

QString text = label->getText();

saveSettings("myLabel", text);

text = TextEdit->getText();

saveSettings("myTextEdit", text);

-----------------------

restoreSettings()
{
    QString text = load("label");

    label->setText(text);

   text = load("TextEdit");

   textEdit->setText(text);
}

т.е. сохраняй не просто в кучу, а в определенном структурированном порядке, а потом, просто пройдя по сохраненному выбери нужное и пошли нужному виджету.
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4732



Просмотр профиля WWW
« Ответ #5 : Январь 14, 2012, 23:49 »

никогда сам так не делал и не знаю будет ли работать, но попробуй вот как. задай каждому виджету, который ты хочешь сохранить, 2 динамических свойства: чтение значения и запись значения. например:
Код
C++ (Qt)
lineEdit->setProperty("getter", "text");
lineEdit->setProperty("setter", "setText");
потом в коде сохранения для каждого виджета будешь вызывать
Код
C++ (Qt)
QVariant retVal;
QMetaObject::invokeMethod(widget, widget->property("getter"), Q_RETURN_ARG(QVariant, retVal));
// сохранить retVal
а при чтении:
Код
C++ (Qt)
// считываешь значение в QVariant value
QMetaObject::invokeMethod(widget, widget->property("setter"), Q_ARG(QVariant, value));
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
andrew.k
Гость
« Ответ #6 : Январь 15, 2012, 00:32 »

никогда сам так не делал и не знаю будет ли работать, но попробуй вот как. задай каждому виджету, который ты хочешь сохранить, 2 динамических свойства: чтение значения и запись значения. например:
Код
C++ (Qt)
lineEdit->setProperty("getter", "text");
lineEdit->setProperty("setter", "setText");
Так чтобы задать эти динамические свойства нужно будет написать код, которого собственно ТС хочет избежать.
И получается шило на мыло.

Чего плохого в таком коде?
Код
C++ (Qt)
QList<QWidget *> widgets = findChildren<QWidget *>();
for (int i = 0, count = widgets.count(); i < count; ++i)
{
 QWidget * w = widgets[i];
 QVariant v;
 if (w->metaObject()->className() == "QLineEdit")
 {
   QLineEdit * le = qobject_cast<QLineEdit *>(w);
   if(le)
   {
     v = le->text();
   }
 }
 else if (w->metaObject()->className() == "QCheckBox")
 {
   QCheckBox *cb = qobject_cast<QCheckBox *>(w);
   if(cb)
     v = cb->isChecked();
 }
 //....
}
 

Аналогично с восстановлением. Правда надо как-то понимать куда восстанавливать данные.

Наверное это не очень технологчино (сохранять данные из формы и в нее загружать), но раз человеку надо.
Записан
mutineer
Гость
« Ответ #7 : Январь 15, 2012, 01:11 »

проверка по имени класса тут даже лишняя - можно просто делать qobject_cast. В случае несовпадения типов он вернет нулевой указатель
Записан
kambala
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4732



Просмотр профиля WWW
« Ответ #8 : Январь 15, 2012, 01:16 »

Чего плохого в таком коде?
та же куча ифов, которой ТС хочет избежать Улыбающийся плюс там могут использоваться свои виджеты, о которых заранее (в момент компиляции) нельзя знать.

ну и конечно же никто не сравнивает const char * с помощью == Подмигивающий
Записан

Изучением C++ вымощена дорога в Qt.

UTF-8 has been around since 1993 and Unicode 2.0 since 1996; if you have created any 8-bit character content since 1996 in anything other than UTF-8, then I hate you. © Matt Gallagher
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Январь 15, 2012, 01:16 »

Частенько находятся "неприятные исключения" который разрушают стройный общий механизм  Улыбающийся
Напр QLineEdit может отображать 2-3 знака после запятой, а само значение хранится с большей точностью.

Также непонятно - а откуда в UI взялись значения? И что, нет никакой реакции на (единичный) пользовательский ввод, данные не запоминаются в текущих структурах? А если запоминаются то надо и сохранять те структуры, а не UI
Записан
andrew.k
Гость
« Ответ #10 : Январь 15, 2012, 01:19 »

Чего плохого в таком коде?
та же куча ифов, которой ТС хочет избежать Улыбающийся плюс там могут использоваться свои виджеты, о которых заранее (в момент компиляции) нельзя знать.
Это существенно меньшая куча ифов.
ну и конечно же никто не сравнивает const char * с помощью == Подмигивающий
Считай, что это опечатка.
QString("QLineEdit") ясное дело.
Записан
alex_beginner
Гость
« Ответ #11 : Январь 15, 2012, 02:26 »

Не знаю, хорошо ли, плохо ли - но нафигачил вот такое, и оно работает:
Код:
void SaveSettings(QWidget * widget, QString organization,QString application, const char * AddPropName)
{
    QSettings settings(organization,application);
    settings.beginGroup(widget->objectName());
    settings.setValue("size", widget->size());
    settings.setValue("pos", widget->pos());
    foreach (QWidget * w, widget->findChildren<QWidget *>())
    {
        if (w->property(AddPropName).toBool()) //Need for save/load
        {
            if (QLineEdit * o = qobject_cast<QLineEdit *>(w))
            {
                settings.setValue(o->objectName(),o->text());
                continue;
            }
            if (QDateEdit * o = qobject_cast<QDateEdit *>(w))
            {
                settings.setValue(o->objectName(),o->date());
                continue;
            }
            if (QTimeEdit * o = qobject_cast<QTimeEdit *>(w))
            {
                settings.setValue(o->objectName(),o->time());
                continue;
            }
            if (QRadioButton * o = qobject_cast<QRadioButton *>(w))
            {
                settings.setValue(o->objectName(),o->isChecked());
                continue;
            }
            if (QCheckBox * o = qobject_cast<QCheckBox *>(w))
            {
                settings.setValue(o->objectName(),o->isChecked());
                continue;
            }
        }
    }
    settings.endGroup();
}
А вызов из формы вот такой:
Код:
SaveSettings(this,organization,application,"Save");
Теперь настройка того, что нужно сохранять, стала очень простой: помечаю с контролом нужные виджеты, оптом добавляю им динамическое свойство Save, и оптом же ставлю ему галку. Всё - эти значения сохраняются. Если что-то нужно отменить - убрал галку (или удалил свойство). Никакой писанины в исходнике.
Ну а функция восстановления аналогична. Если добавятся новые виджеты - ну, допишу функцию (скопирую блочок if и подправлю). Всё равно она только в одном месте, и только один раз (а из форм вызывается).
Записан
stima
Гость
« Ответ #12 : Январь 15, 2012, 03:49 »

Я лично не вьеду. Зачем так сложно?)

Код:
pseudo code

class ISavingWidget
{
   static const QString organization;
   static const QString application;
  
   bool needSave;

   virtual bool saveSettings() {
      реализация по умолчанию;
   }
   virtual bool loadSettings() {
     реализация по умолчанию;
   }
};

claass MyWidget : public ISaveWidget {
    private:
        QLineEdit *e;
        QDateTime *t;
        ----
    public:
        bool saveSettings() {
            if ( !needSave ) return false; // нечего сохранять то что не надо сохранять, поэтому false            


           QSettings s(org, app);
           ....
           s.setValue(e->objectName(), e->text);
           ....  
        }

        bool loadSettings() {
              ...      
        }
};


void saveSettings(ISaveWidget *w)
{
     if ( w->saveSettings() ) {
         LOG << "...."  
     } else {
          ....
     }
}

void loadSettings(ISaveWidget *w)
{
    if ( w->loadSettings() )
    {
       ...
   } else ....
}

void main()
{
   MyWidget w;

   saveSettings(&w); --- если надо расширить функционал
   //или просто w.saveSettings

}


п.с. Ну оочень растроило:
Цитировать
ну, допишу функцию (скопирую блочок if и подправлю)
. Это кхм... а если у вас станет 100 обьектов в одном виджеет и 1 в другом, 99 лишних проверок. 99 непонятных строчек кода. Или вам придеться портировать класс, но про функцию вы забудете. Или прийдет другой программист, и вообще не вьедет зачем она(ведь грубо говоря у вас перебор n виджетов ибо вы еще if подобавляете).
п.с.с. Я вообще не вьеду зачем урезать класс до QWidget, это типо в прикол показать, что знаеш, что такое findChildren?? и qobject_cast?
« Последнее редактирование: Январь 15, 2012, 04:01 от stima » Записан
fuCtor
Гость
« Ответ #13 : Январь 15, 2012, 11:31 »

А если вариант не привязываться к типу, а только имени объекта (тобишь должны быть уникальны):
И так, у нас есть у Qwidget N стандартных свойств + у каждого есть свои M, итого N + M свойств. Все сразу предусмотреть не реально, да и не нужно в принципе что-то знать о них.

Реализация будет такой:
сохранение
Код
C++ (Qt)
bool saveSettings(const QObject * obj, QSettings *settings)
{
if(!(obj && settings))
{
return false;
}
 
QString objectName_(obj->objectName());
 
if(objectName_.isEmpty())
{
qWarning("objectName is empty");
return false;
}
 
settings->beginGroup(objectName_);
 
const QMetaObject * metaObj_ = obj->metaObject();
int count = metaObj_->propertyCount();
for(int i = 0; i < count; ++i)
{
QMetaProperty prop = metaObj_->property(i);
settings->setValue(QString::fromLatin1(prop.name()), prop.read(obj));
}
settings->endGroup();
return true;
}
 

восстановление
Код
C++ (Qt)
bool restoreSettings(QObject * obj, QSettings *settings)
{
if(!(obj && settings))
{
return false;
}
 
QString objectName_(obj->objectName());
 
if(objectName_.isEmpty())
{
qWarning("objectName is empty");
return false;
}
 
settings->beginGroup(objectName_);
 
const QMetaObject * metaObj_ = obj->metaObject();
int count = metaObj_->propertyCount();
for(int i = 0; i < count; ++i)
{
QMetaProperty prop = metaObj_->property(i);
prop.write(obj, settings->value(QString::fromLatin1(prop.name())));
}
settings->endGroup();
return true;
}

Подходит для любого виджета да и объекта в принципе.
« Последнее редактирование: Январь 15, 2012, 11:35 от fuCtor » Записан
alex_beginner
Гость
« Ответ #14 : Январь 15, 2012, 11:48 »

Цитировать
pseudo code

class ISavingWidget
{
   static const QString organization;
   static const QString application;
   bool needSave;
   virtual bool saveSettings() {
      реализация по умолчанию;
   }
   virtual bool loadSettings() {
     реализация по умолчанию;
   }
};

claass MyWidget : public ISaveWidget {
    private:
        QLineEdit *e;
        QDateTime *t;
        ----
    public:
        bool saveSettings() {
            if ( !needSave ) return false; // нечего сохранять то что не надо сохранять, поэтому false           
           QSettings s(org, app);
           ....
           s.setValue(e->objectName(), e->text);
           ....   
        }

        bool loadSettings() {
              ...     
        }
};

void saveSettings(ISaveWidget *w)
{
     if ( w->saveSettings() ) {
         LOG << "...." 
     } else {
          ....
     }
}

void loadSettings(ISaveWidget *w)
{
    if ( w->loadSettings() )
    {
       ...
   } else ....
}

void main()
{
   MyWidget w;

   saveSettings(&w); --- если надо расширить функционал
   //или просто w.saveSettings
}

А тут уже я не очень понял.
Почему будет 100 проверок типов, если 100 объектов? Проверок будет столько, сколько различных типов объектов (если десяток наберётся на форму - то хорошо).
А ваш примерчик я чего-то не разобрал. Не потому, что он плохой (видимо), а потому что я новичок.
Т.е. если правильно понял, вы предлагаете сделать наследников всех этих полей, кнопок и т.д. с встроенной функциональностью сохранения/восстановления? Ну, наверно можно. Т.е. делать свои виджеты, которые добавлять в стандартную панель - так получается - у которых в дизайнере будет галка "Сохранение"? Или как?

Можете набросать простенький пример (ну, скажем, 1 форма, там 3 виджета, и сохранение восстановление)?
Потому что пока я не понимаю до конца, что предложено. Чего-то не знаю видимо. Когда-то давно писал на "голом" C, а вот C++, так получилось, немного прошёл стороной. Пробел этот ощущаю - ну что делать... Буду учиться.
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.165 секунд. Запросов: 19.