Как изменить изображение значка QAction при нажатии QToolButton - PullRequest
0 голосов
/ 08 ноября 2018
  1. Я хочу удалить границу QToolButton при наведении курсора мыши. enter image description here

  2. Я хочу изменить изображение значка QAction при нажатии QToolButton. enter image description here

Я изменил таблицу стилей для QToolButton, но она не работает, пожалуйста, помогите


  1. Я хочу удалить границу QToolButton при наведении курсора мыши. Я изменил таблицу стилей для QToolButton

QToolButton: парить { граница: нет; }
QToolButton: нажать { граница: нет; }

но он отображает границу снизу и кнопка перемещается влево, как изображение

enter image description here

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Для удаления границы QToolButton вы можете использовать таблицу стилей вот так (я проверял, что это работа):

QToolButton { border: 0px;}
QToolButton:pressed {background-color: red;}

Это удаление границы и заливка фона нажатой кнопки инструмента.

Вы не можете изменить изображение нажатой кнопки, потому что обычно мы добавляем QAction на QToolBar в QtDesignet, и нам нужно изменить изображение QAction, но QAction не имеет сигнала от «нажатых», как в QPushButton.

Но если вы добавляете QToolButton в QToolBar вручную - вы можете сделать это, потому что QToolButton имеет сигнал «нажат» и имеет свойство «значок». В каком-то слоте, подключенном к «нажатому» сигналу, вы можете изменить его.

0 голосов
/ 08 ноября 2018

Для «разминки» я начал с QPushButton. Этот класс предоставляет сигналы pressed() и released(), которые можно использовать для изменения значка, соответственно

testQPushButtonDownUp.cc

#include <QtWidgets>

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build UI
  QIcon qIconBtn("dialog-info.svg");
  QIcon qIconBtnDown("dialog-error.svg");
  QPushButton qBtn(qIconBtn, QString::fromUtf8("Click Me."));
  qBtn.show();
  // install signal handlers
  QObject::connect(&qBtn, &QPushButton::pressed,
    [&qBtn, &qIconBtnDown]() { qBtn.setIcon(qIconBtnDown); });
  QObject::connect(&qBtn, &QPushButton::released,
    [&qBtn, &qIconBtn]() { qBtn.setIcon(qIconBtn); });
  // runtime loop
  return app.exec();
}

testQPushButtonDownUp.pro:

SOURCES = testQPushButtonDownUp.cc

QT += widgets

Скомпилировано и протестировано в cygwin64 в Windows 10:

$ qmake-qt5 testQPushButtonDownUp.pro

$ make && ./testQPushButtonDownUp
Qt Version: 5.9.4

Snapshot of testQPushButtonDownUp Snapshot of testQPushButtonDownUp while button pressed

Это было легко. Применение того же к QAction немного сложнее & ndash; QAction обеспечивает только один сигнал triggered(). Я не проверял, испускается ли он для pressed() или released() & ndash; один из обоих необходимых сигналов наверняка отсутствует.

Для решения этой проблемы я использовал QAction::associatedWidgets(), который

Возвращает список виджетов, к которым было добавлено это действие.

Этот список сканируется для каждого вхождения QToolButton, который (выводится из QAbstractButton, а также QPushButton и) дает одинаковые сигналы.

testQToolButtonDownUp.cc

#include <QtWidgets>

void connectAction(QAction &qCmd, const QIcon &qIconDown, const QIcon &qIconUp)
{
  QList<QWidget*> pQWidgets = qCmd.associatedWidgets();
  for (QWidget *pQWidget : pQWidgets) {
    QToolButton *pQBtn = dynamic_cast<QToolButton*>(pQWidget);
    if (!pQBtn) continue;
    QObject::connect(pQBtn, &QToolButton::pressed,
      [pQBtn, qIconDown]() { pQBtn->setIcon(qIconDown); });
    QObject::connect(pQBtn, &QToolButton::released,
      [pQBtn, qIconUp]() { pQBtn->setIcon(qIconUp); });
  }
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build UI
  QToolBar qToolbar;
  QIcon qIconBtn("dialog-info.svg");
  QIcon qIconBtnDown("dialog-error.svg");
  QAction qCmd(qIconBtn, QString::fromUtf8("Click Me."));
  qToolbar.addAction(&qCmd);
  qToolbar.show();
  // install signal handlers
  connectAction(qCmd, qIconBtnDown, qIconBtn);
  // runtime loop
  return app.exec();
}

testQToolButtonDownUp.pro

SOURCES = testQToolButtonDownUp.cc

QT += widgets

Скомпилировано и протестировано снова в cygwin64 в Windows 10:

$ qmake-qt5 testQToolButtonDownUp.pro

$ make && ./testQToolButtonDownUp
Qt Version: 5.9.4

Snapshot of testQToolButtonDownUp Snapshot of testQToolButtonDownUp while button pressed

Это работает, но немного неудобно для обслуживания & ndash; функция connectAction() должна вызываться после добавления QAction ко всем виджетам. (Двойной вызов для одного и того же экземпляра QAction может потребовать дополнительных усилий для предотвращения дублированных обработчиков сигналов для одного и того же экземпляра QToolButton.)

Было бы неплохо автоматически подключить новые QToolButton s, как только связанные виджеты такого соотв. QAction были изменены. Я пролистал документ. вверх и вниз, чтобы найти что-то подходящее & ndash; без удачи Я пытался определить, может ли сигнал QAction::changed() обеспечить требуемое поведение (хотя документ давал меньше надежды), но он не работал.

