Frage

it's my first question here on stackoverflow, but not the first time you help me out (I hope you can).

First I have to mention that I'm not that experienced with C++, especially with QT, where my problem is about. I have a problem with posting (or sending) QMouseEvents from code to a QTableWidget. I want to send multiple clicks to an MultiSelect QTableWidget and I expect, the clicked QTableWidgetItems are selected afterwards.

To reproduce the problem, I created a small sample. There is a button that sends the "clicks" to the QTableWidget (in my real app this is triggered by network). When the button is clicked, two "clicks" are executed (I also see that in the debugger), but only the first clicked TableWidgetItem is selected afterwards. I can't figure out why the second item doesn't get selected. I hope someone of you can :-). I really appreciate your help!

Here the sample code:

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();
}

Edit to mbroadst answer:

Unfortunately it's a hard requirement. I inject my code into another application, where I read several of those QTableWidgets and send them via TCP to my application. That is working well, so far. Now I need to change those selections from my app and that's the problem. My preferred option is to do it with Mouse clicks. The intention behind that is that it then behaves as if a user is working in that application (but it seems that it isn't the case). But if you you have another idea, I'll give it a try. Maybe there's something better, that didn't came to my mind yet.

War es hilfreich?

Lösung 2

Finally I got a working solution:

The QEvent::MouseMove wasn't set up properly.

here is the corrected one. After exchanging this, the sample code does what it is supposed to do.

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

If you don't need to simulate mouse clicks, the first approach of @mbroadst (set selected items programmatically) would probably the better choice (thx for that).

Andere Tipps

You can use QTableWidgetItem::setSelected() in order to programmatically select an item. So your code would look like:

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

Or, if you really need to simulate a mouse click then:

// 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);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top