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

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

Страниц: [1] 2 3 4   Вниз
  Печать  
Автор Тема: QSortFilterProxyModel - удаление строки  (Прочитано 24175 раз)
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« : Апрель 26, 2015, 08:03 »

Удаляю итем в прокси модели через Контекстное меню и клавишу Del. Заодно покритикуйте решение или предолжите лучше.
Контекстное меню устроил так:
Код
C++ (Qt)
void proxyPaneWidget::showCustomMenu(const QPoint &pos)
{
 m_currentItemIndex = m_proxyList->indexAt(pos);
 
 m_proxyMenu->addAction( m_deleteAction );
 m_proxyMenu->exec( m_proxyList->mapToGlobal( pos ) );
 
 m_currentItemIndex...; // HOW TO DO?
}
В методе удаления проверяю как пользователь хочет удалить итем, через Контекстное меню или с помощью клавиши Del:
Код
C++ (Qt)
void proxyPaneWidget::deleteSelectedItem()
{
 QModelIndex index = m_proxyList->currentIndex();
 
 if( m_currentItemIndex.isValid() )
   index = m_currentItemIndex;
 
 m_source->removeItem(m_proxyModel->mapToSource(index).row());
}

Проблема в том, что если пользователь вызывал контекстное меню и передумал удалять, то индекс остается, соответственно есть шанс удалить клавишей не ожидаемый пользователем итем.
В модели дерева файловой системы меню удаления делал подобным же образом, но там можно было просто послать строку пути, которую не сложно было обнулить.
Собственно вопрос такой. Как сделать индекс m_currentItemIndex невалидным или занулить? Наверное подобный вопрос можно было бы задать в ветке для новичков. Но может само решение удаления не выдерживает критики?
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #1 : Апрель 26, 2015, 12:42 »

Ладно будем думать, что молчание знак того, что ерундой занимаюсь и так не делают. Просто не хотел заводить вторую переменную если можно было обойтись одной. Но может это излишняя предосторожность.
Создал булеву переменную.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #2 : Апрель 26, 2015, 13:29 »

По-моему, можно проще удалять:
Код
C++ (Qt)
void proxyPaneWidget::deleteSelectedItem()
{
 const QModelIndex & index = m_proxyList->currentIndex();
 
 if ( index.isValid() ) {
     int row = m_proxyModel->mapToSource(index).row();
     m_source->removeItem(row);
 }
}

Да и с вызовом контекстного меню тоже самое -- проверяйте валидность текущего индекса и если валидный, добавляйте действие удаления.
Смысл хранить текущий индекс в какой-то переменной я не вижу -- у вас уже есть виджет, который сможет текущий индекс вернуть
« Последнее редактирование: Апрель 26, 2015, 13:32 от gil9red » Записан

Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #3 : Апрель 26, 2015, 14:08 »

Так просто не получится иначе бы не заморачивался. Возможно переменную индекса неудачно назвал.
Как видим из меню пользователь не обязательно мог навести курсор на текущий инденкс. Иначе он мог бы удалить не ожидаемый пункт.
Как мне кажется выбрал более интуитивный вариант - отсылаем позицию курсора.
Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #4 : Апрель 26, 2015, 14:48 »

Так просто не получится иначе бы не заморачивался. Возможно переменную индекса неудачно назвал.
Как видим из меню пользователь не обязательно мог навести курсор на текущий инденкс. Иначе он мог бы удалить не ожидаемый пункт.
Как мне кажется выбрал более интуитивный вариант - отсылаем позицию курсора.

Текущий индекс это тот, который выделен в *View, и выделить элемент можно не только курсором, но и клавишами клавиатуры
Записан

Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #5 : Апрель 26, 2015, 15:09 »

Поэтому и говорю, что неудачно назвал переменную индекса.
Дело в том, что в прокси представлении действительно выделен текущий индекс и пользователь может менять его клавиатурой или ЛКМ.
Но пользователь может навести курсор мыши на другой пункт и вызвать контекстное меню. И здесь стоит упоминуть, что действия правой кнопки мыши я переназначил и пункт не становится текущим. Сделано  это, что бы не правоцировать ненужные действия после выбора пункта.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Апрель 26, 2015, 15:31 »

