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

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

Страниц: 1 2 [3] 4   Вниз
  Печать  
Автор Тема: QSortFilterProxyModel - удаление строки  (Прочитано 24191 раз)
gil9red
Administrator
Джедай : наставник для всех
*****
Offline Offline

Сообщений: 1805



Просмотр профиля WWW
« Ответ #30 : Апрель 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());
   }
 
« Последнее редактирование: Апрель 27, 2015, 15:54 от gil9red » Записан

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

Сообщений: 127


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

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

Вроде как на этот раз меня правильно поняли, надеюсь.
« Последнее редактирование: Апрель 27, 2015, 15:53 от Serega » Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #32 : Апрель 27, 2015, 16:06 »

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

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

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

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

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


На вашем скрине выделен Иванов, а удалить мне надо Васю с помощь только ПКМ, Иванов должен остаться текущи пунктом.
Т.е. в примере надо решить только эту проблему. Но здесь уже начинается свистопляска для меня.
« Последнее редактирование: Апрель 27, 2015, 16:36 от Serega » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #33 : Апрель 27, 2015, 16:44 »

[OFF]Сергей, я вижу Вы увлечены и убедить Вас вряд ли удастся Улыбающийся Во-первых, отдохните, "остыньте", пусть разбежавшиеся мысли соберутся. Во-вторых, это не то место где надо что-то "решать" и вообще придумывать. Возьмите "образец" (любое уважаемое приложение) и скопируйте - это будет гораздо продуктивнее, правда  Улыбающийся[/OFF]
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #34 : Апрель 27, 2015, 17:50 »

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

Ну хотя бы туже панель закладок браузера посмотрите. Закладка активируется только при ЛКМ. ПКМ ее не активирует. Может с этого мне и надо было начинать. Проще было бы понять чего я добиваюсь и почему именно. Такое поведение меня бы устроило. Хорошо попорбую иной подход решения задачи.
« Последнее редактирование: Апрель 27, 2015, 18:03 от Serega » Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #35 : Апрель 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 все работает как например в реализациях закладок в браузере. Закладка выделяется, но не активируется. Надеюсь, что такой подход не сложно будет реализовать более подобающе.
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #36 : Апрель 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 перестает работать.
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #37 : Апрель 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 работает.
Не вижу способа сделать Экшин удаления не членом класса.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #38 : Апрель 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
И для первого шортката не надо - ведь такого действия не произойдет если меню не было открыто. Ой - сейчас Вы опять начнете спорить, возражать, не, я пошел  Улыбающийся
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #39 : Апрель 29, 2015, 07:19 »

Спасибо за разъяснения. Буду осозновать и делать как надо, запишу в копилку опыта.

По поводу Del. Вовсе не хочется спорить без дела. Пытаюсь понять. Например это:
Цитировать
Насколько я понял, решили поместить в меню 2 удаления - кликнутого и selected. Не вижу в этом ничего плохого, но тогда распишите в меню "кто есть кто"
Меня ставит в тупик.
В меню у меня один пункт удаления:

Зачем второй?
Разве эта строчка не дублирует действие мыши:
m_deleteAction->setShortcut( QKeySequence::Delete );

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

Сообщений: 127


Просмотр профиля
« Ответ #40 : Апрель 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 );
 }
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #41 : Апрель 29, 2015, 10:22 »

Меня ставит в тупик.
В меню у меня один пункт удаления:
Я отвечал на Ваш пост #36, там два. Решили один - можно и так. Все-таки написать в меню число удаляемых совсем не помешало бы.

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

Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #42 : Апрель 29, 2015, 10:49 »

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

P.S. Наверное главная моя ошибка заключалась в том, что я пытался использовать экшин до создания объекта Улыбающийся.
« Последнее редактирование: Апрель 29, 2015, 11:15 от Serega » Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #43 : Апрель 29, 2015, 17:22 »

Однако, в последнем коде я все таки накуралесил:
m_proxyMenu.addAction( tr( "Ascending" ), &m_proxyMenu, SLOT(sortAscendingOrder()) );
Неверно это.
Записан
Serega
Самовар
**
Offline Offline

Сообщений: 127


Просмотр профиля
« Ответ #44 : Апрель 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 ) );
}
Экшены, как понял, в данном случае сами избирут  правильного родителя.
Записан
Страниц: 1 2 [3] 4   Вверх
  Печать  
 
Перейти в:  


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