QRegExpValidator with QTextEdit - c++

Can QRegExpValidator be used with QTextEdit widget ?
I tried to implement through setValidator() and also set also the qtextedit as parent object. But its not working.

You should use
virtual QValidator::State QRegExpValidator::validate(QString & input, int & pos) const or bool QRegExp::exactMatch(const QString & str) const by yourself. It should not be hard, you just need to determine where to start validate.

You can do the following things
define another slot that will be called when textChanged() signal is
emitted
emit a signal with two parameters(data in qtextedit and
length of same data)
connect the validate() slot with the above slots

Related

Call QAbstractTableModel setData method from QML

I am trying to make a fully generic connection between the QML TableView and my C++ class that subclasses the QAbstractTableModel. So far I am able to read the data through data method, as this is done internally by the TableView module. From what I have read over SO however, I need to call setData myself on the QML side. The problem is, the function header looks as follows:
bool setData(const QModelIndex &index,
const QVariant &value,
int role = Qt::EditRole) override;
In order to call it, I need the QModelIndex, which I dont know how to obtain on the QML side. I would appreciate a QML example.
Edit: I have worked around this issue by wrapping the setData as follows:
Q_INVOKABLE bool setData(const int row,
const int column,
const QVariant& value);
bool CVarTableModel::setData(const int row,
const int column,
const QVariant& value)
{
return setData(index(row, column), value);
}
I can now call it directly on the QML side. The problem is, even though the actual setData is called now, the dataChanged signal doesnt make the QML TableView to update the cell... Is there anything else I am missing?
I can probably answer your edit. It seems like you might not be emitting dataChanged() signal in your setData function. This would explain why the view is not updated.
From QAbstractTableModel::setData() documentation:
The dataChanged() signal should be emitted if the data was successfully set.
Also, about your original question. You could use index method from the qml: model.setData(model.index(row,column), data) to avoid overriding setData.

QT connect a SIGNAL with fewer arguments than SLOT

I have this code:
QObject::connect(lineEdit_1, SIGNAL(textChanged(const QString &)), MainWindow, SLOT(myMethod(const QString &, QLineEdit* )) );
This code works correctly when myMethod has only the first argument (equal to the SIGNAL) but I need to pass a pointer lo lineEdit_1 in order to allow myMethod to know on which LineEdit it has to operate.
What I should to do?
Thanks a lot.
It is not necessary that you send as an additional argument the object that emits the signal for it, the QObjects have the sender() method that allows us to obtain that object:
QObject::connect(lineEdit_1, &QLineEdit::textChanged, MainWindow, &Your_Class::myMethod);
void Your_Class::MyMethod(const QString & text){
if(QLineEdit *le = qobject_cast<QLineEdit *>(sender())){
qDebug() << le;
}
}
If you need to pass other arguments you can use the lambda functions but always take the time to see the limitations (how to use it depends on the context):
QObject::connect(lineEdit_1, &QLineEdit::textChanged, [ /* & or = */](const QString & text){
MainWindow->MyMethod(text, another_arguments);
});

Qt Slots and Signals. Get Slot Receiver Object

I have a QLineEdit which I Want to connect to a QLabel so that depending on the validity of the text entered. I have two problems while doing this.
QLineEdit *text = new QLineEdit(this);
layout->addWidget(text, rowno, 0);
QLabel *button = new QLabel(this);
button->setStyleSheet("QLabel { background-color : green; color : white; }");
button->setAlignment(Qt::AlignCenter);
button->setText("OKAY");
QObject::connect(text, SIGNAL(textEdited(const QString &)), button, SLOT(CheckValidity(const QString &)));
this does not connect any changes made in QLineEdit to my custom slot. I cannot figure out why!
Also in the custom slot, I want to change the background colour of my label depending on the QString passed. How do I get a reference for the label? It is present as the receiver of the signal but I can't figure out a way to refer to it.
CheckValidity is not a QButton's slot, it's a custom slot defined in your own class (I assume that, since you have not specified it).
So, change the last line to:
QObject::connect(text, SIGNAL(textEdited(const QString &)), this, SLOT(CheckValidity(const QString &)));
If you want to know the sender object, use qobject_cast:
QLabel *sender_label = qobject_cast<QLabel*> (sender ());
There is no CheckValidity slot in QLabel (why button is QLabel?). Check output window of debugger after connection trying.
QObject::sender() + cast. Cast may be dynamic_cast or qobject_cast, look their difference in Qt Assistant.
If you want to supply additional arguments into your slot invocation, you can use lambda instead of a slot:
QObject::connect(text, &QLineEdit::textEdited, [=](const QString &text) { checkValidity(button, text); });

itemDoubleClicked signal is not emitted when mouseDoubleClickEvent is implemented

