Move a QGraphicsPixmapItem through keyboard - c++

I have a a character added via QgraphicsPixmapitem and now I want to move it by pressing the arrow keys on the keyboard. But I can't find a way. It gives compilation error. Help me please!
moveship.h (header file for my QPixmapItem)
#ifndef MOVESHIP_H
#define MOVESHIP_H
#include <QGraphicsPixmapItem>
class moveship: public QGraphicsPixmapItem
{
public:
void keyPressEvent(QKeyEvent *event);
};
#endif // MOVESHIP_H
I am just checking if it recognises any key press or not.
Implementation of keyPressEvent:
#include "moveship.h"
#include <QDebug>
void moveship::keyPressEvent(QKeyEvent *event)
{
qDebug() << "moved";
}
My main source file:
#include<QApplication>
#include<QGraphicsScene>
#include<QGraphicsView>
#include<QGraphicsPixmapItem>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene * scene = new QGraphicsScene();
QGraphicsView * view = new QGraphicsView(scene);
QPixmap q = QPixmap("://images/player.png");
if(q.isNull())
{
printf("null\n");
}
else
{
moveship * player = new moveship(q);
scene->addItem(player);
}
view->resize(500,500);
view->show();
return a.exec();
}
Please Help :(
Edit:
The compilation error which I get is:
error: no matching function for call to 'moveship::moveship(QPixmap&)'
moveship * player = new moveship(q);

Well, there's nothing common in the question you ask and the error you get. As I see, you don't have any constructor of your class moveship, and that's exactly what compiler is telling to you. There's got to be smth like:
moveship(const QPixmap & pixmap, QGraphicsItem * parent = 0)
in the header of your class with some implementation, of course and as I see, it's trivial:
moveship::moveship(const QPixmap & pixmap, QGraphicsItem * parent = 0)
: QGraphicsItem(pixmap, parent);
That's the base knowledge you should have when using c++. Here's nothing special about Qt. I advise you to learn c++ a bit.
BTW, reimplemented ...event(...) functions is recommended to place in the protected part of the class and also declare it to be virtual.

Related

Qt/c++ call for a second window

I am creating a desktop application in qt using c++ and am struggling with linking two projects together. The first project is a chess game and the second one is from where i want to start . I want to add a new QPushbutton "Play a game" then a new window will open showing the game . I added all .cpp and .h file from the first projet to the main one and i don't know how can i call it the second window . I could've done it if it had a .ui file with just setmodel but i can't because it doesn't have one. I don't know If i am making any sense right now but i'll provide you with screenshots just so you get me more.
The first project (the game): https://github.com/subeshb1/Chess
My project:
enter image description here
the game :
enter image description here
You do not need .ui files. You just have to write the function yourself. I don't know what the main widget that owns the button is called so I'll call it TLWidget for now. and use ... to represent some other code that may be in there.
#include<QtWidgets/QDialog>
#include "game.h" // this is the widget you want in a new window
class TLWidget ... //this is the class definition of your top level widget. it usually owns the thing created from the .ui
{
...
QDialog* m_ChessWindow; //a member is needed to hold or own the window
Game* m_ChessWidget; //the game itself
...
TLWidget (...) //this is the constructor (where the ui item is created or initialized)
{
...
//by making in the constructor, there's only one and it is easy to track.
//you can alternatively spawn a new window per button push by following the 3 calls here: the two new calls below with appropriate parents, and the show() call further below.
m_ChessWindow = new QDialog(this);
m_ChessWidget = new Game(m_ChessWindow);
...
}
...
void SpawnChess() //function that creates your widget. You may want to put other steps in here or slot this, or call it from your button slot function
{
...
m_ChessWindow->show();//this will show the dialog
...
}
...
};
I tried that and i did some other steps too . Here's where am at right now.
Mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "joueur.h"
#include "partie.h"
#include "game.h"
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_ajouter_joueur_clicked();
void on_lancer_partie_clicked();
..etc
private:
Ui::MainWindow *ui;
Joueur J;
Partie P;
*Game game;
};
#endif // MAINWINDOW_H
Mainwindow.cpp
void MainWindow::on_lancer_partie_clicked()
{
game = new Game();
game->show();
game->displayMainMenu();
}
Main.cpp
#include "mainwindow.h"
#include
#include
#include
#include "game.h"
*Game game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
game = new Game();
w.show();
return a.exec();
}
At this point , a new window pops when i click on the button but the chessboard and the chess pieces are nowhere to be found ! BTW i have all the files and ressources with the right path !
If i do this tho :
Main.cpp
#include "mainwindow.h"
#include
#include
#include
#include "game.h"
*Game game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
a.setStyle("fusion");
MainWindow w;
game = new Game();
game->show();
game->displayMainMenu();
w.show();
return a.exec();
This way it works pretty fine not missing a single piece . So i figured it has something to do with the QApplication but i don't know how to use QApplication in mainwindow.cpp

