Add a delete Button to each Item in QListView - qt

Is it somehow possible to add to each Item in a QListview a Button which is deleting the Object onClick? As shown in the following Picture:
EDIT: As I'm new in QT it would be nice to have some example, to understand it better. And as it seems there are three different Ways? What will be the best? Do use a QAbstractItemView?

Yes. You'll need to use:
QAbstractItemView::setIndexWidget ( const QModelIndex & index, QWidget * widget )
QListView inherits QAbstractItemView and when you're trying to customize list/tree views that's usually the place to look. Be careful though, without a delegate this doesn't scale very well. Check out this thread: http://www.qtcentre.org/threads/26916-inserting-custom-Widget-to-listview

You can also go for a generic approach that can work on variety of containers, including the underlying model of your list view.
Each item in the list has a requestRemoval(Item*) signal and a removeMe() slot, connect the X button to the removeMe() slot in each item constructor, in removeMe() you emit the requestRemoval(this) signal, which is connected to a removeHandler(Item*) slot in your "parent" object upon creation of that item, which receives the pointer of the item which has requests deletion, and removes it from the underlying container being used.
Basically, pressing the remove button causes that particular item to send a pointer of itself to the parent's remove handler which removes that entry.
EDIT: Note that this is a generic approach, as noted in the comments below it can be applied without signals and slots as well, and even though it will work it is not the most efficient solution in your particular case.

Related

How to enable both internal reordering and external dropping in a Qt widget?

I have created a widget which inherits QListWidget.
My goal is for it to accept files dropped into it from an external file manager, and for the user to be able to reorder the elements in the widget. I can achieve both, but not at the same time.
If I just set
myWidget->setDragDropMode(QListView::InternalMove);
myWidget->setDragEnabled(true);
I can reorder the items within the widget, but I can't drop external items into it.
If I reimplement the dragMoveEvent, dragEnterEvent and dropEvent events, all of them just having acceptProposedAction(); and some debug messages inside them, I can drop external files into my widget, but I can no longer rearrange the items.
Is there a way to have the above two at the same time, or do I have to manage the items myself in the reimplemented functions? If so, how can I know if a dropped item is internal or external, and how can I know from which position it was taken and into which position in the list it was dropped into?
If I parse the mimeData which I got from the event, I can see whether it as a file or a text, and I get "qabstractitemmodeldatalist" if it was an internal item, but it still doesn't give me its position.
I can check event->pos() to know in pixels where the drop has been made, and event->source() to learn about what was dropped there, but is this really best practice, to start calculating pixel values and adding objects "manually"?
The solution was very simple: I just had to call the functions of the parent class at the end of each function I've overridden.
void myWidget::dropEvent(QDropEvent *event)
{
do_stuff_with_received_data(event);
QListWidget::dropEvent(event);
}

I want to extend dropEvent() (QListWidget), should I completely reimplement it?

I have a QListWidget and I have set it to accept drops, the mode to be DragDrop etc and I can move QListWidgetItems all around the place (inside the QListWidget of course).
I like this behavior and I want it to let it as is, but I also want my QListWidget to accept drops from a QTreeWidget as well. If I attempt to reimplement the dropEvent() of my QListWidget then I lose the default behavior.
Is there any way to just extend the current behavior so as to have both drag-drop between listwidget items and drag-drop from the treewidget to the listwidget or I have to completely re-write both behaviors in my dropEvent() reimplementation?
Thanks a lot for any answers :)
Two ways:
implement a standalone event filter and make it act upon QEvent::Drop. Install it on your original QListWidget. Return false so that the original dropEvent() handler is called afterwards.
inherit from QListWidget, reimplement dropEvent(evt) and as a last statement, call QListWidget::dropEvent(evt);. Your original behavior will be retained.
No.
Subclass QListWidget, reimplement
virtual void QListWidget::dropEvent ( QDropEvent * event )
and explicitly call
QListWidget::dropEvent(event);
whenever you need the default behavior.
How to call a parent class function from derived class function?

Qt: Custom QListView and live controls

