Can a QListView detect a specific QString and therefore automatically trigger a slot? - qt

I have a specific string on a QLineEdit, this string is passed to a QListView via QPushButton. Those strings are choices of a QComboBox and they are very specific:
1) "[ INFO] Minimum Distance: 5",
2) "[ INFO] Minimum Distance: 10" and
3) "[ INFO] Minimum Distance: 15"
Here a perfectly working minimal verifiable example if you need to test it.
Currently I can successfully change the color of the QGraphicsView but by clicking or double-clicking on the QString entered in the QListView.
The problem: How can I detect the specific QString content inside a QListView in order to change the background color of a QGraphicsView?
What I mean I don't want to click or double-click on the entry of the QListView but I would like the QListView to see that there is a string "[ INFO] Minimum Distance: 5" and therefore change the color of the QGraphicsView automatically without me clicking or double-clicking on the QListView entry.
After I "Go to slot" my choices are the following below:
Below the MVE working code, you can copy /paste on your machine and it will work:
mainwindow.h
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QStringListModel>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void changeColorDetection();
void updateListView();
void updateListView(const QString & message);
private slots:
void on_pushButton_clicked();
void on_listView_entered(const QModelIndex &index);
void on_listView_activated(const QModelIndex &index);
private:
Ui::MainWindow *ui;
QGraphicsView *mView;
QGraphicsScene *mScene;
QGraphicsTextItem *mText;
StringList *newString;
QStringListModel *model;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
mView = new QGraphicsView();
mScene = new QGraphicsScene();
ui->graphicsView->setScene(mScene);
QFont font;
font.setPixelSize(10);
font.setBold(false);
font.setFamily("Calibri");
mText = new QGraphicsTextItem;
mText->setPos(150,70);
mScene->addText(tr("Boat outside alarm area"))->setDefaultTextColor(Qt::black);
model = new QStringListModel();
ui->listView->setModel(model);
ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
emptyIndex();
connect(ui->listView, SIGNAL(loggingUpdated()), this, SLOT(updateListView(const QString &)));
connect(ui->graphicsView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(on_listView_activated(const QModelIndex &index)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::updateListView(const QString & message)
{
if(model->insertRow(model->rowCount())) {
QModelIndex index = model->index(model->rowCount() - 1, 0);
model->setData(index, message);
ui->listView->scrollTo(index);
}
}
void MainWindow::on_pushButton_clicked()
{
QString str = ui->lineEdit->text();
model->insertRow(model->rowCount());
QModelIndex index = model->index(model->rowCount()-1);
model->setData(index, str);
ui->listView->scrollToBottom();
}
void MainWindow::on_comboBox_currentIndexChanged(const QString &arg1)
{
QString list = ui->comboBox->currentText();
ui->lineEdit->setText(list);
Q_UNUSED(arg1)
}
void MainWindow::on_listView_activated(const QModelIndex &index)
{
QStringList allStrings = model->stringList();
QString last = allStrings.last();
if(last.startsWith("[ INFO] Minimum Distance: 5"))
{
ui->graphicsView->setBackgroundBrush(QColor(Qt::red));
}
else if(last.startsWith("[ INFO] Minimum Distance: 10"))
{
ui->graphicsView->setBackgroundBrush(QColor(Qt::yellow));
}
else if(last.startsWith("[ INFO] Minimum Distance: 15"))
{
ui->graphicsView->setBackgroundBrush(QColor(Qt::green));
}
Q_UNUSED(index)
}
EDIT 2
mainwindow.h
#include <QMainWindow>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsTextItem>
#include <QStringListModel>
#include "listview.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void setGraphicViewColor(QColor c);
private:
Ui::MainWindow *ui;
QGraphicsView *mView;
QGraphicsScene *mScene;
QGraphicsTextItem *mText;
QStringListModel *model;
ListView *myListView;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
mView = new QGraphicsView();
mScene = new QGraphicsScene();
ui->graphicsView->setScene(mScene);
QFont font;
font.setPixelSize(10);
font.setBold(false);
font.setFamily("Calibri");
mText = new QGraphicsTextItem;
mText->setPos(150,70);
mScene->addText(tr("Boat outside alarm area"))->setDefaultTextColor(Qt::black);
model = new QStringListModel();
ui->listView->setModel(model);
ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
connect(ui->listView, SIGNAL(changeColor(QColor)), this, SLOT(setGraphicViewColor(QColor)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setGraphicViewColor(QColor c)
{
qDebug() << "Update your graphicsView backgroundBrush" << c;
ui->graphicsView->setBackgroundBrush(Qt::green);
}
listview.h
#ifndef LISTVIEW_H
#define LISTVIEW_H
#include <QListView>
#include <QStringListModel>
class ListView : public QListView
{
Q_OBJECT
public:
ListView(QWidget *parent = nullptr);
signals:
void changeColor(QColor c);
protected:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()) override;
};
#endif // LISTVIEW_H
listview.cpp
#include "listview.h"
ListView::ListView(QWidget *parent)
: QListView(parent)
{}
void ListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
QListView::dataChanged(topLeft, bottomRight, roles);
/**
* Assuming that you have just one item changed
* So topLeft == bottomRight
*/
if (topLeft.row() == model()->rowCount()-1){
QString last = topLeft.data().toString();
if(last.startsWith("[ INFO] Minimum Distance: 5")) {
emit changeColor(Qt::red);
} else if(last.startsWith("[ INFO] Minimum Distance: 10")) {
emit changeColor(Qt::yellow);
} else if(last.startsWith("[ INFO] Minimum Distance: 15")) {
emit changeColor(Qt::green);
}
}
}
Below the error and a screenshot of the ui that does not detect the change event:
The output of the .ui:
What I have done so far:
I have been doinf a lot of research about this problem and came across this source which was useful but could not solve the problem, but in addition it seems to use a QModelIndex and I am not sure this is exactly what I need for this small project.
Also I read this source which was useful to establish and capture the specific and unique string but in terms of changing colors I could not solve that.
Thank you very much for pointing in the right direction for solving this issue.

If I well understand, you want to change the backgroundBrush of your graphicsView if the last item of your QStringListModel starts with your specific strings.
To detect this, you can subclass QListView:
listview.h:
#ifndef LISTVIEW_H
#define LISTVIEW_H
#include <QListView>
#include <QStringListModel>
class ListView : public QListView
{
Q_OBJECT
public:
ListView(QWidget *parent = nullptr);
signals:
void changeColor(QColor c);
protected:
void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>()) override;
};
#endif // LISTVIEW_H
listview.cpp:
#include "listview.h"
ListView::ListView(QWidget *parent)
: QListView(parent)
{
}
void ListView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
{
QListView::dataChanged(topLeft, bottomRight, roles);
/**
* Assuming that you have just one item changed
* So topLeft == bottomRight
*/
if (topLeft.row() == model()->rowCount()-1){
QString last = topLeft.data().toString();
if(last.startsWith("[ INFO] Minimum Distance: 5")) {
emit changeColor(Qt::red);
} else if(last.startsWith("[ INFO] Minimum Distance: 10")) {
emit changeColor(Qt::yellow);
} else if(last.startsWith("[ INFO] Minimum Distance: 15")) {
emit changeColor(Qt::green);
}
}
}
Now you have all what you need, but you need to add a slot to connect the signal of your custom ListView with your QGraphicsView::brush
// Add this in your mainwindows.h
public slots:
void setGraphicViewColor(QColor c);
// This in the ctor of your MainWindow:
connect(ui->listView, SIGNAL(changeColor(QColor)), this, SLOT(setGraphicViewColor(QColor)));
// And the implementation of your custom slot in mainwindows.cpp
void MainWindow::setGraphicViewColor(QColor c)
{
qDebug() << "Update your graphicsView backgroundBrush" << c;
//ui->graphicsView->setBackgroundBrush(c);
}

Related

Accessing a delegate's input value from the model

I'm using a custom QTableView with a custom QAbstractTableModel and a QItemDelegate. I'd need to access the contents of the delegate's editor while the user is editing it, and after several attempts, I couldn't find anything satisfying.
Indeed, I've tried several things.
First: trying to access the delegate's current input (created through createEditor) through a property defined in QItemDelegate but... it seems that none exists. That's why I tried to add a QWidget* editor property and setting it in the createEditor.
Unfortunately, QItemDelegate's createEditor is supposed to be const, which makes me unable to set my property there (and since I don't control what calls createEditor, I can't do it before or after).
I don't really know what to do here. Actually, I also needed to know when the user started (or stopped) editing the cell content, which I eventually achieved by creating two const signals (editingStarted and editingStopped). I could probably create a const editorOpened(QWidget*) signal but it just feels bad and ugly...
I can't believe nothing "official" exists to achieve what I'm trying to do, hence this question. If I have everything wrong from the beginning, I'd be glad to know. If you have any other ideas, please suggest.
EDIT: Here is a minimal working example
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
#include <QTableView>
#include "mytableview.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
auto tableView = new MyTableView(this);
setCentralWidget(tableView);
}
MainWindow::~MainWindow()
{
}
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QItemDelegate>
#include <QLineEdit>
#include <QStandardItemModel>
class MyItemDelegate : public QItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
virtual QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual void onCloseEditor();
virtual ~MyItemDelegate() = default;
signals:
// Const signals trick
void editingStarted() const;
void editingFinished() const;
void editorOpened(const QWidget*) const;
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
MyItemDelegate::MyItemDelegate(QObject* parent) : QItemDelegate(parent)
{
connect(this, &QItemDelegate::closeEditor, this, &MyItemDelegate::onCloseEditor);
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
emit editingStarted();
emit editorOpened(lineEdit);
return lineEdit;
}
void MyItemDelegate::onCloseEditor()
{
emit editingFinished();
}
MyTableView.h
#ifndef MYTABLEVIEW_H
#define MYTABLEVIEW_H
#include <QTableView>
#include <QDebug>
#include "myitemdelegate.h"
class MyTableView : public QTableView
{
Q_OBJECT
public:
explicit MyTableView(QWidget *parent = nullptr);
signals:
public slots:
};
#endif // MYTABLEVIEW_H
MyTableView.cpp
#include "mytableview.h"
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::editingStarted, []() {
qDebug() << "Editing started";
});
connect(delegate, &MyItemDelegate::editingFinished, []() {
qDebug() << "Editing finished";
});
connect(delegate, &MyItemDelegate::editorOpened, [](const QWidget* editor) {
auto lineEdit = qobject_cast<const QLineEdit*>(editor);
connect(lineEdit, &QLineEdit::textChanged, [](const QString& text) {
qDebug() << text;
});
});
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
The following solution maybe fits your needs. I just defined a new signal inside the delegate and connected to it inside the class owning the delegate.
MyItemDelegate.h
#ifndef MYITEMDELEGATE_H
#define MYITEMDELEGATE_H
#include <QStyledItemDelegate>
class MyItemDelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
MyItemDelegate(QObject* parent);
QWidget* createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const;
virtual ~MyItemDelegate() = default;
signals:
void valueChanged(const QString&);
};
#endif // MYITEMDELEGATE_H
MyItemDelegate.cpp
#include "myitemdelegate.h"
#include <QLineEdit>
MyItemDelegate::MyItemDelegate(QObject* parent) : QStyledItemDelegate(parent)
{
}
QWidget* MyItemDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
{
auto lineEdit = new QLineEdit(parent);
connect(lineEdit, &QLineEdit::textChanged, this, &MyItemDelegate::valueChanged);
return lineEdit;
}
MyTableView.cpp
#include "mytableview.h"
#include <QStandardItemModel>
MyTableView::MyTableView(QWidget *parent) : QTableView(parent)
{
MyItemDelegate* delegate = new MyItemDelegate(this);
QStandardItemModel* model = new QStandardItemModel(this);
setItemDelegate(delegate);
setModel(model);
QList<QList<QStandardItem*>> items;
for(int i = 0; i < 10; i++)
{
items << QList<QStandardItem*>();
for (int j = 'A'; j < 'E'; j++)
items[i] << new QStandardItem(QString("%1,%2").arg(i).arg(static_cast<char>(j)));
}
for (const auto& row : items)
model->appendRow(row);
connect(delegate, &MyItemDelegate::valueChanged, [](auto v) { qDebug() << v; });
}

