Russian Qt Forum

Qt => Model-View (MV) => Тема начата: Serega от Апрель 26, 2015, 08:03



Название: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 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 невалидным или занулить? Наверное подобный вопрос можно было бы задать в ветке для новичков. Но может само решение удаления не выдерживает критики?


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 26, 2015, 12:42
Ладно будем думать, что молчание знак того, что ерундой занимаюсь и так не делают. Просто не хотел заводить вторую переменную если можно было обойтись одной. Но может это излишняя предосторожность.
Создал булеву переменную.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 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);
 }
}

Да и с вызовом контекстного меню тоже самое -- проверяйте валидность текущего индекса и если валидный, добавляйте действие удаления.
Смысл хранить текущий индекс в какой-то переменной я не вижу -- у вас уже есть виджет, который сможет текущий индекс вернуть


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 26, 2015, 14:08
Так просто не получится иначе бы не заморачивался. Возможно переменную индекса неудачно назвал.
Как видим из меню пользователь не обязательно мог навести курсор на текущий инденкс. Иначе он мог бы удалить не ожидаемый пункт.
Как мне кажется выбрал более интуитивный вариант - отсылаем позицию курсора.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 26, 2015, 14:48
Так просто не получится иначе бы не заморачивался. Возможно переменную индекса неудачно назвал.
Как видим из меню пользователь не обязательно мог навести курсор на текущий инденкс. Иначе он мог бы удалить не ожидаемый пункт.
Как мне кажется выбрал более интуитивный вариант - отсылаем позицию курсора.

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


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 26, 2015, 15:09
Поэтому и говорю, что неудачно назвал переменную индекса.
Дело в том, что в прокси представлении действительно выделен текущий индекс и пользователь может менять его клавиатурой или ЛКМ.
Но пользователь может навести курсор мыши на другой пункт и вызвать контекстное меню. И здесь стоит упоминуть, что действия правой кнопки мыши я переназначил и пункт не становится текущим. Сделано  это, что бы не правоцировать ненужные действия после выбора пункта.


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


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


Признаю. Ломал голову и ничего не понял. Как устроен слот ясно. Как до него донести индекс с контекстного меню? Естественно в меню у меня не единственный пункт.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 26, 2015, 18:21
Признаю. Ломал голову и ничего не понял. Как устроен слот ясно. Как до него донести индекс с контекстного меню? Естественно в меню у меня не единственный пункт.
Необязательно прямо из меню "сигналить", exec возвращает выбранный QAction.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 26, 2015, 18:36
Спасибо за подсказку. У нас ночь уже. Днем буду разбираться.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 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() );
}
Или я что то недопонимаю, что скорее всего. Или это тупиковая затея.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 27, 2015, 08:58
Поняли меня правильно, только зачем сорите членами класса? m_proxyMenu (кто за Вас удалять его будет?) и m_deleteAction - не видно никакого смысла делать их членами.

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

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


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

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

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

В любом случае спасибо. Пока решаю те или иные вопросы, набираюсь опыта как это делают профи. В данном случае думаю пригодится такой способ работы с контекстным меню. Хотя пока и не удалось применить его для данной задачи. Но зато научился отсылать сигналы и вызывать методы в зависимости от выбранного пунтка меню. Признаюсь был в тупике как это сделать.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 10:48
...
Не всегда представляю (если вообще представляю это правильно) когда я сам должен удалять мусор, когда за меня это сделает мусорщик.

В с++ нет сборщика мусора ;)



Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 10:52
Разве в QT концепция отцов и детей это не один из способов реализации сборщика мусора?


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 10:59
Разве в QT концепция отцов и детей это не один из способов реализации сборщика мусора?

Нет )
Сборщик мусора это фигня, которая вызывается виртуальной машиной, чтобы почистить память за ссылками на которые никто не ссылается и когда вызовится сборщик программист предсказать не может.

