I create class Widget, it creates window, this class paints something on the window (i.e. it works as I want).
I create yet one class, Circle, I want to paint on the window of class Widget.
I pass adress of Widget and try to paint on Widget using QPainter paint (address of Widget); (in the instance of Circle) but i don't see anything.
I've tried to make code as shorter as possible during the execution of program I type out address of object Widget. It doesn't change. It means that the address of Widget was passed right.
Everywhere, where I type out address of Widget I receive the same address. Here is the code:
header Widget
class Widget : public QWidget
{
public:
int mi,mcount;
Widget(QWidget *parent = 0);
QPaintEvent *ev;
virtual void paintEvent(QPaintEvent *);
void drawcircle();
};
Widget.cpp
Widget::Widget(QWidget *parent) : QWidget(parent)
{
QWidget::paintEvent(ev);
qDebug()<<this<<"\n"; //
}
void Widget::drawcircle()
{
QPainter paint(this);
paint.drawEllipse(0,0,100,100);
}
void Widget::paintEvent(QPaintEvent *ev)
{ this->drawcircle(); }
header Circle.h
class Circle :public QWidget
{
public:
Circle(Widget *widget); // i do trick here!!!
Widget *mwidg;
QPaintEvent *ev;
virtual void paintEvent(QPaintEvent *);
void drawcircle(Widget *mwidg);
};
Circle.cpp
Circle::Circle(Widget *widget)
{
qDebug()<<"circle widget"<<widget;
QWidget::paintEvent(ev);
mwidg=widget;
qDebug()<<"\n"<<mwidg;
}
void Circle::paintEvent(QPaintEvent *ev)
{ qDebug()<<"circle paintEvent mwidget"<<mwidg<<"\n";
this->drawcircle(mwidg);
}
void Circle::drawcircle(Widget *mwidg)
{
QPainter paint(mwidg);
paint.drawEllipse(20,10,40,40);
paint.drawLine(0,0,500,500);
}
main
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget *w=new Widget;
qDebug()<<"main address of widget"<<w<<"\n";
Circle *f=new Circle(w);
w->show();
return a.exec();
}
program is compiled and linked successful
What exactly are you trying to achieve? You can only paint on any widget in it's own paintEvent() handler, and you should not call paintEvent() yourself, it won't work. Also, get rid of the QPaintEvent member variables.
I would suggest that you make Circle a child of Widget, and then paint the circle from Circle::paintEvent(). Alternatively, use QGraphicsView.
well , thank you for your attempts to help
but all that i was needing:
this -> setParent(widget);
in costructor Circle::Circle, if somebody'll want to see my solve,one can see that figures are moved
source code is here source code
Related
I am doing a project in Qt and there is an object QPainter which is declared as :
QPainter painter(this);
Where this points to the present class. My problem is that I need to declare this object such that it is accessible to the entire class functions.
If I declare it inside the constructor then its scope is not valid for other functions, and I cannot declare outside all function in my .cpp file as this variable doesn't make any sense.
So how can I declare my object such that it is accessible to all the functions?
Edit : Painter Code :
void MainWindow :: paintEvent(QPaintEvent * e)
{
QMainWindow::paintEvent(e);
if(1)
{
QPainter painter(this);
QPen paintpen(Qt::red);
paintpen.setWidth(5);
QPoint p1;
p1.setX(mFirstX);
p1.setY(mFirstY);
painter.setPen(paintpen);
painter.drawPoint(p1);
}
}
Mouse Event Code :
void MainWindow :: mousePressEvent(QMouseEvent *e)
{
mFirstX=0;
mFirstY=0;
mFirstClick=true;
mpaintflag=false;
if(e->button() == Qt::LeftButton)
{
//store 1st point
if(1)
{
mFirstX = e->x();
mFirstY = e->y();
mFirstClick = false;
mpaintflag = true;
qDebug() << "First image's coordinates" << mFirstX << "," << mFirstY ;
update();
}
}
}
PROBLEM : I want to create the point but I don't want it to disappear from the widget(mainWindow). Here since the object is created during the paintEvent method each time the point that I am drawing is disappearing when the next point is drawn.
And if I declare it outside the paintEvent then I get the following error:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setPen: Painter not active
In general, declaring the QPainter object globally is not a good idea. It is better to construct it in the QWidget::paintEvent (where it will be active) and, as #Mat said, pass it (by reference) to the functions that need it.
In your particular case the point disappears because the widget is redrawn, not because the QPainter is destroyed. So the strategy should be to create and manage a buffer of points. Add a point to the buffer in a mouse event, e.g. QWidget::mousePressEvent (there do some management too, e.g. limiting the number of points) and in the paint event - paint all the points from the buffer.
Here is an oversimplified example which could easily be adapted for your specific purpose:
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMouseEvent>
#include <QPaintEvent>
#include <QPainter>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
protected:
void mousePressEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
private:
QList<QPoint> m_points;
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "MainWindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
QPalette p = QPalette();
p.setColor(QPalette::Window, Qt::white);
setPalette(p);
setAutoFillBackground(true);
resize(400, 400);
}
void MainWindow::mousePressEvent(QMouseEvent *event)
{
m_points.append(event->pos());
update();
}
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setClipping(true);
painter.setClipRect(event->rect());
painter.setPen(QPen(Qt::red, 5));
foreach (QPoint point, m_points) { painter.drawPoint(point); }
}
That's what class attributes are for :
class MyObject : public QObject {
Q_OBJECT
public:
MyObject(QObject *parent = 0) : QObject(parent), painter_(this) {
// Other things if you need them
}
void aFunction() {
// You can use painter_ here !!
}
private :
QPainter painter_;
}
In the private access specifier of your main window class in mainWindow.h, you could write this line
QPainter *painterPointer
creating a pointer accessible in all MainWindow slots. You could use that painterPointer as though it were any painter pointer initialised in any slot. However if you wanted to use this pointer in a developer defined function or method outside of the MainWindow class, you would have to pass the pointer as a reference (or pointer to the pointer).
might have to include a line similar to this in the MainWindow Constructor
painterPointer = new QPainter(this);
I'm new to Qt, and this issue about auto resizing has driven me crazy.
I create a class called RenderArea that inherits QWidget. In its paintEvent(), I use a QPainter to draw an image. In order for the whole window to scale with the image, I resize before painting. The relevant code is
if (image && !image->isNull())
{
resize(image->size());
painter.drawImage(image->rect(), *image, image->rect());
}
However, RenderArea will stretch too much through other widgets (like buttons and menus). It is contained in a centralWidget with a vertical layout. But when I call centralWidget->adjustSize() it does not scale everything together, but instead shrinks RenderArea t and hides the image.
How do I instruct the central widget as well as the window to scale with the new size of my customized widget? I know I could use a QLabel and set its scaledContents to be true, but I need a lot of other sophisticated rendering so a simple QLabel is not enough.
The sizeHint function should return recommended widget's size. So RenderArea should return image size as its sizeHint. When the image is changed the updateGeometry function should be called to update a cached sizeHint value:
class RenderArea : public QWidget
{
public:
explicit RenderArea(const QImage &image, QWidget *parent = 0)
: QWidget(parent), m_image(image)
{
}
QSize sizeHint() const
{
return m_image.isNull() ? QWidget::sizeHint() : m_image.size();
}
void paintEvent(QPaintEvent *event)
{
QWidget::paintEvent(event);
if (!m_image.isNull())
{
QPainter painter(this);
painter.drawImage(rect(), m_image, m_image.rect());
}
}
void setImage(const QImage &image)
{
m_image = image;
updateGeometry();
}
private:
QImage m_image;
};
When the child widget is resized, the parent widget isn't doing it automatically. Fortunately there is QWidget::adjustSize function which lets us to resize the parent widget to fit its content:
class Window : public QWidget
{
Q_OBJECT
private slots:
void onImageChanged(const QString &fileName)
{
m_area->setImage(QImage(fileName));
adjustSize();
}
private:
RenderArea *m_area;
};
I don't have much experience with Qt and I am having trouble using QPainter.
I am trying to make a simple graphing widget which takes in a number of points and to create a QVector of QPoints, and then uses this vector to draw a polygon. However, nothing is appearing right now with my implementation. I am fairly certain that I have added the widget correctly to the window, as I can see the empty space it should occupy. This leads me to believe the problem to be in the graphing widget.
Any assistance is appreciated.
header:
//graph.h
#ifndef GRAPH_H
#define GRAPH_H
#include <QWidget>
#include <QPainter>
#include <QVector>
class Graph : public QWidget
{
Q_OBJECT
public:
Graph(QWidget *parent = 0);
QSize minimumSizeHint() const;
QSize maximumSizeHint() const;
QSize sizeHint() const;
void addPoint(int w, int h);
void clearPoints();
void drawGraph();
protected:
void paintEvent(QPaintEvent *event);
private:
QPen pen;
QBrush brush;
QPixmap pixmap;
QVector<QPoint> points;
};
#endif // GRAPH_H
source:
//graph.cpp
#include "graph.h"
Graph::Graph(QWidget *parent)
: QWidget(parent)
{
points.resize(0);
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
}
void Graph::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setPen(QPen(Qt::NoPen));
painter.setBrush(QBrush(Qt::green, Qt::SolidPattern));
painter.setRenderHint(QPainter::Antialiasing, true);
painter.drawPolygon(points);
}
QSize Graph::minimumSizeHint() const
{
return sizeHint();
}
QSize Graph::maximumSizeHint() const
{
return sizeHint();
}
QSize Graph::sizeHint() const
{
return QSize(500, 200);
}
void Graph::addPoint(int w, int h)
{
points.append(QPoint(w*2, h*2));
}
void Graph::clearPoints()
{
points.clear();
}
void Graph::drawGraph() {
points.prepend(QPoint(0,0)); //The base points of the graph
points.append(QPoint(500,0));
update();
points.clear();
}
In drawGraph(), the call to update() posts an event notifying the widget to paint itself. You then clear the points and the drawGraph() call exits. After that, the event loop will process the update event and trigger a call to the paintEvent() but by then, there are no points in the vector of points to paint.
Don't think of the paintEvent() as painting something permanent onto the widget once that will be displayed forever until you clear it and paint something else. The paintEvent() needs to be able to paint the widget from scratch whenever it needs to be redrawn. This is often due to a request from the system when the widget is moved, minimized and restored etc. This means your vector of points needs to remain until you no longer want a polygon to be displayed or the points are changed.
It looks like you might be adding only two points to your points-list. I don't think it is possible to have a polygon with only two points; try adding a third point and see if you get a triangle.
I'm having trouble getting events in QGraphicsView working. I've subclassed QGraphicsView and tried to overload the mousePressEvent and wheelEvent. But neither mousePressEvent nor wheelEvent get called.
Here's my code (Edited a few things now):
Declaration:
#include <QGraphicsView>
#include <QGraphicsScene>
class rasImg: public QGraphicsView
{
public:
rasImg(QString file);
~rasImg(void);
initialize();
QGraphicsView *view;
QGraphicsScene *scene;
private:
virtual void mousePressEvent (QGraphicsSceneMouseEvent *event);
virtual void wheelEvent ( QGraphicsSceneMouseEvent * event );
}
Definition:
#include "rasImg.h"
void rasImg::initialize()
{
view = new QGraphicsView();
scene = new QGraphicsScene(QRect(0, 0, MaxRow, MaxCol));
scene->addText("HELLO");
scene->setBackgroundBrush(QColor(100,100,100));
view->setDragMode(QGraphicsView::ScrollHandDrag);
view->setScene(scene);
}
void rasImg::mousePressEvent (QGraphicsSceneMouseEvent *event)
{
qDebug()<<"Mouse released";
scene->setBackgroundBrush(QColor(100,0,0));
}
void rasImg::wheelEvent ( QGraphicsSceneMouseEvent * event )
{
qDebug()<<"Mouse released";
scene->setBackgroundBrush(QColor(100,0,0));
}
So, what am I doing wrong?.Why don't I see a message or background color change when I click the view or use the mouse wheel?
You're not getting the events because they're being handled by the scene object you're creating, not your class.
Remove the QGraphicsScene *scene; from your rasImg and try something like this for the constructor:
rasImg::rasImg(QString file)
: QGraphicsScene(QRect(0, 0, MaxRow, MaxCol))
{
addText("HELLO");
setBackgroundBrush(QColor(100,100,100));
setDragMode(QGraphicsView::ScrollHandDrag);
view = new QGraphicsView();
view->setScene(this);
}
If you want that in two steps, you could do:
rasImg::rasImg(QString file)
: QGraphicsScene()
{
// any constructor work you need to do
}
rasImg::initialize()
{
addText("HELLO");
setSceneRect(QRect(0, 0, MaxRow, MaxCol));
setBackgroundBrush(QColor(100,100,100));
setDragMode(QGraphicsView::ScrollHandDrag);
view = new QGraphicsView();
view->setScene(this);
}
The point is that the scene that is displayed must be an actual instance of your rasImg, not an instance of QGraphicsScene.
If it's the view you're subclassing, do the same thing. The view you're displaying must be an instance of your class, not a plain QGraphicsView.
rasImg::rasImg(QString file)
: QGraphicsView()
{
// constructor work
}
void rasImg::initialize()
{
scene = new QGraphicsScene(QRect(0, 0, MaxRow, MaxCol));
scene->addText("HELLO");
scene->setBackgroundBrush(QColor(100,100,100));
setDragMode(QGraphicsView::ScrollHandDrag);
setScene(scene);
}
QGraphicsView is derived from QWidget. Therefore it receives mouse events like regular widgets. If your code really is
void rasImg::mousePressEvent (QGraphicsSceneMouseEvent *event)
It can not receive events since it should be
void rasImg::mousePressEvent ( QMouseEvent *event )
QGraphicsSceneMouseEvent is for items in QGraphicsScene that receive mouse input.
If you would like to handle clicks on a specific GUI element rather than handle click on the whole scene, you should derive your own class either from QGraphicsItem (see example of SimpleClass here) or derive from one of existing elements, e.g. QGraphicsPixmapItem.
In both cases in your derived class you can override void mousePressEvent(QGraphicsSceneMouseEvent *event);
I'm trying for half an eternity now overriding QWidgets keyPressEvent function in QT but it just won't work. I've to say i am new to CPP, but I know ObjC and standard C.
My problem looks like this:
class QSGameBoard : public QWidget {
Q_OBJECT
public:
QSGameBoard(QWidget *p, int w, int h, QGraphicsScene *s);
signals:
void keyCaught(QKeyEvent *e);
protected:
virtual void keyPressEvent(QKeyEvent *event);
};
QSGameBoard is my QWidget subclass and i need to override the keyPressEvent and fire a SIGNAL on each event to notify some registered objects.
My overridden keyPressEvent in QSGameBoard.cpp looks like this:
void QSGameBoard::keyPressEvent(QKeyEvent *event) {
printf("\nkey event in board: %i", event->key());
//emit keyCaught(event);
}
When i change QSGameBoard:: to QWidget:: it receives the events, but i cant emit the signal because the compiler complains about the scope. And if i write it like this the function doesn't get called at all.
What's the problem here?
EDIT:
As pointed out by other users, the method I outlined originally is not the proper way to resolve this.
Answer by Vasco Rinaldo
Use Set the FocusPolicy to Qt::ClickFocus to get the keybordfocus by
mouse klick. setFocusPolicy(Qt::ClickFocus);
The previous (albeit imperfect) solution I gave is given below:
Looks like your widget is not getting "focus". Override your mouse press event:
void QSGameBoard::mousePressEvent ( QMouseEvent * event ){
printf("\nMouse in board");
setFocus();
}
Here's the source code for a working example:
QSGameBoard.h
#ifndef _QSGAMEBOARD_H
#define _QSGAMEBOARD_H
#include <QWidget>
#include <QGraphicsScene>
class QSGameBoard : public QWidget {
Q_OBJECT
public:
QSGameBoard(QWidget *p, int w, int h, QGraphicsScene *s);
signals:
void keyCaught(QKeyEvent *e);
protected:
virtual void keyPressEvent(QKeyEvent *event);
void mousePressEvent ( QMouseEvent * event );
};
#endif /* _QSGAMEBOARD_H */
QSGameBoard.cpp
#include <QKeyEvent>
#include <QLabel>
#include <QtGui/qgridlayout.h>
#include <QGridLayout>
#include "QSGameBoard.h"
QSGameBoard::QSGameBoard(QWidget* p, int w, int h, QGraphicsScene* s) :
QWidget(p){
QLabel* o = new QLabel(tr("Test Test Test"));
QGridLayout* g = new QGridLayout(this);
g->addWidget(o);
}
void QSGameBoard::keyPressEvent(QKeyEvent* event){
printf("\nkey event in board: %i", event->key());
}
void QSGameBoard::mousePressEvent ( QMouseEvent * event ){
printf("\nMouse in board");
setFocus();
}
main.cpp
#include <QtGui/QApplication>
#include <QtGui/qmainwindow.h>
#include "QSGameBoard.h"
int main(int argc, char *argv[]) {
// initialize resources, if needed
// Q_INIT_RESOURCE(resfile);
QApplication app(argc, argv);
QMainWindow oM;
QGraphicsScene o;
QSGameBoard a(&oM, 1, 2, &o);
oM.setCentralWidget(&a);
a.show();
oM.show();
// create and show your widgets here
return app.exec();
}
You don't have to reimplement mousePressEvent yourself just to call setFocus. Qt planed it already.
Set the FocusPolicy to Qt::ClickFocus to get the keybordfocus by mouse klick.
setFocusPolicy(Qt::ClickFocus);
As said in the manual:
This property holds the way the widget accepts keyboard focus.
The policy is Qt::TabFocus if the widget accepts keyboard focus by tabbing, Qt::ClickFocus if the widget accepts focus by clicking, Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if it does not accept focus at all.
You must enable keyboard focus for a widget if it processes keyboard events. This is normally done from the widget's constructor. For instance, the QLineEdit constructor calls setFocusPolicy(Qt::StrongFocus).
If the widget has a focus proxy, then the focus policy will be propagated to it.
Set the FocusPolicy to Qt::ClickFocus to get the keybordfocus by mouse klick.
setFocusPolicy(Qt::ClickFocus);