从列表中选择项目到其他列表的 Qt 实现(双列表、累加器、列表构建器、TwoListSelection ...)

Qt Implementation of selecting items from list into other list (Dual List, Accumulator, List builder, TwoListSelection ...)

我想 select 从任意长度的列表中提取任意数量的项目。 下拉列表 (QComboBox) 不允许选中项目。如果有很多项目,可检查项目列表会变得笨拙。

我发现 this question in the User Experience SE subsite and this answer 似乎是最适合我需要的解决方案。它有很多名字,如上述回答评论中的评论:Dual List、Accumulator、List builder、TwoListSelection ...

来自 OpenFaces.org 的版本显示在上面链接的答案中:

不过,我找不到 Qt 中的实现。我应该自己实现还是在 Qt 中有可用的实现?有推荐的方法吗?

Qt 中默认没有此小部件,但构建它并不复杂,您要做的第一件事就是列出要求:

  • 文本为>>的按钮如果左侧列表不为空则启用,如果按下它必须移动所有项目。

  • 带有文本<<的按钮与上一个类似,但右侧有列表

  • 如果选择左侧列表中的项目,则启用带有文本 > 的按钮,如果按下,则应将所选项目移动到对了

  • 带有文本 < 的按钮相同,但右侧。

  • 如果选择了一个项目并且这不是列表中的第一个项目,则启用带有 "up" 文本的按钮。按下时,您必须将当前项目移动到更高的位置。

  • 如果选择了一个项目并且这不是列表中的最后一个项目,则启用带有 "down" 文本的按钮。按下时,您必须将当前项目移动到较低位置。

正如我们所见,大部分逻辑都取决于项目的选择,为此我们将信号 itemSelectionChanged 与决定按钮是否启用的插槽连接起来。

要移动项目,我们必须使用 takeItem()addItem(),第一个删除项目,第二个添加项目。

向上或向下移动相当于删除项目然后插入它,为此我们再次使用 takeItem()insertItem()

以上所有内容都在以下小部件中实现:

#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

在下面link你会找到一个完整的例子。