How to show all the children items in QTreeView? - qt

I tried to create a QTreeView as example from Qt
http://doc.qt.io/qt-5/qtwidgets-itemviews-editabletreemodel-example.html
When we click on the triangle before each "parent" item, the "children" items will be shown.
In my case I add this line to tree view
myTreeView->setRootIsDecorated(false);
As the result, there is no more triangle before each "parent" item.
But the "children" items are also not shown any more.
My requirements are:
disable the triangle before each "parent" item
show ALL items in the tree, both "parent" and "children"
How can I do it?

As per the comment you can programmatically ensure all items in the tree are visible by calling QTreeView::expandAll...
myTreeView->expandAll();
Note that it may need to be called again as/when child items are added to the model which, depending on the size of the model, could become a performance bottleneck.
As an alternative, it might be better to inherit from QTreeView and override the QTreeView::rowsInserted member.
virtual void MyTreeView::rowsInserted (const QModelIndex &parent, int start, int end) override
{
/*
* Let the base class do what it has to.
*/
QTreeView::rowsInserted(parent, start, end);
/*
* Make sure the parent model index is expanded. If it already
* is expanded then the following should just be a noop.
*/
expand(parent);
}
This should give better performance for large models.

Related

Last empty column to fill QTableView

In a QTableView I need the last (rightmost) column to be empty, expandable but not movable. The goal is that the table not to suddenly end (for I use alternate color for rows) or to ugly expand to the right. In QHeaderView there is a setFirstSectionMovable(bool); I need something similar for the last section, letting the rest of them movable. (in other words: Fill the rest of the table with an empty not movable column). Any clue how to acheive this?
I did override mousePressEvent() in a subclass of QHeaderView to skip the last section but it still can be moved by moving other column in its place and I don't know how to prevent this.
AMOQ:
Be HeaderView a subclass of QHeaderView and have
setSectionsMovable(true);
setStretchLastSection(true);
Treat the sectionMoved signal:
connect(this, &QHeaderView::sectionMoved, [this](int, int, int newVisual) {
if(newVisual == count()-1) { moveSection(newVisual, newVisual-1); }
});
Override mousePressEvent:
void HeaderView::mousePressEvent(QMouseEvent* event) {
int logicalIdx = logicalIndexAt(event->pos());
if(logicalIdx != count()-1) { QHeaderView::mousePressEvent(event); }
}

setParent() not showing child widget

I have a class called TitleBar inherited from QWidget and I created a new widget and did setparent() but after doing setparent child widget is not showing, it is showing only after commenting setparent but not alligned with parent, its displaying in some random placess, On maximized view only it shows on right place
TitleBar::TitleBar(QWidget *parent) : QWidget(parent)
{
m_jobSubmitWidget = csJobSubmitPoolWidget::getSubmitPoolInst();
// m_jobSubmitWidget->setParent(QWidget::window());
}
void csTitleBar::BtnClicked()
{
QPoint pos = m_queueBtn->pos() + m_serverToolBar->pos() + QPoint(-m_jobSubmitWidget->width() + m_queueBtn->width(),62); // these are member variables in TitleBar class
// pos shows always same value on moving parent widget
if(itemCount > 2){
m_jobSubmitWidget->move(pos);
m_jobSubmitWidget->show();
m_jobSubmitWidget->setFocus();
}
}
I really suggest that you take a good read at Qt documentation.
QWidgets that have a parent are displayed inside their parent (except for QDialog). If a widget does not have a parent, it will be shown as a separate window.
Parenting a widget to the result of QWidget::window() is kind of hazardous as you don't really know which widget will be returned, so you do not know where the child widget will end up.
Also you do not need to call show() on widgets that have a parent. By default their visibility follows the parent visibility.
In my case I also had to add the widget which I was changing the parent (here textEdit) to the target containing layout:
ui->textEdit->setParent(ui->groupBox1);
m_lastVboxLayout->removeWidget(ui->textEdit);
m_lastVboxLayout = ui->verticalLayout_groupBox1;
m_lastVboxLayout->addWidget(ui->textEdit);
no need to call show() afterwards.

How to set stylesheet for the current item in QTableView

