QSpacerItem changeSize attracts bug - c++

I'm creating a calendar app and just finished the appointment view and edit. Basicly it's a QVBoxLayout with the viewlayout and editlayout in it and I hide and show either the view or edit using signals.
That works just fine, there is 1 issue: in the viewlayout I have a QSpacerItem for some extra spacing and in order to remove the space when viewing the edit-part I change its size.
Like so
if( show_view_hide_edit )
spacer->changeSize(1, 60, QSizePolicy::Expanding, QSizePolicy::Fixed );
else
spacer->changeSize(0, 0, QSizePolicy::Fixed, QSizePolicy::Fixed );
This code works when the widget shows, and when I swap it to "edit". When I switch it back to view and then go back to edit the spacing is at the top of my screen. It shouldnt really be there. Image shows what happens. (link to image for size)

Without the construction code of your widget it is a little hard to guess, what is going on. Have you tried to insert / remove the SpacerItems with QBoxLayout::insertSpacing ( int index, int size ) and QLayout::removeItem ( QLayoutItem * item )?
And did you call QLayout::invalidate () after changing the size?

Related

Close button only on active tab of QTabWidget

To save space in a QTabWidget, I would like to show the close icon only for the current tab, like e.g. Firefox is doing:
Is there a simple way using a style sheet, some thing like (not working like this)
QTabBar::tab::!selected::close-button {visible: false;}
or do I have to subclass QTabWidget to get the desired behavior?
You won't need to subclass anything, you can use QTabWidget::tabBar() method to obtain a reference (i.e. QTabBar *) to the tab bar associated with your QTabWidget. (Note that this method is no longer protected, so it can be accessed without subclassing the class)
QTabBar *tabBar = tabWidget->tabBar();
You can now use tabBar reference to hide close buttons on non-current tabs. For example to hide ith button, you can do:
tabBar->tabButton(i, QTabBar::RightSide)->hide();
So a simple workflow could be as follows:
Connect QTabWidget::currentChanged(int index) signal to a slot.
In that slot hide all close buttons other than the button at index.
You can subclass QTabWidget to get access to the QTabBar widget using protected method QTabWidget::tabBar. Then you can connect to the QTabBar::currentChanged signal and hide close button for not selected tabs manually:
QTabBar::ButtonPosition closeSide =
(QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
for (int i = 0; i < toolbar->count(); ++i)
{
if (i != toolbar->currentIndex())
{
QWidget *w = toolbar->tabButton(i, closeSide);
w->hide();
}
}
hide() leaves empty space for the invisible close button. This looks funny.
Set the width to 0 instead.

Issue with QLayout with QStackedWidget

I am implementing a tab style UI. where tabs are shown by QListWidget and contents are shown by QStackedWidget. on every page of QStackWidget there is layout which allow to insert panel(widget) in QHBoxlayout. at every panel, there are couple of icons which are again in QHBoxLayout. Below is ideal case which I wanted to implement.
But on other page of QStackWidget this is not the case (with less icons) as below
I want to remove extra space ( or align icon to left to eliminate extra space among icons on panels)
I tried spacer, then this happened :(
please help me to correct this thing. My spacer code is as
inline QSpacerItem * buildSpacer(Qt::Orientation orientation)
{
QSpacerItem * pSpacer = nullptr;
if (orientation == Qt::Horizontal)
{
pSpacer = new QSpacerItem(1000, UNIT_VALUE, QSizePolicy::Expanding, QSizePolicy::Minimum);
}
else
{
pSpacer = new QSpacerItem(UNIT_VALUE, 1000, QSizePolicy::Minimum, QSizePolicy::Expanding);
}
return pSpacer;
}
Note
I donot want to use QTabWidget. By the way this issue is also with QTabWidget
Why not using QTabWidget in the first place?
Anyway, instead of creating the QSpacerItem by yourself, you should use addStretch():
my_layout->addWidget(new Widget("widget1"));
my_layout->addWidget(new Widget("widget2"));
my_layout->addStretch(1); // will "eat" extra space

Area of tree displayed by QTreeView not expands to its parent widget?

I use QTreeView and QStandardItemModel to display its contents (read from xml file) in a tree view. The file parser works just OK, but when I use the view to display the data, the sizePolicy just doesn't work.
Why? How to make the area of tree expand?
(It shows like below, which tree view doesn't expand?)
picture of the display of the tree:
code (edited to add "layout" part, but not work, either.):
...
QStandardItemModel *model = new QStandardItemModel();
preOrder(doc.firstChild(), model);
view = new QTreeView(pageDetails);
view->setModel(model);
model->setHorizontalHeaderLabels(QStringList(""));
QHBoxLayout* lay=new QHBoxLayout(pageDetails);
lay->setContentsMargins(0, 0, 0, 0);
lay->addWidget(view);
view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
pageDetails->setLayout(lay);
view->show();
I got the problem solved now:
But still don't know how to remove the header...
The problem is caused by Qt Designer. I use it to add the parent widget ui, but set it a horizonal layout in the designer(somewhat difficult to find).
I just don't know why the code above just doesn't work in this case.
PS:
If I left the code commented:
//QHBoxLayout* lay=new QHBoxLayout(pageDetails);
//lay->setContentsMargins(0, 0, 0, 0);
//lay->addWidget(view);
//view->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
//pageDetails->setLayout(lay);
It appears:
PS2:
remove header successfully!:
comment model->setHorizontalHeaderLabels(QStringList(""));
add view->header()->setVisible(false);

How test QTableView edition with QTest?

I would like to simulate edition of a cell of QTableView with QTest.
I have tried different approach but without any success:
qtableview->show();
/* I think that in my unit test I should no need
that, could you confirm ? */
QModelIndex modelIndex = qtableview->model()->index(1,1);
//I have tested that modelIndex is valid and that I retrieved expected data
/*First try: set the currentIndex on modelIndex
thinking that keyClicks on qtableview will work
on selected element of the tableview*/
qtableview->setCurrentIndex(modelIndex );
QTest::KeyClicks(qtableview,“Hello Word”);
QCOMPARE->index(1,1).data(), “Hello World”); // —> FAILED
/*Second approach
Get the cell widget*/
QWidget * qwidget = qtableview->indexWidget( modelIndex );
//—> No test since the qwidget is NULL… why ?
/*Third approach
Get the cell widget through the delegate*/
QWidget * qwidget =
qtableview->itemDelegate( modelIndex )->createEditor(qtableview,
QStyleOptionViewItem(),
modelIndex );
QTest::KeyClicks(qwidget ,“Hello Word”);
QCOMPARE->index(1,1).data(), “Hello World”); // —> FAILED
I have also added in the three aproaches without any success
QTest::mouseDClick(qtableview)
QTest::KeyClicks(qtableview,“Hello Word”);
Thanks for your help.
I think you need to process events after a widget is shown. QListView probably won't be doing anything if it's hidden (as it well should!). See if qWaitForWindowShown(qtableview) would do the trick. If that won't work, run the event loop directly by calling QCoreApplication::processEvents(). Have a look in qWaitForWindowShown, it probably spins an event loop anyway.

Modify a tab in a QTabWidget where each tab represents a QTableView

I have a tab widget where every tab is a QTableView. I would like to be able to pass an updated model (QModelIndex) into each tab whenever the contents of that tab need to change.
The alternative (and nastier way) is for me to delete all the tabs, and then recreate them.
I know I can get the widget in the tab by doing something like:
tabWidget->widget(i);
This will return a widget, which is really a QTableView, but I want to update the model that is in that widget without having to delete and recreate the tab.
Thank you!
P.S. This is my current attempt...
for (int i = 0; i < tableView.size(); i++)
{
tabWidget->setCurrentWidget(tableView.at(i));
QTableView* updatedTable = (QTableView*)tabWidget->currentWidget();
updatedTable->setModel(dataModel);
tableView.replace(i, updatedTable);
}
It's not clear why you can't keep the QTableView widget and just change the model, as in your code. Doesn't the view refresh without this tableView.replace thing?
There doesn't appear to be a direct API for replacing the widget you put in with addTab() without going through a tab removal step. But instead of inserting the QTableView directly, you could instead call addTab() on a dummy widget that has a layout in it with a single item. A QStackedLayout, for instance:
QWidget* dummy = new QWidget;
QStackedLayout stackedLayout = new QStackedLayout;
stackedLayout->addWidget(tableView);
dummy->setLayout(stackedLayout);
tabWidget->addTab(dummy);
Then later, when you want to replace the tableView with a new one:
QWidget* dummy = tabWidget->currentWidget();
QStackedLayout newStackedLayout = new QStackedLayout;
newStackedLayout->addWidget(newTableView);
delete dummy->layout();
dummy->setLayout(newStackedLayout);
I still wonder what this is buying you that reusing the old table view couldn't do.