QListWidget doesn't recognize signals from QTest::mouseDClick - qt

I am trying to use QTest to test UI interactions with a QListWidget.
Interactions made from a simple click work fine (QTest::mouseClick()) but interactions from a double click do not (QTest::mouseDClick()).
Here is simplified code sample to reproduce the issue :
Dialog.h
class UILIBSHARED_EXPORT Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
int doubleClickCount = 0;
QString lastItemClicked = "";
QListWidget* GetListW();
private slots:
void on_listWidget_doubleClicked(const QModelIndex &index);
public:
Ui::Dialog *ui;
};
Dialog.cpp
QListWidget*Dialog::GetListW()
{
return ui->listWidget;
}
void Dialog::on_listWidget_doubleClicked(const QModelIndex &index)
{
lastItemClicked = ui->listWidget->item(index.row())->text();
++doubleClickCount;
}
And the test class :
class DoubleClickTest : public QObject
{
Q_OBJECT
public:
DoubleClickTest();
private Q_SLOTS:
void testDoubleClick();
};
void DoubleClickTest::testDoubleClick()
{
Dialog dialog;
dialog.show();
QListWidgetItem* item = dialog.GetListW()->item(1);
QRect rect = dialog.GetListW()->visualItemRect(item);
QTest::mouseDClick(dialog.GetListW()->viewport(), Qt::LeftButton, Qt::KeyboardModifiers(), rect.center());
QCOMPARE(dialog.doubleClickCount, 1);
}
I checked the dialog manually and the slot is called as expected.

I know this is an old topic but I have encountered the same behaviour with a QTreeView and have passed some hours to find a workaround, so I think it can be useful for someone else.
Using QTest, the signal doubleClicked is never emitted due to a part of code in sources of Qt I do not understand (qtreeview.cpp, line 1934 with Qt 5.12.1, or for others, in qabstractitemview.cpp line 1952). I don't know if it is a bug or not.
To avoid this strange code, I just added a call to QTest::mouseClick before the call to QTest::mouseDClick with the same parameters.
It worked for me because my QTreeView do nothing particular on a simple click, but it can distort tests in another case.
If anyone has a better solution I take it !

Related

Qt - QLineEdit does not emit textChanged/textEdited Signal while QTextEdit does

Currently i am learning Qt in C++ and have following issue:
Connecting "textChanged" or "textEdited" with a slot does not work.
Header file:
#include ...
class PersonalPreferences : public QWidget
{
Q_OBJECT
public:
PersonalPreferences(QWidget *parent = nullptr);
public slots:
void make_available();
private:
...
};
Code file:
PersonalPreferences::PersonalPreferences(QWidget *parent) {
// Configuring Layout
connect(line_edit_name, SIGNAL(textEdited()), this, SLOT(make_available()));
}
make_available function:
void PersonalPreferences::make_available() {
label_name->setText("wadwad");
group_box_pref->setEnabled(true);
push_button_ok->setEnabled(true);
push_button_close->setEnabled(true);
}
Please notice that i intentionally reduced the code to it's significant parts and didn't include the main file. I tried the same code with and without the parameter make_available(const QString &text). Yet it does not change the outcome.
I also tried this
connect(line_edit_name, &QLineEdit::textEdited, this, &PersonalPreferences::make_available);
and still it did not work out.
I noticed that using QTextEdit instead of QLineEdit works, but nevertheless i need help to solve this issue with QLineEdit.
Thanks in advance!
you need to study the details carefully)
In QLineEdit, the signal is
void textChanged ()
In QTextEdit, the signal is
void textChanged (const QString & text)
then you need to make such an amendment
void make_available()
change to
void make_available(const QString & text)
and call
connect(line_edit_name, &QLineEdit::textEdited, this, &PersonalPreferences::make_available);
or
connect(line_edit_name, SIGNAL(textEdited()), this, SLOT(make_available()));
change to
connect(line_edit_name, SIGNAL(textEdited(QString)), this, SLOT(make_available(QString)));

QT signal with struct in parameter