My custom QListView has delegates to paint the items. I'd like to add a live control to some of the row items (like a QLineEdit), that'll always be present in the row and will automatically scroll correctly with the list.
Since items are not widgets, I cannot assign a control to be a child of an "item", thus scrolling will leave the control in its fixed spot within the QListView widget.
Is there another way?
Is that even possible?
Normally the edit widget is created (and positioned) by the delegate when an QEvent::EnterEditFocus event occurs then destroyed when a subsequent QEvent::LeaveEditFocus occurs and the data is sent back to the model. The delegate should then repaint with the new model data.
Could you expand on what you mean by a "live" control?
Why would you want to have an edit widget constantly open? I think a better way to do this would be to create a delegate which paints the normal view (i.e. for Qt::DisplayRole) in a way which you want. Assuming you create your subclass view correctly, the delegate should still update when the model changes.
If you really want to do what you're asking though, I suspect you might be able to by:
creating your own item delegate (subclassing QAbstractItemDelegate)
reimplement createEditor() to use a QLineEdit
then use the delegate's updateEditorGeometry()
Have a read of the Delegate Classes section of the Introduction to Model/View Programming though first. The Spin Box Delegate Example and Pixelator Example are worth studying too if you haven't already.

With several widgets sharing the same signal slot (event handler), how do I find out which one has been clicked?

In my project I am using a custom circle-shaped button widget derived from the QWidget class. I have added several of these widgets to a parent widget.
When one of these custom buttons is clicked, how do I find out which one was clicked?
Adding custom button to parent widget:
void ShotViewCTRL::addShot(QString shotNanme)
{
ShotButton *btnShot=new ShotButton(this);
btnShot->shotName=shotNanme;
connect(btnShot,SIGNAL(Shot_Selected()),this,SLOT(SHOT_CLICKED()));
btnShot->CreateButton();
btnShot->show();
}
My parent widget is ShotViewCTRL (inherits from QWidget), the child widget is ShotButton (custom control, inherits from QWidget).
The control is working fine. It's sending sending to parent object. In my problem, I added the same custom control 10 times.
I need to find which control was clicked? Please help me find the solution.
I have referred to the Qt documentation to find the child widget, but I did't understand. Some sample code would be great.
QSignalMapper is what you are looking for. With QSignalMapper, you can add something like an Id (or even a pointer to the QButton itself) as additional data to the signal emittance and you have to adjust your slot so it takes additional data (ID or Pointer).
Then either distinguish in the slot itself by the id you give your objects some virtual function type() so you can distinguish with that or even try casting and catch errors (Tip: don't try the last method, it may work differently on different compiler).
You can use the QObject::Sender function to find which QObject sends the signal. Regarding the first warning in the doc, it's what you are searching for.
you specify different slots for different buttons with same signal.with that you can recognize the different button click

How to remove QWidgets from QSplitter

In my app have a window splitted by a QSplitter, and I need to remove an widget.
How can I do that? I can't find useful methods
It's not clear to me if you want to preserve the widget and put it somewhere else, or if you want to destroy the widget.
Destroying the widget: If you can
get a pointer to the widget, you can
simply delete it. The splitter will
safely be notified that its child is
being deleted and will remove it
from itself.
Preserving the widget: If you grab
the pointer to the widget, you can
simply set its parent to some other
widget and add it to another
widget's layout and it will show up
there. This is safe because the
QSplitter will be notified that one
of its children is being reparented.
If you want to set the parent to NULL (cjhuitt's answer) be aware that you are now responsible for cleaning up that memory because the widget no longer has a parent.
Many things in Qt cannot be "traditionally" removed. Instead call hide() on it and destruct it. From QSplitter documentation:
When you hide() a child its space will
be distributed among the other
children. It will be reinstated when
you show() it again.
I like Tuminoid's answer. But if you absolutely need it removed, try getting the widget you want to remove, and calling setParent( NULL ) on that widget. That's my best guess.
If you hold a pointer to the widget, then just delete it, or use deleteLater() if you want to be on the safe side.
If you do not have the widget pointer, use QSplitter::widget(int index) function. Then, you can use invoke its deleteLater() slot.
If you do not have the widget index, but you still know the widget objectName(), then QObject::findChild() is your only way to get the widget pointer.
I ran into the same problem. In Qt 4.8 to temporally hide one of the widget of a QSplitter I simply hide it. However it is not enough, as the splitter handle is still available to move. But the handle can be accessed and hidden as well:
frameA->setVisible(conditionA);
frameB->setVisible(conditionB);
if ( !(conditionA && conditionB) ) // if only 1 frame is visible
{
splitter->handle(0)->setVisible(false);
}
Another easy way to prevent the child widget from getting deleted is to use QSplitter.takeWidget(child). This is also the recommended way of removing the widget from a splitter. (Qt Documentation)

Resources