I'm trying to create a custom widget in QT that looks something like this:
The red squares will be displaying an image/icon.
How can I achieve this layout through coding the widget? I will need to create many of those widgets with the same layout but different values in their labels. Ideally, I will display those widgets as a list with a scrollbar in my mainwindow. But right now I'm struggling to just create the layout for those widgets through code. Any help is much appreciated.
You need to split you design on to separate segments. Each segment can be either a separate sub layout or a widget. In you example, I see the following segments:
Large red icon,
Two labels: TextLabel and 06-November-2014...
Two labels make a vertical box layout,
Vertical box layout and large red icon make a horizontal box layout,
Small red rectangle makes a separate layout,
All layouts make a main layout.
Now lets code this composition:
QLabel *largeRed = new QLabel(this); // Should set an image for this label
QLabel *lbl1 = new QLabel("06-November-2014...", this);
QLabel *lbl2 = new QLabel("TextLabel", this);
QVBoxLayout *vLayout = new QVBoxLayout;
vLayout->addWidget(lbl1);
vLayout->addWidget(lbl2);
vLayout->addStretch();
QHBoxLayout *hLayout = new QHBoxLayout;
hLayout->addWidget(largeRed);
hLayout->addLayout(vLayout);
QLabel *smallRed = new QLabel(this); // Should set an image for this label
QHBoxLayout *hLayout2 = new QHBoxLayout;
hLayout2->addWidget(smallRed, 0, Qt::AlignRight);
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout->addLayout(hLayout);
mainLayout->addLayout(hLayout2);
[..]
Use this.
QPixmap big(75,65);
big.fill(Qt::red);
QPixmap small(25,15);
QVBoxLayout *box = new QVBoxLayout;
QWidget *window = new QWidget;
QLabel *bigLab = new QLabel;
QLabel *smallLab = new QLabel;
QLabel *textLab = new QLabel("Two");
bigLab->setPixmap(big);
smallLab->setPixmap(small);
QHBoxLayout *hLay = new QHBoxLayout;
hLay->addWidget(bigLab);
hLay->addWidget(textLab);
QHBoxLayout *vLay = new QHBoxLayout;
vLay->addWidget(smallLab,0,Qt::AlignRight);
box->addLayout(hLay);
box->addLayout(vLay);
window->setLayout(box);
window->show();
Result:
What I normally do is:
Design the layout with Qt Designer/Creator using rich features of layouting.
Set its instances (from code) as the item widget of a list or table widget.
Be careful, If the item count of the list is too large, it will perform very slowly.
P.S. If you really need the layout coded, just use the code generated by Qt designer.
Related
I am adding several push buttons in QVBoxLayout and adding this layout in QDockWidget, now I want to add some scroll bar in the same Layout(DockWidget) to change(Increase/Decrease) data shown in separate EditBox.
The problem is the Scroll bar is added above the buttons,I want all the buttons at right side and the scroll bar in the left side.
The reason why I am using QDockWidget is I am also adding animation effect using QPropertyAnimation class.
Below is the sample code
QDockWidget dock(QLatin1String("Last filters"));
QWidget* multiWidget = new QWidget();
QVBoxLayout* layout = new QVBoxLayout();
QPushButton* filter1 = new QPushButton(QLatin1String("Filter number 1"));
QPushButton* filter2 = new QPushButton(QLatin1String("Filter number 2"));
QPushButton* filter3 = new QPushButton(QLatin1String("Filter number 3"));
QPushButton* filter4 = new QPushButton(QLatin1String("Filter number 4"));
QPushButton* filter5 = new QPushButton(QLatin1String("Filter number 5"));
QLabel* label = new QLabel(QLatin1String("QPushButtons"));
layout->addWidget(filter1);
layout->addWidget(filter2);
layout->addWidget(filter3);
layout->addWidget(filter4);
layout->addWidget(filter5);
layout->addWidget(label);
multiWidget->setLayout(layout);
dock.setWidget(multiWidget);
** For animation
QPropertyAnimation *animation = new QPropertyAnimation(dockMenu, "geometry");
animation->setDuration(250);
QRect startRect(-100,20,100,80);
QRect endRect(20,20,100,80);
dockMenu->show();
animation->setStartValue(startRect);
animation->setEndValue(endRect);
animation->start();
For this application this answer at Multiple widgets on a QDockWidget
helped me but now to add the scrollbar I am not able to relocate/move the widgets
Your code sample does not reflect the attached screenshot so I'm not 100% sure if this is what you're looking, but...
If you swap the QVBoxLayout for a QGridLayout, you can place the scrollbar in the first column and set it to expand over the max number of rows. The buttons can be placed in the second column.
QGridLayout documentation: https://doc.qt.io/archives/qt-4.8/qgridlayout.html#details
And some basic layout examples from Qt which may give you some ideas: https://doc.qt.io/qt-5/qtwidgets-layouts-basiclayouts-example.html
I have a problem displaying two labels, the label "label" is displayed with no problem ( it has some buttons adjusted Horizontally ) and the second label "label1" is not being displayed ( it contains a scene which has a view , in the scene i have a title and a picture ). This is the code i am trying to use.
widget1 = new QWidget;
setCentralWidget(widget1);
label1 = new QLabel(widget1);
scene = new QGraphicsScene(label1);
vue = new QGraphicsView(scene);
label1->move(100,100);
label = new QLabel(widget1);
layout = new QHBoxLayout(label);
label->resize(500,100);
It's my first time using QGraphicsScene/View and it is confusing me a little bit.
Thanks for the answers
You're definitly not using all those widgets the right way.
you don't need a label to display a QGraphcisView, neither the QGraphicsScene to be the child of the label.
If you want to display, let's say, a label and a view in the center widget you could write this :
//==== Central widget part
QWidget* widget = new QWidget(this);
setCentralWidget(widget);
//==== Graphics part
QGraphicsScene* scene = new QGraphcisScene(this);
QGraphicsView* view = new QGraphicsView(widget);
view->setScene(scene);
//==== Label part
QLabel* label = new QLabel(widget);
//==== Layout part
QHBoxLayout* layout = new QHBoxLayout(widget);
layout.addWidget(label);
layout.addWidget(view);
widget.setLatout(layout);
This should show a label and a graphics view in row.
If you allow me a piece of advice : you should understand the parenting system before trying to use the QGraphics module. It's one of the cornerstones of Qt and that what you did wrong here. Starts here for the parenting system : https://doc.qt.io/qt-5/objecttrees.html
and here for the graphics : https://doc.qt.io/qt-5/graphicsview.html
Hope that helps you.
I am trying to create a gui that has a QTabWidget with multiple tabs. As a preliminary test I have created one that has two tabs using the same layouts. The first tab (Page 1) is blank but then the second one shows the QTableView I created. Both tabs were created the exact same way, yet they perform differently. Anyone know why the first one is blank...?
I noticed that if I comment out the line int8Window->setLayout(_layout);. Page 1 shows up with the proper layout and the second tab is blank this time...
Here is the code for the gui:
// Main window and layout
QWidget* mainWindow = new QWidget;
QVBoxLayout *mainLayout = new QVBoxLayout;
// Tab widget
QTabWidget* tabWidget = new QTabWidget;
// The pages in the tab widget
QWidget* uInt8Window = new QWidget;
uInt8Window->setWindowTitle(QString("Page 1"));
QWidget* int8Window = new QWidget;
int8Window->setWindowTitle(QString("Page 2"));
QTableView* tableView = new QTableView;
QStandardItemModel* model = new QStandardItemModel(5, 5);
for (int row = 0; row < 5; ++row) {
model->setItem(row, 0, new QStandardItem("3"));
model->setItem(row, 1, new QStandardItem(5));
model->setItem(row, 2, new QStandardItem(2));
model->setItem(row, 3, new QStandardItem(1));
model->setItem(row, 4, new QStandardItem(5));
}
tableView->setModel(model);
// Setting the tab page layouts
_layout = new QVBoxLayout;
_layout->addWidget(tableView);
uInt8Window->setLayout(_layout);
int8Window->setLayout(_layout);
// Add the pages to the tab widget
tabWidget->addTab(uInt8Window, "Page 1");
tabWidget->addTab(int8Window, "Page 2");
// Add the tab widget to the main layout and show
mainLayout->addWidget(tabWidget);
mainWindow->setLayout(mainLayout);
mainWindow->show();
Read logs! I'm sure you have a respective warning.
You are assigning same layout to two different widgets. Once layout is assigned to a widget, it is owned by this widget forever.
You need create separate layout for each widget.
I recommend to split this onto couple methods. One is creating a widget for a page (you can use this couple times). Other creating a data model, and other composing tab widget.
Please remember also about memory management! Best approach is to set parent during construction (as parameter of constructor). You have a leak in data model.
I would like to add two widgets (say QPushButton) to the status bar, one to the left and other to the right side.
I am thinking of adding horizontal spacer in between the two widgets, but don't know how to add.
PS: I tried using addWidget() to add to the left and addPermanentWidget() to add to the right but it doesn't look neat and also it doesn't feel right.
You can add two buttons to a layout in a widget and add the widget to the status bar using QStatusBar::addWidget :
QWidget * widget = new QWidget();
QPushButton * leftBut = new QPushButton("Left");
QPushButton * rightBut = new QPushButton("Right");
QGridLayout * layout = new QGridLayout(widget);
layout->addWidget(leftBut,0,0,1,1,Qt::AlignVCenter | Qt::AlignLeft);
layout->addWidget(rightBut,0,1,1,1,Qt::AlignVCenter | Qt::AlignRight);
ui->statusBar->addWidget(widget,1);
I am thinking of adding horizontal spacer in between the two widgets, but don't know how to add.
Here is a way to use a "fake" spacer.
QPushButton *leftButton = new QPushButton("Left");
QPushButton *rightButton = new QPushButton("Right");
QLabel *spacer = new QLabel(); // fake spacer
ui->statusBar->addPermanentWidget(leftButton);
ui->statusBar->addPermanentWidget(spacer, 1);
ui->statusBar->addPermanentWidget(rightButton);
The second parameter in addPermanentWidget is "used to compute a suitable size for the given widget as the status bar grows and shrinks".
Demo:
I think the simplest way is using a QGridLayout (honestly I never tried to modify a status bar anyway) supposing that the status bar is or descends from widget you can do this:
QGridLayout *myGridLayout = new QGridLayout();
statusbar->setLayout(myGridLayout)
QPushButton *button1 = new QPushButton(this);
myGridLayout->addWidget(button1,0,0,1,1);
QPushButton *button2 = new QPushButton(this);
myGridLayout->addWidget(button2,X,0,1,1);
The biggest is X the more space you want to leave in between, I would suggest to start with 3 and then make few tests to see how it looks.
I'm just a beginner and I wonder if it would be possible to create a form widget on Mac like the info dialog in iTunes.
I tried using:
QGroupBox: I cannot find a way to get rid of the frames.
Creating my own widget: I cannot find a way to fix the spacing between the label and the QLineEdit widget using the QVBoxLayout (actually I'm not sure I understand well the differences between margin/spacing).
QFormLayout: I cannot find a way to reduce the size of the QLabel after using setrowWrapPolicy::WrapAllRows
Also I am not (yet) very comfortable with QtDesigner, so i'd like to avoir using it (for now)
Thanks in advance
Edit: Some precisions on the programs. I use QtCreator 2.6.1 with Qt 4.8.1 and 5.0 on Mac OS X Mountain Lion.
Edit 2: Here is the code.
Subclass of QWidget:
MCLineEdit::MCLineEdit(const QString &header)
{
m_lineEdit = new QLineEdit;
m_lineTitle = new QLabel(header);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(m_lineTitle);
layout->addWidget(m_lineEdit);
layout->setSpacing(0);
setLayout(layout);
}
To display the widget
myView::myView(QWidget *parent) :
QWidget(parent)
{
setFixedSize(600, 500);
MCLineEdit *lineEdit1 = new MCLineEdit("Test 1");
MCLineEdit *lineEdit2 = new MCLineEdit("Test 2");
MCLineEdit *lineEdit3 = new MCLineEdit("Test 3");
MCLineEdit *lineEdit4 = new MCLineEdit("Test 4");
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(lineEdit1);
mainLayout->addWidget(lineEdit2);
mainLayout->addWidget(lineEdit3);
mainLayout->addWidget(lineEdit4);
mainLayout->setSpacing(0);
setLayout(mainLayout);
}
This can be accomplished a ton of ways I am sure. Qt gives you all the possible layouts you could need to achieve this. You could do it with a QGridLayout, and add widgets with different amounts of "cell" spanning, and control the row and column sizes to suit. Or you can just do it with a bunch of nested vertical/horizontal layouts.
For example, you can group a label and a field together in a QVBoxLayout, by adding the widgets with a left alignment, and then setting the spacing to 0 between the items:
layout->setSpacing(0);
layout->addWidget(aLabel, Qt::AlignLeft);
layout->addWidget(aLineEdit, Qt::AlignLeft);
mainVerticalLayout->addLayout(layout);
For something like the track numbers, it is just more nested layouts:
vLayout->addWidget(aLabel);
hLayout->addWidget(aCheckbox);
hLayout->addWidget(aLabel);
hLayout->addWidget(aCheckbox);
vLayout.addLayout(hLayout);
And regarding your bullet points:
QGroupBox lets you remove the frame with setFlat(bool)
With layouts, the margin is the padding around the outside of the contained widgets. What you want is setSpacing(int) to control the amount of space between the items in the layout.
QFormLayout is probably not your best choice here. That is usually for having labels on one side and widgets on the other. Basically it is a 2 column layout. A QGridLayout would be more appropriate. And to reduce the size of the QLabel, you can give it a max or a fix size. Such as using setFixedWidth() or setMaximumWidth() on the label.
So I finally managed to get the expected result after playing a bit with QtCreator.
Here is the code for who might be interested:
myLineEdit:myLineEdit(const QString &header)
{
m_lineEdit = new QLineEdit;
m_groupBox = new QGroupBox;
QFont groupFont;
groupFont.setPixelSize(10);
groupFont.setBold(true);
m_groupBox->setTitle(header);
m_groupBox->setFlat(true);
m_groupBox->setFont(groupFont);
m_groupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
QFont lineFont;
lineFont.setPixelSize(13);
lineFont.setBold(false);
m_lineEdit->setFont(lineFont);
QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(m_lineEdit);
layout->setContentsMargins(0, 10, 0, 0);
layout->setSpacing(10);
layout->setSizeConstraint(QLayout::SetMinAndMaxSize);
m_groupBox->setLayout(layout);
QHBoxLayout *mainLayout = new QHBoxLayout;
mainLayout->addWidget(m_groupBox);
setLayout(mainLayout);
}
One comment though: will only work on Qt 5 since on 4.8 the setFlat() method will display a separating line between the header and the QLineEdit.
Thanks to jdi for his help!