Название: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 15, 2010, 08:56 есть многостраничный диалог настроек с десятками контролов, надо собрать с них всех сигналы changed*(), чтобы знать, когда надо копировать настройки при закрытии диалога, когда не надо (можно, конечно, по Ок переписывать всегда, а по Cancel всегда хренить, но как-то это не очень нравится, тем более, что надо по Cancel выдать предупреждение, если настройки были изменены)
а эти changed*() Тролли умудрились сделать очень разнообразными, где-то параметр int, где-то другой... и теперь грустно, что придется руками писать, кроме копирования настроек, еще и различные слоты, к которым changed*() должны быть присоединены, и в конструкторе диалога настроек еще все это соединять, и не забыть, и не пропустить ничего, а контролов... десятки... может есть какой-то автоматизированный способ это все отследить? я его в документации не вижу, может кто делал уже, подскажет? Название: Re: автоматизировать связи changed*() Отправлено: Kolobok от Июнь 15, 2010, 09:55 и теперь грустно, что придется руками писать, кроме копирования настроек, еще и различные слоты... Воспользуйся QSignalMapper может есть какой-то автоматизированный способ это все отследить? Как вариант, если лень самому все делать, храни настройки в бд. По Ок делай commit, по Cancel rollback. Название: Re: автоматизировать связи changed*() Отправлено: GreatSnake от Июнь 15, 2010, 09:57 Никто вам не мешает навешивать один слот changed() без аргументов на все "changed*()" сигналы.
Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 15, 2010, 10:16 можно конечно и один слот changed() сделать, но это ничего не меняет по существу - все контролы все равно нужно будет по отдельности подключать, поскольку нельзя написать SIGNAL(colorChanged()) если он colorChanged(QColor), подключение просто не выполнится, и регулярный механизм для гомогенного подключения сигналов QtColorPicker::colorChanged(QColor) и QComboBox::currentIndexChanged(int) тут не просматривается
а QSignalMapper наверно было бы то, что надо, но в другой реализации - а так все равно надо руками его подключать ко всем контролам, нет разницы, также точно можно и без QSignalMapper просто один слот в классе диалога создать вот если бы родительские классы для разных контролов имели некий общий сигнал changed(), который выдается, если объект изменился, независимо от его структуры... например, у QWidget если бы такой сигнал был, или даже у QObject... то есть, сигналы changed*() у дочерних классов все равно остаются, но обязательно вызывают этот сигнал у своего родителя - тогда все элементарно бы получалось и автоматизировалось, я бы в цикле по всем контролам пробежал и их подключил, и дальше можно добавлять или удалять контролы, они бы автоматом подключались, но поскольку у их changed*() разные имена и параметры, так не получается :( Название: Re: автоматизировать связи changed*() Отправлено: GreatSnake от Июнь 15, 2010, 10:28 Цитировать ...поскольку нельзя написать SIGNAL(colorChanged()) если он colorChanged(QColor), подключение просто не выполнится Вы меня не поняли. Я говорил про другое.Зачем менять содержимое сигнала? Нужно правильно описать сигнал и повесить на него один общий слот: Код
Другое дело, что юзер может изменить сожержимое контрола, а потом вернуть его обратно и состояние изменения должно по-хорошему сброситься для него. Но это уже вам решать. Название: Re: автоматизировать связи changed*() Отправлено: GreatSnake от Июнь 15, 2010, 10:48 На самом деле, можно сделать намного красивее и вообще не завязываться на "changed*()".
Во время создания диалога в свойствах контрола сохраните его значение. В accept() пробежитесь по всем контролам и сравните текущее с сохраненным. Всё просто) Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 15, 2010, 11:07 Цитировать Вы меня не поняли. Я говорил про другое. Зачем менять содержимое сигнала? Нужно правильно описать сигнал и повесить на него один общий слот: я то как раз понял, поскольку так и предполагал сделать, но вы меня не поняли... :) я могу написать несколько десятков строк с connect, но стараюсь от этого избавиться, поскольку при добавлении или удалении контролов надо добавлять или удалять соответствующие им connect-ы, и вообще в нескольких десятках контролов нетрудно запутаться, что-то потерять и т.д. - я говорю о решении, которое бы подключало ВСЕ контролы диалога, независимо от их числа и типа Цитировать Во время создания диалога в свойствах контрола сохраните его значение. В accept() пробежитесь по всем контролам и сравните текущее с сохраненным. Всё просто с точки зрения количества подключений и вероятности ошибки это практически тоже самое, что подключить все контролы к одному слоту построчно, поскольку функции получения значения контрола у всех типов контролов разные, и возвращают разные типы данных, значит их нельзя просто пробежать в цикле foreach( control, controlList ) Название: Re: автоматизировать связи changed*() Отправлено: GreatSnake от Июнь 15, 2010, 11:17 Цитировать с точки зрения количества подключений и вероятности ошибки это практически тоже самое, что подключить все контролы к одному слоту построчно, поскольку функции получения значения контрола у всех типов контролов разные, и возвращают разные типы данных, значит их нельзя просто пробежать в цикле foreach( control, controlList ) Мде, т.е. вам нужна волшебная палочка) На самом деле тролли подумали о ней. Копайте QObject::property() и QVariant(). Название: Re: автоматизировать связи changed*() Отправлено: BRE от Июнь 15, 2010, 11:21 В Qt есть возможность:
* получить список всех дочерних виджетов на главном; * добавить property для каждого объекта, в том числе дочернего виджета; * получить имя класса для объекта; * для каждого класса виджета имя сигнала об изменении - известно. Все просто. :) Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 15, 2010, 17:14 Цитировать Копайте QObject::property() и QVariant(). вот-вот-вот... истина где-то рядом... (С) Малдер если бы property() понимал сложный запрос с wildcard типа property( "*Changed(*" - можно было бы просто запросить каждый контрол... хотя наверно можно через metaObject получить все сигналы, и QRegExp-ом отобрать нужные кто-нибудь делал? все получается? Название: Re: автоматизировать связи changed*() Отправлено: Igors от Июнь 15, 2010, 20:31 Я накручивал примерно так (псевдокод)
Код Ну понятно DataRec имеет много методов для передачи данных из UI в пользовательские структуры и наоборот. Задумка автоматизировать операции пробегаясь по QHash (знаем источник и приемник). Впрочем для немодальных окон changed() все равно приходится отслеживать/связывать, можно лишь упростить дальнейшую обработку. Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 15, 2010, 20:49 все равно в таблицу надо руками добавлять, и не попутать dataType и ctrlType, хочется чисто динамически, поскольку диалог настроек полностью рисуется в Дизайнере
хватает только написания кода для передачи всех настроек из класса Settings::QSettings и обратно... но там хоть запутаться сложно, хотя пропустить что-нибудь, как нефик делать просто контролов в настройках очень много че-то не вижу я, как получить список слотов КуОбъекта, наверняка есть, но не туда смотрю Название: Re: автоматизировать связи changed*() Отправлено: BRE от Июнь 15, 2010, 21:04 Посмотри эту статью: http://doc.trolltech.com/qq/qq11-mandatoryfields.html
Думаю идея появится. Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 15, 2010, 21:52 ну влоб их способ не годится - там описан метод add() который добавляет контролы, а у меня они в дизайнере рисуются
а вот widget->inherits( <имя класса> ) и подключение сигнала изменения этого класса - похоже на то, что надо, можно пробежать по всем виджетам настроек, и аналогичным образом их подключить надо только не забывать добавлять соответствующую проверку имени класса, если будет использоваться контрол, наследующий какой-нибудь класс, который еще не включен в проверки Название: Re: автоматизировать связи changed*() Отправлено: BRE от Июнь 16, 2010, 08:14 ну влоб их способ не годится - там описан метод add() который добавляет контролы, а у меня они в дизайнере рисуются Ну в лоб его использовать и не нужно, хотя совершенно не важно где рисуются виджеты в дизайнере или непосредственно в коде. В обоих случаях к ним есть доступ.надо только не забывать добавлять соответствующую проверку имени класса, если будет использоваться контрол, наследующий какой-нибудь класс, который еще не включен в проверки Добавить в конец одну секцию else с Q_ASSERT_X вроде сложно забыть. :)Название: Re: автоматизировать связи changed*() Отправлено: hackoff от Июнь 16, 2010, 10:09 А если при закрытии диалога в методе closeEvetn пробегаться по всей форме и сохранять все в реестр, при старте в конструкторе восстанавливать. Или я не понял суть вопроса?
Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 16, 2010, 10:31 Цитировать Или я не понял суть вопроса? именно собственно решение уже фактически найдено, надо только реализовать его, руки дойдут сделаю а реестр идет лесом, у Qt надо пользоваться QSettings BTW: кто знает, можно ли корректно (без хаков с #define) на винде QSettings перенастроить так, чтобы не в реестр писало, а в INI файл, чтобы настройки сохранялись в каталоге приложения (чтобы оно работало без инсталляции, с флешки)? Название: Re: автоматизировать связи changed*() Отправлено: GreatSnake от Июнь 16, 2010, 10:34 Цитировать BTW: кто знает, можно ли корректно (без хаков с #define) на винде QSettings перенастроить так, чтобы не в реестр писало, а в INI файл, чтобы настройки сохранялись в каталоге приложения (чтобы оно работало без инсталляции, с флешки)? QSettings::QSettings ( const QString & fileName, Format format, QObject * parent = 0 )Название: Re: автоматизировать связи changed*() Отправлено: BRE от Июнь 16, 2010, 10:35 BTW: кто знает, можно ли корректно (без хаков с #define) на винде QSettings перенастроить так, чтобы не в реестр писало, а в INI файл, чтобы настройки сохранялись в каталоге приложения (чтобы оно работало без инсталляции, с флешки)? Ну вроде в документации написано:Цитировать QSettings::QSettings ( Format format, Scope scope, const QString & organization, const QString & application = QString(), QObject * parent = 0 ) Constructs a QSettings object for accessing settings of the application called application from the organization called organization, and with parent parent. If scope is QSettings::UserScope, the QSettings object searches user-specific settings first, before it searches system-wide settings as a fallback. If scope is QSettings::SystemScope, the QSettings object ignores user-specific settings and provides access to system-wide settings. If format is QSettings::NativeFormat, the native API is used for storing settings. If format is QSettings::IniFormat, the INI format is used. If no application name is given, the QSettings object will only access the organization-wide locations. Название: Re: автоматизировать связи changed*() Отправлено: Igors от Июнь 16, 2010, 11:31 Пример: есть список нескольких экземпляров объектов одного типа. Данные показываются/редактируются в немодальном окне. Выбрали из списка один экземпляр - его данные в окне. Выбрали другой - его. Что будете делать если завязались на QSettings?
Название: Re: автоматизировать связи changed*() Отправлено: Гурман от Июнь 16, 2010, 12:43 Цитировать вроде в документации написано: пардон, и правда написано... :) а задача решена! работает! ;D кусочек конструктора диалога настроек Код: QWidget* widget; причем последний виджет не из комплекта Qt, добавлен отдельно надо только вынести в отдельный массив список имен виджетов, и список имен их changed() сигналов, чтобы при необходимости просто добавлять туда новые, и больше никакой код не переписывать кстати, совет добавить туда Q_ASSERT_X не годится - findChildren оббегает все виджеты, причем рекурсивно, а кроме активных селекторов на диалоге находятся еще пассивные метки и полуактивные программно изменяемые нередактируемые строки (например, сэмпл текста с разными подсветками) - поэтому в if-ах должны быть только те классы, которые точно будут генерить сигнал изменения Цитировать Пример: есть список нескольких экземпляров объектов одного типа. Данные показываются/редактируются в немодальном окне. Выбрали из списка один экземпляр - его данные в окне. Выбрали другой - его. Что будете делать если завязались на QSettings? а давайте без оффтопика... впрочем, отвечу - редактирование и сохранение данных объектов и редактирование и сохранение настроек приложения - суть разные вещи, и делаются по-разному, хотя, впрочем, в QSettings можно и первое запузырить, если кончено, объекты несложные, поскольку Qsettings - это интерфейс к системно-независимой простейшей иерархической базе данных... создайте отдельную ветку, если интересно дальше это обсуждать Название: Re: автоматизировать связи changed*() Отправлено: BRE от Июнь 16, 2010, 15:44 кстати, совет добавить туда Q_ASSERT_X не годится - findChildren оббегает все виджеты, причем рекурсивно, а кроме активных селекторов на диалоге находятся еще пассивные метки и полуактивные программно изменяемые нередактируемые строки (например, сэмпл текста с разными подсветками) - поэтому в if-ах должны быть только те классы, которые точно будут генерить сигнал изменения Не годиться в том виде, что сделал ты. :)Например, можно было каждому объекту (виджету), который должен участвовать в проверке, добавить свойство. И соответственно проверять вначале, если это свойство true, то смотреть, что это за класс. Вот там бы этот assert пригодился. Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 16, 2010, 17:02 Цитировать Например, можно было каждому объекту (виджету), который должен участвовать в проверке, добавить свойство. ой мама... это же что получилось бы? :o свойство добавлять руками?? тогда в чем глубокий смысл всего этого??? получилось бы еще хуже - добавился виджет, и к нему надо еще дописать хренов код для добавления ему свойства... :-[ а если не руками, то... как определять автоматом какому виджету надо его добавить???? ;D а сейчас я уже переделал на цикл по массивам, и при добавлении виджета единственное что надо сделать - если на диалоге еще не было такого класса виджетов, то его имя класса надо вписать в конец массива char*, а в конец другого массива char* вписать имя сигнала об изменении, И ВСЕ! Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: BRE от Июнь 16, 2010, 17:30 Цитировать Например, можно было каждому объекту (виджету), который должен участвовать в проверке, добавить свойство. ой мама... это же что получилось бы? :o свойство добавлять руками?? тогда в чем глубокий смысл всего этого??? получилось бы еще хуже - добавился виджет, и к нему надо еще дописать хренов код для добавления ему свойства... :-[Подошел простой вариант - хорошо, но... Возможно понадобиться на страницы добавить виждеты, которые не должны влиять на флаг изменения и соответственно не должны сохраняться. Например, это checkbox "Точная настройка", которая показывает большее количество параметров или скрывает их. Этот виджет нужен только для удобства пользователя и никак не влияет на настройки системы. При таких условиях и пригодились бы property, которые можно было задавать в designer'е. Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 16, 2010, 17:44 в частном случае для выбора "точная" или "грубая" настройка мне проще в дереве выбора страниц пару дополнительных веток сделать
но если понадобятся виджеты, которые будут совпадать по классу, но не должны быть сохраняемыми (хотя пока не просматривается, где они могут быть нужны), то их будет принципиальное меньшинство, поэтому гораздо проще в обработчике сигнала changed проверить, не прислан ли он от такого виджета - и соответственно, проигнорировать Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: BRE от Июнь 16, 2010, 17:47 в частном случае для выбора "точная" или "грубая" настройка мне проще в дереве выбора страниц пару дополнительных веток сделать Это знал только ты. :)но если понадобятся виджеты, которые будут совпадать по классу, но не должны быть сохраняемыми (хотя пока не просматривается, где они могут быть нужны), то их будет принципиальное меньшинство, поэтому гораздо проще в обработчике сигнала changed проверить, не прислан ли он от такого виджета - и соответственно, проигнорировать А вот жестко задавать такое поведение в коде, как раз и есть зло, от которого и нужно уходить.Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 16, 2010, 18:04 не согласен
поскольку именно для таких виджетов можно добавить свойство, наличие которого потом проверить в обработчике сигнала в диалоге настроек приложения таких строк для добавления свойств если будет, то 2-3-5, а виджетов, которые генерят нужные сигналы изменений - десятки, возможно даже больше сотни Название: Re: автоматизировать связи changed*() Отправлено: Igors от Июнь 16, 2010, 18:08 if (widget->inherits("QCheckBox")) Это решает лишь частную задачу (отловить "были ли какие-то изменения") да и то плохо, до первого undo, как уже сказали выше. Стандартный путь лучшеconnect(widget, SIGNAL(stateChanged(int)), this, SLOT(slChanged())); Код
Непонятно что же Вы тогда "автоматизируете" если все равно пишете все сигналы/слоты вручную? :) Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: BRE от Июнь 16, 2010, 18:09 не согласен Ну так можно добавить свойства (NoAutoConnect) для 2-3-5 виджетов и проверять его, а все остальные виджеты (без этого установленного свойства) коннектить автоматически.поскольку именно для таких виджетов можно добавить свойство, наличие которого потом проверить в обработчике сигнала в диалоге настроек приложения таких строк для добавления свойств если будет, то 2-3-5, а виджетов, которые генерят нужные сигналы изменений - десятки, возможно даже больше сотни А хардкорить в коде поведение для 2-3-5 избранных виджетов путь к получению кучи сюрпризов во время дальнейшего сопровождения кода. И здесь уже не важно кто с этим согласен, а кто нет. :) Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 16, 2010, 20:31 Igors
Цитировать Стандартный путь лучше хороший путь, но для этого надо научить MySettings копироваться, сравниваться и т.д. - причем для каждого нового контрола надо корректировать соответствующие методы Цитировать Непонятно что же Вы тогда "автоматизируете" если все равно пишете все сигналы/слоты вручную? вручную я пишу только код копирования текущих настроек в контролы диалога и копирования из контролов обратно, по 2 строки на каждую настройку, причем эти же строки в варианте реализации со сравнением настроек тоже будут, только там в разы больше на каждый контрол придется написать и если добавляется контрол, тип которого еще не поддерживается, как написал выше, добавляю только две строчных константы в массивы насчет undo замечание верное, но это пока терпимо, может потом переделаю иначе, это не трудно BRE Цитировать Ну так можно добавить свойства (NoAutoConnect) для 2-3-5 виджетов и проверять его, а все остальные виджеты (без этого установленного свойства) коннектить автоматически. можно, только где именно добавить и где проверять? я пока сделал цикл автоматического коннекта прямо в конструкторе диалога настроек, собственно там же логично сделать и код добавления свойств - ну и какой смысл их иметь рядом? а сейчас я могу проверять наличие этих свойств в ловушке сигнала об изменении Код: if( sender()->specialWidget() ) а сейчас там разумеется просто changed = true; Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: BRE от Июнь 16, 2010, 21:01 можно, только где именно добавить и где проверять? я пока сделал цикл автоматического коннекта прямо в конструкторе диалога настроек, собственно там же логично сделать и код добавления свойств - ну и какой смысл их иметь рядом? а сейчас я могу проверять наличие этих свойств в ловушке сигнала об изменении Мы про одно и тоже говорим?Я про свойства QMetaObject. Посмотри на: QVariant QObject::property ( const char * name ) const bool QObject::setProperty ( const char * name, const QVariant & value ) Также эти свойства можно задавать непосредственно из дизайнера. Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Гурман от Июнь 16, 2010, 21:10 Цитировать Также эти свойства можно задавать непосредственно из дизайнера. про одно и то же... если из дизайнера можно - это очень неплохо, тогда действительно логично при автоматическом коннекте проверять наличие свойства, и если есть, не присоединять такой виджет хотя с точки зрения банальной логики мало разницы между тем, присоединен ли лишний виджет, но его сигнал игнорируется, либо не присоединен - разница только в количестве проходящих сигналов, но если таких виджетов 2-3-5, то их сигналы несущественны Название: Re: автоматизировать связи changed*() РЕШЕНО Отправлено: Igors от Июнь 16, 2010, 22:03 хороший путь, но для этого надо научить MySettings копироваться, сравниваться и т.д. - причем для каждого нового контрола надо корректировать соответствующие методы Наоборот, будут в разы меньше, ведь Вам надо сравнить просто данные - UI уже отработало. Это сравнение длинно но несложно, оно сплошь и рядом встречается, операции == и != интуитивны. А вот зарядить данные в UI и принять их оттуда - прекрасно автоматизируется и ходов здесь не один. Более того, connect легко поставить на автомат/пулемет (а не выписывать каждый раз). Ну а про "научить копироваться" неудобно и вспоминать - если нет "С" структур - то это уже готово :)... вручную я пишу только код копирования текущих настроек в контролы диалога и копирования из контролов обратно, по 2 строки на каждую настройку, причем эти же строки в варианте реализации со сравнением настроек тоже будут, только там в разы больше на каждый контрол придется написать Не стоит гнаться за слишком умной системой которая все делает автоматом/интерактивно. Да, кое-что придется писать руками - и для каждого члена данных. Вопрос в том как сделать это 1 раз, а не долбить как дятел |