seeing undefined reference to `vtable for CollidingMice'

I'm modifying a Qt example 'collidingmice' which comes with the Qt code.
In the original source, the QApplication contains QView and QScene, but I made a class CollidingMice containing the QView and QScene to kill the view and scene using keyboard input. I want to send the keyboard input to CollidingMice class.
I read 4 or 5 questions in stack overflow about 'undefined reference to vtable for..' but could not find the case that fits me. I checked that
1. there is no virtual function in the parent classes that is not defined.
2. I tried adding definition of destructor ~CollidingMices() {}
3. and I'm 99% sure there is no undefined member function in the CollidingMice code below.
#include "mouse.h"
#include <QtGui>
#include <math.h>
static const int MouseCount = 7;
class CollidingMice : public QMainWindow
{
Q_OBJECT
private:
QGraphicsView *view;
QGraphicsScene scene;
QTimer *timer;
public:
CollidingMice(QWidget *parent = 0): QMainWindow(parent) {
scene.setSceneRect(-300, -300, 600, 600);
scene.setItemIndexMethod(QGraphicsScene::NoIndex);
for (int i = 0; i < MouseCount; ++i) {
Mouse *mouse = new Mouse;
mouse->setPos(::sin((i * 6.28) / MouseCount) * 200,
::cos((i * 6.28) / MouseCount) * 200);
scene.addItem(mouse);
}
view = new QGraphicsView(this);
view->setRenderHint(QPainter::Antialiasing);
view->setBackgroundBrush(QPixmap(":/images/cheese.jpg"));
view->setCacheMode(QGraphicsView::CacheBackground);
view->setViewportUpdateMode(QGraphicsView::BoundingRectViewportUpdate);
view->setDragMode(QGraphicsView::ScrollHandDrag);
view->setWindowTitle(QT_TRANSLATE_NOOP(QGraphicsView, "Colliding Mice"));
#if defined(Q_WS_S60) || defined(Q_WS_MAEMO_5) || defined(Q_WS_SIMULATOR)
view->showMaximized();
#else
view->resize(600, 450);
view->move(30,30);
view->show();
#endif
timer = new QTimer;
QObject::connect(timer, SIGNAL(timeout()), &scene, SLOT(advance()));
timer->start(1000 / 33);
}
private:
void keyPressEvent(QKeyEvent *event);
};
void CollidingMice::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_q) {
close();
}
}
int collidingmice_main(int argc, char **argv)
{
QApplication app(argc, argv);
qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
CollidingMice w;
return app.exec();
}
ADD and EDIT : After deleting the QOBJECT above as svlasov told me to, and after fixing the constructor as below (see the setScene..my colleage suggested me.)
view = new QGraphicsView(this);
view->resize(600,500);
view->setScene(&scene);
view->setRenderHint(QPainter::Antialiasing);
I could compile it and execute it.
If you use Q_OBJECT in class definition you have to extract the class into separate header file.
If you don't declare signals and slots in CollidingMice class, just remove Q_OBJECT and it will compile.
UPDATE
As #KubaOber commented, you can simply include to the end of your file.cpp file:
#include "file.moc"
and qmake will do all the job.
It seems your class is declared in .cpp rather than .h
Qt MOC doesn't like it. You may add #include "mysrcfile_moc.cpp" at the end of the file or move the class declaration to mysrcfile.h Don't forget to clean & rebuild after that.
There are 3 issues with your code...
Qt parses the class header and constructs underlying functions related to QObject hierarchy, including symbols for export. This is a rudimentary parser and needs an explicit header file - both for ease of parsing and for symbol export. Create a header - trust me, it's 5 seconds of work to create a file, cut-paste the class declaration and include it back... and saves a lot of time troubleshooting Qt compile issues.
the scene has a scene rectangle, but the view is a regular QWidget - which means the Window should use a layout class and include it in like other QWidgets. Failing this, the view will be sized to something like QSize(1,1) and located at pos(0, 0) by default. This is why you can't see it.
For the QGraphicsScene, you're looking for the slot update() and not advance()

Getting text from QLineEdit to append to QTextEdit upon QLineEdit returnpressed()

I'm trying to write a simple Qt program which takes text inside a QLineEdit and appends it into a QTextEdit object when the return key is pressed.
Here is the code for my program:
#include <QApplication>
#include <QtGui>
#define WIDTH 640
#define HEIGHT 480
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
QTextEdit textArea;
textArea.setReadOnly(true);
QLineEdit lineEdit;
QPushButton quit("Quit");
QObject::connect(&quit, SIGNAL(clicked()), qApp, SLOT(quit()));
QHBoxLayout hLayout;
hLayout.addWidget(&lineEdit);
hLayout.addWidget(&quit);
QVBoxLayout vLayout;
vLayout.addWidget(&textArea);
vLayout.addLayout(&hLayout);
QWidget window;
window.setBaseSize(WIDTH, HEIGHT);
window.setLayout(&vLayout);
window.show();
//This is the line I can not get to work
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
return app.exec();
}
Essentially, the problem is connecting the QLineEdit returnPressed() SIGNAL to the QTextEdit append() SLOT. I am hoping someone can point out what is wrong with my code.
Thank you very much in advance for your time.
When you run your program, you should notice on the console the following Qt error output..
Object::connect: No such slot QTextEdit::append(lineEdit.text()) in ..
You would need to qualify the append reference in your call to connect with the QTextEdit variable name textArea.
But that's not going to help much because you can only specify signal and slot method names and parameter types when calling connect so you can't specify lineEdit.text() in there.
Since the append() slot expects a QString, ideally you would want to connect a signal that includes a QString but there is no such signal for QLineEdits.
You pretty much have to write a slot yourself that you can connect to returnPressed() and call textArea.append(lineEdit.text()) from there. You will need to subclass a QObject of some kind to write a slot which would usually mean subclassing QWidget and putting all of your UI building code in its constructor.
You might also notice that your program crashes when you close it. Since Qt likes to manage the destruction of most QObjects itself, it is usually best to allocate all QObject instances on the heap with new. This isn't technically necessary all the time but it is much easier :)
QObject::connect(&lineEdit, SIGNAL(returnPressed()), &textArea, SLOT(append(lineEdit.text())));
returnPressed() doesn't take any arguments, but append(QString) does take one argument; a QString. Thus, if this would work, you would theoretically call append(""), meaning you wouldn't append anything. Using lineEdit.text() wouldn't work either at this place.
I would recommend you to create a class for the widget:
class Widget : public QWidget
{
public:
Widget(QWidget parent = 0);
//Other public functions
private:
//Private functions and variables
public slots:
void boom();
};
Then you can just use
Widget w(0);
w.show();
in your main function.
void boom() would be called by returnPressed(), and it would take lineEdit.text() and append it to the QTextEdit.
I hope this helps.
here is the code it might be helpful.....
#include "hwidget.h"
Hwidget::Hwidget(QWidget *parent) :
QWidget(parent)
{
}
void Hwidget::mainform_init(void)
{
lineeditp = new QLineEdit;
quitp = new QPushButton("&Exit");
hboxlayoutp = new QHBoxLayout;
hboxlayoutp->addWidget(lineeditp);
hboxlayoutp->addWidget(quitp,0,0);
vboxlayoutp = new QVBoxLayout;
texteditp = new QTextEdit;
texteditp->setReadOnly(true);
vboxlayoutp->addWidget(texteditp,0,0);
vboxlayoutp->addLayout(hboxlayoutp);
QWidget *mywin = new QWidget;
mywin->setLayout(vboxlayoutp);
mywin->setWindowTitle("My Sig and Slot");
mywin->show();
lineeditp->setFocus();
}
void Hwidget::mcopy(void)
{
qDebug() <<"i am your copy slot";
texteditp->setText(lineeditp->text());
lineeditp->clear();
}
#include <QApplication>
#include "hwidget.h"
int main (int argc, char *argv[])
{
QApplication app(argc,argv);
Hwidget *hwin = new Hwidget;
hwin->mainform_init();
hwin->connect(hwin->quitp,SIGNAL(pressed()),
qApp,SLOT(quit()));
hwin->connect(hwin->lineeditp,SIGNAL(returnPressed()),
hwin,SLOT(mcopy()));
return app.exec();
return 0;
}
#ifndef HWIDGET_H
#define HWIDGET_H
#include <QWidget>
#include <QTextEdit>
#include <QLineEdit>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QObject>
#include <QString>
#include <QDebug>
class Hwidget : public QWidget
{
Q_OBJECT
public:
explicit Hwidget(QWidget *parent = 0);
void mainform_init(void);
signals:
public slots:
void mcopy(void);
private:
QHBoxLayout *hboxlayoutp;
QVBoxLayout *vboxlayoutp;
public:
QPushButton *quitp;
QLineEdit *lineeditp;
QTextEdit *texteditp;
};
#endif // HWIDGET_H

QT/C++ - Accessing MainWindow UI from a different class

I'm a beginner to both C++ and Qt, so perhaps this is trivial. It certainly feels like it should be simple, but I've been searching for an answer for a few hours now and can't find the solution. I'm making a simple board game where the MainWindow's ui (made in QtDesigner) contains a canvas for the game board (a QGraphicsView). Now, the main.cpp is as simple as can be:
MainWindow Game;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Game.show();
return a.exec();
}
Since I need to access and edit the MainWindow Widgets from another totally unrelated class, I thought the easiest way would be to just make MainWindow a global variable. It seems that this approach was very wrong, though. Upon trying to run the project in QtDesigner I get a Microsoft Visual C++ runtime library error: the application has requested runtime to terminate it in an unusual way.
So what is the correct way to do what I need?
Aside from the MainWindow I have a dialog for a new game (QDialog, generated from QtDesigner) that is displayed after clicking a menu item in MainWindow. When the user inputs all parameters for the game and clicks OK in the dialog, I instantiate a custom non-Qt class called GameState. This class is meant to operate the game itself, draw the board, prompt the user, etc. However, as this class is created in the QDialog, it does not know of the existence of a MainWindow and so I cannot do anything with the MainWindow from this class. How can I modify the MainWindow from an unrelated class, then?
Also, jsut how does the setEnabled() function work? It never seems to do anything. Any widget I set as disabled in the QtDesigner and then try to enable through this function still stays disabled in the GUI...
First off it's a bad idea to create MainGame before you create your QApplication object.
If you want to have your MainGame object globally available like this it should be a pointer:
MainWindow *Game;
int main (int argc, char **argv)
{
QApplication a (argc, argv);
Game = new MainWindow();
Game->show();
int result = a.exec();
delete Game;
Game = NULL;
return result;
}
This approach is however not the most elegant. There are two much better choices.
The QApplication object actually stores all top level windows like your MainGame which means you can allways aquire it through QApplication::topLevelWidgets() which is a static function and returns a list with all top level widgets. Since you only have one, the first one is your MainGame. The drawback is you'll have to cast it, but using Qts qobject_cast<MainGame*>(...) is fairly safe. You'll have to check the result though to make sure it isn't a NULL pointer.
Use the singelton design pattern. You should store the global Game pointer in the source (cpp) file of the Game class itself (subclass QMainWindow) and your Game class should implement a static public method which returns this global pointer. So if any other class needs the Game pointer, it simply calls:
MyGame *theGame = MyGame::getInstance();
for example.
Regarding your setEnabled() problem. Please post the relevant code. If it's too much feel free to send me the *.ui file and the piece of code via mail.
Best regardsD
I am doing it this way:
QMainWindow* getMainWindow()
{
foreach (QWidget *w, qApp->topLevelWidgets())
if (QMainWindow* mainWin = qobject_cast<QMainWindow*>(w))
return mainWin;
return nullptr;
}
If your application has only one window you can simply use:
MainWindow * win = (MainWindow *) qApp::activeWindow();
The easiest way to do this is to first set up a signal in the header file of your other class to say perform a function to manipulate an object in the main class like this
signals:
void disableLoadButtton();
Then create a slot under private slots in the header file of the main window like this
private slots:
void disableLoadButtton();
Then create the function as a members function in the main window to manipulate the object
void MainWindow::disableLoadButton()
{
ui->loadButton->setenabled(false);
}
Then add the following line in another member function of the main window which say sets up the page. My other class is called searchWidget
void MainWindow::setUpPage()
{
connect(searchWidget, SIGNAL(disableLoadButton()), this, SLOT(disableLoadButton()));
}
Then all you have to do to disable the loadButton (which is a object in MainWindow) is to add the following line in any members function of my other class searchWidget
void searchWidget::performSomething()
{
emit disableLoadButton();
}
This will then manipulate the object loadButton in the mainwindow from within a member function of the other class searchWidget.
In the past I used approach described in this answer (found in Qtractor project).
Now I use QObject 'name' property and discover it anywhere as described here.
main.c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
#include <QString>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "c.h"
MainWindow * MainWindow::pMainWindow = nullptr;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
pMainWindow = this;
setCentralWidget(&m_pb);
connect(&m_pb, SIGNAL(clicked()), this, SLOT(on_pb_clicked()));
}
MainWindow::~MainWindow() {delete ui;}
// kind of singleton reference.
MainWindow *MainWindow::getMainWinPtr()
{
return pMainWindow;
}
void MainWindow::pbSetText()
{
m_pb.setText(QString{"Call from c."});
}
void MainWindow::on_pb_clicked()
{
c C; // call of MainWindow from class c ctor
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QString>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
static MainWindow * getMainWinPtr();
void pbSetText();
public slots:
void on_pb_clicked();
private:
static MainWindow * pMainWindow;
Ui::MainWindow *ui;
QPushButton m_pb{QString{"Press me."}, this};
};
#endif // MAINWINDOW_H
c.cpp
#include "c.h"
#include "mainwindow.h"
c::c()
{
MainWindow * mw = MainWindow::getMainWinPtr();
mw->pbSetText();
}
c.h
#ifndef C_H
#define C_H
class c
{
public:
explicit c();
};
#endif // C_H
If you have to access your MainWindow from another window, you are probably doing it wrong. Using another class to pass information with signals/slots is probably a much better approach

Qt: QPushButton never shows up

I'm trying to learn Qt, with a fairly simple application:
#include <QtGui/QApplication>
#include <QPushButton>
#include <QDebug>
/* -- header begin {{{ */
class BareBase {
public:
BareBase();
};
class BareBones: public QApplication {
private:
BareBase* base;
public:
BareBones(int &argc, char **argv);
~BareBones();
};
/* -- header end }}} */
/* -- implementation begin {{{ */
BareBase::BareBase()
{
QPushButton hello("Hello world!");
hello.resize(100, 30);
hello.show();
}
BareBones::BareBones(int& argc, char** argv): QApplication(argc, argv)
{
qDebug() << "Creating new instance ... ";
base = new BareBase();
}
BareBones::~BareBones()
{
qDebug() << "Cleaning up ... ";
delete base;
}
/* -- implementation end }}} */
int main(int argc, char **argv)
{
//Q_INIT_RESOURCE(files);
BareBones app(argc, argv);
return app.exec();
}
Now, the problem is that the Button created in BareBase never shows up, and i'm puzzled why?
Your QPushButton is creating and display correctly but go out of scope when leaving BareBase constructor. Using a member variable or a pointer will solve your problem.
If you use a pointer, you should add your button to its parent. By this way the button will be automatically deleted when the parent will be deleted.
QPushButton might have shown up but not in the visible area of the widget. That's why, you should add all your widgets to the Layouts that are available in Qt to obtain the desired behaviour. Check out the docs here... It has examples also...
Also, basically you will be having a base QWidget or most probably QMainWindow on which all your controls will be present.. So, your QPushButton will be in the parent widget.. Your QApplication will contain your application specific information like setting the window, setting the font for your entire application kinda stuff..
Hope it helps..