LINUX.ORG.RU

Не могу активировать виджет выбора шрифта через горячие клавиши

 , , ,


0

1

У меня есть виджет EditorFontFamilyComboBox, унаследованный от QFontComboBox. Чтобы установить на нем фокус, я добавил этому виджету свойство:

QAction selectAction; // Действие для активации (выбора) данного виджета

которое можно получить через метод:
QAction *EditorFontFamilyComboBox::getSelectAction()
{
    return &selectAction;
}

Для этого действия я задал соединение сигнала-слота:
    // Активация данного виджета по горячей клавише
    connect(&selectAction, &QAction::changed,
            this, &EditorFontFamilyComboBox::onChangeSelectAction);

И слот выглядит так:
void EditorFontFamilyComboBox::onChangeSelectAction()
{
    qDebug() << "Select EditorFontFamilyComboBox";

    this->setFocus(Qt::ShortcutFocusReason);
}

Внешний код получает у экземпляра класса EditorFontFamilyComboBox действие через getSelectAction(), и через метод setShortcut() устанавливает нужную комбинацию клавиш (в моем примере это происходит в файле EditorToolBar.cpp, строка 375, которая выглядит так:
shortcutManager.initAction("editor-fontSelect", fontSelect->getSelectAction() );

А сам метод initAction() выглядит так:
void ShortcutManager::initAction(QString actionName, QAction *action)
{
    if(keyTable.contains(actionName)) {
        action->setShortcut(  getKeySequence(actionName) );
        action->setStatusTip( getFullDescription(actionName) );
        action->setToolTip(   getDescriptionWithShortcut(actionName) );
        action->setText(      getDescriptionWithShortcut(actionName) );
    } else {
        criticalError("Not found available action name "+actionName);
        return;
    }
}

То есть, если бы вызов этого метода был бы некорректен, была бы ошибка с текстом «Not found available action name ...», но такой ошибки нет.

В общем, проблема в том, что при нажатии шортката, не вызывается слот EditorFontFamilyComboBox::onChangeSelectAction().

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

Ссылка на код: https://github.com/xintrea/mytetra_dev

★★★★★

Так а этот QAction когда-нибудь добавляется на какой-нибудь родительский виджет? Я не вижу этого во время инициализации и не нахожу вызова addAction() с ним в качестве аргумента.

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

В тулбар вставляется только сам виджет EditorFontFamilyComboBox, происходит это в методе:

void EditorToolBar::insertButtonToToolsLine(QString toolName, QToolBar &line)

Я почему-то думал, что если QAction задать шорткат, то где бы оно ни находилось, хоть отдельно, хоть на тулбаре, оно должно отрабатывать.

Теперь надо придумать, как засунуть невидимый QAction на динамический тулбар так, чтобы он отрабатывал, но при этом не мешал работе с этим реконфигурабельным тулбаром.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

Я почему-то думал, что если QAction задать шорткат, то где бы оно ни находилось, хоть отдельно, хоть на тулбаре, оно должно отрабатывать.

Не:

Note that an action must be added to a widget before it can be used;

Теперь надо придумать, как засунуть невидимый QAction на динамический тулбар так, чтобы он отрабатывал, но при этом не мешал работе с этим реконфигурабельным тулбаром.

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

xaizek ★★★★★
()
Ответ на: комментарий от xaizek

В общем, я сделал так: создал дополнительный класс EditorFontToolFocus, и включаю его как public-включение toolFocus в EditorFontFamilyComboBox (и еще в EditorFontSizeComboBox, но с ним буду позже разбираться).

Объект QAction, который должен активировать виджет, я вставляю в тулбар через функцию insertActionAsButton(), которая умеет добавлять «скрытые» действия на тулбар в виде невидимой кнопки:

// Если добавляемый инструмент - это виджет
if(toolAsWidget)
{
    toolAsWidget->setVisible(true);
    line.addWidget(toolAsWidget); // Инструмент добавляется на панель инструментов как виджет

    // Для специальных классов добавляются действия активации виджета
    // как невидимые кнопки
    if( strcmp(toolAsWidget->metaObject()->className(), "EditorFontFamilyComboBox")==0)
    {
        insertActionAsButton(&line, static_cast<EditorFontFamilyComboBox*>(toolAsWidget)->toolFocus.getSelectAction(), false);
    }
    if( strcmp(toolAsWidget->metaObject()->className(), "EditorFontSizeComboBox")==0 )
    {
        insertActionAsButton(&line, static_cast<EditorFontSizeComboBox*>(toolAsWidget)->toolFocus.getSelectAction(), false);
    }
}

Но все равно, и в таком виде не работает вызов слота EditorFontToolFocus::onChangeSelectAction().

Кстати, чтобы сделать кнопки активации видимыми, надо третий параметр insertActionAsButton() поставить в true. И они становятся видны. Но ни горячая клавиша, ни клик на них не приводит к вызову слота EditorFontToolFocus::onChangeSelectAction(), нужное сообщение в консоли не появляется.

Изменения сделаны в коммите b57273ad4b

UPD: Пробовал вмето сигнала changed отлавливать toggled, толку тоже никакого.

Xintrea ★★★★★
() автор топика
Последнее исправление: Xintrea (всего исправлений: 1)
Ответ на: комментарий от xaizek

С точки зрения надежности, плюсовая проверка типов будет лучше. С точки зрения понятности кода, мне проще вот эту конструкцию воспринять. Да, она может привести к ошибке в рантайме, если у класса поменяется название, ибо эта проверка не отследится компилером. И я наверно, когда подниму свой уровень владения C++ буду писать как правильнее, а не как понятнее. Плюсы настолько сложны, что я уже устал все продумывать и учитывать, тем более если рядом не сидит человек и не говорит «не стоит так делать».

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Ты бы лучше вот с этой траблой помог: Перестало работать форматирование текста в QTextEdit. Что ему еще надо?

Я подумывал на праздниках сделать трудовой подвиг, и вплотную приблизиться к релизу. Но чуствую, что не успею, потому что спотыкаюсь на очередных странных особенностях на каждом шагу.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от deep-purple

Переписал так:

// При динамическом приведении типа, если тип не соответсвует заданному,
// dynamic_cast вернет NULL для типа указателя коим является toolAsWidget.
// Т. е. условие сработает только если тип будет успешно приведен к целевому
if( dynamic_cast<EditorFontFamilyComboBox*>(toolAsWidget) )
{
    insertActionAsButton(&line, static_cast<EditorFontFamilyComboBox*>(toolAsWidget)->toolFocus.getSelectAction(), false);
}
if( dynamic_cast<EditorFontSizeComboBox*>(toolAsWidget) )
{
    insertActionAsButton(&line, static_cast<EditorFontSizeComboBox*>(toolAsWidget)->toolFocus.getSelectAction(), false);
}

Стало надежнее, но я в коде хотел бы видеть не игру с приведением типов, а тупое «если объект имеет имя класса такое-то, то...».

К сожалению, я не знаю как плюсах сделать такое явное условие без вынуженной обфускации кода с использованием особенностей языка.

Xintrea ★★★★★
() автор топика
Ответ на: комментарий от Xintrea

обьявляешь енум, у родительского класса или у каждого вида заводишь пропертю с значением из того енума и делаешь в этом месте кода switch (obj->type()) { case ...

deep-purple ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.