how to get drop events of object which is placed in graphic scene?

i have graphic view(QGraphics view) setted scene(QGraphic scene) i am dropping objects on scene its working fine, i have to assign parameter for dropped object by dragging parameter from parameter list .i have implemented drag drop events of object.but when i am dragging parameter from param list non- acceptance symbol on object.how to assign param to object by dropping ? Any other suggestions and examples are welcome where i can get ideas to implementation.
image of gui
speedometer.cpp
#include <QMimeData>
SpeedoMeter::SpeedoMeter( QWidget *parent ):
QwtDial( parent ),
d_label( "km/h" )
{
setAcceptDrops(true);
}
void SpeedoMeter::dragEnterEvent(QDragEnterEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragenter event in speedo" ;
event->accept();
}
}
void SpeedoMeter::dragMoveEvent(QDragMoveEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragmove event in speedo" ;
event->acceptProposedAction();
}
}
void SpeedoMeter::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(paramlistMimeType()))
{
qDebug()<<"dragmove event in speedo" ;
event->accept();
}
}
The following example shows how to implement the logic to accept the drag-and-drop:
speedometer.h
#ifndef SPEEDOMETER_H
#define SPEEDOMETER_H
#include <qwt_dial.h>
class SpeedoMeter : public QwtDial
{
public:
SpeedoMeter(QWidget *parent=nullptr);
protected:
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
void dragMoveEvent(QDragMoveEvent *event);
void paintEvent(QPaintEvent *event);
private:
QString d_label;
};
#endif // SPEEDOMETER_H
speedometer.cpp
#include "speedometer.h"
#include <qwt_dial_needle.h>
#include <QDragEnterEvent>
#include <QMimeData>
#include <QPainter>
SpeedoMeter::SpeedoMeter(QWidget *parent):
QwtDial(parent),
d_label( "km/h" )
{
setAcceptDrops(true);
QwtDialSimpleNeedle *nd = new QwtDialSimpleNeedle(QwtDialSimpleNeedle::Arrow, Qt::white, Qt::red);
setNeedle(nd);
setValue(80);
}
void SpeedoMeter::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->acceptProposedAction();
}
void SpeedoMeter::dropEvent(QDropEvent *event)
{
const QMimeData *mimedata = event->mimeData();
if(mimedata->hasFormat("application/x-qabstractitemmodeldatalist")){
QString text;
// https://stackoverflow.com/questions/1723989/how-to-decode-application-x-qabstractitemmodeldatalist-in-qt-for-drag-and-drop
QByteArray encoded = mimedata->data("application/x-qabstractitemmodeldatalist");
QDataStream stream(&encoded, QIODevice::ReadOnly);
while (!stream.atEnd()) {
int row, col;
QMap<int, QVariant> roleDataMap;
stream >> row >> col >> roleDataMap;
if(roleDataMap.contains(Qt::DisplayRole)){
text = roleDataMap[Qt::DisplayRole].toString();
break;
}
}
// your text
d_label = text;
update();
}
}
void SpeedoMeter::dragMoveEvent(QDragMoveEvent *event)
{
if(event->mimeData()->hasFormat("application/x-qabstractitemmodeldatalist"))
event->accept();
}
void SpeedoMeter::paintEvent(QPaintEvent *event)
{
// https://stackoverflow.com/questions/43904204/qwt-dial-show-unit
QwtDial::paintEvent(event);
QPainter painter(this);
painter.setPen(Qt::black);
QFont font;
font.setPointSize(11);
painter.setFont(font);
QString text = QString("%1 %2").arg(value()).arg(d_label);
QPoint c = rect().center();
QSize Size = painter.fontMetrics().size(Qt::TextSingleLine, text);
painter.drawText(QPointF(c.x() -Size.width()/2, c.y() + 2.5*Size.height()), text);
}
main.cpp
#include "speedometer.h"
#include <QApplication>
#include <QGraphicsView>
#include <QHBoxLayout>
#include <QListWidget>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QHBoxLayout *layout = new QHBoxLayout(&w);
QListWidget listWidget;
listWidget.setDragDropMode(QAbstractItemView::DragOnly);
listWidget.addItems({"km/h", "ft/s", "m/s", "miles/h"});
QGraphicsView view;
QGraphicsScene scene;
view.setScene(&scene);
SpeedoMeter speed;
scene.addWidget(&speed);
layout->addWidget(&listWidget);
layout->addWidget(&view);
w.show();
return a.exec();
}
In the following link you can find the complete example.