I'm implementing a class that inherits the QTreeWidget,
I'm trying to do something only when the user left-clicks on an item.
Since itemDoubleClicked only gives you the item and not the mouse event,
and mouseDoubleClickEvent only gives you the mouse event with no item,
so I thought I would add a member in the class and record whether left or right button was pressed in mouseDoubleClickEvent,
then check that info when entering the slot connected to signal itemDoubleClicked.
That is, if the signal is emitted after the event handler. I was planning on experimenting if this was true, but then I ran into this issue.
Ok, back to the class, it looks something like this:
class myTreeWidget : public QTreeWidget{
Q_OBJECT
private:
Qt::MouseButton m_button;
public:
myTreeWidget(QWidget* parent):QTreeWidget(parent){
m_button = Qt::NoButton;
connect(this, SIGNAL(itemDoubleClicked(QTreeWidgetItem*, int)),
this, SLOT(slot_doubleClick(QTreeWidgetItem*,int)));
}
void mouseDoubleClickEvent(QMouseEvent* event){
m_button = event->button();
}
public slots:
void slot_doubleClick(QTreeWidgetItem* item, int column);
signals:
void itemDoubleClicked(QTreeWidgetItem* item, int column);
}
Yep, something like this.
Then I used gdb to check which was called first,
mouseDoubleClickEvent or slot_doubleClick,
and it turns out that slot_doubleClick was not called at all.
I commented out mouseDoubleClickEvent and tried again,
and slot_doubleClick was called.
So um... what I'm asking here is...
is this a limitation in Qt?
Can I only choose one between signals&slots and event handlers?
Or am I just doing it wrong?
Moreover, if this is a limitation,
can you recommend another solution to what I'm trying to do?
(only respond to left double-clicks)
Sorry for the long post and thanks!
If you override some event handler and want also default behavior, you should call base handler implementation. For example try this:
void mouseDoubleClickEvent(QMouseEvent* event){
m_button = event->button();
QTreeWidget::mouseDoubleClickEvent(event);
}

How does QSignalMapper work?

After my post here : Associate signal and slot to a qcheckbox create dynamically I need to associate :
• The signal clicked() when I click on a qCheckBox to my function cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)
To do so, I have to use QSignalMapper, after two hours of trying to understand how it works, I can't have a good result, here's the code I make, this is obviously wrong :
QSignalMapper *m_sigmapper = new QSignalMapper(this);
QObject::connect(pCheckBox, SIGNAL(mapped(QTableWidget*,int, QCheckBox*)), pCheckBox, SIGNAL(clicked()));
QObject::connect(this, SIGNAL(clicked()), this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));
m_sigmapper->setMapping(pCheckBox, (monTab,ligne, pCheckBox));
QObject::connect(m_sigmapper, SIGNAL(clicked()),this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));
Can you explain to me, how QSignalMapper works ? I don't really understand what to associate with :(
QSignalMapper class collects a set of parameterless signals, and re-emits them with integer, string or widget parameters corresponding to the object that sent the signal. So you can have one like:
QSignalMapper * mapper = new QSignalMapper(this);
QObject::connect(mapper,SIGNAL(mapped(QWidget *)),this,SLOT(mySlot(QWidget *)));
For each of your buttons you can connect the clicked() signal to the map() slot of QSignalMapper and add a mapping using setMapping so that when clicked() is signaled from a button, the signal mapped(QWidget *) is emitted:
QPushButton * but = new QPushButton(this);
QObject::connect(but, SIGNAL(clicked()),mapper,SLOT(map()));
mapper->setMapping(but, but);
This way whenever you click a button, the mapped(QWidget *) signal of the mapper is emitted containing the widget as a parameter.
First I will explain you how QSignalMapper works. Then I will explain you why you don't need it.
How QSignalMapper works:
Create s QSignalMapper. Lets assume that you want to assign an integer value to each checkbox, so every time you click on any checkbox, you will get a signal with the integer value assigned to it.
Connect the mapper signal to your SLOT, that you will implement:
connect(mapper, SIGNAL(mapped(int)), this, SLOT(yourSlot(int)));
Now you can write slot, that will take integer argument. The argument will be different for each checkbox you have.
While you create checkboxes, for each checkbox you need to do following:
mapper->setMapping(checkBox, integerValueForThisCheckbox);
connect(checkBox, SIGNAL(clicked()), mapper, SLOT(map()));
From now on, every time you click on a checkbox, it will emit clicked() signal to the QSignalMapper, which will then map it to the assigned integer value and will emit mapped() signal. You connected to that mapped() signal, so yourSlot(int) will be called with the proper integer value.
Instead of integers, you can assign QString, QWidget* or QObject* (see Qt documentation).
This is how QSignalMapper work.
You don't need it:
The QTableWidget *monTab is the single object, it doesn't change. Keep it as a class member field and use it from your slot function.
The QCheckBox *pCheckBox - you can get it by casting sender() to QCheckBox*.
Like this:
void supervision::yourSlot()
{
QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
if (!pCheckBox) // this is just a safety check
return;
}
The sender() function is from QObject, which you do inherit from, so you have access to it.
The int linge (it's a line number, right?) - when you create checkboxes, you can store pointers to that checkboxes in QList class field and use it from your slot function find out which line is it, like this:
In class declaration:
private:
QList<QCheckBox*> checkboxes;
When creating checkboxes:
QCheckBox* cb = new QCheckBox();
checkboxes << cb;
In your slot function:
void supervision::yourSlot()
{
QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
if (!pCheckBox) // this is just a safety check
return;
int linge = checkboxes.indexOf(pCheckBox);
}
If you want, you can skip that QList and use QSignalMapper and assign lines to checkboxes using mapper. That's just a matter of what you prefer.