QToolbar resizing
-
Hi all,
I have own implementation of docking window subsystem and main window, use QMainWindow as main window of application was rejected. But using QToolbar as well.
Then I noticed when I try to resize to minimum main window (parent for my toolbar), there was appeared ">>" button on the right side of toolbar, but when I've tried click was nothing happened.
What's wrong? Seems to me that part of code implements in QMainWindow? Where that handled? Please point me to peace of source code of Qt.
Thanks a lot,
Alex -
Apparently it's called
extension button
When a toolbar is resized in such a way that it is too small to show all the items it contains, an extension button will appear as the last item in the toolbar. Pressing the extension button will pop up a menu containing the items that do not currently fit in the toolbar.
Check line 409 from: https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qtoolbar.cpp.html#409
If you read further:
When a QToolBar is not a child of a QMainWindow, it loses the ability to populate the extension pop up with widgets added to the toolbar using addWidget(). Please use widget actions created by inheriting QWidgetAction and implementing QWidgetAction::createWidget() instead.
So this is the case here :) Because as you've said, you don't have a
QMainWindow
based "main" window. But you could try what they suggest (QWidgetActions
+createWidget()
) -
@Alexey-Serebryakov said in Toolbar:
QMainWindow as main window of application was rejected
Rejected by whom?
Then I noticed when I try to resize to minimum main window (parent for my toolbar), there was appeared ">>" button on the right side of toolbar, but when I've tried click was nothing happened.
Do you actually use your toolBar? Do you have items / actions in it?
If I'm not mistaken this is to expand or show (and use) your items in your toolBar even when the toolBar is too small to show all its items.
Please point me to peace of source code of Qt.
Have a look yourself :)
Haven't found it yet.
It could also come from your OS (I dont know if it is a Qt thing).ToolBar
MainWindow
-
We've decided to use own implementation of main window of application, not QMainWindow.
Sure, we use QToolbar with actions/items. And when I resized main window too small toolbar resized too, some items disappeared and appeared ">>" button.
But when I clicked then nothing happened. I'm not suer that it OS-platform specific, this is Qt feature. I wish to find where that handled in Qt source code.
-
Apparently it's called
extension button
When a toolbar is resized in such a way that it is too small to show all the items it contains, an extension button will appear as the last item in the toolbar. Pressing the extension button will pop up a menu containing the items that do not currently fit in the toolbar.
Check line 409 from: https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qtoolbar.cpp.html#409
If you read further:
When a QToolBar is not a child of a QMainWindow, it loses the ability to populate the extension pop up with widgets added to the toolbar using addWidget(). Please use widget actions created by inheriting QWidgetAction and implementing QWidgetAction::createWidget() instead.
So this is the case here :) Because as you've said, you don't have a
QMainWindow
based "main" window. But you could try what they suggest (QWidgetActions
+createWidget()
) -
@Pl45m4 hi, thanks a lot, in general all be works!
So, consider following code skeleton
class MeWidget : public QWidget { // some widget implementation public: ... signals: ... public slots: ... } class MyWidgetAction : public QWidgetAction { public: MyWidgetAction(QObject *parent) : QWidgetAction(parent) {} protected: QWidget *createWidget(QWidget *parent) { auto *widget = new MyWidget(); // some widget tuning // but how widget can communicate with application toolbars, menus?? return widget; } };
-
@Alexey-Serebryakov said in QToolbar resizing:
// but how widget can communicate with application toolbars, menus??
Haven't done something like this before and I don't know if you can use the default, empty popUp and simply put in your widgets to connect your
QWidgetActions
with your slots or if you have to create your own "extension widget" withcreateWidget
.QWidgetActions
work like normalQActions
, which will additionally create a widget (button) to make them work in a ToolBar, for example.Maybe it helps to look further into the code.
PopUpMenu setup:
PopUpMenu is filled here:
Found also these two:
- https://stackoverflow.com/questions/32350658/qtoolbar-how-does-the-extension-button-get-called
- https://stackoverflow.com/questions/40597210/issue-with-qt-toolbar-extension-button
Edit:
Or maybe you just have to fill your ToolBar using your
QWidgetActions:createWidget
and the rest is handled automatically... but I dont know :) I usually useQMainWindow
. -
@Pl45m4 thank you for more detailed information. But isn't clear for me. :-(
Unfortunately, QToolBarLayout and QToolExtension button are in Qt private classes.
I can't understand what the purpose of QWidgetAction. So what I do in case when my widget already created outside QWidgetAction::createWidget() ?
Consider,
class MyWidget: public QWidget { // may be some complex widget, with signal/slots... }; ... MyWidget *widget = new MyWidget(); // some tunning of my widget QWidgetAction *action = new QWidgetAction(toolbar); action->setDefaultWidget(widget); toolbar->insertWidget(action);
So by this way widget does not showing in popup menu by clicking extension button (>>). Because QWidgetAction::createWidget() return null pointer by default implementation.
- Ok, make some changes
MyWidget *widget = new MyWidget(); // some tunning of my widget ... class QMyWidgetAction : public QWidgetAction { public: explicit QMyWidgetAction(QWidget *widget, QObject *parent) : QWidgetAction(parent), widget_(widget) QWidget *createWidget(QWidget *parent) { return widget_; } private: MyWidget *widget_; }
This doesn't work too.
- HOW CAN I SHOW MY WIDGET IN POPUP MENU BY CLICKING EXTENSION BUTTON WITHOUT SUBCLASSING QWidgetAction???? I need create my widget outside QToolBar and QWidgetAction! :-((((((((
Thanks a lot, but I'm already go to mad.
Why they do that implementation???????? :-((((( -
@Alexey-Serebryakov said in QToolbar resizing:
class QMyWidgetAction : public QWidgetAction {
public:
explicit QMyWidgetAction(QWidget *widget, QObject *parent) : QWidgetAction(parent), widget_(widget)
QWidget *createWidget(QWidget *parent) { return widget_; }
private:
MyWidget *widget_;
}Forgot
Q_OBJECT
macro?! (But I dont know if this will change anything).I will try it myself and give feedback later.
-
According to the docs, it says that you need a
QMainWindow
mainWindow with your ToolBar so that the so called "extension button[>>]
" works.So I made a Testproject:
(New Qt App ->QWidget
as base class instead ofQMainWindow
).Main.cpp (nothing special)
My main widget (still aQWidget
and no MainWindow) is calledMainWidget
).#include "mainwidget.h" #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWidget w; w.show(); return a.exec(); }
Widget code:
#include "mainwidget.h" #include "ui_mainwidget.h" #include <QToolBar> #include <QAction> #include <QHBoxLayout> #include <QVBoxLayout> #include <QDebug> #include <QPushButton> MainWidget::MainWidget(QWidget *parent) : QWidget(parent) , ui(new Ui::MainWidget) { ui->setupUi(this); QToolBar *tb = new QToolBar(); QAction *a1 = new QAction("A"); QAction *a2 = new QAction("B"); QAction *a3 = new QAction("C"); QAction *a4 = new QAction("D"); QAction *a5 = new QAction("E"); connect(a1, &QAction::triggered, [=](){ qDebug() << "A"; }); QPushButton *pb = new QPushButton("ANOTHER TEST"); MyWidgetAction *wa = new MyWidgetAction(pb, tb); tb->addAction(a1); tb->addAction(a2); tb->addAction(a3); tb->addAction(wa); tb->addAction(a4); tb->addAction(a5); QVBoxLayout *vBox = new QVBoxLayout(); vBox->addWidget(tb); setLayout(vBox); } MainWidget::~MainWidget() { delete ui; }
Custom Widget Action:
#ifndef MYWIDGETACTION_H #define MYWIDGETACTION_H #include <QObject> #include <QWidget> #include <QWidgetAction> class MyWidgetAction: public QWidgetAction { Q_OBJECT public: MyWidgetAction(QWidget *w, QWidget* parent); QWidget* createWidget(QWidget* parent); private: QWidget *m_widget; // Does NOT work }; #endif // MYWIDGETACTION_H
#include "mywidgetaction.h" #include <QPushButton> #include <QLineEdit> #include <QDebug> MyWidgetAction::MyWidgetAction(QWidget *w, QWidget *parent) : QWidgetAction(parent), m_widget(w) // Does NOT work { } QWidget *MyWidgetAction::createWidget(QWidget *parent) { QPushButton *widget = new QPushButton("Test", parent); // QLineEdit *widget = new QLineEdit(parent); return widget; // // #### Does not work #### // m_widget->setParent(parent); // return m_widget; }
When you have custom widgets in your ToolBar and no
QMainWindow
, you'll need the customQWidgetActons
.What you've tried doesn't seem to work. Apparently the
createWidget
function has to create your widget. You can't pass a widget to your widgetAction class and use it there. Even when you re-parent it, it does not work.
I think, it's because it tries to re-build your widget every time the extension menu is shown, so it fills the menu one by one with the hidden widgets and creates its actions.In my case, the PushButton widget saying "ANOTHER TEST" does not work with the extension menu, but the PushButton ("Test") created by
createWidget
insideMyWidgetAction
class works.
Even other widgets likeQLineEdits
or every other custom widget, that you can put in aQToolBar
will work, when you do it like this :)That you can not pass widgets to
WidgetAction
to stay more flexible, is very unfortunate and I also don't like it, but maybe the other way won't work because of some reason.
... but that is something you should ask the Qt Devs :)Edit:
(BTW: Ubuntu + Qt 5.15)
-
@Pl45m4 thank you, my first implementation do the same as your code.
So, this another but doesn't work correctly,
class ToolBarWidgetAction : public QWidgetAction { Q_OBJECT public: explicit ToolBarWidgetAction(QWidget *widget, QObject *parent) : QWidgetAction(parent), widget_(widget) {} ~ToolBarWidgetAction() Q_DECL_OVERRIDE { widget_->setParent(Q_NULLPTR); } QWidget *createWidget(QWidget *parent) Q_DECL_OVERRIDE { // Create container, put my widget and return container widget QFrame *widget = new QFrame(parent); // just container for my widget widget->setMinimumHeight(32); //widget_->setParent(widget); // ??? auto layout = new QHBoxLayout(); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); layout->addWidget(widget_.data()); widget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum); widget->setLayout(layout); widget->show(); widget_->show(); widget->update(); return widget; } void deleteWidget(QWidget *widget) Q_DECL_OVERRIDE { // Reparent my widget and delete container widget_->hide(); widget->layout()->removeWidget(widget_.data()); widget_->setParent(Q_NULLPTR); QWidgetAction::deleteWidget(widget); } private: const QScopedPointer<QWidget, QScopedPointerDeleteLater> widget_; // store pointer to my widget }; // Then use it auto *myWidget = new MyWidget(toolBar); // my original widget toolBar->addAction(new ToolBarWidgetAction(myWidget, toolBar));
My widget does not showing on toolbar but correctly showing in popup menu by click extension button.
What's wrong?
-
@Alexey-Serebryakov said in QToolbar resizing:
widget->show();
widget_->show();
widget->update();I think calling
show()
is wrong and not needed. What kind of widget is yourwidget_
? Maybe try it without theQFrame