Qt QHBoxLayout issue? - c++

I use an extended QGroupBox as the widget for QDockWidget in my QMainWindow.
Here is the code snippet:
RzPlaneViewerControlPanelWidget::RzPlaneViewerControlPanelWidget(QWidget *parent) : QGroupBox(parent) {
// TODO Auto-generated constructor stub
init();
}
void RzPlaneViewerControlPanelWidget::init()
{
QHBoxLayout *hbox=new QHBoxLayout;
hbox->setSizeConstraint(hbox->SetMinimumSize);
hbox->setSpacing(0);
hbox->setStretch(1,0);
setMaximumHeight(50);
QScrollBar *scrollbar=new QScrollBar;
scrollbar->setOrientation(Qt::Horizontal);
scrollbar->setMouseTracking(true);
scrollbar->setFocusPolicy(Qt::StrongFocus);
scrollbar->setMinimum(0);
scrollbar->setSingleStep(1);
QLineEdit *qlineedit = new QLineEdit;
qlineedit->setMaximumWidth(60);
qlineedit->setReadOnly(true);
hbox->addWidget(scrollbar);
hbox->addWidget(qlineedit);
//hbox->addWidget(new )
setLayout(hbox);
}
Here is how I add this widget to QDockWidget :
RzPlaneViewerControlPanelWidget *controlPanel=new RzPlaneViewerControlPanelWidget ;
controlPanel->init();
QDockWidget controlPanelDockWidet=new QDockWidget;
controlPanelDockWidet->setAllowedAreas(Qt::BottomDockWidgetArea);
controlPanelDockWidet->setFeatures(QDockWidget::DockWidgetVerticalTitleBar);
controlPanelDockWidet->setWidget(controlPanel);
But the ScrollBar is not stretched as I expected -
Here's how it looks like -
This is what I want -

From a quick read, I'd try doing:
hbox->addWidget(scrollbar, 1);
The second (optional) argument to addWidget is the stretch factor. From the Qt docs:
If the stretch factor is 0 and nothing else in the QBoxLayout has a stretch factor greater than zero, the space is distributed according to the QWidget:sizePolicy() of each widget that's involved.
Also, note that your:
hbox->setStretch(1,0);
call does not have any effect, as it is setting the qlineedit's stretch factor to 0, but that's already the default.

Related

How can I stretch a QLayout or QFrame, nested within a bigger layout?

I currently have this code set up to create a sidebar and I'm not entirely sure how to stretch it so that the left, top, and bottom sides touch the edge of the window.
QFrame *sidebar = new QFrame;
QLabel *sideItemA = new QLabel("Item A");
QLabel *sideItemB = new QLabel("Item B");
QVBoxLayout *sidebarLayout = new QVBoxLayout;
sidebarLayout->addWidget(sideItemA);
sidebarLayout->addWidget(sideItemB);
sidebarLayout->addStretch();
sidebar->setLayout(sidebarLayout);
sidebar->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
sidebar->setStyleSheet("background-color:#FFFFFF");
sidebar->setMinimumWidth(150);
mainLayout->addWidget(sidebar);
Here is a screenshot of what the above code looks like:
I've tried doing this using nested layouts too and I get the same result. Any pointers? Is this even the best way to do it?

Align to the right text from QLabel and QLineEdit

I have a QLabel just below a QLineEdit with the same size and alignment properties:
QLineEdit *lineEdit = new QLineEdit("999");
lineEdit->setFixedWidth(100);
lineEdit->setAlignment(Qt::AlignRight);
//
QLabel *label = new QLabel("999");
label->setFixedWidth(100);
label->setAlignment(Qt::AlignRight);
//
QLayout *layout = new QVBoxLayout;
layout->addWidget(lineEdit);
layout->addWidget(label);
Here is how this is rendered:
How can I have the text of the bottom label exactly right-aligned to the text of the lineEdit?
Full award if you find a solution that works on all platforms, and that also works when the font sizes are different in the lineEdit and label.
Unfortunately it may not be possible, at least not out of the box, the right margin will not work, as it is always 0 even when the text is obviously offset to the left. The reason for this is this offset is not determined by the margins, but depends on the combination of platform GUI style and particular font's metrics that's being used, and its value is "conveniently" not available in the class public interface, there is no way to get to it.
You can get the font metrics easily, but you can't get the QStyleOptionFrame as the method required is protected, accessing it will require to subclass QLineEdit. However, if you are lucky, that value is very likely to be zero, so you could go with something as simple as this:
QVBoxLayout *layout = new QVBoxLayout;
QLineEdit *lineEdit = new QLineEdit("999");
lineEdit->setAlignment(Qt::AlignRight);
QLabel *label = new QLabel("999");
label->setAlignment(Qt::AlignRight);
int offsetValue = lineEdit->fontMetrics().averageCharWidth();
label->setIndent(offsetValue);
setLayout(layout);
layout->addWidget(lineEdit);
layout->addWidget(label);
If that doesn't work correctly for you, you will have no other choice but to subclass QLineEdit, carefully examine its paint event, determine where the offset is being calculated, and store that value in a public member so it can be accessed from the outside to be used to offset the label.
I personally got lucky with that code:
Would you be able to instead of using a QLineEdit and a QLabel to use two QLineEdits?
Consider the following:
QWidget* widget = new QWidget();
// Original line edit
QLineEdit *lineEdit1 = new QLineEdit("999");
lineEdit1->setFixedWidth(100);
lineEdit1->setAlignment(Qt::AlignRight);
lineEdit1->setStyleSheet("border-width: 2px;");
// A suggestion if you want a label
QLabel *label = new QLabel("999");
label->setFixedWidth(100);
label->setAlignment(Qt::AlignRight);
label->setStyleSheet("border: 2px solid rgba(255, 0, 0, 0%)");
// Alternatively if you can use another QLineEdit
QLineEdit *lineEdit2 = new QLineEdit("999");
lineEdit2->setFixedWidth(100);
lineEdit2->setAlignment(Qt::AlignRight);
lineEdit2->setReadOnly(true);
lineEdit2->setStyleSheet("background: rgba(0, 0, 0, 0%); "
"border-width: 2px; "
"border-style: solid; "
"border-color: rgba(0, 0, 0, 0%);");
// Bring it all together
QLayout *layout = new QVBoxLayout(widget);
layout->addWidget(lineEdit1);
layout->addWidget(label);
layout->addWidget(lineEdit2);
widget->show();
It forces all borders to be 2px, so on different platforms it should be the same. The second QLineEdit should not look different than the QLabel (The text color looks slightly darker than that of the label though, which might be a good thing since it matches the original edit)
The added benefit of using a QLineEdit instead of the QLabel is that the value is now selectable...
Disclaimer: I have only tested on Linux and I have not done a pixel level comparison.
Edit: I see the alignment fails with different font sizes.
simply, you can use the indent property of the QLabel.
https://doc.qt.io/qt-5/qlabel.html#indent-prop
The indent property can take +/- values. maybe the margin feature can do its job.

