How to get left mouse click event in Tree View - qt

I have implemented a QTreeview with QAbstractItemModel how can i be notified if i click on the tree view item with left mouse click.Do we have any function like OnLButtonDown() avalible for the tree view.
WavefrontRenderer::WavefrontRenderer(TreeModel* model , QWidget *parent) :
QMainWindow(parent)
{
setupUi(this);
treeView->setModel(model);
treeView->setDragEnabled(true);
treeView->setAcceptDrops(true);
treeView->installEventFilter(this);
connect(pushButtonAddGroup, SIGNAL(clicked()), this, SLOT(insertRow()));
connect(pushButtonAddChild , SIGNAL(clicked()), this,
SLOT(insertChild()));
connect(pushButtonDeleteGroup , SIGNAL(clicked()), this,
SLOT(removeRow()));
connect( ButtonSphere, SIGNAL(clicked()), this, SLOT(AddSphere()));
connect(treeView , SIGNAL(clicked()), this, SLOT(message()));
}
I tried to connect the treeview to clicked slot but this did not work for me.
Since i am new to qt i am not sure if we connect the treeview same way as we connect buttons to the clicked slots.

You should always check your connections:
bool ok = connect(...);
Q_ASSERT(ok);
If you do that, you'll find that connecting to the clicked() signal doesn't work.
If you then take a look at your error console you'll see a Qt message that the signal clicked() is not found in QTreeView.
That's because the parameters need to be included in the SIGNAL(...) macro.
Either put them there but just the type without the parameter name:
bool ok = connect(treeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(message()));
or avoid this pitfall by using the new connect syntax:
bool ok = connect(treeView, &QAbstractItemView::clicked, this, &WavefrontRenderer::message);
This will give you a compiler error if the signal or slot doesn't exist.

Related

How may I fix my error prone on_foo_bar slots

I have eight list widgets in a tab widget. They have similar names, and Designer's "Go to slot" mechanism has made links to slots it names (in the "private slots" section of "mainwindow.h") like:
void on_SR0listWidget_itemClicked(QListWidgetItem *item);
I saw warnings that "Slots named on_foo_bar are error-prone," and now I need to change their names in order to discover if that's the cause of the weird behaviour I'm getting.
I tried simply refactoring the names, but that stopped the slot code from working. I used Designer's graphical "Edit Signal/Slot" mechanism and was able to connect a newly added list widget's "itemClicked(QListWidgetItem *item)" signal to a newly added slot, and it looks OK in the graphical representation, but there's no debug message (that I set up in the Slot function) when an item is clicked.
I also use those widgets' "entered" signals, so there will be at least 16 to fix. I would write a script if it could be done by parsing the relevant files.
One example of exactly how to rename one of my replacement slots and connect an "item clicked" or "entered" signal to it (and where it should go) would be a great help.
Signals/slots setup through the designer rely on the names of the widgets involved. This can lead to problems if the widget names are changed. There are times when using the designer method will lead to code that compiles but doesn't actually make the connections you expect. This is why you are getting that warning.
You can get more reliable behavior by connecting the signals and slots programmatically. For example, let's say you have a class header such as:
#include <QMainWindow>
namespace Ui {
class MyWindow;
};
class QListWidgetItem;
class MyWindow : public QMainWindow {
Q_OBJECT
public:
explicit MyWindow(QWidget* parent = nullptr);
~MyWindow() override;
private:
void handleItemClicked(QListWidgetItem* item); // this is your slot
Ui::MyWindow* ui;
};
You can connect the signal/slot together in the cpp file like this:
#include "MyWindow.h"
#include "ui_MyWindow.h"
#include <QDebug>
MyWindow::MyWindow(QWidget* parent)
: QWidget(parent),
ui(new Ui::MyWindow()) {
ui->setupUi(this);
// connect() has many overloads, but in this case we are passing:
// 1. the object emitting the signal
// 2. the signal being emitted
// 3. the object whose slot we want to call
// 4. the slot to connect to
connect(
ui->listWidget, &QListWidget::itemClicked,
this, &MyWindow::handleItemClicked);
}
MyWindow::~MyWindow() {
delete ui;
}
void MyWindow::handleItemClicked(QListWidgetItem* item) {
qDebug() << "item clicked";
}
You can still use the designer to layout your UI - but prefer to manage connections directly in code rather than through the designer.

itemChanged() on QStandardItemModel triggered when data hasn't changed

