Russian Qt Forum
Ноябрь 24, 2024, 19:57 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

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

Страниц: [1] 2   Вниз
  Печать  
Автор Тема: QListWidget и война с currentItemChanged  (Прочитано 15377 раз)
l_a_m
Гость
« : Апрель 15, 2010, 12:25 »

Доброе время суток Ув. Коллеги!
Ситуация такая: есть QListWidget, требуется отловить изменение выбранного объекта, и при определённых условиях вернуть выделение сделанное пользователем.
пример:
есть список Item-ов:
1
2
3
4

пользователь выбирает Item1, потом выбирает Item3, появляется сообщение - мол "вы уверены, что хотите выбрать именно этот Item?", если да - то выбираем Item3, если нет, то возвращаем выделение Item1. Версия Qt 4.6.2 ОС: Windows (но возможно приложение будет затачиваться под кроссплатформенность).

делаю я примерно следующее:
Код:
QListWidget myList;
connect(&myList, SIGNAL(currentItemChanged (QListWidgetItem *, QListWidgetItem *)), this, SLOT(MySelectedChanged(QListWidgetItem *, QListWidgetItem *)));

//---
MySelectedChanged(QListWidgetItem * current, QListWidgetItem * previous)
{
   myList.setCurrentItem(previous); //до здравствует рекурсия!!!!
}

собственно вопрос, можно ли как либо заблокировать сигнал currentItemChanged? да бы избежать бесконечной рекурсии?
зы: пробовал делать:
Код:
MySelectedChanged(QListWidgetItem * current, QListWidgetItem * previous)
{
   myList.blockSignals(true);
   myList.setCurrentItem(previous); //до здравствует рекурсия!!!!
   myList.blockSignals(false);
}
тогда вообще ничего не происходит :-(. подскажите как быть. Заранее благодарен.

Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #1 : Апрель 15, 2010, 12:36 »

На самом деле, делать такие вещи в слотах не рекомендуется - у Qt может легко поехать крыша.
Зарядите QTimer и уже в нём изменяйте текущий элемент не забыв про рекурсию.
Записан

Qt 5.11/4.8.7 (X11/Win)
l_a_m
Гость
« Ответ #2 : Апрель 15, 2010, 12:42 »

благодарю за ответ, если можно примерчик, т.к. я в Qt пока новичок. И если можно, объясните почему не рекомендуется делать так в слоте?
Записан
alexman
Гость
« Ответ #3 : Апрель 15, 2010, 12:57 »

Попробуй использовать методы:
void QListWidget::itemSelectionChanged ()   [signal]
QList<QListWidgetItem *> QListWidget::selectedItems () const
void QListWidgetItem::setSelected ( bool select )
...
Записан
l_a_m
Гость
« Ответ #4 : Апрель 15, 2010, 13:01 »

благодарю за ответ, пробовал... Но! так я знаю, что произошло событие которое привело к изменению выделения Item-a, знаю какой текущий Item или коллекция Item-ов выделина, но не знаю какой предыдущий Item был выделен. как быть? :-) вижу только добавление отдельного (внешнего) Item-a, который будет хранить в себе предыдущее значение. но как по мне - это не очень красиво, разве нет более симпотишного способа? :-)
и ещё: можно ли как либо заблокировать определённый сигнал, для определённого объекта?
« Последнее редактирование: Апрель 15, 2010, 13:06 от l_a_m » Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #5 : Апрель 15, 2010, 13:17 »

Дело в том, что при вызове setCurrentItem() вызывается QItemSelectionModel::setCurrentIndex() и уже потом модель вызывает нужные сигналы, которые зарядил QListWidget на эту модель. Заблокировав отработку сигналов для QListWidget вы не дали модели вызвать эти сигналы и сам QListWidget не узнал про изменение текущего элемента.

Код примерно такой:
Код
C++ (Qt)
 
void restoreCurrent()
{
    myList.setCurrentRow( myList.property( "current" ).toInt() );
    myList.setProperty( "current", -1 );
}
 
MySelectedChanged(QListWidgetItem * current, QListWidgetItem * previous)
{
   if( !previous || myList.property( "current" ).toInt() != -1 )
     return;
   myList.setProperty( "current", myList.row( previous ) );
   QTimer::singleShot( 0, this, SLOT( restoreCurrent() ) );
}
 
