Display QCombobox down arrow in custom tree view - c++

I’ve created a custom model, view (tree) and delegate and everything seems to be working OK with one minor issue. Some of the cells of the tree are combo boxes. The combo boxes work as expected when selected by the user (custom createEditor, setEditorData and setModelData delegate methods). The issue I have is the down arrow is only displayed when the cell is selected. I would like the down arrow to be displayed all the time.
I’m not sure which method is control’s the display of the down arrow. Does it come from the model data (maybe the decorationrole) or is it the paint method of the delegate. Note I’m not using any style sheets.
Update:
Found the solution I was after here. Basically ended up with the following in the paint method of my custom delegate.
QStyleOptionComboBox comboBoxOption;
comboBoxOption.rect = option.rect;
comboBoxOption.state = option.state;
comboBoxOption.state |= QStyle::State_Enabled;
comboBoxOption.editable = false;
comboBoxOption.currentText = index.data(Qt::DisplayRole).toString();
QApplication::style()->drawComplexControl(QStyle::CC_ComboBox, &comboBoxOption, painter);
QApplication::style()->drawControl(QStyle::CE_ComboBoxLabel, &comboBoxOption, painter);

When QTreeItemView show own items. It's use QStyledItemDelegate for show content. When you edit cells, creates real QCombobox widget.
So, editing and showing items have different approaches.
You should change QStyledItemDelegate::paint logic for see additional decorations when cells just showing (painting).
Make children of QStyledItemDelegate and define own paint() method.
That will not simple for first time. But that true way to implement "arrow" in cells.

Related

How can I add a custom toggle button to a custom item delegate?

I have a custom item delegate that I would like to draw/attach a custom toggle button (see image), ideally replace the buttons on the delegate with the custom toggle button. Both classes (custom item delegate and custom toggle button) work fine on their own, however, how to attach the toggle button to the delegate is quite a challenge. Any suggestions would be very helpful.
This is the code section that draws the button:
void CustomDelegate::drawButton(QStyleOptionButton& opt, const QPoint& p, QPainter* painter) const
{
QStyle* style = QApplication::style();
opt.text = "button";
if(style){
style->drawControl(QStyle::CE_PushButton, &opt, painter);
opt.state &= ~QStyle::State_Sunken;
opt.rect.translate(opt.rect.width() + offset_button, 0);
}
}
you could achieve this by using a custom editor for the cell and opening a persistent editor on it.
In your item delegate, you'd need to reimplement the createEditor, setEditorData and setModelData methods to create your custom toggle button, set its state according to the model data and write its state back to the model upon change.
With this method, you wouldn't need to draw the button yourself in the delegate because it's not just an image that gets displayed, but a fully functioning button.
https://doc.qt.io/qt-5/qtwidgets-itemviews-stardelegate-example.html is an example that should get you started.

Click on drop-down list of QComboBox

I currently have a QComboBox in a QGraphicsScene and I need it to detect clicks. To see if there is a widget in the clicked position, I use:
void BlockScene::mousePressEvent(QMouseEvent *event)
{
if (itemAt(event->pos()) != m_widgetItem)
{
// ...
}
}
This works well for different widgets except for combo boxes where it only takes into account the original widget and not the drop-down list that appears after a first click.
To know if it came from the scene or not, I tested also by redefining mousePressEvent of the class QComboBox and same problem: It is called only when clicking on the initial widget.
Is there a way to get the drop-down list? To detect a click on it? Ideas?
You can define a custom widget for the view of the combo, or for its completer.
For example, in a subclass of QComboBox, if you need a completer, try this code. MyListView is a subclass of QListView. On that, you can reimplement the mousePressEvent method
completer()->setCompletionMode(QCompleter::PopupCompletion);
MyListView *comboView = new MyListView();
completer()->setPopup(comboView);
if you don't need the completer, do the setView directly on the combobox.
MyListView *comboView = new MyListView();
setView(comboView);

Expandable list view with customized scrollbar in Qt

I want to build a widget like this one that we can find in Word :
So, there is a list view using a specific scrollbar with 3 buttons and no scroll.
When you click on the last button at the bottom right, a new list view with a classic scrollbar is shown over the previous list view (hidden when losing focus). So basically, the smae behavior as the one in Word.
We are already capable of displaying a list view with custom content.
My main concern is how to build the widget in the first image: the list view with the custom scrollbar (3 buttons, no scroll)?
What is the proper way to do this ?
I assume that you're implementing a subclass of QAbstractListView.
I don't believe you need a custom scrollbar - just put the scrollbar and the button into a QVBoxLayout; hide the button once it's checked (you could even connect its toggled() to its setHidden() for that).
At first hide the default scroll-bar by calling the QAbstractScrollArea::setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff) method.
Then create your three buttons on the left side and connect the QPushButton::clicked() signals to some slots where you just scroll your list by calling the QAbstractItemView::scrollTo(index), QAbstractItemView::scrollToBottom() or QAbstractItemView::scrollToTop().
While it is correct that you could just build a custom widget consisting of a view with hidden scrollbars and add the buttons to the layout, connecting the signals/slots needed to provide the proper actions, you can also consider to implement your own QScrollBar class. QListView is derived from QAbstractScrollArea, which provides setVerticalScrollBar() so you can just set an object of it to be used by the view. The integration of scroll area and scroll bar should be much more straightforward this way, but you'll have to do the painting of the scroll bar's content yourself, or put a layout and the buttons in there (QScrollBar derives from QWidget, and you'll have to reimplement paintEvent()).

How can I set Qt tab order for a form with a composite widget?

I have a form written with Qt Designer, which contains a QWidget promoted to a custom widget I have. The custom widget contains several combo boxes. I want the form to have a reasonable tab order, with focus moving from the widget immediately before the custom widget, then going through the combo boxes in the custom widget, and proceeding to the widget after the custom widget. So I set the QWidget to have tab focus in Designer, but the custom widget doesn't handle having focus properly.
I could solve this problem using QWidget::setTabOrder, but that would be messy because I would have to reach into the custom widget from the outside. Alternatively I could give the custom widget a member function to set the tab order. Ideally there should be a simpler way. Is there?

How to draw a progress bar inside a list widget in Qt

I want to have a list of items that need to be processed in a QListWidget. Similar to Windows Media Player CD import, there should be a progress bar for every item in the list.
Now there seems to be a way to do this by creating a regular progress bar, using QPixmap::grabWidget() to save its appearance in a QPixmap and then adding this QPixmap as Icon to the QListWidgetItem via QListWidgetItem::setIcon().
However, this seems to be horribly wacky.
Do you know a more elegant way to achieve a progress bar inside a list widget?
Each item in a QListWidget can be represented by a QWidget of your choice, rather than the default rendering (text). You can set this by calling QListWidget::setItemWidget(). In this case, I'd recommend using QProgressBar as the rendering widget -- you should get the desired result.
From the documentation of QListWidget::setItemWidget():
This function should only be used to
display static content in the place of
a list widget item. If you want to
display custom dynamic content or
implement a custom editor widget, use
QListView and subclass QItemDelegate
instead.
You could do it by converting your list widget into a model/view/delegate combo. Then you can set a delegate on the list view that overrides the paint functions and draws the progress bar wherever you want it. I don't know how easy it would be to get an actual QProgressBar widget into the drawing area, however.
Alternately, you could consider making your own list-widget like container that knows about the progress bars.