链接两个QListWidget

时间:2016-11-03 14:08:06

标签: c++ qt

我想链接两个QListWidget,但我不知道如何处理代码。这是我做的: Help 我们可以看到两个QListWidget。使用左侧QListWidget,我添加(通过示例:“Bonjour”,“Hello”,“Tag”)三个QListWidgetItem。我希望如果我点击左侧QListWidget的三个QListWidgetItem中的一个,我可以使用正确的QListWidget添加QListWidgetItem(例如,对于“Bonjour”:“Tu”,“Vas”,“Bien”)。如果我没有点击三个QListWidgetItem中的一个,我就无法使用正确的QListWidget添加QListWidgetItem。如果我为“Bonjour”做了:“Tu”,“Vas”,“Bien”,我点击“Hello”(显然,“Hello”不包含任何内容),右边的QListWidget中没有任何内容。这只是我想要做的一个例子。下面,如果它有用,我会编写我的代码:

- secondwindow.cpp -

#include "secondwindow.h"
#include "ui_secondwindow.h"
#include "thirdwindow.h"
#include "ui_thirdwindow.h"

SecondWindow::SecondWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::SecondWindow)
{
    ui->setupUi(this);
    ui->button_1->setIcon(QIcon(":/Images/Images/Haut.png"));
    ui->button_2->setIcon(QIcon(":/Images/Images/Bas.png"));
    ui->button_5->setIcon(QIcon(":/Images/Images/Haut.png"));
    ui->button_6->setIcon(QIcon(":/Images/Images/Bas.png"));

    connect(ui->button_1, SIGNAL(clicked()), this, SLOT(UpForLeft()));
    connect(ui->button_2, SIGNAL(clicked()), this, SLOT(DownForLeft()));
    connect(ui->button_3, SIGNAL(clicked()), this, SLOT(DeleteForLeft()));
    connect(ui->button_4, SIGNAL(clicked()), this, SLOT(AddForLeft()));
    connect(ui->button_9, SIGNAL(clicked()), this, SLOT(ShowThirdWindow()));
    connect(ui->button_10, SIGNAL(clicked()), this, SLOT(close()));
    connect(ui->table_1, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
    this, SLOT(EditForLeft(QListWidgetItem *)));
}

SecondWindow::~SecondWindow()
{
    delete ui;
}

void    SecondWindow::ShowThirdWindow()
{
    ThirdWindow *window = new ThirdWindow;

    window->setWindowTitle("B");
    window->setWindowIcon(QIcon(":/Images/Images/Bouclier.png"));
    window->setFixedSize(820, 440);
    window->show();
}

void SecondWindow::UpForLeft()
{
    QListWidgetItem *item;
    int i;

    i = ui->table_1->currentRow();
    item = ui->table_1->takeItem(i);
    ui->table_1->insertItem(i - 1, item);
    ui->table_1->setCurrentRow(i - 1);
}

void SecondWindow::DownForLeft()
{
    QListWidgetItem *item;
    int i;

    i = ui->table_1->currentRow();
    item = ui->table_1->takeItem(i);
    ui->table_1->insertItem(i + 1, item);
    ui->table_1->setCurrentRow(i + 1);
}

void SecondWindow::UpForRight()
{
    QListWidgetItem *item;
    int i;

    i = ui->table_2->currentRow();
    item = ui->table_2->takeItem(i);
    ui->table_1->insertItem(i - 1, item);
    ui->table_1->setCurrentRow(i - 1);
}

void SecondWindow::DownForRight()
{
    QListWidgetItem *item;
    int i;

    i = ui->table_2->currentRow();
    item = ui->table_2->takeItem(i);
    ui->table_1->insertItem(i + 1, item);
    ui->table_1->setCurrentRow(i + 1);
}

void SecondWindow::AddForLeft()
{
    QString string;

    string = ui->line_1->text();
    ui->table_1->addItem(string);
    ui->line_1->clear();
}