Unexpected behaviour with QMouseMoveEvent and QKeyEvent modifiers

I am encountering unexpected behaviour in my code.
I have a QGraphicsView containing a QGraphicsScene. Now I want to detect the mouse wheel for zooming the view and mouse moving for moving items in the scene, the latter only while controll is pressed. Now I have two Problems:
MouseMoveEvent is called even when the mouse is not moved but only the mouse wheel.
Moving with and without controll pressed works fine but when I stop moving while controll is pressed and continue using the mouse wheel not only the mousemoveevent is called but also the controllmodifier is still active. What is the problem?
main.cpp
#include "ppi.h"
#include <QtGui/QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
PPI w;
w.show();
return a.exec();
}
ppi.h
#ifndef PPI_H
#define PPI_H
#include <QtGui/QMainWindow>
#include <QGraphicsView>
#include <QDebug>
#include <QWheelEvent>
#include "ui_ppi.h"
#include "ppiView.h"
#include "ppiscene.h"
class PPI : public QMainWindow
{
Q_OBJECT
public:
PPI(QWidget *parent = 0, Qt::WFlags flags = 0);
~PPI();
int i;
private:
Ui::ppiClass ui;
PPIScene* ppiScene;
protected slots:
void onZoom(QWheelEvent *event);
void onMouseMoved(QGraphicsSceneMouseEvent *event);
};
#endif // PPI_H
ppi.cpp
#include "ppi.h"
PPI::PPI(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
ppiScene = new PPIScene(this);
connect(ppiScene, SIGNAL(mouseMoved(QGraphicsSceneMouseEvent*)), this, SLOT(onMouseMoved(QGraphicsSceneMouseEvent*)));
connect(ui.gVPPI, SIGNAL(zoom(QWheelEvent*)), this, SLOT(onZoom(QWheelEvent*)));
ppiScene->setSceneRect(0,0,1024,1024);
ui.gVPPI->setScene(ppiScene);
ui.gVPPI->setMouseTracking(true);
i = 0;
}
PPI::~PPI()
{
}
void PPI::onZoom(QWheelEvent *event)
{
if(event->delta() > 0)
ui.gVPPI->scale(1.01, 1.01);
else
ui.gVPPI->scale(1/1.01, 1/1.01);
}
void PPI::onMouseMoved(QGraphicsSceneMouseEvent *event)
{
i++;
qDebug() << "slot" << i << event->modifiers();
if(event->modifiers() & Qt::ControlModifier)
{
qDebug() << "ctrl pressed";
}
}
ppiview.h
#ifndef PPIVIEW_H
#define PPIVIEW_H
#include <QGraphicsView>
#include <QMouseEvent>
class PPIView : public QGraphicsView
{
Q_OBJECT
public:
PPIView(QWidget * parent = 0);
~PPIView();
private:
void wheelEvent(QWheelEvent *event);
signals:
void zoom(QWheelEvent *event);
};
#endif // PPIVIEW_H
ppiview.cpp
#include "ppiview.h"
PPIView::PPIView(QWidget * parent)
: QGraphicsView(parent)
{
}
PPIView::~PPIView()
{
}
void PPIView::wheelEvent(QWheelEvent *event)
{
emit zoom(event);
}
ppiscene.h
#ifndef PPISCENE_H
#define PPISCENE_H
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QDebug>
class PPIScene : public QGraphicsScene
{
Q_OBJECT
public:
PPIScene(QObject *parent);
~PPIScene();
int i;
private:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
signals:
void mouseMoved(QGraphicsSceneMouseEvent *event);
};
#endif // PPISCENE_H
ppiscene.cpp
#include "ppiscene.h"
PPIScene::PPIScene(QObject *parent)
: QGraphicsScene(parent)
{
i = 0;
}
PPIScene::~PPIScene()
{
}
void PPIScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
i++;
qDebug() << "signal" << i << event->modifiers();
emit mouseMoved(event);
}
It is really strange. It looks like the Qt::KeyboardModifiers status, which QGraphicsSceneMouseEvent::modifiers returns, is only updated, when the mouse is physically moved. What is even more strange, is that in your code QGraphicsSceneMouseEvents of type QGraphicsSceneMouseMove are sent even when the mouse is not moved at all, but only the wheel is turned. Maybe the relative movement due to your scaling counts as movement, but not as movement, which updates the modifiers.
I was able to reproduce your problem: The status of the modifiers don't change unless the mouse is physically moved.
Fortunately there is an easy workaround. In
void PPI::onMouseMoved(QGraphicsSceneMouseEvent *event)
{
i++;
qDebug() << "slot" << i << event->modifiers();
if(event->modifiers() & Qt::ControlModifier)
{
qDebug() << "ctrl pressed";
}
}
replace:
if(event->modifiers() & Qt::ControlModifier)
with:
if(QApplication::queryKeyboardModifiers() & Qt::ControlModifier)
QApplication::queryKeyboardModifiers() is updated immediately when you press or release the control key.

