问题
I want to select an arbitrary amount of items from a list of arbitrary length. A dropdown (QComboBox) doesn't allow checkable items. A list of checkable items would become clumsy with a lot of items.
I found this question in the User Experience SE subsite and this answer seems to be the solution that best suits my needs. It has many names, as a comment in said answer remarks: Dual List, Accumulator, List builder, TwoListSelection ...
The version from OpenFaces.org shown in the answer linked above:
I couldn't find an implementation in Qt, though. Should I implement it myself or is there an implementation available in Qt? Is there a recommended approach?
回答1:
This widget does not come by default in Qt, but it is not complicated to build it, the first thing you should do is list the requirements:
The button with text >> is enabled if the list on the left is not empty, if pressed it must move all the items.
The button with text << similar to the previous one but with the list on the right
The button with text > is enabled if an item in the list on the left is selected, if pressed, the selected item should be moved to the right one.
The button with text < the same but for the right side.
The button with "up" text is enabled if an item is selected and this is not the first item in the list. when pressed you must move the current item to a higher position.
The button with "down" text is enabled if an item is selected and this is not the last item in the list. when pressed you must move the current item to a lower position.
As we see most of the logic depends on the selection of items, for this we connect the signal itemSelectionChanged
with the slot that decides whether the buttons are enabled or not.
To move items we must use takeItem()
and addItem()
, the first removes the item and the second adds it.
Moving up or down is equivalent to removing the item and then inserting it, for this we use takeItem()
again with insertItem()
All the above is implemented in the following widget:
#ifndef TWOLISTSELECTION_H
#define TWOLISTSELECTION_H
#include <QHBoxLayout>
#include <QListWidget>
#include <QPushButton>
#include <QWidget>
class TwoListSelection : public QWidget
{
Q_OBJECT
public:
explicit TwoListSelection(QWidget *parent = nullptr):QWidget{parent}{
init();
connections();
}
void addAvailableItems(const QStringList &items){
mInput->addItems(items);
}
QStringList seletedItems(){
QStringList selected;
for(int i=0; i<mOuput->count(); i++)
selected<< mOuput->item(i)->text();
return selected;
}
private:
void init(){
QHBoxLayout *layout = new QHBoxLayout(this);
mInput = new QListWidget;
mOuput = new QListWidget;
mButtonToSelected = new QPushButton(">>");
mBtnMoveToAvailable= new QPushButton(">");
mBtnMoveToSelected= new QPushButton("<");
mButtonToAvailable = new QPushButton("<<");
layout->addWidget(mInput);
QVBoxLayout *layoutm = new QVBoxLayout;
layoutm->addItem(new QSpacerItem(10, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
layoutm->addWidget(mButtonToSelected);
layoutm->addWidget(mBtnMoveToAvailable);
layoutm->addWidget(mBtnMoveToSelected);
layoutm->addWidget(mButtonToAvailable);
layoutm->addItem(new QSpacerItem(10, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
layout->addLayout(layoutm);
layout->addWidget(mOuput);
mBtnUp = new QPushButton("Up");
mBtnDown = new QPushButton("Down");
QVBoxLayout *layoutl = new QVBoxLayout;
layoutl->addItem(new QSpacerItem(10, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
layoutl->addWidget(mBtnUp);
layoutl->addWidget(mBtnDown);
layoutl->addItem(new QSpacerItem(10, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
layout->addLayout(layoutl);
setStatusButton();
}
void connections(){
connect(mOuput, &QListWidget::itemSelectionChanged, this, &TwoListSelection::setStatusButton);
connect(mInput, &QListWidget::itemSelectionChanged, this, &TwoListSelection::setStatusButton);
connect(mBtnMoveToAvailable, &QPushButton::clicked, [=](){
mOuput->addItem(mInput->takeItem(mInput->currentRow()));
});
connect(mBtnMoveToSelected, &QPushButton::clicked, [=](){
mInput->addItem(mOuput->takeItem(mOuput->currentRow()));
});
connect(mButtonToAvailable, &QPushButton::clicked, [=](){
while (mOuput->count()>0) {
mInput->addItem(mOuput->takeItem(0));
}
});
connect(mButtonToSelected, &QPushButton::clicked, [=](){
while (mInput->count()>0) {
mOuput->addItem(mInput->takeItem(0));
}
});
connect(mBtnUp, &QPushButton::clicked, [=](){
int row = mOuput->currentRow();
QListWidgetItem *currentItem = mOuput->takeItem(row);
mOuput->insertItem(row-1, currentItem);
mOuput->setCurrentRow(row-1);
});
connect(mBtnDown, &QPushButton::clicked, [=](){
int row = mOuput->currentRow();
QListWidgetItem *currentItem = mOuput->takeItem(row);
mOuput->insertItem(row+1, currentItem);
mOuput->setCurrentRow(row+1);
});
}
void setStatusButton(){
mBtnUp->setDisabled(mOuput->selectedItems().isEmpty() || mOuput->currentRow() == 0);
mBtnDown->setDisabled(mOuput->selectedItems().isEmpty() || mOuput->currentRow() == mOuput->count()-1);
mBtnMoveToAvailable->setDisabled(mInput->selectedItems().isEmpty());
mBtnMoveToSelected->setDisabled(mOuput->selectedItems().isEmpty());
}
QListWidget *mInput;
QListWidget *mOuput;
QPushButton *mButtonToAvailable;
QPushButton *mButtonToSelected;
QPushButton *mBtnMoveToAvailable;
QPushButton *mBtnMoveToSelected;
QPushButton *mBtnUp;
QPushButton *mBtnDown;
};
#endif // TWOLISTSELECTION_H
In the following link you will find a complete example.
来源:https://stackoverflow.com/questions/48327558/qt-implementation-of-selecting-items-from-list-into-other-list-dual-list-accum