void SecondWindow::DeleteForLeft()
{
    QListWidgetItem *item;
    int i;

    i = ui->table_1->currentRow();
    item = ui->table_1->takeItem(i);
    delete item;
}

void SecondWindow::EditForLeft(QListWidgetItem *item)
{
    item->setFlags(item->flags() | Qt::ItemIsEditable);
    item = ui->table_1->currentItem();
    ui->table_1->editItem(item);
}

- secondwindow.h -

#ifndef SECONDWINDOW_H
#define SECONDWINDOW_H

#include <QListWidgetItem>
#include <QWidget>
#include <QString>
#include <QIcon>
#include "thirdwindow.h"
#include "ui_thirdwindow.h"

namespace Ui {
class SecondWindow;
}

class SecondWindow : public QWidget
{
    Q_OBJECT

public:
    explicit SecondWindow(QWidget *parent = 0);
    ~SecondWindow();

public slots:
    void ShowThirdWindow();
    void UpForLeft();
    void DownForLeft();
    void UpForRight();
    void DownForRight();
    void AddForLeft();
    void DeleteForLeft();
    void EditForLeft(QListWidgetItem *item);

private:
    Ui::SecondWindow *ui;
    ThirdWindow *window;
};

#endif // SECONDWINDOW_H

感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

QListWidget是一个方便的小部件,它将模型与视图混合在一起。这使得事情变得有点困难,因为您需要使用来自代表树结构数据的顶级模型的数据来补充模型。

相反,您可以使用QStandardItemModel,并通过QListView公开它。视图仅显示树的给定级别的一列,没有任何子级。要查看子项,请选择适当的根索引。

QStandardItemModel的关键缺失功能是moveRows,需要上下移动项目。这很容易通过支持在同一父项中移动单个项目的有限实现来补救。因此,通过使用moveRow,视图可以完全与模型无关。我们将首先实施moveRows

// https://github.com/KubaO/stackoverflown/tree/master/questions/list-widgets-40403640
#include <QtWidgets>

class StandardItemModel : public QStandardItemModel {
   bool moveRows(const QModelIndex &srcParent, int srcRow, int count,
                 const QModelIndex &dstParent, int dstRow) override {
      if (count == 0) return true;
      if (count != 1 || srcParent != dstParent) return false;
      if (srcRow == dstRow) return true;
      if (abs(srcRow - dstRow) != 1) return false;
      auto root = srcParent.isValid() ? itemFromIndex(srcParent) : invisibleRootItem();
      if (!root) return false;
      auto srcItem = root->takeChild(srcRow);
      auto dstItem = root->takeChild(dstRow);
      if (!srcItem || !dstItem) return false;
      root->setChild(srcRow, dstItem);
      root->setChild(dstRow, srcItem);
      return true;
   }
public:
   using QStandardItemModel::QStandardItemModel;
};

随后,ListUi窗口小部件实现了视图,而不知道模型的工作方式。出于此示例的目的,新项目就地编辑,而不是使用单独的控件。

The appearance of ListUi widget.

