QT: выберите несколько элементов QTableWidgetItem из кода с помощью QMouseEvent

это мой первый вопрос в stackoverflow, но вы мне не в первый раз помогаете (надеюсь, сможете).

Во-первых, я должен упомянуть, что у меня нет такого опыта работы с C++, особенно с QT, где моя проблема. У меня проблема с публикацией (или отправкой) QMouseEvents из кода в QTableWidget. Я хочу отправить несколько кликов в MultiSelect QTableWidget, и я ожидаю, что щелкнутые QTableWidgetItems будут выбраны впоследствии.

Чтобы воспроизвести проблему, я создал небольшой образец. Есть кнопка, которая отправляет «клики» в QTableWidget (в моем реальном приложении это запускается сетью). При нажатии кнопки выполняются два «щелчка» (я также вижу это в отладчике), но впоследствии выбирается только первый щелкнутый TableWidgetItem. Я не могу понять, почему второй элемент не выбран. Я надеюсь, что кто-то из вас может :-). Я очень ценю вашу помощь!

Вот пример кода:

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QTableWidgetExamples w;
    w.show();
    return a.exec();
}

QTableWidgetExample.h:

#ifndef QTABLEWIDGETEXAMPLES_H
#define QTABLEWIDGETEXAMPLES_H

#include <QtGui/QMainWindow>
#include "ui_qtablewidgetexamples.h"

QT_BEGIN_NAMESPACE  // QT_BEGIN_NAMESPACE / QT_END_NAMESPACE are not needed in Qt user code
class QTableWidget; //forward declaration
class QTableWidgetItem; //forward declaration
QT_END_NAMESPACE

class QTableWidgetExamples : public QMainWindow
{
    Q_OBJECT

public:
    QTableWidgetExamples(QWidget *parent = 0, Qt::WFlags flags = 0);
    ~QTableWidgetExamples();

private:
    Ui::QTableWidgetExamplesClass _ui;
    QTableWidget* _tableWidget;
    void clickItemFromCode(int index);

public slots:
    void btnClicked();
    void onItemClick(QTableWidgetItem* item);
};

#endif // QTABLEWIDGETEXAMPLES_H

QTableWidgetExample.cpp:

#include <QTableWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QMouseEvent>
//#include <QTest>
#include "qtablewidgetexamples.h"

QTableWidgetExamples::QTableWidgetExamples(QWidget *parent, Qt::WFlags flags)
    : QMainWindow(parent, flags)
{
    _ui.setupUi(this);
    QVBoxLayout *vlay = new QVBoxLayout(this);

    _tableWidget = new QTableWidget(3,1,this);
    _tableWidget->verticalHeader()->hide();
    _tableWidget->horizontalHeader()->hide();
    _tableWidget->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection);
    _tableWidget->setObjectName("list_1");
    _tableWidget->setItem(0, 0, new QTableWidgetItem("Item_0"));
    _tableWidget->setItem(1, 0, new QTableWidgetItem("Item_1"));
    _tableWidget->setItem(2, 0, new QTableWidgetItem("Item_2"));
    connect(_tableWidget, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(onItemClick(QTableWidgetItem*)));

    QPushButton *btn1 = new QPushButton("btn1");
    connect(btn1, SIGNAL(clicked()), this, SLOT(btnClicked()));

    vlay->addWidget(_tableWidget);
    vlay->addWidget(btn1);

    QWidget * wdg = new QWidget(this);
    wdg->setLayout(vlay);
    setCentralWidget(wdg);
}

QTableWidgetExamples::~QTableWidgetExamples() {}

void QTableWidgetExamples::onItemClick(QTableWidgetItem *item)
{
    bool isSel = item->isSelected();
    QString text = item->text();
}

void QTableWidgetExamples::btnClicked()
{
    clickItemFromCode(1);
    clickItemFromCode(2);   
}