Та концепция совсем другое -- просто, когда у родителя вызывается деструктор, он смотрит список детей и их удаляет, дети смотрят у себя список детей и их удаляют, и так пока не закончится все дети :)
Простой пример: родитель окно, а всякие фреймы, кнопки, таблицы его дети


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 11:13
Тогда извините за мое невежество.
Однако все таки в литературе вроде как по разному разъясняется концепция уборки мусора. И один из способов такой как реализован в Qt. Да и вроде в литературе Qt припоминается употребление подобного термина.
Но особо спорить не буду. Нет так нет. Значить перефразирую. Что не особо понимаю когда я сам должен удалять мусор, а когда это сделают за меня? Т.е. ясно, что я обычно назначаю родителя, который и проследит за этим. Но всегда ли я правильно это делаю не ясно. Ведь вроде для меню назначил родителя. Так почему Игорь не доволен :)?
Но не хотелось бы пока удаляться от текущей задачи. Добить это меню до победного.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 27, 2015, 11:17
В контекстном меню просто напоминание, что работает клавиша Del. Зачем же пользователю открывать контестное меню, что бы нажать клавишу Del? И что в данном случае я сделал не так, мне не понятно. Если пользователь без всякого контекстного меню давит Del - удаляется текущий пункт, только и всего.
Вот именно: по клавише Del - текущий. А с меню - НЕ текущий (а тот где выпало меню). Это 2 РАЗНЫХ операции удаления. Поэтому клавишу Del совать в меню не надо. Наоборот, там надо показать имя айтема который будет удален (это я имел ввиду под "подчернуть").

По поводу постановки/дизайна. Я бы не мудрил а сделал стандартно. По нажатию правой кнопки если айтем не выбран (selected) - он выбирается, сбрасывая предыдущий выбор. Если юзер хочет оставить текущий выбор - нехай тисне Shift, це стандарт. Если же айтем уже выбран - то никаких изменений в selection не происходит. Вот и все, теперь ОДНА операция удаления и Del в меню на месте.

Ну а насчет "сборщика мусора" и без меня ответят, такое комментировать любят :)

[OFF]
К сожалению, при работе с Qt время в основном тратится на изучение Qt классов - а вот с точки зрения языка и собственно программирования - как-то маловато для этого остается. Вас я ни в чем не обвиняю, просто это "объективная проблема"  :)
[/OFF]


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 11:42
По поводу изучения самого языка. Как раз на год и засел за учебники и видеолекции C/C++, но именно за учебники и лекции, а не за практику. И сейчас гораздо легче. Просто более менее читаю код и на это раз более осознанно понимаю то, что мне говорят. И как раз больше изучаю Qt, а практику прохожу вот на текущих задачах.

Вернемся к меню. Ну что тут сказать? Вы забываете, что в меню не один пункт. И увод фокуса с текщего пункта (карточки, которая привязана к этом пункту) при выборе иных пунктов меню, мне порядком надоел. Понимаю, зачем такое меню? С этим списком мне необходимо делать другие манипуляции: сортировка, фильтр..., а не только удаление или просмотр информации. И эти пункты никак не связаны с конкретным айтемом. А стандартная концепция не вариант...

Значит иных предложений нет для организации предложенной концепции, кроме как изначальной? Ладно вернемся к ней до лучших времен. Это вариант отвечает в полной мере задуманному:
- Удаление текущего пункта с помщью Del.
- Удаление текущего и не текущего пункта под курсором мыши с помощью контекстного меню.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 13:10
Сделал простенький пример, в котором есть модели (QAbstractTableModel и QSortFilterProxyModel), есть два представления QTableView -- для оригинальной модели и отсортированной.
Есть возможность добавления и удаления записей из таблицы (применимо только к оригинальной, но без проблем можно доработать, чтобы и отсортированная таблица удаляла)
Для оригинальной таблицы есть простенькое контекстное меню и удаления возможно также с помощью кнопки Delete

Serega, посмотрите, возможно вам это поможет :)


Update. Щас вспомнил... при удалении студента из списка нужно удалить память за ним :)
Всё из-за плохого влияния явы и питона ;D

В файле studentsmodel.cpp нужно строку students.removeAt(row); поменять на delete students.takeAt(row);


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 27, 2015, 14:10
Вернемся к меню. Ну что тут сказать? Вы забываете, что в меню не один пункт. И увод фокуса с текщего пункта (карточки, которая привязана к этом пункту) при выборе иных пунктов меню, мне порядком надоел. Понимаю, зачем такое меню? С этим списком мне необходимо делать другие манипуляции: сортировка, фильтр..., а не только удаление или просмотр информации. И эти пункты никак не связаны с конкретным айтемом. А стандартная концепция не вариант...
UI - весьма консервативная область. Прежде чем так резво (совершенно не подумавши) отказываться от стандартных вещей - неплохо бы к ним повнимательнее присмотреться. То же Win7 - откройте список файлов и давите правую кнопку. Нажали на файле - все происходит как я рассказал выше. Нажали в пустое место - выпало др контекстное меню (те самые общие операции). Чем это плохо? По-моему ничем, нормально сделано, и юзер с этим уже знаком, глупых вопросов задавать не будет.

