我创建了一个小部件类(在C++中)ToolTray,基本上在QToolButton中添加了几个QHboxLayout。用户使用这些按钮进行SaveOpen等操作。最初,添加按钮时将toolButtonStyle设置为Qt::ToolButtonTextBesideIcon

如果新大小不足以显示toolButtonStyle的文本和图标,我想将Qt::ToolButtonIconOnly更改为resizeEvent。见下图:

c++ - 根据窗口大小动态更改QToolButtons的ToolButtonStyle-LMLPHP

如果调整了窗口的大小,并且新的大小足以显示所有QToolButton的文本和图标,则应将QToolButton更改回toolButtonStyle

c++ - 根据窗口大小动态更改QToolButtons的ToolButtonStyle-LMLPHP

我试图通过以下代码实现这一目标:

void ToolTray::resizeEvent(QResizeEvent *event)
{
    int totalWidth = 0;
    bool mode = runBtn_->toolButtonStyle() == Qt::ToolButtonStyle::ToolButtonIconOnly;
    // Mode => True => For ICON Only
    // Mode => False => For ICON + Text
    for (auto btn: toolBtns_) {
        if (btn->isVisible())
            totalWidth += btn->size().width();
    }

    qDebug() << "Total Width: " << totalWidth ;
    qDebug() << "Event Size: " << event->size() << " Old size " << event->oldSize();

    if (event->oldSize().isEmpty()) // Ignore ResizeEvent for QSize(-1,-1)
        return;

    if (mode) { // Already Small
        if (event->size().width() < preferedFullWidth_)
            return;
        for (auto btn: toolBtns_) {
            if (btn == moreBtn_)
                continue;
            btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        }
        return;
    }
    // The QToolButtons are Text Beside Icon
    if (event->size().width() >= totalWidth)
        return;

    qDebug() << "Here";
    for (auto btn: toolBtns_)
        btn->setToolButtonStyle(Qt::ToolButtonIconOnly);
    preferedFullWidth_ = totalWidth;
}


但是,我无法实现我想要的:


每当我尝试缩小窗口的大小时,QToolButton的“文本”都会首先开始剪切,然后再减小一些大小后,将Qt::ToolButtonTextBesideIcon更改为ToolButtonStyle。我不想剪辑发生。
我还想在实现中增加一些余量(或滞后)。就像将QToolButton更改为特定宽度的Qt::ToolButtonIconOnly一样,该宽度应大于preferredFullWidth_ +一定的裕度才能切换回Qt::ToolButtonIconOnly

最佳答案

工具栏本周似乎是a theme ... :)

因此,您基本上有一个正确的想法,但棘手的部分是确定所需的大小。不幸的是,QToolBar layout是完全私有的,因此我们必须自己弄清楚(即使它是从QLayout继承的,您也无法通过QToolBar::layout()获得它的实例)。

该实现是相当基本的,可能不会处理所有情况(我仅使用基本操作进行了测试,没有自定义小部件等),但确实可以使用(在Windows和Linux上以各种样式进行了测试)。

新增:我知道您并不是在专门要求QToolBar,但这实际上就是您要描述的内容...我不确定为什么要重新发明那个轮子(QToolBar可以放置在任何布局中,不必在主窗口中),但是如果您要实现自己的版本,我认为很多示例仍然适用。我个人也几乎总是使用QAction来触发UI事件(相对于按钮),因为它们可以分配给任意数量的UI元素(工具栏,菜单栏,上下文菜单,窗口快捷方式等)。

留给练习者留一个裕度/滞后是一种练习... :)我认为它不需要,但您可以在m_expandedSize中的initSizes()处加上一些任意的空白。

折叠工具栏

#include <QtWidgets>

class CollapsingToolBar : public QToolBar
{
    Q_OBJECT
  public:
    explicit CollapsingToolBar(QWidget *parent = nullptr) : CollapsingToolBar(QString(), parent) {}