When QTableView edit control is visible for the current item the shylesheet of the edit takes place. When there is no active edit control in the QTableView the current item is styled using the QTableView { selection-background-color: } How to set different style only for the current item?
Qt style sheets support sub-controls and pseudo states, you can use it to improve your customization. see Qt6 docs
In this case you can use the ::item sub-control and the :focus pseudo state (the "current" pseudo state doesn't exist, but the :focus does the same).
This is an example that you can use:
QTableView::item:focus
{
selection-background-color: yellow;
}
See also Qt6 documentation of customizing a qtableview
1. As it IGHOR said you can use data() method in your model and provide a color when role is Qt::BackgroundColor. But there is a stumble here because you don't know whether index is current or not. You'll ought to set a current index in the model when it changes and then make a check like this:
if (index == m_currentIndex and role==Qt::BackgroundRole) return Qt::black;
Actually it's not the best idea to tell the model about currentIndex according to Model/View pattern, because you can have two views for one model.
2. Descendants of QAbstractItemView has method setItemDelegate. A delegate is used to draw a cell.
All you need is to inherit from QStyledItemDelegate, pass a pointer to the view to the delegate and override method initStyleOption.
Then do something like this:
void MyStyledItemDelegate::initStyleOption(QStyleOptionViewItem *option,
const QModelIndex &index) const
{
QStyledItemDelegate::initStyleOption(option, index);
QStyleOptionViewItemV4 *v4 = qstyleoption_cast<QStyleOptionViewItemV4 *>(option);
if (index == view()->currentIndex())
{
v4->backgroundBrush = QBrush(Qt::grey);
}
}
3. If you really need to use css (for example you have themes) you can do it this way:
Add something like this in your css file:
QTableView
{
qproperty-currentItemBackground: #cccccc;
}
Modify initStyleOption from the previous example to use the property:
v4->backgroundBrush = view()->property("currentItemBackground").toColor();
With this approach you can set a specific style via css for a column, a row, a single cell or a group of cells.
You need to create a new delegate, that renders itself based on the data model (custom role, for example). You need to base its style on a special control created for the purpose (that can be changed via stylesheet) . I'll post some code when I find time.
One can use variadic templates, and crtp (Coplien) to good effect to layer one's delegates

Need to display the widgets inside my QListWidget with an offset, basically shifted a bit to the right

I have a panel.ui file done using QTDesigner. It's a QFrame class, rectangular shape with few labels on it. And I have a QListWidget class where I insert 3 instances of the panel.ui.
I create a QListWidgetItem and then use List->SetItemWidget(..) to populate my list.
The Result is a list filled with three panels. I was also able to move the panels inside the list using dragDropMode internalMove.
I also tested the ability to shift the panels a bit to the right when I click on them and that worked:
in procedure List::mousePressEvent(QMouseEvent *event)
Panel *child = static_cast<Panel*>(childAt(event->pos()))
...
int y= child->pos().y();
int x = child->pos().x();
child->move (x +10, y); `
Problem: When I run the app and display the list, I want all the panels to be displayed with that 10 offset to the right. So in the List constructor and inside the loop after this->setItemWidget(myPanelItem, myPanel); I try using myPanel->move() like above but it doesn't seem to work.
I run the app, the panels are displayed without my offset ( not sure why?) but when I click on one, it shifts.
move() won't work reliably since the widgets are in a layout. (Well, not a layout as in a QLayout, but the effect is comparable: When any metric in your application changes, e.g. you resize or scroll the list, the widgets are repositioned by the list widget.)
What you can do is wrap your actual widget in a container widget with a layout margin:
QWidget* wrapIntoContainerForOffset(QWidget* widget, int offset /*in pixels*/) {
QWidget* container = new QWidget;
QHBoxLayout* layout = new QLayout(container);
layout->setContentsMargins(/*left=*/ offset, /*others=*/ 0, 0, 0);
layout->addWidget(widget);
return container;
}
Then you add these containers to the listwidget instead.
Have You tried StyleSheets. The QListWidget supports Box model( http://doc.qt.digia.com/qt/stylesheet-customizing.html#box-model ). So You may want to try playing around with margins in the stylesheets.
Style sheet reference: http://doc.qt.digia.com/qt/stylesheet-reference.html

GWT - Styling TreeItems

in my application I have a tree structure made out of treeitems.
What I wanted to do was change the background of certain tree items if their userObject satisfies certain conditions. The problem I have is when a root tree item is getting its background changed (only tested it on criteria being satisfied at tree items at the root level), all child treeitems of that tree item also have their background changed despite me going in and removing that style sheet on the children.
Long story short: I want it to only change the background on the tree item itself, and not its children.
code:
if(item.getUserObject() != null && ((Device)item.getUserObject()).getDeviceType() == type)
{
item.setStyleName("labelHighlight");
}
else
{
item.removeStyleName("labelHighlight");
}
for(int i = 0; i < item.getChildCount(); i++)
{
highlightNodes(type, item.getChild(i));
}
Use a widget instead of directly styling treeItem. Like this, you can change background of your widget and not the background of all your tree item

Resources