I have the class :
class SupervisionManager : public QThread {
Q_OBJECT public:
explicit SupervisionManager(ComAds* com, ComRegEtat* comEt,
ComRegOrdonnanceur* comOrdo,
QObject *parent = 0);
~SupervisionManager();
protected:
virtual void run();
private:
void actionFromPlc();
ComRegEtat::Antichoc antichoc;
signals:
void majAntichoc(ComRegEtat::Antichoc&);
};
and the implementation:
void SupervisionManager::run() {
manage=true;
while(manage)
{
actionFromPlc();
usleep(5000);
}
}
void SupervisionManager::actionFromPlc() {
antichoc.SAS = false;
emit majAntichoc(antichoc);
}
And I connect this signal with :
connect(manager, SIGNAL(majAntichoc(ComRegEtat::Antichoc&)),
preparation, SLOT(affichageAntichoc(ComRegEtat::Antichoc&)));
How do to emit a signal with a struct in its parameter list?
I think I have to use a QSignalMapper but I don't understand how.
In absolutely same way as you emit other things..
ComRegEtat::Antichoc myStruct;
.. some initialisation code
emit majAntichoc(myStruct);
I dont know for sure about latest Qt (after they changed signals/slot be templates based), but before 'emit' was just empty define, so you should look on emit like on function call...
With my code, the slot isn't called whereas the signal is emitted.
I found the solution :
signals:
void majAntichoc(ComRegEtat::Antichoc *);
and
slot :
void affichageAntichoc(ComRegEtat::Antichoc *);
And I don't have to use a QSignalMapper.
Thanks

How do I connect slot to user defined variable in Qt?

Sorry if I'm missing something obvious, but I can't seem to find an answer to my question. Any help would be appreciated.
I am trying to use a QSlider to manipulate data in a class I created.
In the main window constructor I have the following:
connect(ui->horizontalSlider, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
With a slot defined in the same class:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
AFrame *frame;
Ui::MainWindow *ui;
public slots:
void setValue(int val)
{
frame->setMphValue(val);
}
};
My frame class is a promoted widget to allow for drawing over the image I have set and is defined as follows:
class AFrame : public QLabel
{
Q_OBJECT
public:
AFrame( QWidget *parent );
void setMphValue(int val) { m_mph = val; }
protected:
void paintEvent( QPaintEvent *event );
private:
int m_mph;
};
The problem is that when I try assigning the m_mph value in the paintEvent function of the AFrame class, the integer value is lost.
Is there something obvious that I'm missing? Is there a better way to approach this problem?
And my paintEvent code:
void AFrame::paintEvent(QPaintEvent *event)
{
QLabel::paintEvent(event);
QPainter painter(this);
QPen pen("#FF0099");
pen.setWidth(8);
painter.setPen(pen);
//rpm
painter.drawLine(250,275,165,165);
//oil
painter.drawLine(450,100,400,75);
//fuel
painter.drawLine(650,95,600,65);
//mph
QRect rec(0,0,125,3);
int velocity = m_mph;
int rpmStartVal = -225;
float mph = velocity * 1.68;
painter.translate(870,275);
painter.rotate(rpmStartVal + mph);
painter.drawRect(rec);
}
The integer value is not being lost. The widget has no magical insight into the fact that it should repaint when the mph value is updated. Your setMphValue should look like below. That's all there's to it.
void setMphValue(int val) {
m_mph = val;
update();
}
To add to Kuba's reply:
You should also check whether val is the same value as previous, in order to avoid avoid repainting when it's not actually necessary - and side-effect infinite loops should anything called by update() later touch setMphValue().
In full:
void setMphValue(int val) {
if (val == m_mph) return;
m_mph = val;
update();
}

Qt: TextEdit created by QStyledItemDelegate can't receive Escape key press event?

