QToolButton with text: Overwrite minimal height to minic regular button height - qt

I am displaying QToolButtons with icon plus text (Qt::ToolButtonTextBesideIcon) outside of a tool bar. Each button has a QAction associated with it which determines the used icon and the displayed text. All those buttons are placed inside a QGridLayout. So far so good.
Unfortunately, it looks like that as soon as you add a QAction to a QToolButton, Qt automatically decides to shrink it down to the minimal size, which is not what I want given my QGridLayout. I used the following lines to correct that behavior in the horizontal dimension:
QToolButton* pButton = new QToolButton(0);
pButton->addDefaultAction(pAction);
pButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
pButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
However that still leaves my button with a smaller height than a regular (push) button. I already tried various other size policies without success.
How to best solve this issue? Is there a reliable way to determine the "normal" button height?
One idea I had was to create a regular dummy button, place it in the same layout and then read its size. This size could then be applied to my QToolButton and the dummy button would be destroyed again. Is there a more elegant / reliable way?

I do not understand what do you want to achieve.
Difference between QPushButton and QToolButton is that, QToolButton has implemented PopupMenu ( can be done easily for QPushButton also )
As I understand visual difference is only small arrow in lower right corner of QToolButton, when you use added QActions to QToolButton
This arrow is for me only difference between QToolButton and QPushButton. But maybe I am missing something.
From your examples ( QToolButton with icon + text: How to center both? )
it does not look like you want to use that popup feature. Thats why I do not understand, why to use QToolButton instead of QPushButtons.
In this example shows:
1) Same height of QToolButton and QPushButton
2) PopuMenu for QPushButton
As for me, I do not understand why to use QToolButton and try to make it look like QPushButton when it is simple to use QPushButton as QToolButton
#include <QtGui>
#include <QtWidgets>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// Prepare layout
QMainWindow *window = new QMainWindow;
QWidget *centralWidget = new QWidget(window);
QGridLayout *grid = new QGridLayout(centralWidget);
QTextEdit *textEdit = new QTextEdit();
window->setCentralWidget(centralWidget);
QAction *toolAction = new QAction(window->style()->standardIcon(QStyle::SP_MediaPlay), "ToolButton", window);
QObject::connect(toolAction, &QAction::triggered, [=]() {
qDebug() << "action";
});
QPushButton *pushButton = new QPushButton(toolAction->icon(), "PushButton1", window);
pushButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QPushButton *pushButton2 = new QPushButton(toolAction->icon(), "PushButton2", window);
pushButton2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QPushButton *pushButton3 = new QPushButton(toolAction->icon(), "PushButton2", window);
pushButton3->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
QObject::connect(pushButton3, &QPushButton::released, [window, pushButton3, toolAction](){
QMenu menu;
menu.addAction(toolAction);
QPoint pos = window->mapToGlobal(pushButton3->pos());
pos += QPoint(0, pushButton3->height());
menu.exec(pos);
});
QObject::connect(pushButton, SIGNAL(pressed()), toolAction, SLOT(trigger()));
QObject::connect(pushButton2, SIGNAL(pressed()), toolAction, SLOT(trigger()));
QToolButton *toolButton = new QToolButton(window);
toolButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolButton->setText("Popup action");
toolButton->addAction(toolAction);
toolButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
QToolButton *toolButton2 = new QToolButton(window);
toolButton2->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
toolButton2->setDefaultAction(toolAction);
toolButton2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
toolButton->setMaximumHeight(pushButton->sizeHint().height());
toolButton->setMinimumHeight(pushButton->sizeHint().height());
toolButton2->setMaximumHeight(pushButton->sizeHint().height());
toolButton2->setMinimumHeight(pushButton->sizeHint().height());
grid->addWidget(textEdit ,0,0,1,2);
grid->addWidget(toolButton ,1,0,1,1);
grid->addWidget(pushButton ,1,1,1,1);
grid->addWidget(toolButton2 ,2,0,1,1);
grid->addWidget(pushButton2 ,2,1,1,1);
grid->addWidget(pushButton3 ,3,0,1,2);
window->show();
return a.exec();
}