class ListUi : public QWidget {
   Q_OBJECT
   QGridLayout m_layout{this};
   QVBoxLayout m_column;
   QPushButton m_up{"⬆"}, m_down{"⬇"}, m_remove{"−"}, m_add{"+"};
   QLabel m_caption;
   QListView m_list;
   inline QAbstractItemModel * model() const { return m_list.model(); }
   inline QModelIndex root() const { return m_list.rootIndex(); }
   inline QModelIndex index(int row) const { return model()->index(row, 0, root()); }
public:
   ListUi(const QString & caption, QWidget * parent = nullptr) :
      QWidget{parent},
      m_caption{caption}
   {
      m_layout.addWidget(&m_up, 0, 0);
      m_layout.addWidget(&m_down, 1, 0, 1, 1, Qt::AlignTop);
      m_layout.addLayout(&m_column, 0, 1, 3, 1);
      m_column.addWidget(&m_caption);
      m_column.addWidget(&m_list);
      m_layout.addWidget(&m_remove, 0, 2);
      m_layout.addWidget(&m_add, 2, 2);
      m_caption.setAlignment(Qt::AlignCenter);
      connect(&m_add, &QPushButton::clicked, [this]{
         int row = model()->rowCount(root());
         if (model()->columnCount(root()) == 0)
            model()->insertColumn(0, root());
         if (model()->insertRow(row, root())) {
            m_list.setCurrentIndex(index(row));
            m_list.edit(index(row));
         }
      });
      connect(&m_remove, &QPushButton::clicked, [this]{
         if (m_list.currentIndex().isValid())
            model()->removeRow(m_list.currentIndex().row(), root());
      });
      connect(&m_up, &QPushButton::clicked, [this]{
         auto row = m_list.currentIndex().row();
         if (row > 0 && model()->moveRow(root(), row, root(), row - 1))
            m_list.setCurrentIndex(index(row-1));
      });
      connect(&m_down, &QPushButton::clicked, [this]{
         auto row = m_list.currentIndex().row();
         if (row >= 0 && row < (model()->rowCount(root()) - 1) &&
             model()->moveRow(root(), row, root(), row + 1))
            m_list.setCurrentIndex(index(row+1));
      });
   }
   void setModel(QAbstractItemModel * model) {
      m_list.setModel(model);
      connect(m_list.selectionModel(), &QItemSelectionModel::currentChanged, this, &ListUi::currentIndexChanged);
   }
   void setRootIndex(const QModelIndex & index) {
      m_list.setRootIndex(index);
   }
   Q_SIGNAL void currentIndexChanged(const QModelIndex &);
};

一个简单的测试工具实例化两个ListUi,一个StandardItemModel,从JSON源填充模型,并链接它们以获得所需的功能。

class Window : public QWidget {
   Q_OBJECT
   QGridLayout m_layout{this};
   ListUi m_programs{"Liste des programmes"};
   ListUi m_sessions{"Liste des sessions"};
   QPushButton m_generate{"Générer les données"};
   StandardItemModel m_model;
public:
   explicit Window(QWidget * parent = nullptr) : QWidget{parent}
   {
      m_layout.addWidget(&m_programs, 0, 0);
      m_layout.addWidget(&m_sessions, 0, 1);
      m_layout.addWidget(&m_generate, 1, 1, 1, 1, Qt::AlignRight);
      m_programs.setModel(&m_model);
      m_sessions.setModel(&m_model);
      m_sessions.setDisabled(true);
      connect(&m_programs, &ListUi::currentIndexChanged, [this](const QModelIndex & root){
         m_sessions.setEnabled(true);
         m_sessions.setRootIndex(root);
      });
      connect(&m_generate, &QPushButton::clicked, this, &Window::generateData);
   }
   Q_SIGNAL void generateData();
   void setJson(const QJsonDocument & doc) {
      m_model.clear();
      auto object = doc.object();
      for (auto it = object.begin(); it != object.end(); ++it) {
         if (!m_model.columnCount()) m_model.appendColumn({});
         auto root = new QStandardItem(it.key());
         m_model.appendRow(root);
         if (it.value().isArray()) {
            auto array = it.value().toArray();
            for (auto const & value : array) {
               if (!root->columnCount()) root->appendColumn({});
               root->appendRow(new QStandardItem{value.toString()});
            }
         }
      }
   }
};

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   auto json = R"--({
               "Foo":["Foo-1", "Foo-2", "Foo-3"],
               "Bar":["Bar-1", "Bar-2"]
               })--";
   Window ui;
   ui.connect(&ui, &Window::generateData, [&]{ ui.setJson(QJsonDocument::fromJson(json)); });
   ui.show();
   return app.exec();
}

#include "main.moc"

迭代标准项模型以重新生成JSON表示是一件简单的事情。

示例结束。