How can I remove an layout_newInfo from layout_main in runtime (pressing button)?
code I tried:
QLayout *layout = this->layout();
QLayoutItem *item;
while ((item = layout->takeAt(0)) != 0)
layout->removeItem (item);
delete layout_newInfo;
layout_main->update();
What exactly do you want to achieve?
If you want to show/hide the widgets that are now in layout_newInfo, then
don't use a layout. Use a widget that you put in a layout_main (vertical layout), which itself has the newInfo items and layout, then just use setVisible(true/false) on the widget as you need.
How can I remove layout_newInfo from layout_main in runtime given layout_newInfo is nested to layout_main?
The semantically clearer method:
layout_main->removeItem(layout_newInfo); // make sure layout_newInfo object deleted
// after either by parent or somehow else
BTW, usually this should also do the same removing of nested layout:
delete layout_newInfo; // also removes it from upper layout
layout_main->update(); // triggers update on the screen
So, just 2 bottom lines of your code example should be sufficient where layout_main->update() call is needed only sometimes if no other update triggered.
The example from here shows that deleting QLayoutItem which is parent for QLayout does remove it from upper layout structure as well (its destructor does it).
Finally find an answer best way is making void method like void showNewInfo(QString action);
In class cpp file
void MainWind::showNewInfo(QString action)
{
if(action == "true")
{
bt_search->setEnabled(false);
bt_production->setEnabled(false);
bt_drying->setEnabled(false);
bt_storage->setEnabled(false);
ln_spent->show();
cb_thickness1->show();
cb_thickness2->show();
cb_thickness3->show();
cb_EFL1->show();
cb_EFL2->show();
bt_newItem->show();
}
else if(action == "false")
{
bt_search->setEnabled(true);
bt_production->setEnabled(true);
bt_drying->setEnabled(true);
bt_storage->setEnabled(true);
ln_spent->hide();
cb_thickness1->hide();
cb_thickness2->hide();
cb_thickness3->hide();
cb_EFL1->hide();
cb_EFL2->hide();
bt_newItem->hide();
}
}
Also there is possible to use setText(""), so next time showing fragment, it will be clear;
Related
So I'm having trouble with removing a QGraphicsPixMapItem. I add it to my view by setting it's parent so I expected that if I would change the parent to nullptr it would be removed but it didn't work. I read online that I could also use functions like hide but when I use these the program crashes. Whats the best way to fix this?
Btw I'm sure the code crashes when I call the hide function and the rest of my code is good.
A left click should add a 'stamlid' (QGraphicsPixMapItem) to the QGraphicsEllipsItem (this). And It should be removed with a right click.
void Vakje::mousePressEvent(QGraphicsSceneMouseEvent *event) {
Speler *speler = m_spel->getAanDeBeurt();
if (event->button() == Qt::LeftButton && m_stamlid == nullptr) {
m_stamlid = speler->getVrijeStamleden()[0]; //stamlid van speler dat niet op bord staat
m_stamlid->getStamlidView()->setParentItem(this);
m_stamlid->setOpBord(true);
m_stamlid->getStamlidView()->setVisible(true);
speler->getSpelerView()->updateMembers();
} else if (event->button() == Qt::RightButton && m_stamlid != nullptr) { //verwijder pion
m_stamlid->setOpBord(false);
m_stamlid->getStamlidView()->setParentItem(nullptr);
m_stamlid = nullptr;
speler->getSpelerView()->updateMembers();
}
}
The Qt documentation for the base class QGraphicsItem explains that setting the parent item to 0 does not remove the item, but makes it a top-level item instead.
Perhaps what you should do is get the item's scene and use it to remove the item.
if (m_stamlid->scene())
m_stamlid->scene()->removeItem(m_stamlid);
delete m_stamlid;
m_stamlid = nullptr;
I have a list of layouts with items inside. It forms a custom table.
To clean the table i loop through all the layouts and take out the items one by one. Then delete the layout.
// Delete all items
QHBoxLayout* row = NULL;
while( !rowLyts_.isEmpty() && (row = rowLyts_.takeAt(0)) != 0 )
{
QLayoutItem *item;
while ((item = row->takeAt(0)) != 0)
delete item;
delete row;
}
This seems to work. But when i start filling the table again i see "ghosts" of the items that were there before cleaning. Most of the times they are between lines, behind the new objets. And they still work.
This happens too when you use only a layout with widgets.
I just want to clean the whole layout of layouts without deleting the content widget. A safe way to clean a layout!.
You are deleting the layout items, but not the widgets that the items used to manage. You must delete the widgets. All of the non-layout items will be deleted automatically when you delete the layout itself.
QHBoxLayout* row;
while(!rowLyts_.isEmpty() && (row = rowLyts_.takeAt(0)))
{
QLayoutItem *item;
while ((item = row->takeAt(0))) {
// The item will be deleted when the layout itself is
// destructed. Items such as spacers will return a null
// widget, its deletion is a safe no-op.
delete item->widget();
// We don't handle recursion into sublayouts.
// We check for it so that we won't leak the layout.
Q_ASSERT(!item->layout());
}
delete row;
}
The assert is there to make sure the layout that the code works on matches the implied precondition: there must be no sub-layouts, since the code as written doesn't recurse into them. Any sub-layouts, with their widgets, would leak (not memory leak, but resource leak). The assert will abort the execution if the precondition is violated.
clearing the layout can be done by:
QLayoutItem* item;
while ( ( item = row->takeAt( 0 ) ) != NULL )
{
delete item->widget();
delete item;
}
I wave a QListView that is backed by a QStandardItemModel. Under certain circonstances, the QStandardItem are made checkable. A checkbox gets displayed besides the item's display. At some point, I want to remove hide the QStandardItem checkbox. I set its checkable state to false but it doesn't hide the checkbox (though it cannot be checked anymore).
The only way I have found of hiding the checkbox is to replace the item with a new one. This doesn't seem the proper way to preceed.
This is the code:
MyModel::MyModel(QObject *parent):QStandardItemModel(parent){}
void MyModel::createItem(int row, const QString &text)
{
setItem(row, new QStandardItem(text));
}
void MyModel::setCheckable(int row)
{
item(row)->setCheckState(Qt::Unchecked);
item(row)->setCheckable(true); // A checkbox appears besides the text
}
void MyModel::hideCheckBox(int row)
{
item(row)->setCheckState(Qt::Unchecked);
item(row)->setCheckable(false); // does not work
// I need to completely replace the item for the checkbox to disapear.
// This doesn't seem the proper way to proceed
setItem(row, new QStandardItem(item(row)->data(Qt::DisplayRole).toString()));
}
Is there better way to proceed?
When you call setCheckState or setCheckable, the qt will update the data of list item by adding or setting a Qt::CheckStateRole data. If the Qt::CheckStateRole data is existed, the check icon will be shown. So you need remove it from the data map of the list item.
Finally, the code of hideCheckBox should be:
void MyModel::hideCheckBox(int row)
{
// check the item pointer
QStandardItem* pitem = item(row);
if (pitem == NULL) return;
// find and delete the Qt::CheckStateRole data
QMap<int, QVariant> mdata = itemData(pitem->index());
if (mdata.remove(Qt::CheckStateRole))
{
setItemData(pitem->index(), mdata);
}
}
Hope it useful. :)
I think the presence of the check boxes in items defined by item flags, so that I would write the function in the following way:
void MyModel::hideCheckBox(int row)
{
// Does not set the Qt::ItemIsUserCheckable flag.
item(row)->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
I have a QVBoxLayout inside a scrollArea. I dynamically add QFormLayouts.
widgetTreeStruct* tree = new widgetTreeStruct(QString::number(numberOfGraphs));
QFormLayout* layout = tree->getTree(); // get QFormLayout
ui->verticalLayout_2->addLayout(layout); //add to the vertical layout
At one point I need to remove all the added QFormLayouts from the QVBoxLayout.
I tried several ways to do this.
Using qDeleteAll()
qDeleteAll(ui->verticalLayout_2->children());
2.delete item one by one
QLayoutItem* child;
while((child = ui->verticalLayout_2->takeAt(0)) != 0)
{
if(child->widget() != 0)
{
delete child->widget();
}
delete child;
}
But nothing happened. Only thing is when I try to add items to QVBoxLayout again new items are added on top of the previously added items.
I sense that I have to redraw, repaint, update, refresh or something. I tried ui->verticalLayout_2->update(); but didn't work for me.
So, What should I do?
I recursively deleted all the children and it worked for me.
This is my code.
void Widget::remove(QLayout* layout)
{
QLayoutItem* child;
while(layout->count()!=0)
{
child = layout->takeAt(0);
if(child->layout() != 0)
{
remove(child->layout());
}
else if(child->widget() != 0)
{
delete child->widget();
}
delete child;
}
}
remove(ui->verticalLayout_2);
Probably the widgets's parent is the containing widget, not their layout (what is passed to their constructors for the parent parameter?).
Maybe QObject::dumpObjectTree() can help you to understand the parent-child relationships.
What happens with your approach 2 (which does not rely on the widgets being children in the QObject-sense of the layout) is that it removes all items from the layout with the takeAt() method but deletes none of them: The children of your toplevel QVBoxLayout are the QFormLayouts, so calling widget() on their QLayoutItems returns 0. Just use delete child unconditionally to delete the child QLayouts. However, this still does not delete the child widgets. You could either recursively call takeAt() on the child layouts or delete all children of the parent widget (your QScrollArea) or keep a list of widgets and/or layouts yourself.
I have a simple class which inherits QTableView and I want the following behavior: when the user selects a few cells, I want the first cell selected to be set as the current index.
So for example if I select from (0, 0) towards (2, 2), when I start typing the text would show up in (0, 0), not (2, 2) which seems to be the default.
I have tried overriding the setSelection function with the following:
void SampleTable::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command)
{
if((command & QItemSelectionModel::Current) != 0)
{
QModelIndex curr = indexAt(rect.topLeft());
selectionModel()->select(curr, QItemSelectionModel::Current);
command ^= QItemSelectionModel::Current;
}
QTableView::setSelection(rect, command);
}
but to no avail. It seems to have something to do with the mouse events, but I can't quite locate the problem in the source code and I'm hoping there's an easier way anyway.
What are you trying to achieve? If you'd like the user to edit/select a single cell only, use setSelectionBehaviour to force this. Otherwise you could try chinfoo's idea but make sure to communicate the behavior in a way the user is able to understand it (i.e. he's able to see that his edit will change the first cell/row).
I figured out the problem and how to fix it, but it's not pretty. The problem is in the mouse moved event for a QAbstractItemView. After much debugging and searching through the source code I found this in qabstractitemview.cpp:
void QAbstractItemView::mouseMoveEvent(QMouseEvent *event)
...
if (index.isValid()
&& (index != d->selectionModel->currentIndex())
&& d->isIndexEnabled(index))
d->selectionModel->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
}
I fixed it by giving my class a QModelIndex member which stores the last location of the top left QModelIndex (set in my overriden version of setSelection like above) and then I overrode the mouseMoveEvent with this:
void SampleTable::mouseMoveEvent(QMouseEvent *event)
{
QTableView::mouseMoveEvent(event);
if (state() == ExpandingState || state() == CollapsingState || state() == DraggingState || state() == EditingState)
return;
if ((event->buttons() & Qt::LeftButton)) {
if (m_topLeft.isValid())
{
selectionModel()->setCurrentIndex(m_topLeft, QItemSelectionModel::NoUpdate);
}
}
}
Not a pretty solution, but it works.
The QtableWidget class has a signal itemSelectionChanged(), connect it to your custom slot. In that slot, use selectedIndexes() to get all indexes, then use setCurrentIndex() to set the cell which you want to be the current index.