Тут правда есть разница - нажать именно на имя файла (текст) а не на пустое место справа). Не хотите с этим возиться? Хорошо, тогда показывайте одно меню. Общие операции в нем всегда, а файловые - только когда есть selection. Разделите эти группы операций сепаратором в меню. А для Del просто напишите в меню
Цитировать
Delete 2 selected items   Del
Вместо этого разрабатывать какой-то свой, особый стиль - весьма накладно, и не видно необходимости. Обычным рез-том является "велосипед" в худшем смысле этого термина  :)


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 14:43
Спасибо gil9red, посмотрел ваш пример. С таким вариантом проблем нет. Вот теперь представьте. Слева у вас список эдак тысяч на 5-10. Справа окно для соответствующего пункта из списка, в котором открывается такая партянка с километр и само по себе действие затратно. И пользователь просто открыл контекстное меню в окне списка в призвольном месте, только для того что бы отсортировать или отфильтровать. Забавно ему после этого искать место от куда зашел. Конечно я могу сделать возврат и он сделан, но зачем провоцировать пользователя на неприятнсти и лишние действия?

Переделал пример. Там ситуация предельно ясна. Теперь проделайте трюк с мышкой :).


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 14:45
Igors знаете прежде чем менять ситуацию вы не представляете сколько мне пришлось подумать? А если нет пустого места в виджете, список обычно большой? И это не файловый менеджер. И в этом меню в общем то единственный пункт который каким то образом завязан на конкретном айтеме списка. Как раз это Удаление и есть. Но проблемы с уводом фокуса или как в данном случае назвать..., не дают возможности делать удаляемый пункт текущим. Если пользователь хочет просмотреть пусть жмет ЛКМ, думаю в данном конкретном случае для него это будет более удобно (во всяком случае для меня именно так). Удаление дело разовое, а сортировка и тому подобное более часто... Так что решаем, что это выбор из двух зол.

Мало того, если делать удаляемый пункт текущим то сначала открывается информационная карточка для удаляемого пункта списка, затем соседнего. Вообще каша...

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


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 15:07
Serega, после вашего исправления представления все-равно кликабельно :)

Как я вас понял, у вас в контекстном меню есть сортировка и фильтрация, после которых выделенный элемент теряется?
После сортировки представление ведь сохраняет выделение элемента, вызовите у представления функцию scrollTo, чтобы отмотать к выделенному элементу

Да и не лучше было бы разметить действия сортировки и фильтрации вне контекстного меню, например, сделать кнопками над представлением?


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 15:10
Serega, после вашего исправления представления все-равно кликабельно :)
Представление то кликабельно, так и должно быть. Но сможете удалить пункт над которым находится курсор без помощи ЛКМ, при этом, что бы клавиша Del работала? В общем то задача в том и состоит, что бы удаляемый пункт не становился текущим.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 15:15
Serega, после вашего исправления представления все-равно кликабельно :)
Представление то кликабельно, так и должно быть. Но сможете удалить пункт над которым находится курсор без помощи ЛКМ, при этом, что бы клавиша Del работала?

Да, спокойно.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 15:17
Serega, после вашего исправления представления все-равно кликабельно :)
Представление то кликабельно, так и должно быть. Но сможете удалить пункт над которым находится курсор без помощи ЛКМ, при этом, что бы клавиша Del работала?

Да, спокойно.
Так покажите решение. Не мучайте уже :). Мне многому еще предстоит научиться.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 15:24
Serega, после вашего исправления представления все-равно кликабельно :)
Представление то кликабельно, так и должно быть. Но сможете удалить пункт над которым находится курсор без помощи ЛКМ, при этом, что бы клавиша Del работала?

Да, спокойно.
Так покажите решение. Не мучайте уже :). Мне многому еще предстоит научиться.