    explicit CollapsingToolBar(const QString &title, QWidget *parent = nullptr) :
      QToolBar(title, parent)
    {
      initSizes();
      // If icon sizes change we need to recalculate all the size hints, but we need to wait until the buttons have adjusted themselves, so we queue the update.
      connect(this, &QToolBar::iconSizeChanged, [this](const QSize &) {
        QMetaObject::invokeMethod(this, "recalcExpandedSize", Qt::QueuedConnection);
      });
      // The drag handle can mess up our sizing, update preferred size if it changes.
      connect(this, &QToolBar::movableChanged, [this](bool movable) {
        const int handleSz = style()->pixelMetric(QStyle::PM_ToolBarHandleExtent, nullptr, this);;
        m_expandedSize = (movable ? m_expandedSize + handleSz : m_expandedSize - handleSz);
        adjustForSize();
      });
    }

  protected:

    // Monitor action events to keep track of required size.
    void actionEvent(QActionEvent *e) override
    {
      QToolBar::actionEvent(e);

      int width = 0;
      switch (e->type())
      {
        case QEvent::ActionAdded:
          // Personal pet-peeve... optionally set buttons with menus to have instant popups instead of splits with the main button doing nothing.
          //if (QToolButton *tb = qobject_cast<QToolButton *>(widgetForAction(e->action())))
          //    tb->setPopupMode(QToolButton::InstantPopup);
          //Q_FALLTHROUGH;
        case QEvent::ActionChanged:
          width = widthForAction(e->action());
          if (width <= 0)
            return;

          if (e->type() == QEvent::ActionAdded || !m_actionWidths.contains(e->action()))
            m_expandedSize += width + m_spacing;
          else
            m_expandedSize = m_expandedSize - m_actionWidths.value(e->action()) + width;
          m_actionWidths.insert(e->action(), width);
          break;

        case QEvent::ActionRemoved:
          if (!m_actionWidths.contains(e->action()))
            break;
          width = m_actionWidths.value(e->action());
          m_expandedSize -= width + m_spacing;
          m_actionWidths.remove(e->action());
          break;

        default:
          return;
      }
      adjustForSize();
    }

    bool event(QEvent *e) override
    {
      // Watch for style change
      if (e->type() == QEvent::StyleChange)
        recalcExpandedSize();
      return QToolBar::event(e);
    }

    void resizeEvent(QResizeEvent *e) override
    {
      adjustForSize();
      QToolBar::resizeEvent(e);
    }

  private slots:

    // Here we do the actual switching of tool button style based on available width.
    void adjustForSize()
    {
      int availableWidth = contentsRect().width();
      if (!isVisible() || m_expandedSize <= 0 || availableWidth <= 0)
        return;

      switch (toolButtonStyle()) {
        case Qt::ToolButtonIconOnly:
          if (availableWidth > m_expandedSize)
            setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
          break;

        case Qt::ToolButtonTextBesideIcon:
          if (availableWidth <= m_expandedSize)
            setToolButtonStyle(Qt::ToolButtonIconOnly);
          break;

        default:
          break;
      }
    }

    // Loops over all previously-added actions and re-calculates new size (eg. after icon size change)
    void recalcExpandedSize()
    {
      if (m_actionWidths.isEmpty())
        return;
      initSizes();
      int width = 0;
      QHash<QAction *, int>::iterator it = m_actionWidths.begin();
      for ( ; it != m_actionWidths.end(); ++it) {
        width = widthForAction(it.key());
        if (width <= 0)
          continue;
        m_expandedSize += width + m_spacing;
        it.value() = width;
      }
      adjustForSize();
    }

  private:
    void initSizes()
    {
      // Preload some sizes based on style settings.
      // This is the spacing between items
      m_spacing = style()->pixelMetric(QStyle::PM_ToolBarItemSpacing, nullptr, this);
      // Size of a separator
      m_separatorWidth = style()->pixelMetric(QStyle::PM_ToolBarSeparatorExtent, nullptr, this);
      // The layout margins (we can't even get the private QToolBarLayout via layout() so we figure it out like it does)
      m_expandedSize = (style()->pixelMetric(QStyle::PM_ToolBarItemMargin, nullptr, this) + style()->pixelMetric(QStyle::PM_ToolBarFrameWidth, nullptr, this)) * 2;
      // And the size of the drag handle if we have one
      if (isMovable())
        m_expandedSize += style()->pixelMetric(QStyle::PM_ToolBarHandleExtent, nullptr, this);
    }