Наконец, я решил изменить это - ndash; то есть обнаружение, когда QAction добавлено к QToolButton. Тем не менее, в моем коде я добавляю QAction к QToolBar и соотв. QToolButton появляется автоматически. Таким образом, я сделал фильтр событий , установленный на qApp. Этот фильтр событий получит любое событие и, следовательно, будет полезен для обнаружения любых QAction, добавленных к любому QWidget. Все, что я должен сделать дополнительно, это отфильтровать эти события для QAction с и QToolButton с, для которых требуются значки вниз.

testQActionDownUp.cc

#include <set>
#include <QtWidgets>

class Action: public QAction {
  public:
    class FilterSingleton: public QObject {
      private:
        std::set<Action*> _pActions;
      public:
        FilterSingleton(): QObject()
        {
          qApp->installEventFilter(this);
        }
        ~FilterSingleton() { qApp->removeEventFilter(this); }
        FilterSingleton(const FilterSingleton&) = delete;
        FilterSingleton& operator=(const FilterSingleton&) = delete;

        void addAction(Action *pAction)
        {
          _pActions.insert(pAction);
        }
        bool removeAction(Action *pAction)
        {
          _pActions.erase(pAction);
          return _pActions.empty();
        }

      protected:
        virtual bool eventFilter(QObject *pQObj, QEvent *pQEvent) override;
    };

  private:
    static FilterSingleton *_pFilterSingleton;

  private:
    QIcon _qIcon, _qIconDown;

  public:
    Action(
      const QIcon &qIcon, const QIcon &qIconDown, const QString &text,
      QObject *pQParent = nullptr);  
    ~Action();
    Action(const Action&) = delete;
    Action& operator=(const Action&) = delete;

  private:
    void addToolButton(QToolButton *pQBtn)
    {
      QObject::connect(pQBtn, &QToolButton::pressed,
        [pQBtn, this]() { pQBtn->setIcon(_qIconDown); });
      QObject::connect(pQBtn, &QToolButton::released,
        [pQBtn, this]() { pQBtn->setIcon(_qIcon); });
    }
};

bool Action::FilterSingleton::eventFilter(QObject *pQObj, QEvent *pQEvent)
{
  if (QToolButton *pQBtn = dynamic_cast<QToolButton*>(pQObj)) {
    if (pQEvent->type() == QEvent::ActionAdded) {
      qDebug() << "Action::eventFilter(QEvent::ActionAdded)";
      QAction *pQAction = ((QActionEvent*)pQEvent)->action();
      if (Action *pAction = dynamic_cast<Action*>(pQAction)) {
        pAction->addToolButton(pQBtn);
      }
    }     
  }
  return QObject::eventFilter(pQObj, pQEvent);
}

Action::FilterSingleton *Action::_pFilterSingleton;

Action::Action(
  const QIcon &qIcon, const QIcon &qIconDown, const QString &text,
  QObject *pQParent):
  QAction(qIcon, text, pQParent),
  _qIcon(qIcon), _qIconDown(qIconDown)
{
  if (!_pFilterSingleton) _pFilterSingleton = new FilterSingleton();
  _pFilterSingleton->addAction(this);
}

Action::~Action()
{
  if (_pFilterSingleton->removeAction(this)) {
    delete _pFilterSingleton;
    _pFilterSingleton = nullptr;
  }
}

int main(int argc, char **argv)
{
  qDebug() << "Qt Version:" << QT_VERSION_STR;
  QApplication app(argc, argv);
  // build UI
  QMainWindow qWin;
  QToolBar qToolbar;
  QIcon qIconBtn("dialog-info.svg");
  QIcon qIconBtnDown("dialog-error.svg");
  Action qCmd(qIconBtn, qIconBtnDown, QString::fromUtf8("Click Me."));
  qToolbar.addAction(&qCmd);
  qWin.addToolBar(&qToolbar);
  QToolBar qToolbar2;
  qWin.setCentralWidget(&qToolbar2);
  qWin.show();
  QTimer qTimer;
  qTimer.setInterval(5000); // 5000 ms = 5s
  qTimer.start();
  // install signal handlers
  int i = 0;
  QObject::connect(&qTimer, &QTimer::timeout,
    [&i, &qToolbar2, &qCmd]() {
      if (++i & 1) qToolbar2.addAction(&qCmd);
      else qToolbar2.removeAction(&qCmd);
    });
  // runtime loop
  return app.exec();
}

Существует класс Action (производный от QAction) для объединения всего необходимого вместе. Класс Action внутренне использует синглтон (класса Action::FilterSingleton), так что один фильтр событий совместно используется всеми экземплярами Action.

A QTimer используется для периодического добавления / удаления образца Action qCmd в QToolBar qToolbar2 для проверки / демонстрации правильности работы автоматического управления.

testQActionDownUp.pro

SOURCES = testQActionDownUp.cc

QT += widgets

Скомпилировано и протестировано снова в cygwin64 в Windows 10:

$ qmake-qt5 testQActionDownUp.pro

$ make && ./testQActionDownUp
Qt Version: 5.9.4

Snapshot of testQActionDownUp Snapshot of testQActionDownUp while button pressed

Snapshot of testQActionDownUp while 2nd button added Snapshot of testQActionDownUp while 2nd button added and pressed

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