запускаете пример, тыкаете на клавиатуре стрелку вниз или вверх, элемент выделяется и жмете Del :D


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 15:30
Сортирую кнопкой (я о ней писал выше), выделение остается на элементе, если обрабатывать Del, то и он сработает


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 15:37
Мне казалось, что я ясно изложил суть дела. Но может просто это кажется.
В переделанном примере http://www.prog.org.ru/index.php?topic=28819.msg211225#msg211225 выделите любой пункт меню. Затем переместите курсор мыши на другой пункт меню и не нажимая предварительно левую кнопку мыши вызовите контекстное меню и произведите удаление. Заметьте какой пункт вы на самом деле удалили. Необходимо удалить пункт под курсором, а не текущий выделенный.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 27, 2015, 15:42
Мне казалось, что я ясно изложил суть дела. Но может просто это кажется.
В переделанном примере http://www.prog.org.ru/index.php?topic=28819.msg211225#msg211225 выделите любой пункт меню. Затем переместите курсор мыши на другой пункт меню и не нажимая предварительно левую кнопку мыши вызовите контекстное меню и произведите удаление. Заметьте какой пункт вы на самом деле удалили. Необходимо удалить пункт под курсором, а не текущий выделенный.


Как много пунктов, то, что в списке это элементы, а не пункты, разграничьте их, пожалуйста, а то это запутывает :)


Всееее понял...
Вам не нравится, что меню отрабатывает на себе правый клик кнопки мыши.
То, что при клике на пунктах контекстного меню правой кнопкой происходит срабатывание того пункта, который в данный момент выделен в меню, как будто мы кликнули левой кнопкой




И если я все-таки правильно вас понял, тогда нужно решать не с представлениями, а с меню, которое и вызываем.
И теперь меню будет только левую кнопку на себе обрабатывать

Создал наследника от меню:
Код
C++ (Qt)
class MyMenu : public QMenu {
protected:
   void mouseReleaseEvent(QMouseEvent * e) {
       if (e->button() != Qt::LeftButton)
           return;
 
       QMenu::mouseReleaseEvent(e);
   }
};

И использую его в своем примере:
Код
C++ (Qt)
   const QModelIndex & index = ui->view->currentIndex();
   if (index.isValid()) {
       MyMenu menu;
//        QMenu menu;
       menu.addAction(ui->actionAddStudent);
       menu.addAction(ui->actionRemoveStudent);
 
       menu.exec(QCursor::pos());
   }
 


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 15:51
И наверное ввел в заблуждение с термином фокус. В общем то не фокус текущего выбранного пункта списка теряется. С сортировкой и фильтром все в порядке.
Просто к каждому пункту меню привязана карточка в другом окне. И если ткнуть правой кнопкой мыши для удаления пункта в списке, то карточка сменится, что как раз не нужно, тем более пользователь мог не обязательно вызвать меню для удаления, а например для сортировки.. Ну это выглядит примерно так как в браузере слева список закладок. Нет смысла делать удаляемый пункт текущим. Пусть текущий остается тот который просматривает пользователь.

Вроде как на этот раз меня правильно поняли, надеюсь.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 16:06
Слушайте с вами не соскучишся или со мной :).
- Мне не нравится, что при клике ПКМ для удаления какого либо пункта меню этот пункт становится текущим и в браузере (назовем вспомогательное окно так) открывается закладка, а затем когда пункт удалили открывается вдобавок соседняя закладка.
- Не нравится, что когда пользователь вызвал контекстное меню для сортировки, опять же текущей становится та закладка над которой случайно оказался курсор в данный момент.

Левая кнопка мыши должна работать как обычно - делать пункт текущим. ПКМ сейчас не делает пункт текущим, как и задумано, но удалять пункт она должна именно под курсором, даже если он не текущий (не выделен) в данный момент.

В вашем примере переделал так, что этих проблем нет. События кнопок мыши переназначил, объявил класс представления. Но если я попытаюсь удалить пункт под курсором, то удалится не он а тот который в данный момент выделен. Вот это я хочу поправить, что бы при этом не отвалилась кнопка Del.

Так вот все работает как надо в изначально предложенном варианте. Но сказали, что вариант исполнен не красиво. Пытаюсь сдеать красиво :).

Если пытаюсь сделать иным способом, Del перестает работать.