void QTableWidgetExamples::clickItemFromCode(int rowIndex)
{
    float subX, subY;
    subX = subY = 0.5;

    QModelIndex index = _tableWidget->model()->index(rowIndex, 0);
    QRect rc = _tableWidget->visualRect(index); // view()->visualRect(index);
    QPoint pt(rc.x()+rc.width()*subX,rc.y()+rc.height()*subY);

    // just for debug purposes
    QTableWidgetItem* item = _tableWidget->item(rowIndex,0);
    QString itemText = item->text();

    QWidget *widget = (QWidget*) _tableWidget; //view();
    widget = widget->childAt(10,10);

    QEvent *e = QMouseEvent::createExtendedMouseEvent(QEvent::MouseMove,
            pt,widget->mapToGlobal(pt), Qt::LeftButton,Qt::LeftButton,0);
    QApplication::sendEvent(widget, e);

    e = QMouseEvent::createExtendedMouseEvent(QEvent::MouseButtonPress,
            pt,widget->mapToGlobal(pt), Qt::LeftButton,Qt::LeftButton,0);
    QApplication::sendEvent(widget, e);

    e = QMouseEvent::createExtendedMouseEvent(QEvent::MouseButtonRelease,
            pt,widget->mapToGlobal(pt), Qt::LeftButton,Qt::LeftButton,0);
    QApplication::sendEvent(widget, e);

    //QApplication::sendPostedEvents();
}

Отредактируйте самый широкий ответ:

К сожалению, это жесткое требование. Я ввожу свой код в другое приложение, где я читаю несколько из этих QTableWidget и отправляю их через TCP в свое приложение. Пока это работает хорошо. Теперь мне нужно изменить эти выборы из моего приложения, и это проблема. Мой предпочтительный вариант - сделать это с помощью щелчков мыши. Целью этого является то, что затем он ведет себя так, как будто пользователь работает в этом приложении (но кажется, что это не так). Но если у вас есть другая идея, я попробую. Может быть, есть что-то лучше, что еще не пришло мне в голову.


person Jack    schedule 15.05.2014    source источник
comment
Есть ли жесткое требование, чтобы вы имитировали щелчки мыши? Или вы просто пытаетесь установить эти элементы как выбранные?   -  person mbroadst    schedule 15.05.2014
comment
Спасибо за ответ, mbroadst. Я обновил свой вопрос.   -  person Jack    schedule 15.05.2014


Ответы (2)


Вы можете использовать QTableWidgetItem::setSelected(), чтобы программно выберите предмет. Таким образом, ваш код будет выглядеть так:

void QTableWidgetExamples::clickItemFromCode(int rowIndex)
{
    QTableWidgetItem *item = tableWidget->item(rowIndex, 0);
    item->setSelected(true);
}

Или, если вам действительно нужно имитировать щелчок мыши, тогда:

// NOTE: I haven't explicitly tested this, but its the general idea
void QTableWidgetExamples::clickItemFromCode(int rowIndex)
{
    QTableWidgetItem *item = tableWidget->item(rowIndex, 0);
    QRect visualItemRect = tableWidget->visualRectItem(item);

    QMouseEvent *event = new QMouseEvent(QEvent::MouseButtonRelease, visualItemRect.center(),     
                                         Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QCoreApplication::sendEvent(tableWidget, event);
}
person mbroadst    schedule 15.05.2014
comment
Еще раз спасибо за ваш ответ. Первое решение, которое программно устанавливает selectedItems, работает. Второй к сожалению нет. Поскольку он не скомпилировался, я редактирую строку, которая получает QRect, на: QRect visualRectItem = tableWidget->visualRectItem(item); - person Jack; 16.05.2014
comment
Я обновил второй пример, это все, что вам нужно было сделать, чтобы он заработал? Я тут ленивый :) - person mbroadst; 16.05.2014
comment
Нет, тогда он просто компилируется, но я смог заставить его работать. В моем примере QEvent::MouseMove не был настроен должным образом. Я опубликую свой рабочий код позже. Есть еще одна проблема, что Мышь не перемещается в эту позицию. Я имею в виду, что когда я нажимаю кнопку, я ожидаю, что мышь переместится к элементу, на который нажали, но это еще не так. - person Jack; 16.05.2014

Наконец я получил рабочее решение:

QEvent::MouseMove не был настроен должным образом.

вот исправленный. После обмена пример кода делает то, что должен делать.

QEvent *e = QMouseEvent::createExtendedMouseEvent(QEvent::MouseMove,
            pt,widget->mapToGlobal(pt), Qt::NoButton, Qt::RightButton, Qt::NoModifier);
QApplication::postEvent(widget, e);

Если вам не нужно имитировать щелчки мыши, первый подход @mbroadst (установить выбранные элементы программно), вероятно, будет лучшим выбором (спасибо за это).

person Jack    schedule 16.05.2014