Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Создание вложенного действия QAction
Форум на CrossPlatform.RU > Библиотеки > Qt > Qt GUI
Litkevich Yuriy
Не могу понять как создать вложенное действие (подменю)

Есть указатель на QAction, например:
QAction *createSubAction(QAction *action, const QString &newaction)
{
...
}
Нужно что бы функция сделала, для входного "действия" выпадающее меню с пунктом newaction и вернула указатель на "действие" ассоциированное с этим пунктом.
Схема меню:
пункт1
пункт2
action.text() > newaction
пункт3

где:
action.text() - существующий пункт меню, к которому требуется добавить подменю
newaction - вновь созданный пункт подменю
Алексей1153
А вот это разве не оно ?
Цитата
QMenu * QAction::menu () const
Returns the menu contained by this action. Actions that contain menus can be used to create menu items with submenus, or inserted into toolbars to create buttons with popup menus.

See also setMenu() and QMenu::addAction().

+
Цитата
QAction * QMenu::addAction ( const QString & text )
This is an overloaded function.

This convenience function creates a new action with text. The function adds the newly created action to the menu's list of actions, and returns it.


Litkevich Yuriy
И?
Алексей1153
А что И )
QAction *createSubAction(const QAction *action, const QString &newaction)
{
   return action->menu()->addAction ( newaction );
}


(но не проверял)
Litkevich Yuriy
это ты просто создаёшь новый пункт в меню, а мне нужно вложенное меню создать.

Здаётся мне, что в Qt это очередная не решаемая задача, среди, казалось бы, простейших
Алексей1153
Ещё мысль (по аналогии с тем, как это делается в WinAPI)

создать объект QMenu, вставить в него пункты, а затем присобачить это меню к действию методом
void QAction::setMenu ( QMenu * menu )

И это действие добавить как очередной пункт родительского меню


Собственно, что и требовалось доказать
    QAction* pAsub=0;    
    QMenu& m=*new QMenu(this);
    m.addAction("1");
    pAsub=m.addAction("2");
    m.addAction("3");
        
    QMenu& m2=*new QMenu(&m);
    m2.addAction("11");
    m2.addAction("22");
    m2.addAction("33");
    pAsub->setMenu(&m2);
    
    m.popup(QPoint(0,0));



(блин, не пойму, как картинку вставить в пост)
Litkevich Yuriy
Цитата(Алексей1153 @ 1.8.2010, 0:18) *
QMenu& m=*new QMenu(this);
не понятно за чем вся эта химия с ссылками и указателями
Алексей1153
со ссылками приятнее работать , точка меньше загромождает код, чем стрелка :) А так разницы нет
Litkevich Yuriy
Цитата(Алексей1153 @ 1.8.2010, 0:18) *
И это действие добавить как очередной пункт родительского меню
пункт уже есть. Схема меню:
Было:

пункт1
пункт2
action.text()
пункт3

Стало:

пункт1
пункт2
action.text() > newaction
пункт3



Цитата(Алексей1153 @ 1.8.2010, 0:48) *
со ссылками приятнее работать , точка меньше загромождает код
ничуть, напиши тоже самое в более естественной форме и сравни.
Алексей1153
Ну так ведь доступ к action есть ?
пункт1
пункт2
action.setMenu(&m2);
пункт3


Или я что-то не понимаю...
DEADHUNT
а почему подменю нельзя так добавить QMenu::addMenu, зачем что придумывать для QAction?
Litkevich Yuriy
Цитата(Алексей1153 @ 1.8.2010, 0:18) *
void QAction::setMenu ( QMenu * menu )
в принципе близок к истине. Только прийдётся разруливать повторный вызов функции.

Цитата(DEADHUNT @ 1.8.2010, 1:08) *
QMenu::addMenu, зачем что придумывать для QAction?
потому-что есть только указатель на QAction
DEADHUNT
Цитата(Litkevich Yuriy @ 31.7.2010, 22:10) *
потому-что есть только указатель на QAction

значит можно удалить QAction, а вместо него вставить QMenu и наоборот если надо.
Алексей1153
Цитата(DEADHUNT @ 1.8.2010, 0:08) *
а почему подменю нельзя так добавить QMenu::addMenu, зачем что придумывать для QAction?

тут какая-то интересная иерархия

Вроде бы первично QMenu.
Затем, QMenu содержит список QAction.
....Каждый QAction содержит свой QMenu m , который, если нет подменю, пуст.
........Ну, а QMenu - ... (рекурсивно повторять до талого снега)

А удалить QAction - значит удалить пункт
Litkevich Yuriy
Цитата(DEADHUNT @ 1.8.2010, 1:15) *
значит можно удалить QAction, а вместо него вставить QMenu и наоборот если надо.


Цитата(Алексей1153 @ 1.8.2010, 1:16) *
А удалить QAction - значит удалить пункт
не только, ещё и те объекты которые прицеплены к его сигналам, могут стать глухими.


Цитата(Алексей1153 @ 1.8.2010, 1:16) *
Вроде бы первично QMenu.
поидее и QMenu имеет ассоциированный с ним QAction, и является визуальным контейнером QAction'ов. И пункт на панели меню - тоже QAction. Т.е. QAction всему голова. Однако иерархию построить невозможно.


Вообще понадобилась относительно простая вещь. Плагины возвращают строку такого вида:
"Правка/Копировать"
"Правка/Вставить"
"Настройки/Модули/Редактор"