some error with mousepressevent()

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
#include <QDebug>
#include "my_qlabel.h"
#include<QTimer>
int px;
int py;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
tmrTimer = new QTimer(this);
connect(tmrTimer,SIGNAL(timeout()),this,SLOT(showthepositionofmouse()));
tmrTimer->start(20);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::showthepositionofmouse()
{
ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py));
}
void my_qlabel::mousePressEvent(QMouseEvent *event)
{
if (event->button()==Qt::RightButton){
px = event->x();
py = event->y();
}
}
i Want to display the position of Mouse clicked
i use ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py)); to display this position. although i click mouse,it only show x,y = 0 0. why that?
The py and px that are accessed in my_qlabel::mousePressEvent, are member variables of my_qlabel and are not visible to MainWindow::showthepositionofmouse.
If you want them to be visible you should send them using a signal and slot.
http://qt-project.org/doc/qt-4.8/signalsandslots.html
Here is a way to implement it:
In my_qlabel.h have something like this:
class my_qlabel : public QLabel
{
Q_OBJECT
signals:
void right_click_xy(int x, int y);
// ...constructor and other functions
public slots:
void mousePressEvent(QMouseEvent *event)
{
int px, py;
if (event->button()==Qt::RightButton){
px = event->x();
py = event->y();
emit right_click_xy(px, py);
}
}
}
In mainwindow.h have something like this:
class MainWindow : public QMainWindow
{
Q_OBJECT
// ... constructor and other functions
public slots:
void on_display_click_xy(int px, int py)
{
qDebug() << "Received xy over signal slot:" << px << py;
ui->plainTextEdit->appendPlainText(QString(" x , y = ")+QString::number(px)+QString::number(py));
}
}
And inside your MainWindow constructor put the following:
QObject::connect(ui->my_qlabel_instance, SIGNAL(right_click_xy(int,int)),
this, SLOT(on_display_click_xy(int, int)));
Another alternate way of doing this, but is isn't as kosher, would be to drill down into your ui object and access px and py that way.
qDebug() << ui->my_qlabel_instance->py;
But this is not as elegant, and isn't signaled the same way.
Another idea to look into is to use a QPoint object instead of two ints.
Hope that helps.
The whole idea is bad, you must process this event within my_qlabel class via signals and slots, not outside of it. I would suggest something like this (emit signal with coordinates of mouse click):
Header my_qlabel.h:
#ifndef MY_QLABEL_H
#define MY_QLABEL_H
#include <QLabel>
#include <QPoint>
#include <QEvent>
class my_qlabel : public QLabel
{
Q_OBJECT
public:
my_qlabel( const QString & text="", QWidget * parent = 0 );
signals:
void clicked(QPoint pos);
protected:
void mouseReleaseEvent ( QMouseEvent * event );
};
#endif // MY_QLABEL
Source my_qlabel.cpp:
#include "my_qlabel.h"
#include <QMouseEvent>
my_qlabel::my_qlabel( const QString & text, QWidget * parent )
:QLabel(parent)
{
setText(text);
}
void my_qlabel::mouseReleaseEvent ( QMouseEvent * event )
{
emit clicked(event->pos());
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "my_qlabel.h"
#include <QtGui/QWidget>
class MainWindow : public QWidget
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
void showthepositionofmouse(QPoint pos);
};
#endif // MAINWINDOW_H
and mainwindow.cpp:
#include "mainwindow.h"
#include <QDebug>
#include <QPoint>
#include <QHBoxLayout>
MainWindow::MainWindow(QWidget *parent) :
QWidget(parent)
{
my_qlabel* label=new my_qlabel("Text of my label",this);
label->setAlignment(Qt::AlignCenter);
QGridLayout *lay=new QGridLayout(this);
this->setLayout(lay);
lay->addWidget(label,0,0,1,1);
connect(label,SIGNAL(clicked(QPoint)),this,SLOT(showthepositionofmouse(QPoint)));
}
MainWindow::~MainWindow()
{
}
void MainWindow::showthepositionofmouse(QPoint pos)
{
qDebug()<< "Clicked, position="<<pos;
}

