将参数传递给qt5c++中的槽

Passing arguments to a slot in qt5 c++

本文关键字:qt5c++ 参数传递      更新时间:2023-10-16

我正在c++ qt中创建一个ToDo列表应用程序。当一个加号按钮被按下时,它会添加一个包含QLabel和QToolButton的QHBoxLayout到我的gui中的垂直布局,所以我得到了带有'ToDos'的新框,以及在它们旁边删除它们的按钮。我已经在我的插槽内设置了各种小部件,当单击添加按钮时调用。但是,我需要将它们作为参数传递给插槽,当按下remove按钮时调用该插槽。我已经研究过了,所有我找到的是QSignalMapper。然而,我找不到任何足够接近我的案例来复制,我读过它只适用于某些参数,而不是我需要的三个(QHBoxLayout, QLineEdit和QToolButton)。当'add'按钮被按下时调用的插槽的一些代码如下:

//Creates a read only LineEdit which the user will add
   QLineEdit *toDoBox = new QLineEdit(this);
   toDoBox->setText(ui->lineEdit->text());
   toDoBox->setReadOnly(true);
   //Creates a new X button for removal of ToDo's
    QToolButton *removeButton = new QToolButton;
    removeButton->setText("X");
    //Adds a horizontal layout with the ToDo and the remove button in it, to keep them together
    QHBoxLayout *toDoLayout = new QHBoxLayout;
    toDoLayout->addWidget(toDoBox);
    toDoLayout->addWidget(removeButton);
    //Removes a ToDo when the remove button is clicked
    connect(removeButton, SIGNAL(clicked()), this, SLOT(on_removeButton_clicked()));

我的代码是托管在GitHub上,如果你想看到整个项目:https://github.com/DanWilkes02/ToDoList

谢谢你的耐心-我很难解释的事情是如此清楚在我的头脑!

如果我理解你的问题,你想要得到分配的对象,代表一个todo为了释放它们和更新你的视图。

你可以通过简单地包装你的QLineEdit, QToolButton和QHBoxLayout对象到一个类中,并在你的ToDoList类中使用一个容器(例如一个向量)来实现这一点。这样,每次你按下on_toolButton_clicked方法时,你都会把你的"todo object"推回去。

然后,你只需要使用一个带有索引的信号触发on_delete_todo插槽,从你的向量中删除一个"todo对象"并更新视图。

另外,看看这个Qt模型视图编程

下面是一个示例(在QT5下测试和工作):

您的Todo小部件

#ifndef TODOVIEW_H
#define TODOVIEW_H
#include <QString>
class QLineEdit;
class QToolButton;
class QHBoxLayout;
#include <QWidget>
class TodoView : public QWidget
{
    Q_OBJECT
private:
    QLineEdit*      frame;
    QToolButton*    removeButton;
    QHBoxLayout*    toDoLayout;
    int             index;
public:
    TodoView(const QString& what, int index, QWidget* parent);
    ~TodoView();
    inline void setIndex(int i) { index = i; }
    inline int getIndex(){ return index; }
private slots:
    void emitIndex();
signals:
    void selectedIndex(int);
};
#endif // TODOVIEW_H

#include "todoview.h"
#include <QLineEdit>
#include <QToolButton>
#include <QHBoxLayout>
TodoView::TodoView(const QString& what, int index, QWidget* parent) : QWidget(parent), index(index)
{
    frame = new QLineEdit(this);
    frame->setText(what);
    frame->setReadOnly(true);
    removeButton = new QToolButton(this);
    removeButton->setText("X");
    toDoLayout = new QHBoxLayout(this);
    toDoLayout->addWidget(frame);
    toDoLayout->addWidget(removeButton);
    connect(removeButton, SIGNAL(clicked()), this, SLOT(emitIndex()));
}
TodoView::~TodoView() {}
void TodoView::emitIndex()
{
    emit selectedIndex(getIndex());
}

你的主窗口

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <vector>
class TodoView;
class QVBoxLayout;
namespace Ui {
    class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void addTodo();
    void delTodo(int);
private:
    Ui::MainWindow*         ui;
    QVBoxLayout*            vBoxLayout;
    std::vector<TodoView*>  todoView;
    int                     max = -1;
};
#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "todoview.h"
#include <QVBoxLayout>
#include <QAction>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    vBoxLayout = new QVBoxLayout(centralWidget());
    QAction* add = new QAction(ui->mainToolBar);
    ui->mainToolBar->addAction(add);
    connect(add, SIGNAL(triggered()), this, SLOT(addTodo()));
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::addTodo()
{
    if(max > 9)
    {
        // Error msg.
    }
    else
    {
        TodoView* tdV = new TodoView("Yolo", max, centralWidget());
        connect(tdV, SIGNAL(selectedIndex(int)), this, SLOT(delTodo(int)));
        vBoxLayout->addWidget(tdV);
        todoView.push_back(tdV);
        ++max;
    }
}

void MainWindow::delTodo(int i)
{
    // check if i < todoView.size().
    delete todoView.at(i);
    // update vector indexes !!!
    --max;
}

我快速编辑了这段代码,我可能犯了几个错误,但你至少有一个解决方案的想法。

也可以为向量使用固定大小(更好的解决方案)。将TodoView已删除的对象设置为矢量中的nullptr,并在想要添加新的Todo视图组件时搜索nullptr:

在MainWindow构造函数中

todoView.reserve(10);
for(std::size_t i = 0; i < 10; ++i)
{
    todoView[i] = nullptr;
}

addTodo槽

// Do not use push back.
// retrieve the max index.
// if < 10
for(std::size_t i = 0; i < todoView.size(); ++i)
{
    if(todoView[i] == nullptr)
    {
        // allocate TodoView and affect it to the i° element
    }
}

delTodo槽

delete todoView[i];
todoView[i] = nullptr;

使用一对向量也是可能的(一对int TodoView)。

我可以想到两种方法。

  1. 使用QObject::sender() .
  2. 使用QSignalMapper

QObject::sender()

这个静态方法返回发出信号的发送方对象的QObject *。在这个例子中是QToolButton,所以你可以使用这个引用来找到它的父节点(即QHBoxLayout)和它的兄弟节点(即QLineEdit)。


QSingalMapper

首先定义一个列表用于保存对所有行的引用,然后为每一行分配一个唯一的标识符(例如行号),然后根据官方文档的示例使用此标识符作为每个按钮的QSignalMapper键。现在,如果用户单击一个按钮,在您的插槽中,您将获得相同的标识符,使用它并在行列表中查找整行。