How to put QGraphicsEffect on QScrollBar inside QScrollArea?

I try to set QGraphicsDropShadowEffect on a QScrollBar. This code works:
QGraphicsDropShadowEffect * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setOffset(0);
ui->verticalScrollBar->setGraphicsEffect(dse); // verticalScrollBar is `QScrollBar`.
However the following does not:
QGraphicsDropShadowEffect * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setOffset(0);
ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
ui->scrollArea->verticalScrollBar()->setGraphicsEffect(dse);
In the second example code I try to set effect on a slider inside QScrollArea but it does not apply to it. However, it can be applied to the whole scrollArea by ui->scrollArea->setGraphicsEffect(dse). What am I doing wrong?
The problem I had was caused by parent widget of QScrollBar. So, QScrollArea has item area and scroll bar area. Scroll bar area contains QWidgets and QScrollBars actually placed on these QWidgets. So, to make this work I actually had to set effect for the parent widget:
for(auto *child : ui->scrollArea->findChildren<QScrollBar*>()) {
if (child->orientation() == Qt::Vertical) {
auto * dse = new QGraphicsDropShadowEffect();
dse->setBlurRadius(10);
dse->setColor(Qt::red);
dse->setXOffset(-3);
dse->setYOffset(0);
child->parentWidget()->setGraphicsEffect(dse);
qDebug() << child->metaObject()->className(); // QScrollBar
qDebug() << child->parentWidget()->metaObject()->className(); // QWidget
}
}

Qt setGeometry to negative value doesn't work

Im working with QT and I have a form with a QLabel in a QFrame. I want to set the QLabel's geometry so the bottom part of the QLabel is in the same place of the bottom of the frame. Since the label is longer than the frame, it's y coordinate should be negative.
int pos = ui->imageFrame->height() - ui->imageLabel->pixmap()->height();
ui->imageLabel->setGeometry(0, pos, ui->imageFrame->width(), p.height());
Although when printing the QLabel's geometry, the y coordinate is correct, the label is showing on the upper part of the frame.
Help is much appreciated.
You can set the label's alignment with setAlignment. Here's a working example:
#include <QtWidgets>
#include "MyWidget.h"
MyWidget::MyWidget()
{
setFixedSize(200,200);
QLabel *label = new QLabel;
label->setPixmap(QPixmap("/some/image/file.jpg"));
label->setAlignment(Qt::AlignBottom);
QHBoxLayout *hbox = new QHBoxLayout;
hbox->addWidget(label);
hbox->setContentsMargins(0,0,0,0);
setLayout(hbox);
}

QLineEdit visible width Setting?

How may I set the visible width of QLineEdit with Qt 4.8.1 and up. Example would be to set the visible width to some pixel size or character width. I wish to only use C++ not QML.
My thought is in the direction of this block:
QHBoxLayout *nameRow = new QHBoxLayout;
QLineEdit *firstNameText = new QLineEdit,
*middleIntText = new QLineEdit,
*lastNameText = new QLineEdit;
//Whatever method is needed here to edit visible width
//firstNameText->???
//middleIntText->???
//lastNameText->???
nameRow->addWidget(firstNameText);
nameRow->addWidget(middleIntText);
nameRow->addWidget(lastNameText);
layout->addLayout(nameRow);
QWidget window;
window.setLayout(layout);
window.show();
Answer Update: (or see below)
firstNameText->setMaximumWidth(100);
firstNameText->setFixedWidth(120);
middleIntText->setMaximumWidth(50);
middleIntText->setFixedWidth(60);
lastNameText->setMaximumWidth(100);
lastNameText->setFixedWidth(120);
firstNameText->setMaximumWidth(100);
firstNameText->setFixedWidth(120);
You can use thse two functions and they will adjust the width accordingly.