property() можно не использовать, а держать current_row в вашем классе не забыв инициализировать его в -1
Записан

Qt 5.11/4.8.7 (X11/Win)
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #6 : Апрель 15, 2010, 13:27 »

Если хотите сделать красиво, то отнаследуйтесь от QListWidget и перегрузите в нём currentChanged() метод:

Код
C++ (Qt)
void YourListView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
   if( current.row() == 2 && QMessageBox::question() != QMessageBox::Yes )
     return;
   QListWidget::currentChanged( current, previous );
}
 
Записан

Qt 5.11/4.8.7 (X11/Win)
alexman
Гость
« Ответ #7 : Апрель 15, 2010, 13:34 »

Если хотите сделать красиво, то отнаследуйтесь от QListWidget и перегрузите в нём currentChanged() метод:

Код
C++ (Qt)
void YourListView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
   if( current.row() == 2 && QMessageBox::question() != QMessageBox::Yes )
     return;
   QListWidget::currentChanged( current, previous );
}
 
Наверное лучше назвать класс YourListWidget Улыбающийся Хотя это не принципиально!
Записан
alexman
Гость
« Ответ #8 : Апрель 15, 2010, 13:38 »

но как по мне - это не очень красиво, разве нет более симпотишного способа? :-)
Иногда поиск "красивого" способа не оправдан! Если можно обойтись двумя строчками кода лучше влепить две строчки кода (это по-моему) и не париться!
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #9 : Апрель 15, 2010, 13:45 »

"Более симпатишный" вероятно был бы хорошо заметен в документации и назывался как-нибудь "bool canChangeSelection(..)" (хотя неясно было бы это в плюс или минус). Но поскольку его нет - сохранять предыдущий выбор придется так или иначе.
Записан
l_a_m
Гость
« Ответ #10 : Апрель 15, 2010, 17:08 »

попробовал реализовать вариант, который описал GreatSnake (который со свойствами).
Так у меня ничего и не получилось :-( виджет делает вид восстанавливает значение (вызывает пару раз сам себя) и в конечном итоге всё равно становится значением которое выделил пользователь, а не предыдущим значением :-(. ЗЫ: свойство я пробовал инициализировать как в -1, так и в 0 - результат одинаковый :-(... 
Записан
Marat(Qt)
Гость
« Ответ #11 : Апрель 15, 2010, 20:33 »

Поведение нетипичное для обычного ListView и его стандартными методами, на мой взгляд, описывать его не правильно. В данном случае лучшим решением является переопределение метода(ов) как это предложил GreatSnake:
Если хотите сделать красиво, то отнаследуйтесь от QListWidget и перегрузите в нём currentChanged() метод:

Код
C++ (Qt)
void YourListView::currentChanged( const QModelIndex & current, const QModelIndex & previous )
{
   if( current.row() == 2 && QMessageBox::question() != QMessageBox::Yes )
     return;
   QListWidget::currentChanged( current, previous );
}
 

Т.е. если нужно получить нетипичное поведение виджета - ни в коем случае не начинайте "войну" с ним и его сигналами/слотами, меняйте их и все у вас получится.
Записан
l_a_m
Гость
« Ответ #12 : Апрель 16, 2010, 08:40 »

спасибо...
а можете ещё разъяснить что означает     
Код:
if( current.row() == 2 
это количество выделенных строк или индекс на выделенную строку?
Записан
GreatSnake
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 2921



Просмотр профиля
« Ответ #13 : Апрель 16, 2010, 08:44 »

Индекс.
А вы что, ассистентом вообще не пользуетесь?
« Последнее редактирование: Апрель 16, 2010, 08:46 от GreatSnake » Записан

Qt 5.11/4.8.7 (X11/Win)
l_a_m
Гость
« Ответ #14 : Апрель 16, 2010, 08:54 »

пользуюсь, но сегодня тяжёлое утро :-) я ещё сплю....
спс, за ответы :-)
Записан
Страниц: [1] 2   Вверх
  Печать  
 
Перейти в:  


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