На вашем скрине выделен Иванов, а удалить мне надо Васю с помощь только ПКМ, Иванов должен остаться текущи пунктом.
Т.е. в примере надо решить только эту проблему. Но здесь уже начинается свистопляска для меня.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 27, 2015, 16:44
[OFF]Сергей, я вижу Вы увлечены и убедить Вас вряд ли удастся :) Во-первых, отдохните, "остыньте", пусть разбежавшиеся мысли соберутся. Во-вторых, это не то место где надо что-то "решать" и вообще придумывать. Возьмите "образец" (любое уважаемое приложение) и скопируйте - это будет гораздо продуктивнее, правда  :)[/OFF]


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 17:50
Меня действительно сложно переубедить. Решения посмотрел. В общем то они в основном сходны с моим. Однако может быть на самом деле не с того конца начал жечь лучину. Наверное проще все таки сделать выбранный пункт текущим, возможно делать его таковым только при выборе удаления, а сигнал на просмотр текущего пунтка не посылать. Возможно такая реализация будет проще.

Ну хотя бы туже панель закладок браузера посмотрите. Закладка активируется только при ЛКМ. ПКМ ее не активирует. Может с этого мне и надо было начинать. Проще было бы понять чего я добиваюсь и почему именно. Такое поведение меня бы устроило. Хорошо попорбую иной подход решения задачи.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 27, 2015, 19:53
Переделать переопределение собития правой кнопки мыши так, что бы пункт становился текущим, но при этом не активным не составило труда:
Код
C++ (Qt)
void ProxyList::mousePressEvent(QMouseEvent *event)
{
 if(event->button() == Qt::MidButton)
 {
   return;
 }
 if(event->button() == Qt::RightButton)
 {
   setCurrentIndex( indexAt( event->pos() ) );
   return;
 }
 QListView::mousePressEvent(event);
}
И в купе с первоначально предложенным вариантом http://www.prog.org.ru/index.php?topic=28819.msg211186#msg211186 все работает как например в реализациях закладок в браузере. Закладка выделяется, но не активируется. Надеюсь, что такой подход не сложно будет реализовать более подобающе.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 28, 2015, 17:44
Хорошо, отдохнул, собрал волю  в кулак, признаю, что в чем то был не прав. В любом случае всем спасибо, что заставили думать в ином русле. Изначально видимо не точно разъяснил суть проблемы. С другой стороны теперь известно два пути, устраивающих меня и кое что осознал глубже и вывел для себя с вашей помощью несколько приемов работы с меню. Хорошо, делаем пункт текущим, но не делаем его активным. Так проще.

Работа над ошибками. Как справедливо заметили, сорю членами класса. Сделать я могу все, что угодно, но нет вырабатанного стиля и не знаю приемов и целесообразности того или иного применения. Не всегда представляю кого в качестве родителя назначить. Как понял это не совсем имеет отношение к наследованию. Т.е. имеет, но можно назначать любого вверх по иерархии, а не только непосредственного.
Так вот код меню. Что в нем не так?
Код
C++ (Qt)
void ProxyPaneWidget::showCustomMenu( QPoint const & pos )
{
 bool selectionEmpty = m_proxyList->selectionModel()->selection().empty();
 
 QAction * deleteAction = new QAction( this );
 deleteAction->setText( tr( "Delite" ) );
 deleteAction->setShortcut( QKeySequence( QKeySequence::Delete ) );
 deleteAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
 connect( deleteAction, SIGNAL( triggered() ),
          this, SLOT( deleteSelectedItem() ) );
 
 QMenu * proxyMenu = new QMenu( this );
 proxyMenu->addAction( tr( "Ascending" ), this, SLOT(sortAscendingOrder()) );
 proxyMenu->addAction( tr( "Descending" ), this, SLOT(sortDescendingOrder()) );
 proxyMenu->addAction( tr( "Reset" ), this, SLOT(resetProxy()) );
 if ( !selectionEmpty ){
   proxyMenu->addSeparator();
   proxyMenu->addAction( m_deleteAction );
 }
 proxyMenu->exec( m_proxyList->mapToGlobal( pos ) );
}

Проблема такова:
Если deleteAction определяю в конструкторе виджета то все работает как положенно. Если же как в приведенном примере, то клавиша Del перестает работать.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 29, 2015, 06:22
Однако, Экшин удаления предварительно приходится добавлять в конструктор виджета:
Код
C++ (Qt)
 explicit ProxyPaneWidget( QWidget * parent = 0 ) : QWidget( parent )
 {
   m_deleteAction = new QAction( this );
   m_deleteAction->setText( tr( "Delite" ) );
   m_deleteAction->setShortcut( QKeySequence::Delete ) ;
   m_deleteAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
 
   connect( m_deleteAction, SIGNAL( triggered() ),
            this, SLOT( deleteSelectedItem() ) );
 
   addAction( m_deleteAction );
 }