I have the following connect line:
connect(my_QStandardItemModel ,SIGNAL(itemChanged(QStandardItem*)),
this,SLOT(cellEditEndedCalled(QStandardItem*)));
For some reason whenever I go into edit mode on a cell inside my table (double click) and click on another cell, cellEditEndedCalled() is being called even though I didn't make any changes to my data.
Any ideas on why this might be happening?
EDIT:
Tried with dataChanged(...) instead of itemChanged(...) but the slot is still being called.
Implementation of my_QStandardItemModel :
class my_QStandardItemModel :public QStandardItemModel
{
typedef QStandardItemModel baseClass;
Q_OBJECT
public:
my_QStandardItemModel ();
virtual ~my_QStandardItemModel ();
...
Not overwriting any signals afterwards.
Because the signal itemChanged is not the correct for your situation. QStandardItemModel inherits another singal form QAbstractItemModel
void QAbstractItemModel::dataChanged(const QModelIndex &topLeft, const
QModelIndex &bottomRight, const QVector<int> &roles = QVector<int> ())
that emits with QModelIndex information on the index where changes occured : your cell.
you need to connect that signal to your slot (to be modified to match new signal signature).
Why the itemChanged signal is emitted even you did not modify the data: because that signal emits when you change your item NOT the data in it.

How to know which QLineEdit is focused?

I'm new in QT. Could someone help me with this?
I'm coding a widget application (with QMainWindow) with three QLineEdits widgets, I used setText to set a random text and connect the timeout() signal to a slot. When the timer "interrupts" I want to know in which QLineEdit the cursor is.
MainWindow constructor:
ui->setupUi(this);
timer = new QTimer(this);
timer -> start(1000); // 1 sec
connect(timer, SIGNAL(timeout()), this, SLOT(FinishTimer()));
ui->lineEdit1->setText("Line1");
ui->lineEdit2->setText("Line2");
ui->lineEdit1->setFocus();
In finish timer function I want to move the cursor but first I need to know in wich QLineEdit I am and the position of the cursor.
FinishTimer slot:
QString debug;
debug = this->focusWidget()->objectName(); //this is a debug line, it works fine
// this line doesn't work
int position = this->focusWidget()->cursorPosition();
cursorPosition it's a method of QLineEdit, the error is "class QWidget has no member named 'cursorPosition'". I hope you will understand me.
I used qobject_cast and it works really well. Thanks
position=qobject_cast<QLineEdit*>(this->focusWidget())->cursorPosition();

Passing signals through hierarchies

I am having some difficulty fully grasping how signals and slots are used in Qt. I am sure it is really basic but I'm just no getting it today.
I have a set of widgets a bit like this:
MainWindow
-->StackedWidget
-->ChildForms
Now the idea is that there are some actions on the Child widgets that will cause the stacked widget to display a different page.
So if I understand it properly I thought the way to connect signals and slots is to use the connect() at the scope that knows about the objects but what I have managed to get working doesn't do it this way. At the moment in my child form I use parentWidget() to access the slot of the StackedWidget but I am not very happy with really because it is giving the child information about the parent which it shouldn't have:
void TaskSelectionForm::setButtonMappings()
{
// Set up a mapping between the buttons and the pages
QSignalMapper *mapper = new QSignalMapper(this);
connect(mapper, SIGNAL(mapped(int)), parentWidget(), SLOT(setCurrentIndex(int)));
mapper->setMapping(ui->utilitiesButton, 2); // Value of the index
connect(ui->utilitiesButton, SIGNAL(clicked()), mapper, SLOT(map()));
}
But I am not really sure how I should do this and connect it up. Do I need to have signals at each level and emit through the tree?
A Bit of Signal-Slot Theory
The signal-slot connections are oblivious to parent-child relationships between QObjects, and any such relationship doesn't matter. You're free to connect objects to their children, to their siblings, to their parents, or even to QObjects that are in a separate hierarchy, or to lone QObjects that have neither parents nor children. It doesn't matter.
A signal-slot connection connects a signal on a particular instance of QObject to slot on another instance of QObject. To use the connect method, you need the pointers to the instance of sender QObject and the instance of receiver QObject. You then use the static QObject::connect(sender, SIGNAL(...), receiver, SLOT(...)). Those connections have nothing to do with any hierarchy there is between the sender and receiver.
You can also connect a signal to a signal, to forward it -- for example from a private UI element to a signal that's part of the API of the class. You cannot connect a slot to a slot, because it'd incur a bit of runtime overhead for a rarely-used case. The overhead would be an extra bool member in QObjectPrivate, plus a failed if (bool) test. If you want to forward slots to slots, there are at least two ways to do it:
Emit a signal in the source slot and connect that signal to the destination slot.
Obtain a list of all signals connected to the source slot, iterate on it and connect them to to the target slot. There's no easy way to maintain such connections when further signals are connected or disconnected from the source slot. Unfortunately, QObject only has a connectNotify(const char*) protected function, but not a signal -- so you can't hook up to it unless you would modify src/corelib/kernel/qobject[.cpp,_p.h,.h] to emit such a signal. If you truly need it, just modify the Qt source, you have access it for a reason, after all. Hacking the vtable without modifying Qt is possible, but discouraged for obvious reasons.
The Answer
Below is a self contained example that shows how to do what you want. Turns out I have answers to quite a few questions from my various experiments I've done in Qt in the past. I'm a packrat when it comes to test code. It's all SSCCE to boot :)
// https://github.com/KubaO/stackoverflown/tree/master/questions/signal-slot-hierarchy-10783656
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class Window : public QWidget
{
QSignalMapper m_mapper;
QStackedLayout m_stack{this};
QWidget m_page1, m_page2;
QHBoxLayout m_layout1{&m_page1}, m_layout2{&m_page2};
QLabel m_label1{"Page 1"}, m_label2{"Page 2"};
QPushButton m_button1{"Show Page 2"}, m_button2{"Show Page 1"};
public:
Window(QWidget * parent = {}) : QWidget(parent) {
// the mapper tells the stack which page to switch to
connect(&m_mapper, SIGNAL(mapped(int)), &m_stack, SLOT(setCurrentIndex(int)));
// Page 1
m_layout1.addWidget(&m_label1);
m_layout1.addWidget(&m_button1);
// tell the mapper to map signals coming from this button to integer 1 (index of page 2)
m_mapper.setMapping(&m_button1, 1);
// when the button is clicked, the mapper will do its mapping and emit the mapped() signal
connect(&m_button1, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page1);
// Page 2
m_layout2.addWidget(&m_label2);
m_layout2.addWidget(&m_button2);
// tell the mapper to map signals coming from this button to integer 0 (index of page 1)
m_mapper.setMapping(&m_button2, 0);
connect(&m_button2, SIGNAL(clicked()), &m_mapper, SLOT(map()));
m_stack.addWidget(&m_page2);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
Connect(stackedwidget->currentactivewidget,SIGNAL(OnAction()),this,SLOT(PrivateSlot()));
PrivateSlot() is a slot declared privately. So in this function, you can add your code to change the page of stackedwidget corresponding to the action produced by currentactivewidget.
Again if you really want to pass the signal up the heirarchy, emit a publicsignal() at the end of private slot function.
Connect(this,SIGNAL(publicsignal()),Parentwidgetofstackedwidget(here mainwindow),SLOT(mainwindow_slot()));

difference between connections in qt

I have some constructor for the class LCDRange:
LCDRange::LCDRange(QWidget *parent)
: QWidget(parent)
{
QLCDNumber *lcd = new QLCDNumber(2);
lcd->setSegmentStyle(QLCDNumber::Filled);
slider = new QSlider(Qt::Horizontal);
slider->setRange(0, 99);
slider->setValue(0);
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(lcd);
layout->addWidget(slider);
setLayout(layout);
}
but I can't understand the difference between these lines:
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
thanks in advance
Remember that we are in OO land, so we are operating on objects.
In order to connect a signal to something, those signal/slots have to be apart of an object.
Another way to think about it is you can't have a signal by itself, because a signal has to come from somewhere. Likewise, you can't have a slot all by itself it has to be attached to something.
Now, Qt allows you to connect a signal to a slot, but it also allows you to connect a signal to a signal, which is what is happening in the second connect line. This allows you to chain signals from one object to another, or you could think about it as passing a signal through.
Usually this happens when an Object or Widget has a private internal child that emits a signal, and the parent Object/Widget wants to emit the same signal to whoever is listening to it.
In the case of your example the LCDRange Widget contains a slider, which is an internal implementation detail. The user of LCDRange doesn't need to know about all the different components that make up the LCDRange (slider, lcdnumber, layout, etc), that's a basic requirement of encapsulation which is a huge advantage of OO.
However, the user of LCDRange will want to know when the value of LCDRange changes. And rather then creating a slot in LCDRange, that simply re-emits the signal valueChanged signal, you can forward or passthrough the valueChanged signal from the slider.
The following achieves the same effect of passing the signal through, however it requires much more code.
class LCDRange : public QWidget
{
// constructor and other methods
//...
signals:
void valueChanged(int)
private slots:
void sliderValueChanged(int);
// ...
};
// in the LCDRange constructor
connect(slider, SIGNAL(valueChanged(int)),
this, SLOT(sliderValueChanged(int)));
// elsewhere in LCDRange's definition
void LCDRange::sliderValueChanged( int value )
{
emit valueChanged( value );
}
connect(slider, SIGNAL(valueChanged(int)),
lcd, SLOT(display(int)));
tells, if the value of the slider gets changed then valueChanged signal will be emited and it will be reflected in LCD view. i.e display slots gets called, whose implementation will be present in QLCDNumber
connect(slider, SIGNAL(valueChanged(int)),
this, SIGNAL(valueChanged(int)));
Qt offers, mechanism of connecting one signal to another signal, it implies if slider valueChangedsignal is emited means present class valueChangedsignal is emited.
the connected slot for valueChanged gets called

Resources