Related

How to resize qt dock widget to fit qCustomPlot widget?

A qDockWidget containing a qCustomPlot always starts with zero height. I am able to catch the qDockWidget resize event and change the qCustomPlot geometry using these answers, but the qCustomPlot is always hidden until it is manually stretched. Should this happen automatically, or do I need to calculate and set the dock height at startup?
This sample code creates a new qCustomPlot widget, places it in a layout, places that layout in another widget, and sets it to the dock. I have also tried placing the qCustomPlot widget directly into the dock. qCustomPlot setGeometry, setMinimumSize, and setSizePolicy seem to have no effect on the dock height.
#include <QMainWindow>
#include "qcustomplot.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
QCustomPlot *m_customPlot;
QDockWidget *dock;
resize(1200, 600);
//create the plot
QWidget *plot_frame_temp= new QWidget();
plot_frame_temp->setSizePolicy(QSizePolicy::MinimumExpanding,QSizePolicy::MinimumExpanding);
m_customPlot = new QCustomPlot(plot_frame_temp);
m_customPlot->axisRect()->setupFullAxesBox(true);
m_customPlot->setBackground(Qt::black);
//size and margin settings
m_customPlot->setGeometry(QRect(0, 0, 500, 400));
m_customPlot->axisRect()->setMinimumSize(500,400);
m_customPlot->axisRect()->setAutoMargins(QCP::msLeft|QCP::msBottom|QCP::msRight|QCP::msTop);
// zoom and drag only on horrizontal axis
m_customPlot->axisRect()->setRangeZoomAxes(m_customPlot->xAxis,nullptr);
m_customPlot->axisRect()->setRangeDragAxes(m_customPlot->xAxis,nullptr);
//setup the top axis and labels
m_customPlot->xAxis->setVisible(false);
m_customPlot->xAxis2->setVisible(true);
m_customPlot->xAxis2->setTicks(true);
m_customPlot->xAxis2->setTickLabels(true);
m_customPlot->xAxis2->setTickPen(QColor(136, 136, 136));
m_customPlot->xAxis2->setTickLength(0,10);
m_customPlot->xAxis2->setTickLabelColor(QColor(136, 136, 136));
m_customPlot->xAxis2->setSubTickPen(Qt::NoPen);
m_customPlot->xAxis2->setBasePen(Qt::NoPen);
QFont font;
font.setStyleStrategy(QFont::PreferOutline);
m_customPlot->xAxis2->setTickLabelFont(font);
//setup the left axis and hide
m_customPlot->yAxis->setVisible(false);
m_customPlot->yAxis->setRangeReversed(true);
m_customPlot->yAxis2->setVisible(false);
//first graph
m_customPlot->addGraph();
m_customPlot->graph()->setPen(QPen(QColor(165, 165, 165)));
m_customPlot->graph()->setLineStyle((QCPGraph::lsStepLeft));
//second graph
m_customPlot->addGraph();
m_customPlot->graph()->setPen(QPen(QColor(165, 165, 165)));
m_customPlot->graph()->setLineStyle((QCPGraph::lsStepLeft));
// make some data
QVector<double> x(500), y0(500), y1(500);
for (int i=0; i<500; ++i)
{
x[i] = i;
y0[i] = (rand() % 2 + 0.2)/2;
y1[i] = (rand() % 2 + 1.4)/2;
}
//add data to graph
m_customPlot->graph(0)->setData(x, y0);
m_customPlot->graph(1)->setData(x, y1);
// set some options
m_customPlot->setNotAntialiasedElements(QCP::aeAll);
m_customPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
//add plot widget to layout
QHBoxLayout *laLayout = new QHBoxLayout();
laLayout->addWidget(plot_frame_temp);
//add layout to another widget
QWidget *laWidget=new QWidget();
laWidget->setLayout(laLayout);
//add second widget to dock
dock = new QDockWidget(tr("qcustomplot"), this);
dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
dock->setWidget(laWidget);
addDockWidget(Qt::BottomDockWidgetArea, dock);
QWidget *centralWidget=new QWidget();
setCentralWidget(centralWidget);
}
};
Here is a minimum example done directly in mainwindow.h. A dock with a central widget and a QDockWidget with a qCustomPlot. I am using the compiled DLL version of qCustomPlot
Image: dock starts with zero height:
Initially the dock looks like this. The plot is hidden and the dock is claiming no height in an otherwise empty layout.
Image: dock stretched to show the plot
The plot is visible when the user stretches the dock.
I strongly suspect there is a way for the dock to adjust to the height of the qCustomPlot automatically. I can set the dock height from code, but that seems like a hack.
The most direct approach to solve your issue might be to define a minimum size for your QCustomPlot Widget. This can easily achieved with the following reduced example. Actually, the problems has nothing to do with QCustomPlot at all. It could have been any kind of widget with minimum size (0,0).
#include <QMainWindow>
#include "qcustomplot.h"
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(){
auto m_customPlot = new QCustomPlot();
m_customPlot->axisRect()->setupFullAxesBox(true);
auto dock = new QDockWidget(tr("qcustomplot"), this);
dock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
dock->setWidget(m_customPlot);
m_customPlot->setMinimumSize(QSize(500,500));
dock->setMinimumSize(m_customPlot->minimumSize());
addDockWidget(Qt::DockWidgetArea::BottomDockWidgetArea, dock);
setCentralWidget(new QWidget);
}
};
A better solution might to save and to restore the geometry of your dock widget configuration in the registry. This leaves the user with just the dock widget configuration that he finds desirable.
void MainWindow::closeEvent(QCloseEvent *event)
{
QSettings settings("MyCompany", "MyApp");
settings.setValue("geometry", saveGeometry());
QMainWindow::closeEvent(event);
}
QSettings settings("MyCompany", "MyApp");
dock->restoreGeometry(settings.value("myWidget/geometry").toByteArray());

