QListWidget с пользовательскими виджетами - не вызывает сигнал itemClicked

У меня есть listwidgetitem, которые имеют собственный виджет (step_widget), который содержит 3 QPushButton и QLabel. Когда я нажимаю одну из кнопок в виджете, это не вызывает itemClicked, который мне нужен, чтобы увидеть индекс списка виджетов, который был нажат. Если я нажимаю QLabel, сигнал срабатывает, и я могу получить индекс. Как можно вызвать сигнал, когда нажата одна из кнопок? Почему не срабатывает?

QListWidgetItem *item = new QListWidgetItem();
stepWidget *step_widget = new stepWidget();
ui->listWidget->addItem(item);
ui->listWidget->setItemWidget(item,step_widget);

1 ответ

itemClicked() сигнал не излучается, потому что QPushButton потребляет событие click.
Есть самое простое решение, которое я нашел.
Во-первых, в вашем классе stepWidget добавить сигнал, который будет издаваться, когда любой QPushButton по щелчку, например:

signals:
    void widgetClicked();

Затем подключите clicked() сигнал каждого QPushButton с этим сигналом. Этот код находится в конструкторе виджета stepWidget:

connect(ui->pushButton1, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton2, &QPushButton::clicked, this, &stepWidget::widgetClicked);
connect(ui->pushButton3, &QPushButton::clicked, this, &stepWidget::widgetClicked);

Чтобы проверить это, я добавил 10 виджетов в QListWidget которые проживают в MainWindow учебный класс. Вы должны подключить этот сигнал к слоту (в данном случае я использую лямбда-функцию C++11, но вместо этого вы можете создать слот), где вы устанавливаете текущий элемент как элемент под виджетом. Этот код находится в конструкторе MainWindow:

for (int i = 0; i < 10; ++i) {
    QListWidgetItem *item = new QListWidgetItem;
    stepWidget *step_Widget = new stepWidget;
    ui->listWidget->addItem(item);
    ui->listWidget->setItemWidget(item, step_Widget);
    connect(step_Widget, &stepWidget::widgetClicked, [=]() {
        ui->listWidget->setCurrentItem(item);
    });
}

Теперь это не сделает itemClicked() сигнал, который будет издан, потому что пользователь не нажал на элемент. Но я советую вам подключить вместо сигнала currentRowChanged() так как он будет выдан с этим кодом, а также имеет то преимущество, что позволяет напрямую получить строку. Если у вас есть строка, вы можете получить элемент и виджет, очевидно.
Однако эта процедура неудобна тем, что currentRowChanged() сигнал будет издаваться, даже когда пользователь выбирает строку с помощью клавиатуры или когда пользователь нажимает и перемещает мышь над QListWidget не отпуская это.
Обходным решением может быть, например, использование флага в качестве атрибута для вашего MainWindow класс, который всегда false кроме как во время этой связи:

connect(ste_pWidget, &stepWidget ::widgetClicked, [=]() {
    buttonPressed = true;
    ui->listWidget->setCurrentItem(item);
    buttonPressed = false;
});

Затем вы должны манипулировать двумя сигналами от QListWidget: clicked() а также currentRowChanged(), я выбираю clicked() вместо itemClicked() потому что это дает почти прямой доступ к строке:

void MainWindow::on_listWidget_clicked(const QModelIndex &index)
{
    ui->statusBar->showMessage(tr("Row clicked: %1").arg(index.row()), 1000);
}

void MainWindow::on_listWidget_currentRowChanged(int currentRow)
{
    if (buttonPressed) {
        ui->statusBar->showMessage(tr("Row clicked: %1").arg(currentRow), 1000);
    }
}

Вы можете просто сделать qpushbutton на qlabel, и тогда qpushbutton станет интерактивным. Затем вы можете переопределить этот метод:- on_listWidget_itemClicked(QListWidgetItem *item) для двойного щелчка по qpushbutton. Я попробовал, и он работал отлично, это довольно простой способ решения проблемы.

Другие вопросы по тегам