    int widthForAction(QAction *action) const
    {
      // Try to find how wide the action representation (widget/separator) is.
      if (action->isSeparator())
        return m_separatorWidth;

      if (QToolButton *tb = qobject_cast<QToolButton *>(widgetForAction(action))) {
        const Qt::ToolButtonStyle oldStyle = tb->toolButtonStyle();
        // force the widest size
        tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
        const int width = tb->sizeHint().width();
        tb->setToolButtonStyle(oldStyle);
        return width;
      }

      if (const QWidget *w = widgetForAction(action))
        return w->sizeHint().width();

      return 0;
    }

    int m_expandedSize = -1;   // The maximum size we need with all buttons expanded and allowing for margins/etc
    int m_spacing = 0;         // Layout spacing between items
    int m_separatorWidth = 0;  // Width of separators
    QHash<QAction *, int> m_actionWidths;  // Use this to track action additions/removals/changes
};


测试/演示


// An XPM icon ripped from QCommonStyle
static const char * const info_xpm[]={
"32 32 5 1",
". c None",
"c c #000000",
"* c #999999",
"a c #ffffff",
"b c #0000ff",
"...........********.............",
"........***aaaaaaaa***..........",
"......**aaaaaaaaaaaaaa**........",
".....*aaaaaaaaaaaaaaaaaa*.......",
"....*aaaaaaaabbbbaaaaaaaac......",
"...*aaaaaaaabbbbbbaaaaaaaac.....",
"..*aaaaaaaaabbbbbbaaaaaaaaac....",
".*aaaaaaaaaaabbbbaaaaaaaaaaac...",
".*aaaaaaaaaaaaaaaaaaaaaaaaaac*..",
"*aaaaaaaaaaaaaaaaaaaaaaaaaaaac*.",
"*aaaaaaaaaabbbbbbbaaaaaaaaaaac*.",
"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
"*aaaaaaaaaaaabbbbbaaaaaaaaaaac**",
".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
".*aaaaaaaaaaabbbbbaaaaaaaaaac***",
"..*aaaaaaaaaabbbbbaaaaaaaaac***.",
"...caaaaaaabbbbbbbbbaaaaaac****.",
"....caaaaaaaaaaaaaaaaaaaac****..",
".....caaaaaaaaaaaaaaaaaac****...",
"......ccaaaaaaaaaaaaaacc****....",
".......*cccaaaaaaaaccc*****.....",
"........***cccaaaac*******......",
"..........****caaac*****........",
".............*caaac**...........",
"...............caac**...........",
"................cac**...........",
".................cc**...........",
"..................***...........",
"...................**..........."};

class MainWindow : public QMainWindow
{
    Q_OBJECT
  public:
    MainWindow(QWidget *parent = nullptr)
      : QMainWindow(parent)
    {
      QToolBar* tb = new CollapsingToolBar(this);
      tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
      tb->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);

      QIcon icon = QIcon(QPixmap(info_xpm));
      for (int i=0; i < 6; ++i)
        tb->addAction(icon, QStringLiteral("Action %1").arg(i));

      addToolBar(tb);
      show();

      // Adding another action after show() may collapse all the actions if the new toolbar preferred width doesn't fit the window.
      // Only an issue if the toolbar size hint was what determined the window width to begin with.
      //tb->addAction(icon, QStringLiteral("Action After"));

      // Test setting button style after showing (comment out the one above)
      //tb->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);

      // Test changing icon size after showing.
      //tb->setIconSize(QSize(48, 48));

      // Try this too...
      //tb->setMovable(false);
    }
};

int main(int argc, char *argv[])
{
  QApplication app(argc, argv);
  //QApplication::setStyle("Fusion");
  //QApplication::setStyle("windows");

  MainWindow w;
  return app.exec();
}


c&#43;&#43; - 根据窗口大小动态更改QToolButtons的ToolButtonStyle-LMLPHP
c&#43;&#43; - 根据窗口大小动态更改QToolButtons的ToolButtonStyle-LMLPHP

关于c++ - 根据窗口大小动态更改QToolButtons的ToolButtonStyle,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57913277/

10-15 07:51
查看更多