И здесь стоит упоминуть, что действия правой кнопки мыши я переназначил и пункт не становится текущим. Сделано  это, что бы не правоцировать ненужные действия после выбора пункта.
А что мешает вызвать удаление сразу после закрытия контекстного меню? m_currentItemIndex просто застрелить, а удаление оформить напр так
Код
C++ (Qt)
void proxyPaneWidget::deleteSelectedItem( QModelIndex * delIndex )  // delIndex = 0 в прототипе
{
 QModelIndex index = delIndex ? *delIndex : m_proxyList->currentIndex();
 
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #7 : Апрель 26, 2015, 18:00 »

И здесь стоит упоминуть, что действия правой кнопки мыши я переназначил и пункт не становится текущим. Сделано  это, что бы не правоцировать ненужные действия после выбора пункта.
А что мешает вызвать удаление сразу после закрытия контекстного меню? m_currentItemIndex просто застрелить, а удаление оформить напр так
Код
C++ (Qt)
void proxyPaneWidget::deleteSelectedItem( QModelIndex * delIndex )  // delIndex = 0 в прототипе
{
 QModelIndex index = delIndex ? *delIndex : m_proxyList->currentIndex();
 


Признаю. Ломал голову и ничего не понял. Как устроен слот ясно. Как до него донести индекс с контекстного меню? Естественно в меню у меня не единственный пункт.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Апрель 26, 2015, 18:21 »

Признаю. Ломал голову и ничего не понял. Как устроен слот ясно. Как до него донести индекс с контекстного меню? Естественно в меню у меня не единственный пункт.
Необязательно прямо из меню "сигналить", exec возвращает выбранный QAction.
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #9 : Апрель 26, 2015, 18:36 »

Спасибо за подсказку. У нас ночь уже. Днем буду разбираться.
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #10 : Апрель 27, 2015, 07:02 »

Снова наэкспериментировался. Запустить слот удалось. Проблема в том, что клавиша Del не работает. Видимо в этом случае ей не хватает соединения сигнал-слот. Но стандартного сигнала для экшина отправляющего хотя бы позицию курсора я не нашел. Не заводить же неаследника для создания сигнала? Как то затратно. Можно навесить событие на Del, но хрен редьки не слаще.
В общем вопрос. Что не так? Можно ли как то исправить?
Код
C++ (Qt)
void proxyPaneWidget::showCustomMenu(const QPoint &pos)
{
 QAction * m_deleteAction = new QAction( this );
 m_deleteAction->setText( tr( "Delite" ) );
 m_deleteAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
 m_deleteAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
 
 m_proxyMenu = new QMenu( m_proxyList );
 m_proxyMenu->addAction( m_deleteAction );
 
 QModelIndex selectedItemIndex = m_proxyList->indexAt(pos);
 
 QAction *menuAct = new QAction(this);
 menuAct = m_proxyMenu->exec( m_proxyList->mapToGlobal( pos ) );
 
 if( menuAct->text() == "Delite" )
   deleteSelectedItem(&selectedItemIndex);
}


Код
C++ (Qt)
void proxyPaneWidget::deleteSelectedItem(QModelIndex * delIndex)
{
 m_currentItemIndex = delIndex ? *delIndex : m_proxyList->currentIndex();
 m_source->removeItem( m_proxyModel->mapToSource( m_currentItemIndex ).row() );
}
Или я что то недопонимаю, что скорее всего. Или это тупиковая затея.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #11 : Апрель 27, 2015, 08:58 »

Поняли меня правильно, только зачем сорите членами класса? m_proxyMenu (кто за Вас удалять его будет?) и m_deleteAction - не видно никакого смысла делать их членами.

Проблема в том, что клавиша Del не работает.
..
В общем вопрос. Что не так? Можно ли как то исправить?
Не так = непродуманная постановка. При выпадании контекстного меню Вы решили не менять selection а действия меню прилагаются к тому айтему на котором меню появилось. Возможно этот айтем сейчас и не выбран. Это решение спорно. Ну ладно, но тогда причем тут клавиша Del? Что должно произойти если без всякого меню юзер давит Del? Должны удалиться выбранные. А в выпавшем контекстном меню у Вас совсем другое удаление - так чего Вы туда shortcut Del лепите?

Правильно подчеркнуть что удаляться будет именно тот айтем на котором выпало меню, пункт меню должен выглядеть так
Цитировать
Delete <имя айтема>
И без всяких щорткатов
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #12 : Апрель 27, 2015, 10:39 »

Спасибо! По поводу членов класса. Есть такое дело. Необучен. Не всегда представляю (если вообще представляю это правильно) когда я сам должен удалять мусор, когда за меня это сделает мусорщик. Но это был бы следующий ученический вопрос по поводу правильности оформления данного кода (как бы забежали вперед на счет работы над ошибками). Учту и исправлю. Экшин и Меню изначально инициализировались в конструкторе виджета, теперь вроде как осознаю, что такой подход не верен. Хотя вроде как часто видел в кодах, что Акшины именно там готовились, потом заряжались в методе меню.

По поводу непродуманной постановки. Попробую объяснить. Пользователь не просто просматривает список, при выборе пункта списка открывается информационное окно для данного пункта. И когда надо удалить пункт списка вовсе не обязательно, что бы фокус уходил с уже открытого инфоокна, следовательно необязатель, а возможно и не желательно делать айтем текущим. Если же захочет, то для этого ЛКМ.
Считал, что клавиша Del для того и существует, что бы пользователь мог работать клавиатурой без применения мыши, манипулируя клавишами стрелок и удаления. Это происходит гораздо быстрее при быстром списковом просмотре. Изначально предложенная http://www.prog.org.ru/index.php?topic=28819.msg211186#msg211186 реализация именно так и работает (совместно и мышь как надо и клавиша Del). Подумывал сделать это более правильно если есть способ. В контекстном меню просто напоминание, что работает клавиша Del. Зачем же пользователю открывать контестное меню, что бы нажать клавишу Del? И что в данном случае я сделал не так, мне не понятно. Если пользователь без всякого контекстного меню давит Del - удаляется текущий пункт, только и всего.

Третий абзац я как то пока не осознал, что вы хотели сказать. Не ясно как надо подчеркнуть тот айтем который хочу удалить? Или это не решение вопроса, а то как вы считает как надо было продумать саму концепцию меню?

В любом случае спасибо. Пока решаю те или иные вопросы, набираюсь опыта как это делают профи. В данном случае думаю пригодится такой способ работы с контекстным меню. Хотя пока и не удалось применить его для данной задачи. Но зато научился отсылать сигналы и вызывать методы в зависимости от выбранного пунтка меню. Признаюсь был в тупике как это сделать.
« Последнее редактирование: Апрель 27, 2015, 10:47 от Serega » Записан
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #13 : Апрель 27, 2015, 10:48 »

...
Не всегда представляю (если вообще представляю это правильно) когда я сам должен удалять мусор, когда за меня это сделает мусорщик.

В с++ нет сборщика мусора Подмигивающий

Записан

Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #14 : Апрель 27, 2015, 10:52 »

Разве в QT концепция отцов и детей это не один из способов реализации сборщика мусора?
Записан
Страниц: [1] 2 3 4   Вверх
  Печать  
 
Перейти в:  


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