Qt实现从列表中选择项目到其他列表(双列表,累加器,列表生成器,TwoListSelection ...)
Posted
技术标签:
【中文标题】Qt实现从列表中选择项目到其他列表(双列表,累加器,列表生成器,TwoListSelection ...)【英文标题】:Qt Implementation of selecting items from list into other list (Dual List, Accumulator, List builder, TwoListSelection ...) 【发布时间】:2018-01-18 17:56:50 【问题描述】:我想从任意长度的列表中选择任意数量的项目。 下拉列表 (QComboBox) 不允许检查项目。可检查的项目列表会因为项目太多而变得笨拙。
我在 User Experience SE 子站点中找到了 this question,this answer 似乎是最适合我需求的解决方案。它有很多名字,正如所说的答案评论中的评论:Dual List, Accumulator, List builder, TwoListSelection ...
上面链接的答案中显示的来自OpenFaces.org 的版本:
不过,我在 Qt 中找不到实现。我应该自己实现它还是 Qt 中有可用的实现?有推荐的方法吗?
【问题讨论】:
对 Qt 示例进行调查...我在一个示例中看到过这种情况.. 实在想不起来是哪个! 在问这个问题之前完成它。找不到类似的东西。你还记得这个例子吗?也许我错过了。 您可以从左侧 QListWidget 获取当前项目并使用 addItem(new QListWidgetItem()) 添加右侧,您可以从其他 QListWidgetItem 创建 QListWidgetItem。如果要从左侧取出所有项目,可以使用 while(ui->leftList->count() > 0) and take a item from a index,有什么问题? @Taz742,这似乎是一种常见的模式,不想重新发明***。我将自己实现它并将其添加为我和其他人将来参考的答案。谢谢! 如果您有任何问题,我在这里。我已经为自己做了确切的事情。 【参考方案1】:这个小部件在Qt中默认没有,但是构建它并不复杂,首先你应该列出需求:
如果左侧列表不为空,则启用带有文本>>的按钮,如果按下它必须移动所有项目。
带有文本的按钮与上一个类似,但右侧有列表
如果左侧列表中的项目被选中,则带有文本 > 的按钮被启用,如果按下,则所选项目应移动到右侧。
带有文本的按钮相同,但在右侧。
如果选择了一个项目并且这不是列表中的第一项,则启用带有“向上”文本的按钮。按下时,您必须将当前项目移动到更高的位置。
如果选择了一个项目并且这不是列表中的最后一个项目,则会启用带有“向下”文本的按钮。按下时,您必须将当前项目移动到较低的位置。
正如我们所见,大部分逻辑取决于项目的选择,为此我们将信号 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):QWidgetparent
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你会找到一个完整的例子。
【讨论】:
+ 这是一个很好的例子,但从 cmets 看来,他自己也想这样做。 我尝试编译它(在 Qt Creator 和 qmake && make 中)并且它引发了太多错误来修复我自己。但理论上它与我最终做的非常相似,所以 +1 并接受了。 @Alechan 你的 Qt 版本是什么? @eyllanesc,QMake 3.0 版。在 /usr/lib/x86_64-linux-gnu 中使用 Qt 5.2.1 版 它的 Qt 版本很老,从 5.6 或 5.7 Qt 开始支持 C++ 11,您可以使用新的连接方式:wiki.qt.io/New_Signal_Slot_Syntax,以及其他功能。这就是为什么它与其版本不兼容的原因。我已经用 Qt 5.10 对其进行了测试,但我认为它与 Qt 5.7 向前兼容。如果我有时间,我会支持以前的版本。以上是关于Qt实现从列表中选择项目到其他列表(双列表,累加器,列表生成器,TwoListSelection ...)的主要内容,如果未能解决你的问题,请参考以下文章