QT hangs my toolbar and its buttons

I've created 2 classes, each:
has QWidget as a parent
has Q_OBJECT macros
inits some actions, creates menubar and toolbar, and connects actions to them
Then I created the main program file, created QMainWindow, and init my two classes by qmainwnd pointer.
And what I've got - menu works, the second toolbar works, but the first toolbar (created by class 1) doesn't respond to mouse clicks.
What happed with it? Why I can not even move this first toolbar or click its buttons?
Here a sample:
main.cpp
#include <QApplication>
#include <QMainWindow>
#include "CModDocument.h"
#include "CModEditor.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow wnd;
// init CA
CModDocument a(&wnd);
// init CB
CModEditor b(&wnd);
wnd.show();
return app.exec();
}
CModDocument.h
#ifndef CMODDOCUMENT_H
#define CMODDOCUMENT_H
#include <QWidget>
QT_BEGIN_NAMESPACE
class QAction;
class QToolBar;
class QMainWindow;
QT_END_NAMESPACE
class CModDocument: public QWidget
{
Q_OBJECT
public:
CModDocument(QWidget *parent = 0);
QMainWindow *getMainWnd();
public slots:
void newFile();
void open();
bool save();
bool saveAs();
private:
void createActions();
void createToolBars();
void interCom();
QMainWindow *mainWnd;
QToolBar *fileToolBar;
QAction *newAct;
QAction *openAct;
QAction *saveAct;
QAction *saveAsAct;
};
#endif // CMODDOCUMENT_H
CModDocument.cpp
#include <QtGui>
#include <QDebug>
#include "CModDocument.h"
CModDocument::CModDocument( QWidget *parent )
: QWidget( parent )
, mainWnd( (QMainWindow*)parent )
{
createActions();
createToolBars();
interCom();
mainWnd->statusBar()->showMessage(tr("Ready"));
}
void CModDocument::newFile()
{
qDebug() << "newFile";
}
void CModDocument::open()
{
qDebug() << "open";
}
bool CModDocument::save()
{
qDebug() << "save";
bool retVal;
return retVal;
}
bool CModDocument::saveAs()
{
qDebug() << "saveAs";
bool retVal;
return retVal;
}
void CModDocument::createActions()
{
newAct = new QAction(tr("&New"), this);
newAct->setShortcuts(QKeySequence::New);
newAct->setStatusTip(tr("Create a new file"));
openAct = new QAction(tr("&Open..."), this);
openAct->setShortcuts(QKeySequence::Open);
openAct->setStatusTip(tr("Open an existing file"));
saveAct = new QAction(tr("&Save"), this);
saveAct->setShortcuts(QKeySequence::Save);
saveAct->setStatusTip(tr("Save the document to disk"));
saveAsAct = new QAction(tr("Save &As..."), this);
saveAsAct->setShortcuts(QKeySequence::SaveAs);
saveAsAct->setStatusTip(tr("Save the document under a new name"));
}
void CModDocument::createToolBars()
{
fileToolBar = mainWnd->addToolBar(tr("File"));
fileToolBar->addAction(newAct);
fileToolBar->addAction(openAct);
fileToolBar->addAction(saveAct);
}
void CModDocument::interCom()
{
connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
connect(saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));
}
CModEditor.h
#ifndef CMODEDITOR_H
#define CMODEDITOR_H
#include <QWidget>
// #include "CModEdiWidget.h"
QT_BEGIN_NAMESPACE
class QMainWindow;
class QAction;
class QMenu;
class QMenuBar;
class QToolBar;
QT_END_NAMESPACE
class CModEditor : public QWidget
{
Q_OBJECT
public:
CModEditor(QWidget *parent = 0);
public slots:
void cut();
private:
void createActions();
void createToolBars();
void interCom();
QAction *cutAct;
QToolBar *editToolBar;
// parent
QMainWindow *mainWnd;
};
#endif
CModEditor.cpp
#include <QtGui>
#include <QDebug>
#include "CModEditor.h"
CModEditor::CModEditor(QWidget *parent)
: QWidget(parent)
, mainWnd( (QMainWindow*)parent )
{
createActions();
createToolBars();
interCom();
}
void CModEditor::cut()
{
qDebug() << "cut";
}
void CModEditor::createActions()
{
cutAct = new QAction(tr("Cu&t"), this);
cutAct->setShortcuts(QKeySequence::Cut);
cutAct->setStatusTip(tr("Cut the current selection's contents to the clipboard"));
}
void CModEditor::createToolBars()
{
editToolBar = mainWnd->addToolBar(tr("Edit"));
editToolBar->addAction(cutAct);
editToolBar->setIconSize(QSize(16, 16));
}
void CModEditor::interCom()
{
connect(cutAct, SIGNAL(triggered()), this, SLOT(cut()));
}
build.pro
CONFIG -= app_bundle
HEADERS = CModDocument.h CModEditor.h
SOURCES = CModDocument.cpp CModEditor.cpp main.cpp
The problem seems to be that you are trying to configure the QMainWindow as the parent to two QWidgets. I modified your main() function as follows and it worked:
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QMainWindow wnd;
QWidget w;
// init CA
CModDocument a(&wnd, &w);
// init CB
CModEditor b(&wnd, &w);
wnd.show();
return app.exec();
}
Notice the new QWidget w that parents a and b. I'm not even sure my approach is adequate (it probably isn't). I think it is better to add a QLayout to w and add a and b to that QLayout. Then you could set w as wnd's central widget.

Resources