QPushButton Main Gui

I'm beginning with Qt and I do not understand something. Here is my code:
#include <QApplication>
#include <QtWebKitWidgets/QWebView>
#include <QMainWindow>
#include <QPushButton>
QApplication a(argc, argv);
QMainWindow *mWin = new QMainWindow();
QPushButton *button = new QPushButton("Button");
button->setGeometry(0,0,128,56);
button->show();
mWin->setGeometry(QRect(300,300,1024,640));
mWin->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
mWin->show();
return a.exec();
When I launch the program, it makes a pushbutton, but not on the main GUI. It instead makes it in the upper lefthand corner of my scoeen. How do I make the pushbutton part of the main GUI?
Both QMainWindow and QPushButton derive from QWidget and generally, QWidgets can display themselves independently, so don't need to be attached to a parent, though it's likely you'll want to group and organise the widgets you're presenting to the user.
For a beginner, I think that QMainWindow is a bit misleading as you don't actually need it to display widgets. If, for example, you wanted to just display the button, you only need create the QPushButton and call show: -
QPushButton pButton = new QPushButton("Test");
pButton->show();
Though it's rare that you'll actually want to do this. In actuality, though it appears pointless, you can even just create a QWidget and display that: -
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
w.show();
return a.exec();
}
The QWidget can now be the parent to all other widgets, still without you defining a QMainWindow.
It is likely that you will want other widgets to display and Qt uses a parent / child hierarchy system of linking them together. Amongst other things, an advantage here is that you don't need to keep track of the different widgets in order to release their memory. When you're finished, you just delete the top level item, which may be a QMainWidget, or QDialog or other QWidget based object. In the case of Windows, all you need to do is close them and their children are cleaned up too.
Adding Widgets to a QMainWindow can be done in different ways, depending upon what you're trying to achieve. Eventually, you'll likely want to use layouts that allow grouping of widgets in logical arrangements, but to start with, if you look at the constructor of the QPushButton, you'll see that it takes an optional parameter of QWidget* : -
QPushButton(QWidget * parent = 0)
This allows you to attach the widget you're creating (QPushButton in this case) to a parent. Therefore, create the QMainWindow and then pass its pointer to the QPushButton.
QMainWindow* pWindow = new QMainWindow; // create the main window
QPushButton pButton = new QPushButton(pWindow); // create the push button
pWindow->show(); // Display the main window and its children.
You're creating a button and a window, but you're not associating them together. Therefore, the button is not part of the main UI. In order to add the button to the main window, you should add the following line-
mWin->setCentralWidget(button);
When creating user interfaces with Qt, it's better to avoid setting the geometry explicitly. Here is a nice page which describes the layouting in Qt.
Also, you seem to be missing a main function.
You are not setting parent child relationship, you need QPushbutton as a child of QMainwindow. Then you can see QPushbutton on QMainwindow.
Please try this, I am not sure what exactly you want to achive..but below code will give some hind about how to proceed..
QApplication a(argc, argv);
QMainWindow *mWin = new QMainWindow();
QPushButton *button = new QPushButton(mWin); // setting parent as QMainwindow
button->setGeometry(0,0,128,56);
// button->show();
//mWin->setCentralWidget( button );
mWin->setGeometry(QRect(300,300,1024,640));
mWin->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowMinimizeButtonHint | Qt::WindowCloseButtonHint);
mWin->show()
;
Create a central widget for the main window and then use a layout to place the push button on the central widget. For example:
QMainWindow *mWin = new QMainWindow();
// Place the button in a layout
QHBoxLayout *layout = new QHBoxLayout;
QPushButton *button = new QPushButton("Button");
layout->addWidget(button);
// Set up a central widget for the main window
QWidget *centralWidget = new QWidget();
centralWidget->setLayout(layout);
mWin->setCentralWidget(centralWidget);
If you've placed your button into a layout this way (or as a central widget itself, as one of the other answers has indicated), you don't need to set the geometry on the button, nor do you need to call setVisible or show on the button explicitly (but you still need to on the main window).
Consider looking through some of Qt's examples, such as the application example for more information.