Затем в меню:
Код
C++ (Qt)
void ProxyPaneWidget::showCustomMenu(QPoint const & pos)
{
 bool selectionEmpty = m_proxyList->selectionModel()->selection().empty();
 
 QMenu * m_proxyMenu = new QMenu( this );
 m_proxyMenu->addAction( tr( "Ascending" ), this, SLOT( sortAscendingOrder()) );
 m_proxyMenu->addAction( tr( "Descending" ), this, SLOT( sortDescendingOrder()) );
 m_proxyMenu->addAction( tr( "Reset" ), this, SLOT( resetProxy()) );
 
 if ( !selectionEmpty )
 {
   m_proxyMenu->addSeparator();
   m_proxyMenu->addAction( m_deleteAction );
 }
 
 m_proxyMenu->exec( m_proxyList->mapToGlobal( pos ) );
}
Только в этом случае клавиша Del работает.
Не вижу способа сделать Экшин удаления не членом класса.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 29, 2015, 06:30
Не всегда представляю кого в качестве родителя назначить.
Код
C++ (Qt)
 QAction * deleteAction = new QAction( this );
...
 QMenu * proxyMenu = new QMenu( this );
 
При выполнении этого кода будут созданы QMenu и QAction которые будут существовать до тех пор пока живет экземпляр ProxyPaneWidget. При след выполнении новые такие объекты опять будут созданы и.т.д. Др словами Вы льете и льете в ProxyPaneWidget объекты временного пользования. "Парент удаляет чайлдов" - это хорошо как раз для указателей-членов класса, которые живут вместе с родителем. А если объект нужен "только здесь" - то и делайте его локальным, напр так
Код
C++ (Qt)
 QMenu proxyMenu( this );
 QAction * deleteAction = new QAction( &proxyMenu );
 
Теперь proxyMenu автоматычно удалится при выходе из метода и удалит чайлда deleteAction. Можно и "все на указателях", но тогда не забыть удалить, напр
Код
C++ (Qt)
 QAction * deleteAction = new QAction( this );
 QMenu * proxyMenu = new QMenu( this );
...
 delete proxyMenu;
 delete deleteAction;
 

Возвращаясь к злополучной клавише Del :)  Насколько я понял, решили поместить в меню 2 удаления - кликнутого и selected. Не вижу в этом ничего плохого, но тогда распишите в меню "кто есть кто"
Цитировать
Delete <item name>
...
---------
Delete 2 selected items  Del
И для первого шортката не надо - ведь такого действия не произойдет если меню не было открыто. Ой - сейчас Вы опять начнете спорить, возражать, не, я пошел  :)


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 29, 2015, 07:19
Спасибо за разъяснения. Буду осозновать и делать как надо, запишу в копилку опыта.

