Russian Qt Forum

Qt => Пользовательский интерфейс (GUI) => Тема начата: CoderInside от Март 03, 2006, 21:08



Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: CoderInside от Март 03, 2006, 21:08
Добрый день!
Есть QTreeWidget (полный QTreeWidgetItem'ов ;)). Программа должна работать так: когда пользователь нажимает на этом дереве левой кнопкой мыши - строка должна подсвечиваться, а когда правой кнопкой - должно появляться контекстное меню...
Показ меню привязываем к сигналу itemClicked QTreeWidget'а, но этот сигнал возникает всегда, неважно т.е. на какую кнопку нажали. Сколько не бились сделать так, чтобы меню появлялось по правой кнопке мыши - так ничего и не получилось  :? Оно появляется всегда!
Подскажите как поступить в этом случае... Как сделать так, чтобы контекстное меню вызывалось по правому клику мышки?
Заранее большое спасибо!
Qt 4.1.1 (VS2003)


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Joe от Март 03, 2006, 22:23
НЕ НАДО перехватывать itemClicked - надо просто переопределить contextMenuEvent!

void contextMenuEvent(QContextMenuEvent * e);

он как раз для этих целей и написан - чтоб по событию, которое ассоциировано с "требованием" контекстного меню это самое меню предоставить. или НЕ предоставить.

void QTreeWDeriv::contextMenuEvent(QContextMenuEvent * e)
{
// где-то там определились с кучей  actions - чтоб не плодить и коннектить их кажный раз
   if(actions.count() > 0)
   {
      QMenu* menu = new QMenu(this);
      foreach(QAction* action, actions)
      {
         menu->addAction(action);
      }
      menu->exec(e->globalPos());
   }
};


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Вудруф от Март 04, 2006, 11:51
foreach(QAction* action, actions)
{
menu->addAction(action);
}

Э? Разве так можно?!?
*в ауте*


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: CoderInside от Март 04, 2006, 12:26
Получилось!
В классе наследованном от QTreeWidget создал сигнал:
Код:
signals:
void itemRMBClicked ( QTreeWidgetItem * item, int column );

Переопределил функцию
Код:
void QWidget::contextMenuEvent ( QContextMenuEvent * event )  [virtual protected]


и в реализации вызываю сигнал

Код:
void SourceTreeWidget::contextMenuEvent (QContextMenuEvent * event)
{
emit itemRMBClicked (currentItem(), currentColumn());
}


Затем соединяю этот сигнал со слотом в которой выполняются требуемые операции и создается PopUp меню:
Код:
connect(mpTWidget,SIGNAL(itemRMBClicked( QTreeWidgetItem*,int)), this,SLOT(OnItemClicked(QTreeWidgetItem*,int)));


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 04, 2006, 13:34
Хммм... Задача нетривиальная. У меня сходу не получилось её решить. Вопрос к Joe:

А как теперь сделать, чтобьІ по средней кнопке мьІши делалось ещё какое-то собьІтие для item'а, на котором кликнул юзер? А по левой? А по левой с зажатьІм альтом?


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Steven_Orko от Март 04, 2006, 14:19
Цитата: "Dendy"


А как теперь сделать, чтобьІ по средней кнопке мьІши делалось ещё какое-то собьІтие для item'а, на котором кликнул юзер? А по левой? А по левой с зажатьІм альтом?

Я тут посмотрел в Assitant, там про QContextMenuEvent написано следующее:
Цитировать
Context menu events are sent to widgets when a user performs an action associated with opening a context menu. The actions required to open context menus vary between platforms; for example, on Windows, pressing the menu button or clicking the right mouse button will cause this event to be sent.


Т.е. это событие посылается при нажатии правой кнопки мышки. Насколько я знаю в Х11  и Виндах это действие как раз считается вызовом контектсного меню. А вот нажатие правой кнопки мышки совместно с alt, ctrl или shift будет считаться аналогичным действием?
Это я все про Qt 4.1.1, так как ща пользуюсь им.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 04, 2006, 14:28
Для етого есть QMouseEvent. Но в случае с QAbstractItemView никакой дополнительной информации как узнать каким образом бьІла нажата кнопка я не нашёл. Може сліпенький... (-:


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Sergey B. от Март 04, 2006, 16:33
Цитата: "Dendy"
Для етого есть QMouseEvent. Но в случае с QAbstractItemView никакой дополнительной информации как узнать каким образом бьІла нажата кнопка я не нашёл. Може сліпенький... (-:


Где-то на забурном сайте пролетала инфа, около года назад...
Чувак с MFC на Qt проги свои переписывал, такая проблема тоже была... решение ему не сказали  :( ... Хотя в MFC это тривиальная задача...


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 04, 2006, 17:01
Около года назад Qt 4 ещё не бьІло. На Qt 3 для item'ов существует множество перегруженньІх сигналов для получения информации с каким переподвьІподвертом мьІ на него нажали. В Qt 4 етот механизм упростили и теперь сложно найти концьІ. Отсюда и вопросьІ...


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Joe от Март 06, 2006, 18:20
Есть одна загвоздка. не на всех платформах есть мыши с 3мя кнопками (кое где и с 2мя, не дай Бог), поэтому скорее всего Qt решили не заморачивать на "кнопки", а сказали, что будут обслуживать прецеденты. мне кажется, это более правильный подход. А вот как вы сгенерируете это самый прецедент - уже вопрос второй, хотя на самом деле здесь - первый. Определитесь, чего хочется - уметь кнопки от мыши перехватывать, или более полезные вещи делать? :)
Конечно, это несколько экзотичное решение, узнавать о назджатии правой кнопки по факту вызова contextMenuEvt, я думаю, всё лежит на поверхности, уж больно рапространённая задача. К тому же, когда есть MouseEvent.

QAbstractItemView - а не слишком ли глубоко зарылись :)? Может всё-таки более конкретный класс посмотрите? Часто можно определить, какой item находится под точкой, этого бывайт достаточно для некоторых целей. А если писать свой ItemView (упаси Бог), то такую функциональность бывает полезно самим добавить - и самим же пользовать.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Steven_Orko от Март 06, 2006, 23:46
to Joe and Dendy
Хотел вот узнать, чем мой пост не подошел? Почему "несколько экзотичное решение, узнавать о назджатии правой кнопки по факту вызова contextMenuEvt"? Если даже в Assistant написано, что эта функция вызывается в случае, когда необходимо показать контекстное меню? В Винде и в Линуксах (точно скажу про Mandriva) нажатие правой кнопки мышки считается вызовом контекстного меню?
Собственно человеку это и надо было, обработать данное событие. Вот и переопределил соответствующую виртуальную член-функцию. ИМХО, в данном вопросе обобщение излишне.
Про mouseEvent. Согласен, что здесь можно отлавливать разные нажатия кнопки мышки и т.д. Но не кажется ли вам, что это стрелять по воробьям из пушки? Зачем повторять тот же код, который уже есть в Qt?


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: nEoN от Март 07, 2006, 12:01
2 Steven_Orko
Контекстное меню (contextMenuEvent) может вызываться по разным причинам, не только из за нажатия правой кнопки мыши. Типичный пример соответствующая кнопка на клавиатуре для вызова контекстного меню.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 07, 2006, 13:53
В данном случае решение подходит. Но ето как раз та ситуация, когда вьІпрямившись в полньІй рост дотрагиваешься волосами до потолка. Ещё чуть-чуть и прийдётся сгинать шею в поисках черезжопньІх решений. (-:  Извините мой французкий.

Момент принципиальньІй. Ведь поиск как именно бьІла нажата кнопка мьІши можно узнать обратившись к испустившему сигнал обьекту, что нарушает обьектно-ориентированньІй подход, когда испускатель и получатель собьІтия ничего друг о друге не знают. Например, если вьІ захотите ловить нажатие на итем в другом потоке - у вас ничего не получится. Тролли жёстко документируют каждую функцию, которая нарушает етот принцип.

И примеров, где может использоваться реагирование на произвольньІе нажатия мьІши - масса.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Joe от Март 07, 2006, 20:36
to Steven_Orko
не так сложно взять и переопределить default поведение widget' а для  показа contextmenu. Я посто попытался указать, что задача решается несколько иным образом, это о контесктном меню, а про нажатые клавиши - это вообще из другого места надо смотреть. Но смешивать понятия не всегда полезно, как раз для этого trolltech и сделалито вынесенный event. И многое другое тоже. Вообще, глядя на то, в каком ключе организован этот API - можно многому поучиться - и если следовать этому, весьма простому, правилау - делать то что хочешь в тех местах где это на самом деле надо - можно реализовать весьма сложное поведение с наименьшей головной болью. Они не на 100% придерживаются этой идеологии (точнее - с избытком :)) - рассчитывая на разные категории пользователей.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 09, 2006, 10:26
КрасивьІе слова. (0:  Но! Почему же тогда Тролли в собственном Ассистанте оставляют такой же ляп:

Когда клацаешь на списке содержимого в Ассистанте левой кнопкой - открьІвается соответствующая страница в текушем окне. Вроде всё верно.

Когда клацаешь правой... (!) Тоже открьІвается страница, заменяя предьІдущую + ОткрьІвается контекстное меню с вариантами "как вьІ хотите открьІть ету страницу".

А теперь попробуйте найти концьІ етого бага и способьІ его исправить. Он тянется из версии в версию. Ощущение, что нет гибкого и красивого способа его исправить, продолжая пользоваться при етом сигналом itemClicked().


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Вудруф от Март 09, 2006, 11:38
А ведь это баг... Ибо при нажатии правой кнопки мыши *на ссылке* выводится только контекстное меню...


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Joe от Март 09, 2006, 17:05
Думаю, что баг. И скорее всего -от того, что сперва был один обработчик, а потом дописали ещё один, а про старый забыли. Это болезни роста, и в общем - не такие страшные. Эта фишка забарывает, не вопрос, но мало ли какие мерзкие особенности поведения инструментальных средств нам встречаются :) бывает намного хуже :).
Это ни насколько не умаляет собстевенно красоты всей затеи :)
Спросите их, а ещё лучше - посмотрите в сурцы и скажите, где им стоило бы что подправить, чтобы это не выглядело так пугающе.


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: comrade от Март 09, 2006, 17:49
Цитата: "Dendy"
Он тянется из версии в версию.

ну почему из версии в верисию... в третьей куте у QListView такое слово mouseButtonClicked(...) было и там можно было найти какую кнрпку нажали. непонятно почему троли етот сигнал в четвертую версию не положили :(


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 09, 2006, 18:17
Цитата: "Dendy"
Он тянется из версии в версию.


:D  Я имел в виду версии четвёрки. Ещё с августа 2005. В ассистанте реально нехватает вкусностей ОперьІ, именно поетому многие смотрят именно из броузера. А етот глюк задалбьІвает: правой - открьІть в новой закладке - клацнуть на старую - назад.

Я даже думал подправить код ассистанта. Но там настолько елементарно написан обработчик, что возникают сомнения в правильности идеи. Реально я не нашёл способа решить проблему, ведь сигнал испускается ПОСЛЕ отжатия кнопки мьІши, следовательно, если не запомнить состояние QApplication::mouseButtons() - в момент принятия сигнала флаги будут очищеньІ. Как раз поетому mouseReleaseEvent() принимается асинхронно с сохранённьІми флагами в самом собьІтии.

Есть ещё идея - повесить eventFilter() на QEvent::MouseButtonRelease, запоминать состояния флагов и передавать собьІтие дальше на обработчик окна и вьІзов сигнала. ЧерезжопньІй метод, но может так Троллями и задумьІвалось?  :roll:


Название: QTreeWidget, сигнал itemClicked и кнопки мышки
Отправлено: Dendy от Март 28, 2006, 12:33
Решил вьІтянуть тему из клоаки на свет Божий (-:
Итак, кого задолбало открьІтие окошек в Ассистанте по средней и правой кнопкам мьІши - дружно внимаем моему варварскому способу.

Всё что нужно - подправить код Ассистанта в паре мест всего лишь в одном файле:

tools/assistant/helpdialog.cpp

Где-нить повьІше:
Код:
static bool was_left_button = false;


В любом месте етого метода:
Код:
void HelpDialog::initialize()
{
  ...
  ui.listContents->viewport()->installEventFilter( this );
  ...
}


В самом верху метода:
Код:
void HelpDialog::showTopic()
{
  if ( !was_left_button )
    return;
  ...
}


В самом верху метода:
Код:
bool HelpDialog::eventFilter(QObject * o, QEvent * e)
{
  if ( o == ui.listContents->viewport() && e->type() == QEvent::MouseButtonRelease )
    was_left_button = ((QMouseEvent *)e)->button() == Qt::LeftButton;
  ...
}


Вуаля! (-:  Может так Троллями и задумьІвалось.