Qt: Architectural advice needed regarding QAbstractScrollArea

I'd like to design a scrollable "controls container" widget. Meaning, a scrollable view that'll be able to contain live controls (any QWidget derivative). By "live controls" i mean, if a animated QWidget derived is placed in it, i'd like to see the animation, as i scroll up and down, while the sub-control moves up and down.
Would basing such a widget on "QAbstractScrollArea" be the right way to approach it? i'd simply add controls as children? positioning them in a column? will that be enough?
EDIT:
This is the constructor code from my QAbstractScrollArea derived class. Why don't I ever see a scrollbar that can scroll the controls? (not all are visible on the same page based on the height I gave my control)
// add controls
QPushButton *a = new QPushButton(QString("a"), this);
a->setGeometry(QRect(10,10,100,30));
QPushButton *b = new QPushButton(QString("b"), this);
b->setGeometry(QRect(10,40,100,30));
QPushButton *c = new QPushButton(QString("c"), this);
c->setGeometry(QRect(10,70,100,30));
QPushButton *d = new QPushButton(QString("d"), this);
d->setGeometry(QRect(10,100,100,30));
QPushButton *e = new QPushButton(QString("e"), this);
e->setGeometry(QRect(10,130,100,30));
QPushButton *f = new QPushButton(QString("f"), this);
f->setGeometry(QRect(10,160,100,30));
QPushButton *g = new QPushButton(QString("g"), this);
g->setGeometry(QRect(10,190,100,30));
QPushButton *h = new QPushButton(QString("h"), this);
h->setGeometry(QRect(10,220,100,30));
this->addScrollBarWidget(new QScrollBar(this), Qt::AlignRight);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
Basically, that is enough. Use the concrete QScrollArea class and a generic container widget, then position your controls as children of the container.
QScrollArea scrollArea;
QWidget container;
// Create controls and add them to container.
scrollArea.setWidget( &container );

