Qt Newbie here experiencing a problem where it claims that I did not declare a class which I'm pretty sure is declared.
I cannot for the life of me figure this out. Please help.
Commenting out the problematic lines in Connection.h and .cpp results in compilable output.
Here is a slimmed down version of my code where the problem still exists:
Btw, Map.ui only has a Graphics View dragged into it.
Error message:
In file included from ../Map/Map.h:17:0,
from ../Map/City.cpp:1:
../Map/Connection.h:14:11: error: 'City' was not declared in this scope
QPair<City*, City*> cities;
^
../Map/Connection.h:14:18: error: 'City' was not declared in this scope
QPair<City*, City*> cities;
^
../Map/Connection.h:14:23: error: template argument 1 is invalid
QPair<City*, City*> cities;
^
../Map/Connection.h:14:23: error: template argument 2 is invalid
../Map/Connection.h:19:22: error: 'City' was not declared in this scope
Connection(QPair<City*, City*> cities, int cost);
^
../Map/Connection.h:19:29: error: 'City' was not declared in this scope
Connection(QPair<City*, City*> cities, int cost);
^
../Map/Connection.h:19:34: error: template argument 1 is invalid
Connection(QPair<City*, City*> cities, int cost);
Map.pro:
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = Map
TEMPLATE = app
SOURCES +=\
City.cpp \
Connection.cpp \
Map.cpp \
Driver.cpp
HEADERS += \
City.h \
Connection.h \
Map.h
FORMS += \
Map.ui
Map.h:
#ifndef MAP_H
#define MAP_H
#include <QApplication>
#include <QGraphicsItem>
#include <QMainWindow>
#include <QtCore>
#include <QtGui>
#include <QGraphicsScene>
#include <QGraphicsEllipseItem>
#include <QDebug>
#include <QPainter>
#include <QString>
#include <QVector>
#include "ui_Map.h"
#include "Connection.h"
#include "City.h"
namespace Ui
{
class Map;
}
class Map : public QMainWindow
{
Q_OBJECT
public:
explicit Map(QWidget *parent = 0);
~Map();
private:
Ui::Map *ui;
QGraphicsScene *scene;
};
#endif // MAP_H
Map.cpp:
#include "Map.h"
#include "ui_Map.h"
Map::Map(QWidget *parent) : QMainWindow(parent), ui(new Ui::Map)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
City *c1 = new City(30, 30, 30, "K");
City *c2 = new City(30, 90, 30, "O");
Connection *conn1 = new Connection(45, 45, 45, 105, 1);
c1->setZValue(4);
c2->setZValue(4);
conn1->setZValue(2);
scene->addItem(c1);
scene->addItem(c2);
scene->addItem(conn1);
}
Map::~Map()
{
delete ui;
}
City.h:
#ifndef CITY_H
#define CITY_H
#include "Map.h"
class City : public QGraphicsItem
{
private:
int x;
int y;
int r;
QString name;
QRectF bounds;
QVector<QPair<City*, int> > neighbors;
public:
City();
City(int x, int y, int r, QString name);
int getX() { return this->x; }
int getY() { return this->y; }
int getR() { return this->r; }
QString getName() { return this->name; }
QVector<QPair<City*, int> > getNeighbors() { return this->neighbors; }
void setNeighbors(QVector<QPair<City*, int> >) { this->neighbors = neighbors; }
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
#endif // CITY_H
City.cpp:
#include "Map.h"
City::City()
{
this->bounds = QRectF(0, 0, 0, 0);
}
City::City(int x, int y, int r, QString name)
{
this->x = x;
this->y = y;
this->r = r;
this->name = name;
this->bounds = QRectF(x, y, r, r);
}
QRectF City::boundingRect() const
{
return QRectF(x, y, r, r);
}
void City::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec;
if (this->bounds == QRectF(0, 0, 0, 0))
rec = boundingRect();
else
rec = this->bounds;
QBrush brush(Qt::blue);
QPen pen(Qt::blue);
painter->setBrush(brush);
painter->setPen(pen);
painter->drawEllipse(rec);
}
Connection.h:
#ifndef CONNECTION_H
#define CONNECTION_H
#include "Map.h"
class Connection : public QGraphicsItem
{
private:
int x1, x2;
int y1, y2;
int cost;
QRectF bounds;
QPair<City*, City*> cities; // PROBLEMATIC LINE -- CLAIMS CITY WAS NOT DECLARED
public:
Connection();
Connection(int x1, int y1, int x2, int y2, int cost);
Connection(QPair<City*, City*> cities, int cost); // PROBLEMATIC LINE -- CLAIMS CITY WAS NOT DECLARED
int getCost() { return this->cost; }
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
};
#endif // CONNECTION_H
Connection.cpp:
#include "Map.h"
Connection::Connection()
{
this->bounds = QRectF(0, 0, 0, 0);
}
Connection::Connection(int x1, int y1, int x2, int y2, int cost)
{
this->x1 = x1;
this->x2 = x2;
this->y1 = y1;
this->y2 = y2;
this->bounds = QRectF(x1, x2, y1, y2);
}
Connection::Connection(QPair<City*, City*> cities, int cost) // PROBLEMATIC BLOCK
{
int r = cities.first->getR();
this->x1 = cities.first->getX() + r/2;
this->x2 = cities.second->getX() + r/2;
this->y1 = cities.first->getY() + r/2;
this->y2 = cities.second->getY() + r/2;
this->cost = cost;
this->bounds = QRectF(x1, x2, y1, y2);
}
QRectF Connection::boundingRect() const
{
return QRectF(0, 0, 0, 0);
}
void Connection::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec;
if (this->bounds == QRectF(0, 0, 0, 0))
rec = boundingRect();
else
rec = this->bounds;
QBrush brush(Qt::red);
QPen pen(Qt::red);
painter->setPen(pen);
painter->drawLine(QLine(this->x1, this->y1, this->x2, this->y2));
}
Driver.cpp:
#include "Map.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Map w;
w.show();
return a.exec();
}
Thank you for taking the time to look at this. I appreciate any feedback whatsoever. The problematic lines were compilable for a while but it seems that adding certain things "broke" it.
The answer to this thread got me thinking it might be something silly, but my attempts to change the order of things have not fixed it.
Just looking at the error message one can see that the City class is indeed not defined at Connection.
In file included from ../Map/Map.h:17:0,
from ../Map/City.cpp:1:
City.cpp starts out with a #include "Map.h" which is odd because there are no references to the Map type in the cpp file. City.cpp should start out with an #include "City.h".
City.h starts out with an #include "Map.h" which is even stranger because the City class make no mention of Map.
So at this point City.cpp:1 -> Map.h :17 you are including "Connection.h". At this point, there are no defined types. Not City, not Map. The compiler approaches the class Connection with no types defined.
Fixing it:
It is hard to guess how your dependencies actually look like but one solution for this particular include might be.
Start by including City.h first in your City.cpp. You should #include "X.h" for all X.cpp files.
Remove the #include "Map.h" from the City.h file.
If the Map type is required in City.cpp, include it.
The Connection.h obviously requires at least a forward declared class class City because of the pointers. So either do a forward declaration or an `#include "City.h"
In conclusion: Only include files in the header that your class actually requires. In the corresponding cpp, first include the header. Any type the header requires will also be required by the implementation. After that you include the additional types your implementation requires.
Related
Sorry, I use google translator.
I am exploring how QGraphicsItem works.
But I don’t understand how the data is transmitted through the pointers to the scene.
Here is a code
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "qmyscene.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QMyScene(this);
ui->graphicsView->setScene(scene);
scene->setSceneRect(0,0,800,600);
}
MainWindow::~MainWindow()
{
delete ui;
}
qmyscene.cpp
#include "qmyscene.h"
#include "qpixitem.h"
#include <qdebug.h>
QMyScene::QMyScene(QObject *parent) : QGraphicsScene(parent)
{
QPixItem *pix1 = new QPixItem (this,100,100);
QPixItem *pix2 = new QPixItem (this,50,50);
}
QMyScene::~QMyScene()
{
}
qpixitem.cpp
#include "qpixitem.h"
#include <QMessageBox>
QPixItem::QPixItem (QGraphicsScene *MyScene,int x,int y): QGraphicsPixmapItem()
{
QPixmap pic (":/Items/OutLet.png");
this->setPixmap(pic);
this->setPos(x, y);
this->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges);
qDebug() << "create";
QGraphicsLineItem* line = MyScene->addLine(QLineF(40, 40, 80, 80));
MyScene->addItem(this);
}
QVariant QPixItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemPositionChange)
{
QPointF newPos = value.toPointF();
int p1 = newPos.x();
int p2 = newPos.y();
MyScene->addLine(QLineF(40,40,p1, p2)); //error
//this->line->setLine(QLineF(40,40,p1, p2)); //error
qDebug() << "Scene::move";
}
return QGraphicsItem::itemChange(change, value);
}
qmyscene.h
#ifndef QMYSCENE_H
#define QMYSCENE_H
#include <QGraphicsScene>
#include <QDebug>
class QMyScene: public QGraphicsScene
{
Q_OBJECT
public:
explicit QMyScene(QObject *parent = 0);
~QMyScene();
private:
};
#endif // QMYSCENE_H
qpixitem.h
#ifndef QPIXITEM_H
#define QPIXITEM_H
#include <QGraphicsItem>
#include "QGraphicsScene"
#include "mainwindow.h"
#include <QGraphicsPixmapItem>
class QPixItem: public QGraphicsPixmapItem
{
public:
QPixItem (QGraphicsScene *MyScene,int x,int y);
QGraphicsScene *MyScene;
int x,y;
private:
QGraphicsLineItem* line;
QVariant itemChange(GraphicsItemChange change, const QVariant &value);
};
#endif // QPIXITEM_H
// error - the lines cause an error (closing the program due to memory access), I am sure that this is due to improperly used pointers. How to use them correctly in such code?
You never seem to allocate this->line.
Did you mean:
this->line = MyScene->addLine(QLineF(40, 40, 80, 80));
Instead of
QGraphicsLineItem* line = MyScene->addLine(QLineF(40, 40, 80, 80));
I am just creating a simple program which displays a point where a car object is, and updates where this point is using a timer so that later it is possible for it to move.
My code is currently just displaying the point at (0, 0), and I can't work out why.
My mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <iostream>
#include "twovector.h"
#include "car.h"
#include "vehicle.h"
#include <vector>
#include <QTimer>
#include <QStandardItem>
#include <QPainter>
using namespace std;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
fCar = new Car(TwoVector(150, 2), 4);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(paintEvent()));
// connect(timer, SIGNAL(timeout()), this, SLOT(Drive()));
timer->start(10);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::Drive(){
fCar->Drive(fCar->GetVelocity());
}
void MainWindow::paintEvent(QPaintEvent *){
QPainter painter(this);
QPen DotPen(Qt::red);
DotPen.setWidth(10);
painter.setPen(DotPen);
//painter.drawPoint(0, 0);
painter.drawPoint((fCar->GetPosition().GetRadius())*(cos(fCar->GetPosition().GetAngle()))
, (fCar->GetPosition().GetRadius())*(sin(fCar->GetPosition().GetAngle())));
//Draw the dot, where the centre of the window is (0,0)
}
The mainwindow header file:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "car.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void Drive();
void paintEvent(QPaintEvent *);
private:
Ui::MainWindow *ui;
Car *fCar;
};
#endif // MAINWINDOW_H
vehicle.ccp (from which the car class inherits from)
#include "vehicle.h"
#include "twovector.h"
#include <iostream>
using namespace std;
Vehicle::Vehicle(){
}
Vehicle::Vehicle(TwoVector position, double velocity){
fPosition = position;
fVelocity = velocity;
}
Vehicle::~Vehicle(){
}
void Vehicle::SetValue(string ValueName, double Value) {
if(ValueName.compare("Radius") == 0)
fPosition.SetRadius(Value);
else{
if(ValueName.compare("Angle") == 0)
fPosition.SetAngle(Value);
else if(ValueName.compare("Velocity") == 0)
fVelocity = Value;
else
cerr << "Unknown field entered: " << ValueName << endl;
}
}
void Vehicle::Drive(int velocity){
fPosition.SetAngle(fPosition.GetAngle() + (velocity)/(fPosition.GetRadius()));
}
vehicle.h:
#ifndef VEHICLE_H
#define VEHICLE_H
#include "twovector.h"
#include <iostream>
using namespace std;
class Vehicle
{
public:
Vehicle();
Vehicle(TwoVector position, double velocity);
~Vehicle();
inline TwoVector GetPosition() {return fPosition;}
inline double GetVelocity() {return fVelocity;}
inline void SetPosition(TwoVector position) {fPosition = position;}
void SetValue(string ValueName, double Value);
void Drive(int velocity);
private:
TwoVector fPosition;
double fVelocity;
};
#endif // VEHICLE_H
Twovector.ccp:
#include "twovector.h"
TwoVector::TwoVector(){
fRadius = 0;
fTheta = 0;
}
TwoVector::TwoVector(double radius, double theta){
fRadius = radius;
fTheta = theta;
}
TwoVector::~TwoVector(){
}
TwoVector TwoVector::operator +=(TwoVector position1){
TwoVector position2;
//Creates a new object which is given a position
position2.fRadius = sqrt(((fRadius)*(fRadius))+((position1.fRadius)*(position1.fRadius))
+ 2*((position1.fRadius)*(fRadius))*cos((position1.fTheta)-(fTheta)));
position2.fTheta = fTheta + atan2((position1.fRadius)*(sin((position1.fTheta)-(fTheta))),
fRadius + (position1.fRadius)*(cos((position1.fTheta)-fTheta)));
return(position2);
//New position returned
}
TwoVector.h:
#ifndef TWOVECTOR_H
#define TWOVECTOR_H
#include <math.h>
class TwoVector {
public:
TwoVector();
TwoVector(double radius, double theta);
~TwoVector();
inline double GetX() {return fRadius*cos(fTheta);}
inline double GetY() {return fRadius*sin(fTheta);}
inline double GetRadius() const {return fRadius;}
inline double GetAngle() const {return fTheta;}
//Accessor functions, these simply return the value of the coordinates
inline void SetRadius(double radius) {fRadius = radius;}
inline void SetAngle(double theta) {fTheta = theta;}
inline void SetRadiusAndAngle(double radius, double theta) {
fRadius = radius, fTheta = theta;}
//Mutator function to change the position
TwoVector operator += (TwoVector);
//Operator overloading so that vectors can be added
private:
double fRadius;
double fTheta;
};
#endif // TWOVECTOR_H
car.h:
#ifndef CAR_H
#define CAR_H
#include "twovector.h"
#include "vehicle.h"
#include <iostream>
using namespace std;
class Car: public Vehicle {
public:
Car();
Car(TwoVector position, double velocity);
~Car();
private:
TwoVector fPositioncar;
double fVelocitycar;
};
#endif // CAR_H
car.cpp:
#include "car.h"
Car::Car(){
}
Car::Car(TwoVector position, double velocity){
fPositioncar = position;
fVelocitycar = velocity;
}
Car::~Car(){
}
Any help will be appreciated!
Do not call the paintEvent method directly, you must do it through the update() method and as in your case you want to update the position, it is advisable to make the following modifications:
[...]
QTimer *timer = new QTimer(this);
//connect(timer, SIGNAL(timeout()), this, SLOT(paintEvent()));
connect(timer, SIGNAL(timeout()), this, SLOT(Drive()));
timer->start(10);
[...]
void MainWindow::Drive(){
fCar->Drive(fCar->GetVelocity());
update();
}
[...]
Another problem is that you have not called the parent's constructor:
car.cpp
#include "car.h"
Car::Car():Vehicle(){
}
Car::Car(TwoVector position, double velocity):Vehicle(position, velocity){
fPositioncar = position;
fVelocitycar = velocity;
}
Car::~Car(){
}
Also velocity is a value of type double, on the other hand Drive is configured for integer, you must change it to:
vehicle.cpp
[...]
void Vehicle::Drive(double velocity){
fPosition.SetAngle(fPosition.GetAngle() + (velocity)/(fPosition.GetRadius()));
}
The complete project with the modifications can be seen in the following link.
I added a Line subclass from the GraphicsScene class , to draw a line. From MainWindow I call the line function in that class, there are no errors, but the line isn't drawn. I know this must be lack of my c++ skills. But searching didn't help me on this one. What I want is to make different classes for drawing different shapes, instead of polluting the GraphicsScene with all that code, to keep things a bit structured. But what am I doing wrong? I posted my code on github github.com/JackBerkhout/QT_Draw001
line.h
#ifndef LINE_H
#define LINE_H
#include <QMainWindow>
#include <QObject>
#include <QDebug>
#include "graphicsscene.h"
class Line: public GraphicsScene
{
public:
Line();
void drawLine(int x1, int y1, int x2, int y2);
};
#endif // LINE_H
line.cpp
#include "line.h"
Line::Line():
GraphicsScene()
{
}
void Line::drawLine(int x1, int y1, int x2, int y2)
{
// Just draw something by clicking a button
qDebug() << "line"; // This debug message is shown
QColor color;
color.setRgb(128, 0, 255);
QPen pen;
pen.setColor(color);
pen.setWidth(20);
pen.setCapStyle(Qt::RoundCap);
this->addLine(x1, y1, x2, y2, pen); // Didn't draw the line on the scene
}
graphicsscene.cpp
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPointF>
#include <QList>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent);
QPointF getMousePoint(void);
int getMouseX(void);
int getMouseY(void);
int getNumber(void);
void setNumber(int num);
QPointF mousePoint;
int MouseX, MouseY;
int myNumber;
signals:
void changedMousePosition(QPointF mousePoint);
void changedNumber(int myNumber);
public slots:
private:
QList <QPointF> mousePoints;
// int Number;
};
#endif // GRAPHICSSCENE_H
graphicsscene.cpp
#include "mainwindow.h"
#include "graphicsscene.h"
#include <QDebug>
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
this->setBackgroundBrush(Qt::black);
myNumber = 0;
// this-> ->setMouseTracking(true);
}
void GraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
// mousePoint = mouseEvent->scenePos();
// MouseX = mousePoint.x();
// MouseY = mousePoint.y();
qDebug() << Q_FUNC_INFO << mouseEvent->scenePos();
QGraphicsScene::mouseDoubleClickEvent(mouseEvent);
}
void GraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
mousePoint = mouseEvent->scenePos();
MouseX = mouseEvent->scenePos().x();
MouseY = mouseEvent->scenePos().y();
emit changedMousePosition(mousePoint);
QGraphicsScene::mouseMoveEvent(mouseEvent);
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
mousePoint = mouseEvent->scenePos();
MouseX = mouseEvent->scenePos().x();
MouseY = mouseEvent->scenePos().y();
mousePoints.append(mouseEvent->scenePos());
MainWindow *mainWindow = new MainWindow();
mainWindow->Count++;
if(mousePoints.size() == 2)
{
myNumber++;
emit changedNumber(myNumber);
QColor color;
color.setRgb(128, 0, 255);
QPen pen;
pen.setColor(color);
pen.setWidth(20);
pen.setCapStyle(Qt::RoundCap);
this->addLine(mousePoints.at(0).x(), mousePoints.at(0).y(), mousePoints.at(1).x(), mousePoints.at(1).y(), pen);
mousePoints.clear();
}
QGraphicsScene::mousePressEvent(mouseEvent);
}
void GraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
mousePoint = mouseEvent->scenePos();
MouseX = mouseEvent->scenePos().x();
MouseY = mouseEvent->scenePos().y();
QGraphicsScene::mouseReleaseEvent(mouseEvent);
}
QPointF GraphicsScene::getMousePoint(void)
{
return mousePoint;
}
int GraphicsScene::getMouseX(void)
{
MouseX = mousePoint.x();
return mousePoint.x();
}
int GraphicsScene::getMouseY(void)
{
MouseY = mousePoint.y();
return mousePoint.y();
}
void GraphicsScene::setNumber(int num)
{
myNumber = num;
}
int GraphicsScene::getNumber(void)
{
return myNumber;
}
You are complicating too much, besides that I think you do not understand what is the purpose of the inheritance, you just have to create a function in GraphicsScene called drawLine and use it when you need it.
GraphicsScene.h
public:
void drawLine(int x1, int y1, int x2, int y2);
GraphicsScene.cpp
void GraphicsScene::drawLine(int x1, int y1, int x2, int y2)
{
QColor color;
color.setRgb(128, 0, 255);
QPen pen;
pen.setColor(color);
pen.setWidth(20);
pen.setCapStyle(Qt::RoundCap);
addLine(x1, y1, x2, y2, pen);
}
And then you call in Mainwindow:
void MainWindow::on_toolButtonDraw_clicked()
{
scene->drawLine(300, 100, 500, 300);
}
When you create a Line object you are creating a new scene and it will be drawn in that scene, so you will not see it.
I'm having some problems with my script. Everything was fine for a while but now when I #include a file I get errors that occur on any line pointing to another class. Like these (there's actually 12 of them..):
x:\development\inkpuppet\newdialog.h:20: error: C2143: syntax error : missing ';' before '*'
x:\development\inkpuppet\newdialog.h:20: error: C4430: missing type specifier - int assumed. Note: C++ does not support default-int
Occurs when I say InkPuppet *pointerToPuppet;
Edit: the include I can't put in the header is inkspot.h in the inkpuppet.h header.
For each pointer I get the two above errors x3.
Then I get errors because obviously the pointers no longer work.
I'm going to go ahead and post all my code because I do not know which parts will be relevant.
inkpuppet.h
#ifndef INKPUPPET_H
#define INKPUPPET_H
#include "inkspot.h"
//#include "ui_inkpuppet.h"
#include <QMainWindow>
#include <QWidget>
namespace Ui {
class InkPuppet;
}
class InkPuppet : public QMainWindow
{
Q_OBJECT
public:
explicit InkPuppet(QWidget *parent = 0);
~InkPuppet();
Ui::InkPuppet *ui;
private slots:
void setMinimum(int value);
void setMaximum(int value);
void actionNew();
void actionAbout();
void setSpacing(int);
void on_colorAButton_clicked();
};
#endif // INKPUPPET_H
inkpuppet.cpp
#include "inkpuppet.h"
#include "ui_inkpuppet.h"
#include "newdialog.h"
#include "aboutdialog.h"
#include "inkspot.h"
#include <Qt>
#include <QtCore>
#include <QtGui>
#include <QWidget>
#include <QDialog>
#include <QMainWindow>
#include <QDebug>
#include <QColorDialog>
InkPuppet::InkPuppet(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::InkPuppet)
{
ui->setupUi(this);
//connect the frame range boxes to the timeslider
connect(ui->lowerFrameBox, SIGNAL(valueChanged(int)), this, SLOT(setMinimum(int)));
connect(ui->upperFrameBox, SIGNAL(valueChanged(int)), this, SLOT(setMaximum(int)));
//connect tool palette items
connect(ui->spacingBox, SIGNAL(valueChanged(int)), this, SLOT(setSpacing(int)));
connect(ui->colorAButton, SIGNAL(clicked()), this, SLOT(on_colorAButton_clicked()));
//connect the menu items
connect(ui->actionNew, SIGNAL(triggered()), this, SLOT(actionNew()));
connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(actionAbout()));
}
void InkPuppet::setMinimum(int value)
{
ui->timeSlider->setMinimum(value);
ui->frameNumberBox->setMinimum(value);
}
void InkPuppet::setMaximum(int value)
{
ui->timeSlider->setMaximum(value);
ui->frameNumberBox->setMaximum(value);
}
void InkPuppet::setSpacing(int)
{
InkSpot *spot = new InkSpot(this);
//spot->puppet = this;
spot->spacing = ui->spacingBox->value();
}
//menu items
void InkPuppet::actionNew()
{
NewDialog *nDialog = new NewDialog;
//nDialog->createNew(this);
nDialog->pointerToPuppet = this;
nDialog->setModal(true);
nDialog->show();
}
void InkPuppet::actionAbout()
{
AboutDialog *aDialog = new AboutDialog;
aDialog->setModal(true);
aDialog->show();
}
//tool menu
void InkPuppet::on_colorAButton_clicked()
{
// QColor color = QColorDialog(QColor->setRgb(255, 0, 0));
// //color->setRgb(0, 0, 0);
// qDebug() << "done";
// if(color->isValid())
// {
// QString qss = QString("background-color: %1").arg(color->name());
// ui->colorAButton->setStyleSheet(qss);
// }
}
InkPuppet::~InkPuppet()
{
delete ui;
}
inkspot.h
#ifndef INKSPOT_H
#define INKSPOT_H
#include "newdialog.h"
//#include "inkpuppet.h"
#include <QObject>
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
#include <QLabel>
#include <QPoint>
#include <QImage>
namespace Ui {
class InkSpot;
}
class InkSpot : public QWidget
{
Q_OBJECT
public:
explicit InkSpot(QWidget *parent = 0);
void draw(QPainter *painter);
QWidget *widget;
int canvasWidth;
int canvasHeight;
float spacing;
NewDialog *newDialog;
QPixmap pixmap;
signals:
//int sendWidthOfCanvas();
//void sendHeightOfCanvas();
public slots:
//void widthOfCanvas();
//void heightOfCanvas();
protected:
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void paintEvent(QPaintEvent *event);
private:
void drawLineTo(const QPoint &endPoint);
bool drawing;
QPoint lastPoint;
QImage image;
QImage test2;
Ui::InkSpot *ui;
};
#endif // INKSPOT_H
inkspot.cpp
#include "inkspot.h"
#include "inkpuppet.h"
#include "ui_inkpuppet.h"
#include "newdialog.h"
#include "ui_newdialog.h"
#include <QtCore>
#include <QtGui>
#include <QWidget>
#include <QPainter>
#include <QPaintEvent>
InkSpot::InkSpot(QWidget *parent) :
QWidget(parent)
{
widget = this;
drawing = false;
//spacing = puppet->ui->spacingBox->value();
spacing = 1;//puppet->ui->spacingBox->value();
}
void InkSpot::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
lastPoint = event->pos();
drawing = true;
}
}
void InkSpot::mouseMoveEvent(QMouseEvent *event)
{
if((event->buttons() & Qt::LeftButton) && drawing)
{
drawLineTo(event->pos());
}
}
void InkSpot::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton && drawing)
{
drawLineTo(event->pos());
drawing = false;
}
}
void InkSpot::drawLineTo(const QPoint &endPoint)
{
QPainter painter(&pixmap);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::NoBrush);
QFile *stencilInput; // file for input, assumes a SQUARE RAW 8 bit grayscale image, no JPG no GIF, no size/format header, just 8 bit values in the file
char *brushPrototype; // raw brush prototype
uchar *brushData; // raw brush data
stencilInput = new QFile("C:/brush3.raw"); // open raw file
stencilInput->open(QIODevice::ReadOnly);
QDataStream in;
in.setDevice(stencilInput);
int size = stencilInput->size(); // set size to the length of the raw file
brushPrototype = new char[size]; // create the brush prototype array
in.readRawData(brushPrototype, size); // read the file into the prototype
brushData = new uchar[size]; // create the uchar array you need to construct QImage
for (int i = 0; i < size; ++i)
brushData[i] = (uchar)brushPrototype[i]; // copy the char to the uchar array
QImage test(brushData, 128, 128, QImage::Format_Indexed8); // create QImage from the brush data array
// 128x128 was my raw file, for any file size just use the square root of the size variable provided it is SQUARE
QImage test2(128, 128, QImage::Format_ARGB32);
QVector<QRgb> vectorColors(256); // create a color table for the image
for (int c = 0; c < 256; c++)
vectorColors[c] = qRgb(c, c, c);
test.setColorTable(vectorColors); // set the color table to the image
for (int iX = 0; iX < 128; ++iX) // fill all pixels with 255 0 0 (red) with random variations for OIL PAINT effect
// use your color of choice and remove random stuff for solid color
// the fourth parameter of setPixel is the ALPHA, use that to make your brush transparent by multiplying by opacity 0 to 1
{
for (int iY = 0; iY < 128; ++iY)
{
test2.setPixel(iX, iY, qRgba(255, 100, 100, (255-qGray(test.pixel(iX, iY)))*0.5));
}
}
// final convertions of the stencil and color brush
QPixmap testPixmap = QPixmap::fromImage(test2);
QPixmap testPixmap2 = QPixmap::fromImage(test);
painter.setBrush(Qt::NoBrush);
painter.setPen(Qt::NoPen);
// in a paint event you can test out both pixmaps
// QLineF line = QLineF(lastPoint, endPoint);
// float lineLength = line.length();
// qDebug() << line.length();
// line.setLength(100.01f);
// qDebug() << line.length();
QPainterPath path = QPainterPath(lastPoint);
path.lineTo(endPoint);
//qDebug() << path.currentPosition();
//qDebug() << path.length();
qreal length = path.length();
qreal pos = 0;
while (pos < length)
{
qreal percent = path.percentAtLength(pos);
painter.drawPixmap(path.pointAtPercent(percent).x() - 16, path.pointAtPercent(percent).y() - 16, 32, 32, testPixmap);
pos += spacing;
}
//painter.drawPixmap(line.p1().x() - 16, line.p1().y() - 16, 32, 32, testPixmap);
//delete all dynamically allocated objects with no parents
delete [] brushPrototype;
delete [] brushData;
delete stencilInput;
lastPoint = endPoint;
}
void InkSpot::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
painter.setPen(Qt::NoPen);
painter.setBrush(Qt::NoBrush);
QRect rect = event->rect();
painter.drawPixmap(rect, pixmap, rect);
qDebug() << spacing;
update();
}
newdialog.h
#ifndef NEWDIALOG_H
#define NEWDIALOG_H
//#include "ui_newdialog.h"
#include "inkpuppet.h"
#include <QDialog>
namespace Ui {
class NewDialog;
}
class NewDialog : public QDialog
{
Q_OBJECT
public:
explicit NewDialog(QWidget *parent = 0);
~NewDialog();
InkPuppet *pointerToPuppet;
Ui::NewDialog *ui;
public slots:
//void createNew(InkPuppet *existingPuppet);
void createNew();
};
#endif // NEWDIALOG_H
newdialog.cpp
#include "newdialog.h"
#include "ui_newdialog.h"
#include "inkpuppet.h"
#include "ui_inkpuppet.h"
#include "inkspot.h"
#include <QDebug>
#include <QSignalMapper>
#include <QObject>
#include <QtOpenGL/QGLWidget>
NewDialog::NewDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::NewDialog)
{
ui->setupUi(this);
connect(ui->buttonBox, SIGNAL(accepted()), SLOT(createNew()));
//connect(ui->buttonBox, SIGNAL(accepted()), SLOT(createNew(InkPuppet*)));
}
void NewDialog::createNew()
{
InkSpot *ink;
ink = new InkSpot();
ink->newDialog = this;
pointerToPuppet->ui->canvas->addWidget(ink->widget);
//QSize size = pointerToPuppet->ui->canvas->sizeHint();
ink->widget->resize(ui->widthBox->value(), ui->heightBox->value());
pointerToPuppet->ui->scrollCanvasItems->resize(ui->widthBox->value(), ui->heightBox->value());
//pointerToPuppet->ui->canvas->setAlignment(ink->widget, Qt::AlignAbsolute);
ink->pixmap = QPixmap(QSize(ui->widthBox->value(), ui->heightBox->value()));
close();
}
NewDialog::~NewDialog()
{
delete ui;
}
main.cpp
#include "inkpuppet.h"
#include "inkspot.h"
#include "newdialog.h"
#include "aboutdialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
InkPuppet w;
w.show();
return a.exec();
}
You have circular dependencies. "inkpuppet.h" includes "inkspot.h", which includes "newdialog.h", which includes "inkpuppet.h". Use forward declarations instead, where you can.
You have circular includes, that are prevented by your header guardians. This means that in your newdialog.h the line #include "inkpuppet.h" does nothing, resulting in the InkPuppet class is not declared. You need to replace the include line by a forward declaration class InkPuppet; and don't forget to include the file in the cpp (in that case, you've got it already).
EDIT: You have to be careful with the namespaces as well, you've got all your classes in two namespaces (global and Ui).
I have a problem with the execution of multiple functions at once.
Specific , I have two classes (MyRect and space). The Idea is similar to space invaders but I stuck on the beginning. In class MyRect I have defined two rectangles :: body (ship body) and bullet (ship bullet).In the main class space is created ship as MyRect new object with body && bullet rectangles.Also there is definition for keyPress events.
Problem is that when I fire bullet , everythig stops excetp moving of bullet and until loop MyRect::fireBullet(int x, int y) is done , i cant move ship during this event.Obviously, I do some fundamental mistakes so if someone is willing to clarify this.
here is sample code ::
MyRect.h
#include <QWidget>
#include <QRect>
#include <QMainWindow>
#include <QPainter>
#include <QLabel>
#include <ctime>
#include <QtGui/QMainWindow>
class space;
class MyRect : public QObject {
Q_OBJECT
public:
MyRect(int in_x, int in_y, int in_w, int in_h, QWidget* parent)
{
itsx = in_x;
itsy = in_y;
itsw = in_w;
itsh = in_h;
body = new QRect(itsx, itsy, itsw, itsh);
bullet = new QRect(itsx+41, itsy-15, itsw/8, itsh/2);
itsParent = parent;
}
~MyRect() {}
void move(int x ,int y);
public slots:
void fireBullet(int x, int y);
private:
int itsx;
int itsy;
int itsw;
int itsh;
QWidget* itsParent;
QRect* body;
QRect* bullet;
friend class space;
};
MyRect.cpp
#include "MyRect.h"
void wait( float seconds )
{
clock_t endwait;
endwait = clock () + seconds * CLOCKS_PER_SEC ;
while (clock() < endwait) {}
}
void MyRect::move(int x, int y)
{
body->moveTo(x,y);
bullet->moveTo(x+35, y-15);
}
void MyRect::fireBullet(int x, int y)
{
y = y-15;
for(int i=0 ; i<200 ; i++)
{
bullet->moveTo(x+41, y--);
itsParent->repaint();
wait(0.001);
}
}
space.h
#include <QKeyEvent>
#include <QMouseEvent>
#include "MyRect.h"
class space : public QMainWindow
{
Q_OBJECT
public:
space(QWidget *parent = 0);
~space(){}
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent* event);
private:
private:
int x;
int y;
int w;
int h;
MyRect* ship;
signals:
void fireBullet(int x, int y);
};
space.cpp
#include "space.h"
#include <QApplication>
space::space(QWidget *parent)
: QMainWindow(parent)
{
x = 170;
y = 250;
w = 90;
h = 25;
ship = new MyRect(x,y,w,h, this);
connect(this, SIGNAL(fireBullet(int,int)), ship, SLOT(fireBullet(int,int)) );
}
void space::paintEvent(QPaintEvent *event)
{
QPen pen(Qt::black, 2, Qt::SolidLine);
QColor hourColor(0, 255, 0);
QPainter painter(this);
painter.setBrush(hourColor);
painter.setPen(pen);
painter.drawRect( *(ship->body) );
painter.drawRect( *(ship->bullet) );
}
void space::keyPressEvent(QKeyEvent* event)
{
switch(event->key()) {
case Qt::Key_D :
{
x = x+10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_A :
{
x = x-10;
ship->move(x,y);
this->update();
break;
}
case Qt::Key_M :
{
emit fireBullet(x,y);
break;
}
}
}
main.cpp
#include "space.h"
#include <QDesktopWidget>
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
space window;
window.setWindowTitle("Lines");
window.resize(500,500);
window.show();
return app.exec();
}
Thanks for the answers.
You have an architectural problem. What you are doing is moving the bullet in a loop in its fireBullet method. While that loop is running, the rest of the program isn't, since a single thread can only be doing one thing at a time.
The solution is to refactor your code so that everything on the screen gets updated by one frame-worth of animation every time you call some kind of update method. Basically, you just need to retain enough state, where you are, how fast you are moving, how far you can go before disappearing, so that you can move by the desired amount each frame.
Another thing that you would change is to have the keyPressEvent update the state of the spaceship to know which way it should be moving, so that it can move on its regular paintEvent. For that you can use a QTimer