I have a QTableView to display a bunch of data, which is stored in a QAbstractTableModel. I also want to edit the data sometime, so I use a QStyledItemDelegate to create an editor (of QTextEdit type) when I double click on the cell. However, I want to handle the key Press event myself, but I never catch Key_Escape pressing in the Text Edit editor (Other keys such as Enter and Ascii can be captured). I checked the code, and found that Escape is directly connected to QTableView's closeEditor() function, which is a virtual method and is automatically invoked. As far as I know, key press event is the bottom layer of event handling, but it is not true with such case.
I do need to capture the Escape key press event so that I can handle it myself, can anyone tell me how to do this? Thanks!
I got the answer, and I think would help others:
Override QStyledItemDelegate::eventFilter() method:
MyItemDelegate::eventFilter(QObject* editor, QEvent* event)
{
if(event->type()==QEvent::KeyPress)
return false;
return QStyledItemDelegate::eventFilter(editor, event);
}
According to Qt's documentation, QStyledItemDelegate::eventFilter() returns true if the given editor is a valid QWidget and the given event is handled; otherwise returns false. Tab, Backtab, Enter, Return and Ecs are handled by default. So, if you want to handle the key press event yourself, you must let eventFilter return false when KeyPress event occurs. So that the editor's keyPressEvent() method will be invoked instead.
QStyledItemDelegate::eventFilter is not a possibility beacuse is virtual protected
In order to get the events you should subclass your own QEditLine and override ::keyPressEvent there. Take notice of the code. I pass actual row and colum of my QTableWidget cell in order to know what we are editing in the overrided QLineEditor.
//.h
class MyStyledItemDelegate : public QStyledItemDelegate
{
public:
MyStyledItemDelegate(QObject *parent = 0);
QWidget* createEditor(QWidget* parent,const QStyleOptionViewItem &option,const QModelIndex &index) const;
};
//.cpp
#include "mylineedit.h"
MyStyledItemDelegate::MyStyledItemDelegate(QObject *parent)
:QStyledItemDelegate(parent)
{
}
QWidget* MyStyledItemDelegate::createEditor(QWidget* parent,const QStyleOptionViewItem &option,const QModelIndex &index) const
{
MyLineEdit* editor = new MyLineEdit(parent,index.row(),index.column());
return editor;
}
/////////////////////////////////////////////////////////////
//My own QLineEdit
/////////////////////////////////////////////////////////////
//.h
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
int _nRow;
int _nCol;
public:
MyLineEdit(QWidget *parent = 0,int nRow=-1, int nCol=-1);
virtual void keyPressEvent(QKeyEvent* event);
signals:
void mySignal(const QVector<QVariant> &);
public slots:
};
//.cpp
MyLineEdit::MyLineEdit(QWidget *parent, int nRow,int nCol):
QLineEdit(parent)
{
_nRow=nRow;
_nCol=nCol;
}
/////////////////////////////////////////////////////////////////////////
void MyLineEdit::keyPressEvent(QKeyEvent* event)
{
qDebug() << "MyLineEdit::OnKeyPressEvent:"<<event->text()<< " row="<<_nRow<<" col=" <<_nCol;
///SET YOUR CODE HERE
QLineEdit::keyPressEvent(event);
}

Is it possible to emit a Qt signal from a const method?

In particular, I am implementing a QWizardPage ("MyWizardPage") for a QWizard, and I want to emit a signal ("sigLog") from my override of the QWizardPage::nextId virtual method.
Like so:
class MyWizardPage
: public QWizardPage
{
Q_OBJECT
public:
MyWizardPage();
virtual int nextId() const;
Q_SIGNALS:
void sigLog(QString text);
};
int MyWizardPage::nextId() const
{
Q_EMIT sigLog("Something interesting happened");
}
But when I try this, I get the following compile error on the Q_EMIT line:
Error 1 error C2662: 'MyWizardPage::sigLog' : cannot convert 'this' pointer from 'const MyWizardPage' to 'MyWizardPage &'
It is possible to emit a signal from a const method by adding "const" to the signal declaration, like so:
void sigLog(QString text) const;
I tested this and it does compile and run, even though you don't actually implement the signal as a normal method yourself (i.e. Qt is okay with it).
You may try to create another class , declare it as friend for your wizard page and add to wizard as a mutable member. after that you may emit it's signal instead of wizard's.
class ConstEmitter: public QObject
{
Q_OBJECT
...
friend class MyWizardPage;
Q_SIGNALS:
void sigLog(QString text);
};
class MyWizardPage
: public QWizardPage
{
Q_OBJECT
public:
MyWizardPage();
protected:
mutable CostEmitter m_emitter;
Q_SIGNALS:
void sigLog(QString text);
};
int MyWizardPage::nextId() const
{
Q_EMIT m_emitter.sigLog("Something interesting happened");
}
MyWizardPage::MyWizardPage()
{
connect(&m_emitter,SIGNAL(sigLog(QString)),this,SIGNAL(sigLog(QString)));
}
or you may just use
int MyWizardPage::nextId() const
{
Q_EMIT const_cast<MyWizardPage*>(this)->sigLog("Something interesting happened");
}
that is not recommended way, because const_cast is a hack, but it's much shorter :)

Resources