How does designer create a Line widget?

In Qt Designer , you can drag a "Line" widget , which will create a line in your layout.
But I checked the document and headers , I didn't find the "Line" header / widget , what was it ?
In Qt 5.7 the code generated by Qt Designer for a Horizontal Line (which can be checked in the menu using "Form/View Code...") is:
QFrame *line;
line = new QFrame(Form);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
This will create the lines you see in Qt Designer.
The current answers do not seem to give working solutions, here is a comparison of all answers (this solution is the first line):
Full code:
#include <QtWidgets>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QWidget widget;
auto layout = new QVBoxLayout;
widget.setLayout(layout);
widget.resize(200, 200);
auto lineA = new QFrame;
lineA->setFrameShape(QFrame::HLine);
lineA->setFrameShadow(QFrame::Sunken);
layout->addWidget(lineA);
QWidget *lineB = new QWidget;
lineB->setFixedHeight(2);
lineB->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
lineB->setStyleSheet(QString("background-color: #c0c0c0;"));
layout->addWidget(lineB);
auto lineC = new QFrame;
lineC->setFixedHeight(3);
lineC->setFrameShadow(QFrame::Sunken);
lineC->setLineWidth(1);
layout->addWidget(lineC);
QFrame* lineD = new QFrame;
lineD->setFrameShape(QFrame::HLine);
layout->addWidget(lineD);
widget.show();
return app.exec();
}
I guess you mean a horizontal / vertical line widget: it's just a simple QWidget with a gray background color and the horizontal is a fix height (1-3 pixel) and expanding width widget, the vertical is a fix width expanding height widget.
Horizontal example code:
QWidget *horizontalLineWidget = new QWidget;
horizontalLineWidget->setFixedHeight(2);
horizontalLineWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
horizontalLineWidget->setStyleSheet(QString("background-color: #c0c0c0;"));
Check out QFrame::setFrameShape(). To get a line, use either QFrame::HLine or QFrame::VLine as the function's argument.
// Create a horizontal line by creating a frame and setting its shape to QFrame::HLine:
QFrame* hFrame = new QFrame;
hFrame->setFrameShape(QFrame::HLine);
// Create a vertical line by creating a frame and setting its shape to QFrame::VLine:
QFrame* vFrame = new QFrame;
vFrame->setFrameShape(QFrame::VLine);
It is a QFrame with height 3, sunken shadow and line width equal to 1.
You can see it if examine header generated by uic tool.

Reversing the layout of a QToolButton

I would like to make a QToolButton where the text is the left of its icon. I've tried to find related information, and tried things with:
button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
but this sets the text to the right side of the button. I've looked into trying stylesheets, but text-alignment is only for push buttons. Is there any way to do this?
My highest-level goal is to make an interface bar which looks like this:
with a text label and image right beside it. Currently I'm using a toolbar with checkable toolbuttons because of the style (no border unless moused-over, still has the indent with checkable, contains text and an icon...). It's entirely possible that I'm using the wrong type widgets, so if I can't change the layout of this, is there any way to emulate this style?
This is what I currently have:
.
You can use QWidget::setLayoutDirection:
toolbar->setLayoutDirection(Qt::RightToLeft);
Your best bet is probably to create this functionality yourself in a QWidget. It should have a QLabel and a QToolButton (or QPushButton) arranged in a QHBoxLayout. Then you can add this custom widget to the toolbar using QToolBar::addWidget() or QToolBar::insertWidget().
Here's an example of a widget you could use:
#include <QtGui>
class CoolButton : public QWidget
{
public:
CoolButton(QWidget *parent = 0) : QWidget(parent)
{
QLabel *label = new QLabel("Hi!", this);
QToolButton *button = new QToolButton(this);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(label);
layout->addWidget(button);
setLayout(layout);
}
};

Resources