Delete A Row From QGridLayout - c++

All, I am maintaining a QGridLayout of QLabels which show the coefficients of a polynomial. I represent my polynomial using QList<double>.
Each time I update my coefficients, I update my labels. When changing the size of the list, my method does not works well. QGridLayout::rowCount() doesn't update correctly. I am wondering if there's a way to remove rows from a QGridLayout.
Code follows, updating the QGridLayout size with more (or less) QLabels
int count = coefficients->count(); //coefficients is a QList<double> *
if(count != (m_informational->rowCount() - 1)) //m_information is a QGridLayout
{
SetFitMethod(0);
for(int i = 0; i < count; ++i)
{
QLabel * new_coeff = new QLabel(this);
new_coeff->setAlignment(Qt::AlignRight);
m_informational->addWidget(new_coeff, i+1, 0);
QLabel * param = new QLabel(this);
param->setAlignment(Qt::AlignLeft);
param->setText(QString("<b><i>x</i><sup>%2</sup></b>").arg(count-i-1));
m_informational->addWidget(param, i+1, 1);
QSpacerItem * space = new QSpacerItem(0,0,QSizePolicy::Expanding);
m_informational->addItem(space, i+1, 1);
}
m_informational->setColumnStretch(0, 3);
m_informational->setColumnStretch(1, 1);
m_informational->setColumnStretch(2, 1);
}
The SetFitMethod (it's an initial mockup)
void SetFitMethod(int method)
{
ClearInformational();
switch(method)
{
case 0: //Polynomial fit
QLabel * title = new QLabel(this);
title->setText("<b> <u> Coefficients </u> </b>");
title->setAlignment(Qt::AlignHCenter);
m_informational->addWidget(title,0,0,1,3, Qt::AlignHCenter);
}
}
The Clearing Method:
void ClearInformational()
{
while(m_informational->count())
{
QLayoutItem * cur_item = m_informational->takeAt(0);
if(cur_item->widget())
delete cur_item->widget();
delete cur_item;
}
}

The issue is that QGridLayout::rowCount() doesn't actually return the number of rows that you can see, it actually returns the number of rows that QGridLayout has internally allocated for rows of data (yes, this isn't very obvious and isn't documented).
To get around this you can either delete the QGridLayout and recreate it, or if you're convinced that your column count won't change, you can do something like this:
int rowCount = m_informational->count()/m_informational->columnCount();

I solved this by creating a QVBoxLayout (for rows) and within this I was adding QHBoxLayout (for columns). In the QHBoxLayout I was then inserting my widgets (in one row). This way I was able to nicely remove rows - overall row count was working as it should be. Additionally to this I got also an insert method, thanks to which I was able to insert new rows into specific locations (everything was correctly reordered/renumbered).
Example (only from head):
QVBoxLayout *vBox= new QVBoxLayout(this);
//creating row 1
QHBoxLayout *row1 = new QHBoxLayout();
QPushButton *btn1x1 = new QPushButton("1x1");
QPushButton *btn1x2 = new QPushButton("1x2");
row1->addWidget(btn1x1);
row1->addWidget(btn1x2);
//adding to vBox - here you can use also insertLayout() for insert to specific location
vBox->addlayout(row1);
//creating row 2
QHBoxLayout *row2 = new QHBoxLayout();
QPushButton *btn2x1 = new QPushButton("2x1");
QPushButton *btn2x2 = new QPushButton("2x2");
row2->addWidget(btn2x1);
row2->addWidget(btn2x2);
//adding to vBox - here you can use also insertLayout() for insert to specific location
vBox->addlayout(row2);

Well, my solution was to also delete the QGridLayout in ClearInformational

Related

QTableWidget real screen size

I work with A QTableWidget in my app. To calculate the max. Columns to show I need to get the real width of the QTableWidget. I tried different ways:
this (QTableWidget)
this->geometry()->width() = Will always report 640.
this->horizontalHeader()->length() = Will always report 1660 here in case of the amount of columns.
But the QTableWidget has a size of exact 1000 pixel. This confuse me.
My first Idea wa, ok you ask the app at the wrong position about the size.
SO I also asked after the MDIChild was build.
QVBoxLayout * dlgSplitter = new QVBoxLayout(this);
QHBoxLayout * topNav = new QHBoxLayout(this);
QWidget * wdgSplitter = new QWidget(this);
QLabel *labelTopNav = new QLabel(this);
labelTopNav->setText(tr("This is a header"));
topNav->addWidget(labelTopNav);
topNav->setContentsMargins(1,8,1,0);
dlgSplitter->setContentsMargins(0,0,0,0);
dlgSplitter->setSpacing(0);
dlgSplitter->setMargin(0);
dlgSplitter->addLayout(topNav);
scanBoard = new QScanBoard(200, 83); //This ist he "this->" control from above
//scrollArea->setWidget(scanBoard);
dlgSplitter->addWidget(scanBoard);
wdgSplitter->setLayout(dlgSplitter);
this->setCentralWidget(wdgSplitter);
int nWidth = scanBoard->geometry().width();
qDebug("Breite: %d ",nWidth);
But this also throws the same data as the class itself do.
Do anybody know a way to read the size of the QTableWidget without its contents, just its frame?

QTableView bigger than its container

I am working on Qt applicaction. There I have QMainWindow. Inside it I have added QTableView. When I run the application I see that I need to scroll to display the whole table and also blank space shows up below it.
I would like main window to resize horizontally in order to use space needed by the table. Also I would like it to resize vertically to not having space unused. How could I achieve that?
This is my code so far:
void MainWindow::initUi() {
setWindowTitle(tr("Main Window"));
QWidget* centralWidget = new QWidget(this);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
QFormLayout *upperLayout = new QFormLayout;
// Default layout appearance of QMacStyle
upperLayout->setRowWrapPolicy(QFormLayout::DontWrapRows);
upperLayout->setFieldGrowthPolicy(QFormLayout::FieldsStayAtSizeHint);
upperLayout->setFormAlignment(Qt::AlignHCenter | Qt::AlignTop);
upperLayout->setLabelAlignment(Qt::AlignLeft);
QVBoxLayout *resultsLayout = new QVBoxLayout;
QTableView* table = new QTableView(centralWidget);
table->verticalHeader()->hide();
QStandardItemModel* model= new QStandardItemModel(4, 4);
for (int row = 0; row < 4; ++row) {
for (int column = 0; column < 4; ++column) {
QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column));
model->setItem(row, column, item);
}
}
table->setModel(model);
QLabel* upperLabel = new QLabel(tr("Label:"), centralWidget);
upperLabel->setAlignment(Qt::AlignLeft);
resultLabel = new QLabel(tr("Result goes here"), centralWidget);
mainLayout->addLayout(resultsLayout);
resultsLayout->addLayout(upperLayout);
resultsLayout->addWidget(table);
upperLayout->addRow(upperLabel, resultLabel);
centralWidget->setLayout(mainLayout);
setCentralWidget(centralWidget);
this->adjustSize();
}
Set the sizeAdjustPolicy of the table to AdjustToContents view, then set the size policy to Fixed in both horizontal and vertical directions.
AdjustToContents might incur a slight performance penalty for dynamic contents in the view, since every data change may change the layout.
The Qt Designer is a really nifty tool to figure layout issues out quickly; the {table,list,tree} widgets behave exactly the same as the views do (because they're the same) and the widgets can be quickly filled with dummy data in Qt Designer.

Qt C++ - QListWidget layout doesn't scale to fit the content

I have a QWidget rzadKontener that represents a row in a QListWidget.
QWidget* rzadKontener = new QWidget;
QHBoxLayout* rzadKontenerLayout = new QHBoxLayout();
rzadKontenerLayout->setAlignment(Qt::AlignLeft);
rzadKontenerLayout->setAlignment(Qt::AlignTop);
rzadKontener->setObjectName("rzadKontener_" + poziom);
rzadKontener->setFixedHeight(200);
rzadKontener->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
rzadKontener->setLayout(rzadKontenerLayout);
(....)
QListWidgetItem* newItemRzad = new QListWidgetItem;
newItemRzad->setSizeHint(QSize(listSize*225, 200));
QString poziomText = poziom;
newItemRzad->setText(poziomText);
newItemRzad->setTextColor(QColor(Qt::white));
ui->listWidgetZdjeciaModelu->addItem(newItemRzad);
ui->listWidgetZdjeciaModelu->setItemWidget(newItemRzad, rzadKontener);
It contains a number of items, that are QWidgets with pictures, buttons and text. It is then placed in a QListWidget as a row full of these items. When I add 5 items at once, while creating a new rzadKontener, scroll bars in the QListWidget will appear. But if I add 3 and then 2 items later on, they'll go out of bounds without a scrollbar. How can I force the layout to scale to the new rzadKontener's size?
I found an answer. Instead of modifying the QWidget inside the list, I should be modifying the QListWidgetItem it's inside of (the parent...).
QWidget* newPicture = new QWidget;
yadda yadda yadda (....)
int currentRowWidth = ui->listWidgetZdjeciaModelu->findChild<QWidget*>(objectName)->width(); //gets max width of rzadKontener, which fills the entirety of the row - it equals the QListWidgetItem's width
int newWidth = currentRowWidth + 225; //225 is a fixed width of newPicture
ui->listWidgetZdjeciaModelu->item(0)->setSizeHint(QSize(newWidth, 200));
ui->listWidgetZdjeciaModelu->findChild<QWidget*>(objectName)->layout()->addWidget(newPicture );
We can do ui->listWidgetZdjeciaModelu->item(0)->setSizeHint(QSize(newWidth, 200)); instead of a specific row (->item(row)), because the list is a rectangle. Doesn't matter which row we enlarge, the entire thing will stretch anyway.
But, if you want to get the row number, you can do it this way:
int row=0;
//we make a list. Each of my QListWidgetItem has a unique string poziom in it, so I can filter by that.
QList<QListWidgetItem *> items = ui->listWidgetZdjeciaModelu->findItems(poziom, Qt::MatchContains);
if (items.size() > 0) {
//we use the first (and only, in my case) item on this list to get row number
row = ui->listWidgetZdjeciaModelu->row(items[0]);
}
Weird thing is, I already tried this. Must've kept making a typo.

Spacing between widgets in QHBoxLayout

I'm trying to create a GUI with QtCreator. For this GUI, I need to display several images with different sizes next to each other. These images should be touching each other.
I use a QWidget with a QHBoxLayout, where I add the labels (with different sizes) containing the images.
According to related questions, I should use setSpacing and setContentsMargin to remove these spaces, but that won't work; I tried several times.
Here's the code:
QWidget *widget = new QWidget(ui->tagcloud);
QHBoxLayout * l = new QHBoxLayout(widget);
ui->tagcloud->setWidget(widget);
for(int i=0;i<list.size();++i)
{
QLabel *lab = new QLabel;
QPixmap pic((list[i].imgPath).c_str()); //This fetches the image
int sizeChange = 50 + (2*list[i].percent); //Calculates the size of the image
lab->setFixedSize(QSize(sizeChange, sizeChange));
lab->setPixmap(pic);
lab->setScaledContents(true);
l->addWidget(lab);
l->setSpacing(0);
}
However, when I run this, the spacing remains the same (i.e. definitely not zero).
If I add more labels to the layout, the spacing seems to get smaller.
Can anyone explain or help me? Thanks!
Setting spacing to 0 and adding stretch before and after works for me :
l->addStretch();
for(int i = 0; i < list.size(); ++i)
{
QLabel *lab = new QLabel;
QPixmap pic((list[i].imgPath).c_str()); //This fetches the image
int sizeChange = 50 + (2*list[i].percent); //Calculates the size of the image
lab->setFixedSize(QSize(sizeChange, sizeChange));
lab->setPixmap(pic);
lab->setScaledContents(true);
l->addWidget(lab);
}
l->addStretch();
l->setSpacing(0);
Also this works I think
l->setSizeConstraint(QLayout::SetMaximumSize);

Add widgets to QFileDialog

I need to add a widget (QTableWidget) into QFileDialog's layout. I know that it is QGridLayout with sizes (3,4). The table must be in 3-rd row and span all columns.
QTableWidget* tableWidget = new QTableWidget(this);
QGridLayout *layout = static_cast<QGridLayout*>(QFileDialog::layout());
layout->addWidget(tableWidget, 2, 0, 1, 4);
With this code the original 3-rd row which contains lineEdit and save/open pushButton disappears. How can I add widgets between already existing widgets of QGridLayout so that original widgets remain in the layout.
I strongly recommend you not to rely on QFileDialog's implementation. The layout can be different on different platforms or different versions of Qt. It may be more correct to place your table under the dialog or to the right of it. This can be done easily without altering the layout of the QFileDialog itself. Just create a QVBoxLayout and put QFileDialog and QTableWidget inside it.
However, the question has been asked, and the solution exists. QGridLayout has no functionality such as QBoxLayout::insertItem. So we need to implement this behavior manually. The plan is:
Obtain the list of layout items placed in 3rd and 4th rows.
Calculate new positions of items.
Take elements out of item and add them back at new positions.
Working code:
QFileDialog* f = new QFileDialog();
f->setOption(QFileDialog::DontUseNativeDialog, true); //we need qt layout
QGridLayout *layout = static_cast<QGridLayout*>(f->layout());
QList< QPair<QLayoutItem*, QList<int> > > moved_items;
f->show();
for(int i = 0; i < layout->count(); i++) {
int row, column, rowSpan, columnSpan;
layout->getItemPosition(i, &row, &column, &rowSpan, &columnSpan);
if (row >= 2) {
QList<int> list;
list << (row + 1) << column << rowSpan << columnSpan;
moved_items << qMakePair(layout->takeAt(i), list);
i--; // takeAt has shifted the rest items
}
}
for(int i = 0; i < moved_items.count(); i++) {
layout->addItem(moved_items[i].first,
moved_items[i].second[0],
moved_items[i].second[1],
moved_items[i].second[2],
moved_items[i].second[3]);
}
QTableWidget* tableWidget = new QTableWidget();
layout->addWidget(tableWidget, 2, 0, 1, 4);