PDA

View Full Version : Plotting points



afflictedd2
17th February 2009, 17:32
Hi everyone,

Where can I get a library, or application, where a user can click on the screen some points, and then write to a file the points that the user picked. I would like to integrate this in an application I'm building.?

wysota
17th February 2009, 19:27
I suggest you implement your own widget for that. It's about 20 minutes of work.

afflictedd2
17th February 2009, 21:02
It's about 20 minutes of work.

For someone that knows what they're doing ;)

Anyway, any good tutorials on that, or what QWidget could I use as a basis for this plotting widget?

wysota
17th February 2009, 23:01
No, really it is 20 minutes of work :)

QWidget is the obvious candidate for the base class. You might also search the forum, I remember implementing something like that as an example snippet, but it was few months ago, so it might not be easy to find it.

Basically you need to subclass QWidget and reimplement its paintEvent() for drawing and mouseReleaseEvent() for clicking. In the mouse event store coordinates of points you click on in some list (QVector<QPoint> is probably a good candidate) and schedule an update of the widget where you will repaint all the points. As for saving the result to a file, use QFile and optionally QDataStream or QTextStream.

Here is a rough implementation of the widget (not tested):


class Widget : public QWidget {
Q_OBJECT
Q_PROPERTY(int count READ count)
Q_PROPERTY(QVector<QPoint> points READ points WRITE setPoints)
public:
Widget(QWidget *parent = 0) : QWidget(parent){}
const QVector<QPoint> &points() { return m_points; } // for saving
void setPoints(const QVector<QPoint> &pts) { m_points = pts; update(); } // for loading
const QPoint &point(int i) const { return m_points.at(i); }
void setPoint(int i, const QPoint &pt) { m_points[i] = pt; update(); }
int count() const { return m_points.count(); }
public slots:
void clear() { m_points.clear(); update(); }
protected:
void paintEvent(QPaintEvent *pe){
QPainter painter(this);
painter->drawPoints(m_points.constData(), m_points.size());
}
void mouseReleaseEvent(QMouseReleaseEvent *me){
m_points << me->pos();
update();
}
private:
QVector<QPoint> m_points;
};

There... 7 minutes :) 13 more to serialize and deserialize the points to a file ;)

wysota
17th February 2009, 23:01
No, really it is 20 minutes of work :)

QWidget is the obvious candidate for the base class. You might also search the forum, I remember implementing something like that as an example snippet, but it was few months ago, so it might not be easy to find it.

Basically you need to subclass QWidget and reimplement its paintEvent() for drawing and mouseReleaseEvent() for clicking. In the mouse event store coordinates of points you click on in some list (QVector<QPoint> is probably a good candidate) and schedule an update of the widget where you will repaint all the points. As for saving the result to a file, use QFile and optionally QDataStream or QTextStream.

Here is a rough implementation of the widget (not tested):


class Widget : public QWidget {
Q_OBJECT
Q_PROPERTY(int count READ count)
Q_PROPERTY(QVector<QPoint> points READ points WRITE setPoints)
public:
Widget(QWidget *parent = 0) : QWidget(parent){}
const QVector<QPoint> &points() { return m_points; } // for saving
void setPoints(const QVector<QPoint> &pts) { m_points = pts; update(); } // for loading
const QPoint &point(int i) const { return m_points.at(i); }
void setPoint(int i, const QPoint &pt) { m_points[i] = pt; update(); }
int count() const { return m_points.count(); }
public slots:
void clear() { m_points.clear(); update(); }
protected:
void paintEvent(QPaintEvent *pe){
QPainter painter(this);
painter->drawPoints(m_points.constData(), m_points.size());
}
void mouseReleaseEvent(QMouseReleaseEvent *me){
m_points << me->pos();
update();
}
private:
QVector<QPoint> m_points;
};

There... 7 minutes :) 13 more left to serialize and deserialize the points to a file ;)

afflictedd2
25th February 2009, 20:40
Hmmm I don't get it. I have this 2 files:

widget.h


#include <QtGui>
#include <QVector>
#include <QPoint>
#include <QPainter>
#include <QPaintDevice>
#include <QEvent>
#include <QCursor>

class Widget : public QWidget {
Q_OBJECT
Q_PROPERTY(int count READ count)
Q_PROPERTY(QVector<QPoint> points READ points WRITE setPoints)
public:
Widget(QWidget *parent = 0) : QWidget(parent){}
const QVector<QPoint> &points() { return m_points;} // for saving
void setPoints(const QVector<QPoint> &pts) { m_points = pts; update();} // for loading
const QPoint &point(int i) const { return m_points.at(i);}
void setPoint(int i, const QPoint &pt) { m_points[i] = pt; update();}
int count() const { return m_points.count();}
public slots:
void clear() { m_points.clear(); update();}
protected:
void paintEvent(QPaintEvent *pe){
QPainter painter(this);
painter.drawPoints(m_points.constData(), m_points.size());
}
void mouseReleaseEvent(QEvent *e){
if ( e->type() == QEvent::MouseButtonRelease ) {
m_points << QCursor::pos();
update();
}
}
private:
QVector<QPoint> m_points;
};



and

main.cpp


#include <QApplication>
#include <QHBoxLayout>
#include "widget.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QWidget *window = new QWidget;

window->setWindowTitle("Blah");

Widget *wid = new Widget();


QHBoxLayout *layout = new QHBoxLayout;
layout->addWidget(wid);

window->show();

return app.exec();
}

It's not painting though :\

wysota
25th February 2009, 22:12
Compare my mouseReleaseEvent and yours. Mine is incorrect but is closer to being correct than yours ;)

afflictedd2
26th February 2009, 01:24
Aghh I don't get it :\

I mean, don't I need an if stmt to verify what type of event it was.

I tried this:


void mouseReleaseEvent(QMouseEvent *e){
if ( e->type() == QMouseEvent::MouseButtonRelease ) {
m_points << QCursor::pos();
update();
}
}

I mean this is how Interpreting this: Maybe I've got something wrong.

1. You click.
2. mouseReleaseEvent() is called, it checks what type of MouseEvent it was if it is a release then it goes in.
3. point is added to the list of points.
4. update() is called which in turn calls paintEvent( )... I'm guessing.

Yet it still doesn't paint.. so there must be a flaw in my logic :(

btw the code I showed above is all I have, I shouldn't need more code to paint points on the widget, do I? O_o.

wysota
26th February 2009, 08:20
My implementation is correct and sufficient. It's just it should say QMouseEvent and not QMouseReleaseEvent in the signature.

In mouseReleaseEvent you can't get other event than a mouse release, that's why it's called "mouseReleaseEvent" and not "someGenericMouseEvent", there is no point in checking the event type. QCursor::pos() returns a global cursor position (relative to the origin of the screen) whereas QMouseEvent::pos() returns a local position (relative to the widget origin) and as you want to paint on the widget, you need coordinates relative to the widget and not the screen.