gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-28 04:10:35 25 4
gpt4 key购买 nike

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

如果新尺寸不足以显示文本和图标,我想在 resizeEvent 中将 toolButtonStyle 更改为 Qt::ToolButtonIconOnly QToolButton。见下图:

enter image description here

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

enter image description here

我尝试用下面的代码实现这个:

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;
}

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

  1. 每当我尝试缩小窗口的大小时,QToolButton 的文本首先开始裁剪,在进一步缩小尺寸后,ToolButtonStyle 更改为 Qt::ToolButtonIconOnly。我不想剪裁发生。

  2. 我还想在我的实现中添加一些余量(或滞后)。就像一旦 QToolButton 在特定宽度更改为 Qt::ToolButtonIconOnly,那么宽度应该大于 preferedFullWidth_ + 一定的边距以切换回 Qt::ToolButtonTextBesideIcon

最佳答案

工具栏似乎是a theme这周……:)

所以您的想法基本上是正确的,但棘手的部分是计算出所需的大小。不幸的是 QToolBar layout是完全私有(private)的,因此我们必须自己解决问题(即使它继承自 QLayout,您无法通过 QToolBar::layout() 获取它的实例)。

此实现相当基础,可能无法处理所有情况(我只测试了基本操作,没有自定义小部件等),但它确实适用于此(在 Windows 和 Linux 上以各种样式测试)。

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

添加边距/滞后留给读者作为练习... :) 我不认为它需要一个,但你可以填充 m_expandedSizeinitSizes()有一些任意余量。

折叠工具栏

#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();
}

enter image description here enter image description here

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

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com