По поводу Del. Вовсе не хочется спорить без дела. Пытаюсь понять. Например это:
Цитировать
Насколько я понял, решили поместить в меню 2 удаления - кликнутого и selected. Не вижу в этом ничего плохого, но тогда распишите в меню "кто есть кто"
Меня ставит в тупик.
В меню у меня один пункт удаления:
(http://s020.radikal.ru/i711/1504/1b/fda1246a450at.jpg) (http://radikal.ru/fp/b9bb630c0e4345ba932307a82170b28b)
Зачем второй?
Разве эта строчка не дублирует действие мыши:
m_deleteAction->setShortcut( QKeySequence::Delete );

Зачем открывать меню, если для виджета назначен этот же Экшин. Все работает. Значит сделано все Верно?
Мне кажется (возможно только кажется) здесь  я сделал все верно, но веду себя как будто это не так. Скорее всего дело проще - я не осознал, что сдела правильно. И это не ради спора. Видимо, что то мне пока не дано осознать. Наверное на практике псотепенно пойму.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 29, 2015, 10:08
Пока как понял, что бы действия жили только в момент вызова меню, делаем так:
Код
C++ (Qt)
void ProxyPaneWidget::showCustomMenu(QPoint const & pos)
{
 bool selectionEmpty = m_proxyList->selectionModel()->selection().empty();
 
 QMenu m_proxyMenu( this );
 m_proxyMenu.addAction( tr( "Ascending" ), &m_proxyMenu, SLOT(sortAscendingOrder()) );
 m_proxyMenu.addAction( tr( "Descending" ), &m_proxyMenu, SLOT(sortDescendingOrder()) );
 m_proxyMenu.addAction( tr( "Reset" ), &m_proxyMenu, SLOT(resetProxy()) );
 
 if ( !selectionEmpty )
 {
   m_proxyMenu.addSeparator();
   m_proxyMenu.addAction( m_deleteAction );
 }
 
 m_proxyMenu.exec( m_proxyList->mapToGlobal( pos ) );
}

m_deleteAction все же придется делать членом класса виджета, поскольку приходится привязывать это действие и к самому виджету
Код
C++ (Qt)
 explicit ProxyPaneWidget( QWidget * parent = 0 ) : QWidget( parent )
 {
   m_deleteAction = new QAction( this );
   m_deleteAction->setText( tr( "Delite" ) );
   m_deleteAction->setShortcut( QKeySequence::Delete ) ;
   m_deleteAction->setShortcutContext( Qt::WidgetWithChildrenShortcut );
 
   connect( m_deleteAction, SIGNAL( triggered() ),
            this, SLOT( deleteSelectedItem() ) );
 
   addAction( m_deleteAction );
 }


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Igors от Апрель 29, 2015, 10:22
Меня ставит в тупик.
В меню у меня один пункт удаления:
Я отвечал на Ваш пост #36, там два. Решили один - можно и так. Все-таки написать в меню число удаляемых совсем не помешало бы.

Не вижу способа сделать Экшин удаления не членом класса.
Можно, но здесь (при одной операции удаления) он членом лучше.
Пока как понял, что бы действия жили только в момент вызова меню, делаем так:
Правильно, только не надо давать локальное имя в стиле члена класса (m_proxyMenu)



Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 29, 2015, 10:49
Спасибо! Что касается 36 ответа. Моя вина не подчистил при вставке и ввел в заблуждение. Впрочем и последнего поста со стилем касается. В конечном итоге конечно же не так все. Это пробы с черновиком. Постараюсь учесть, что бы в  следующий раз проще было бы понять мои каракули. Со стилем тоже будут вопросы, но наверное уже в ветке для новичков. Надо более менее выработать приемлемый.
По поводу текущего кода, вроде как более менее ясно и остановлюсь на последней заготовке и буду добавлять новые пункты.
И если честно в начале темы не все моменты осозновал, даже если мой первоначальный код вполне работал. Проблема отцов и детей ясно дело.
Не понимал почему мне приходилось назначать один и тот же Экшин удаления в констуркторе и меню. Не сразу понял, что назначал я его разным объектам. Вроде код то простой и учил все, но как то растерялся, а осознание пришло постепенно на практике.
Застрял я на этом меню, но думаю с пользой. Спасибо за терпение.

P.S. Наверное главная моя ошибка заключалась в том, что я пытался использовать экшин до создания объекта :).


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 29, 2015, 17:22
Однако, в последнем коде я все таки накуралесил:
m_proxyMenu.addAction( tr( "Ascending" ), &m_proxyMenu, SLOT(sortAscendingOrder()) );
Неверно это.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 30, 2015, 08:04
Более правильно наверное так:
Код
C++ (Qt)
void ProxyPaneWidget::showCustomMenu(QPoint const & pos)
{
 bool selectionEmpty = m_proxyList->selectionModel()->selection().empty();
 
 QMenu m_proxyMenu( this );
 m_proxyMenu.addAction( tr( "Ascending" ), this, SLOT(sortAscendingOrder()) );
 m_proxyMenu.addAction( tr( "Descending" ), this, SLOT(sortDescendingOrder()) );
 m_proxyMenu.addAction( tr( "Reset" ), this, SLOT(resetProxy()) );
 
 if ( !selectionEmpty )
 {
   m_proxyMenu.addSeparator();
   m_proxyMenu.addAction( m_deleteAction );
 }
 
 m_proxyMenu.exec( m_proxyList->mapToGlobal( pos ) );
}
Экшены, как понял, в данном случае сами избирут  правильного родителя.


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: gil9red от Апрель 30, 2015, 09:10
Экшены, как понял, в данном случае сами избирут  правильного родителя.

Когда вы создаете экшены из qmenu, они сразу становятся его детьми, так что родитель будет правильный


Название: Re: QSortFilterProxyModel - удаление строки
Отправлено: Serega от Апрель 30, 2015, 15:56
Спасибо всем за разъяснения!
Здесь более/менее для себя разобрался и вывел приемлемый вариант действий.