И т.п. плагины могут быть как дочерним окном в MDI, соответственно менюхи должны перестраиваться в зависимости от активного окна. Также плагины могут быть не визуальными но содержать диалоги, поэтому для доступа к диалогам, они просят главное окно создать цепочку пунктов меню. Если часть цепочки существует, то туда просто, что-то добавляется.

Если бы QAction был полноценным классом, эту идею можно было бы довольно легко реализовать.
DEADHUNT
Цитата(Litkevich Yuriy @ 31.7.2010, 22:27) *
не только, ещё и те объекты которые прицеплены к его сигналам, могут стать глухими.

можно создать список подключенных сигналов, затем их переподключать.
Алексей1153
Цитата(Litkevich Yuriy @ 1.8.2010, 0:27) *
поидее и QMenu имеет ассоциированный с ним QAction, и является визуальным контейнером QAction'ов. И пункт на панели меню - тоже QAction. Т.е. QAction всему голова. Однако иерархию построить невозможно.

Ну почему же невозможно, всё вроде стройно: ассоциированный с ним QAction - это собственник этого QMenu , и он (этот ваще-основной QAction) никогда не будет вызван

То есть, схематично будет как-то так:

class QAction
{
   QMenu* pm;
};

class QMenu
{
    QAction* pParentAction;
    vector<QAction> acts;
};


А почему QAction вдруг не полноценный класс ? )) Из исходников Qt:

class Q_GUI_EXPORT QAction : public QObject
{
    Q_OBJECT
    Q_DECLARE_PRIVATE(QAction)
...
...
};


Цитата
"Правка/Копировать"
"Правка/Вставить"
"Настройки/Модули/Редактор"

....они просят главное окно создать цепочку пунктов меню. Если часть цепочки существует, то туда просто, что-то добавляется.


То есть, из текстового описания меню нужно создать свой объект меню с этими пунктами, так ?
Litkevich Yuriy
Цитата(Алексей1153 @ 1.8.2010, 1:44) *
А почему QAction вдруг не полноценный класс ? ))
потомучто не имеет методов:
void setSubActon(QAction *)
QAction *parentAction()
QList<QAction *> childActions()

чтобы получить эту информацию, нужно костылей понаделать.
Алексей1153
void setSubActon(QAction *) - Скорее должно бы выглядеть так

void setSubActon(QMenu *)

То есть, такой метод уже есть - SetMenu

-------------------------
QAction * QAction::parentAction() - это относится к QMenu, то есть

а это вроде есть тоже
Цитата
QAction * QMenu::menuAction () const
Returns the action associated with this menu.


-----------------------------
QList<QAction *> childActions() - это тоже метод меню должОн быть. (аналога не нашёл :( )

---------------------
Если меню создаётся с нуля, то проще всего вести ассоциативный список map<QString,QAction*>
Пример содержимого (адреса абстрактные, а ключи - реальные):

"Правка/" , 0x1
"Правка/Копировать/" , 0x2
"Правка/Вставить/", 0x3
"Настройки/", 0x4
"Настройки/Модули/", 0x5
"Настройки/Модули/Редактор/", 0x6

А для полного комфорту, возможно, ещё придётся вести эквивалентный список map<QAction*,QString>
DEADHUNT
Цитата(Алексей1153 @ 31.7.2010, 23:21) *
Если меню создаётся с нуля, то проще всего вести ассоциативный список map<QString,QAction*>

можно hash map использовать(быстрее будет, в STL std::unordered_map)
Алексей1153
DEADHUNT, ну это уже не суть важно. А чем быстрее то , кстати?

В любом случае, на скорость тут пофиг )) Чай меню, а не миллисекундные точности
DEADHUNT
а что хэш таблица медленнее идеально сбалансированного дерева(с временной сложностью поиска O(log n) )?
Алексей1153
При таком небольшом размере списка - сомневаюсь :) Хеш ещё и посчитать надо. Но это уже оффтоп, я ж говорю - скорость тут фигня, не заметишь
DEADHUNT
вычисление хэша наверняка не будет выполняться дольше чем сравнивается QString(а их будет O(log n) ).
Алексей1153
DEADHUNT, обрати внимание на количество элементов :) А сравнение двух строк - это одна цепочечная машинная команда, если удачно соптимизируется. Опять оффтоп )) Увязнем в теории, которая тут ни к чему
Litkevich Yuriy
Накидал класс YAction, наследник QAction поддерживающий иерархию.
Нажмите для просмотра прикрепленного файла

применять легко:
QAction *addItem(const QString &menuPath)
{
    const QStringList items = menuPath.split("/");
    QAction *action = 0;
    for(int i = 0; i != items.size(); ++i){
        if (!action){
            action = new YAction(items.at(i), menuBar);
        }else{
            action = new YAction(items.at(i), action);
        }
    }
    return action;
}
menuBar - где-то объявлен.

П.С.
писалось только-что (без двадцати минут 4 утра) ;)
Litkevich Yuriy
Сообщение переместил сюда: Секреты и интересные возможности Qt
(В копилку так сказать)
Алексей1153
Хм, надо тогда более детально протестировать будет :)
Litkevich Yuriy
копилку эту разобрать бы, да в вики перенести. Да что-то никак с силами не соберусь. Может, кто-то возьмётся
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.