I am making a game requiring qgraphicspixmapitem moving around in the view.
Now, I plan to move my QGraphicsPixmapitem up and down with my keyboard. It works perfectly fine initially.
But since my scene's and view's size are unequal then, which looks pretty wired. So I added some functions to adjust my scene and view's size to be equal.
However, after setting my QGraphicsScene and QGraphicsView same size,
I cannot move my qgraphicspixmapitem with my keyboard anymore.
I've tried adding setFocus, Flag to enable my qgraphicspimapitem stay controlled by my keyboard, but in vain.
Any idea will be very appreciated. Thank you!
main window.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent):
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//scene
scene = new QGraphicsScene(0, 0, 1050, 600);
//player
player = new QGraphicsPixmapItem(QPixmap(":/img/whitedog.png").scaled(100,100));
player->setFlag(QGraphicsPixmapItem:: ItemIsFocusable,true);
player->setFocus();
player->setPos(350, 500);
scene->addItem(player);
playertimer->start(10);
//view
view = new QGraphicsView(this);
view ->setScene(scene);
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setCentralWidget(view);
view->setFixedSize(1055,605);
}
void MainWindow::keyPressEvent(QKeyEvent *e)
{
if (e->key() == Qt::Key_Down){
player->setPos(player->x(),player->y()+10);
}
else if (e->key() == Qt::Key_Up){
player->setPos(player->x(),player->y()-10);
}
}
}
main window.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsPixmapItem>
#include <QKeyEvent>
#include <QtGui>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public slots:
virtual void keyPressEvent(QKeyEvent *e);
private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
QGraphicsItem *player;
QGraphicsView * view;
};
#endif // MAINWINDOW_H
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
You have never been able to move the item, what you have done is to move the scrollbars making the same effect in the visual part.
What you have to do is use the KeyPress event of the QGraphicsView, one way to do it is to create a new class that inherits from QGraphicsView, but another simpler way is to install an event filter as shown below:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QKeyEvent>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//scene
scene = new QGraphicsScene(0, 0, 1050, 600);
//player
player = new QGraphicsPixmapItem(QPixmap(":/img/whitedog.png").scaled(100,100));
player->setPos(350, 500);
scene->addItem(player);
//view
view = new QGraphicsView;
view ->setScene(scene);
view->installEventFilter(this);
setCentralWidget(view);
view->setFixedSize(1055,605);
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if(watched == view && event->type() == QEvent::KeyPress){
QKeyEvent *kevent = static_cast<QKeyEvent *>(event);
if(kevent->key() == Qt::Key_Down){
player->setPos(player->pos() + QPointF(0, 10));
return true;
}
else if(kevent->key() == Qt::Key_Up){
player->setPos(player->pos() - QPointF(0, 10));
return true;
}
}
return QMainWindow::eventFilter(watched, event);
}
MainWindow::~MainWindow()
{
delete ui;
}
In the following link you can find the complete example
Related
I am trying to arrange my subWindows in the QMdiArea vertically. I saw lot of examples online and they all were doing the same thing as I am doing here.
I have two textEdits which needs to be tiled vertically both covering half of the screen. So in the constructor of the MainWindow I add the two textEdits as subWindow to the qMdiArea and then find the height and width of the qMdiArea divide the height by 2 and resize the subWindow. Please see the code below.
My mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->showMaximized();
qMdiArea = new QMdiArea();
qTextEdit1 = new QTextEdit();
qTextEdit2 = new QTextEdit();
setCentralWidget(qMdiArea);
qMdiArea->adjustSize();
qMdiArea->addSubWindow(qTextEdit1);
qMdiArea->addSubWindow(qTextEdit2);
QPoint position(0, 0);
foreach (QMdiSubWindow *window, qMdiArea->subWindowList())
{
QRect rect(0, 0, qMdiArea->width(), qMdiArea->height() / qMdiArea->subWindowList().count());
window->setGeometry(rect);
window->move(position);
position.setY(position.y() + window->height());
}
}
MainWindow::~MainWindow()
{
delete ui;
}
My window.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMdiArea>
#include <QTextEdit>
#include <QPoint>
#include <QMdiSubWindow>
#include <QRect>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
QMdiArea *qMdiArea;
QTextEdit *qTextEdit1;
QTextEdit *qTextEdit2;
};
#endif // MAINWINDOW_H
and my Main File :
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
But its not happening as expected. The window just occupy a part of the screen though they are tiled vertically. My screen resolution is 1920x1200
The height() and width() of mdiArea are invalid at that stage, because the widget hasn't been exposed/shown yet. Calling show() only schedules a widget for display, the act of sizing it and showing it on screen happens later when the control has returned to the event loop.
As a solution, you can override the resizeEvent handler. Once you do, your project will work again:
Definition in mainwindow.h:
virtual void resizeEvent(QResizeEvent *ev) override;
Implementation in mainwindow.cpp:
void MainWindow::resizeEvent(QResizeEvent *ev)
{
Q_UNUSED(ev)
QPoint position(0, 0);
foreach (QMdiSubWindow *window, qMdiArea->subWindowList())
{
QRect rect(0, 0, qMdiArea->contentsRect().width(), qMdiArea->contentsRect().height() / qMdiArea->subWindowList().count());
window->setGeometry(rect);
window->move(position);
position.setY(position.y() + window->height());
}
}
Also it seems that you don't really need to have this->showMaximized(); call inside MainWindow's constructor. You can call it from main.cpp, for example.
I have a display window like this:
Above display widgets are QGraphicsView widgets (they are in a QGridLayout) and what I want to achieve is that:
when user click in MainWindow, I want to seize that clicked position and decide which QGraphicsView widget contains that position and set the border of that selected QGraphicsView widget to green color. And only one QGraphicView widget can be selected at a time.
Can anyone give me some ideas?
Thanks
You can use installEventFilter for your QGraphicsViews and detect mouse press events on them. So, you can define current view and make border for it as you want. Small example:
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
public:
bool eventFilter(QObject* watched, QEvent* event) override;
private:
Ui::MainWindow *ui;
QGraphicsView* view1_;
QGraphicsView* view2_;
QGraphicsView* selectedView_;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGridLayout>
#include <QMessageBox>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow),
view1_(nullptr),
view2_(nullptr),
selectedView_(nullptr)
{
ui->setupUi(this);
QGridLayout* grid = new QGridLayout(this->centralWidget());
view1_ = new QGraphicsView(this);
view2_ = new QGraphicsView(this);
grid->addWidget(view1_, 0, 0);
grid->addWidget(view2_, 0, 1);
view1_->viewport()->installEventFilter(this);
view2_->viewport()->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
qDebug() << event->type();
if (event->type() == QEvent::MouseButtonPress)
{
if (watched == view1_->viewport()){
selectedView_ = view1_;
QMessageBox::information(this, "!", "First");
return false;
}
else if (watched == view2_->viewport()){
selectedView_ = view2_;
QMessageBox::information(this, "!", "Second");
return false;
}
}
return QMainWindow::eventFilter(watched, event);
}
If you only want to change the border color on mouse hover, you wouldn't need such complicated programming. Qt supports style sheets, just like CSS.
In this case, it's enough to attach the following stylesheet to your MainWindow.
QGraphicsView:hover {
border-style: solid;
border-width: 2px;
border-color: green;
}
There's two ways to get this done:
Using the Designer: First select the MainWindow and then in its properties panel click on the styleSheet and copy and paste the style sheet.
Using code: Use setStyleSheet(...) method of QMainWindow and pass the style sheet as a string.
I'm trying to create a simple animation of a ball that is wandering on a screen and simply bounces off on walls. Since I'm fairly new to C++, I've got some problems with this task. I'm also using the Qt-library.
The ball just stays on the same spot and moves back and forth a little which is odd, because I create a SceneRect with the same size as my graphicsView.
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsScene>
#include <QtWidgets>
float movement_x = 2.5;
float movement_y = 2.0;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
void MainWindow::showEvent(QShowEvent *event){
scene = new QGraphicsScene(this);
scene -> setSceneRect(ui->graphicsView->geometry().x(), ui->graphicsView->geometry().y(),
ui->graphicsView->geometry().width(), ui->graphicsView->geometry().height());
ui->graphicsView->setScene(scene);
QPen redpen(Qt::red);
QBrush brush(Qt::green);
//QBrush brush2(Qt::black);
QPen mypen(Qt::blue);
mypen.setWidth(7);
ellipse = scene->addEllipse(100.0,100.0,20.0,20.0,mypen,brush);
timer1 = startTimer(50);
timer2 = startTimer(600);
}
void MainWindow::timerEvent(QTimerEvent *event){
// check for radius
if(ellipse->pos().x() >= scene->sceneRect().right() || ellipse->pos().x() <= scene->sceneRect().left()){
movement_x = -movement_x;
}
if(ellipse->pos().y() >= scene->sceneRect().bottom() || ellipse->pos().y() <= scene->sceneRect().top()){
movement_y = -movement_y;
}
ellipse->moveBy(movement_x, movement_y);
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsScene>
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
protected:
void showEvent(QShowEvent* event);
void timerEvent(QTimerEvent* event);
private:
Ui::MainWindow *ui;
QGraphicsScene *scene;
QGraphicsEllipseItem *ellipse;
};
#endif // MAINWINDOW_H
main.cpp:
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.resize(800,600);
w.show();
return a.exec();
}
The initial value of pos is (0,0). Because of this your update oscillate between two values. After addEllipse you have to set an initial position within the scene rect. For example
ellipse->setPos(100,100);
You should map the ellipse position from the scene to find the boundaries :
QPoint posOfEclps = ellipse->mapToScene(ellipse->pos());
if(posOfEclps.x() >= scene->sceneRect().right() || posOfEclps.x() <= scene->sceneRect().left())
{
movement_x = -movement_x;
}
if(posOfEclps.y() >= scene->sceneRect().bottom() || posOfEclps.y() <= scene->sceneRect().top())
{
movement_y = -movement_y;
}
ellipse->moveBy(movement_x, movement_y);
What it should do: When the QComboBox is on the first item (index 0) it should hide the QStackedWidget. Which causes the QComboBox to extend as much as possible. As soon as you change the item in the QComboBox to anything, the QComboxBox should shrink and the QStackedWidget should display the correct page.
What I have and what it does instead: I test what the current index item is of the QComboBox and depending on that I change the size policies and visibility of widgets in order to obtain what I want. But it doesn't work. I tried to do workarounds but I cant seem to figure this out.
I also used qDebug() to see what currentIndexItem returns, and it seems to be stuck at 0, no matter to what index I change the QComboBox to. Do I have to update the currentItemIndex?
Note: I have a signal connected in the designer from QComboBox to QStackedWidget: currentIndexChanged(int) -> setCurrentIndex(int)
Here is my code.
My code:
interfacewindow.h
#ifndef INTERFACEWINDOW_H
#define INTERFACEWINDOW_H
#include <QMainWindow>
#include <QPainter>
#include <QComboBox>
namespace Ui
{
class InterfaceWindow;
}
class InterfaceWindow : public QMainWindow
{
Q_OBJECT
public:
explicit InterfaceWindow(QWidget *parent = 0);
~InterfaceWindow();
private:
Ui::InterfaceWindow *ui;
private slots:
void on_actionClose_triggered();
};
#endif // INTERFACEWINDOW_H
interfacewindow.cpp
#include "interfacewindow.h"
#include "ui_interfacewindow.h"
#include <QDebug>
InterfaceWindow::InterfaceWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::InterfaceWindow)
{
ui->setupUi(this);
if(ui->comboBox->currentIndex() == 0)
{
ui->comboBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
ui->stackedWidget->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(false);
}
else
{
ui->comboBox->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
ui->stackedWidget->setVisible(true);
}
}
InterfaceWindow::~InterfaceWindow()
{
delete ui;
}
void InterfaceWindow::on_actionClose_triggered()
{
this->close();
}
main.cpp
#include <QApplication>
#include "interfacewindow.h"
int main(int argc, char **argv)
{
QApplication a(argc, argv);
InterfaceWindow w;
w.show();
return a.exec();
}
Hello Im working through Qt tutorials I've have copy the code for the communicate section of this tutorial. the code compiles and shows but none of my buttons are clickable.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class QPushButton;
class QLabel;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void OnPlus();
void OnMinus();
private:
Ui::MainWindow *ui;
QLabel *label;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtGui>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
QPushButton *plus = new QPushButton("+", this);
plus->setGeometry(50, 40, 75, 30);
QPushButton *minus = new QPushButton("-", this);
minus->setGeometry(50, 100, 75, 30);
label = new QLabel("0", this);
label->setGeometry(190, 80, 20, 30);
connect(plus, SIGNAL(clicked()), this, SLOT(OnPlus()));
connect(minus, SIGNAL(clicked()), this, SLOT(OnMinus()));
ui->setupUi(this);
}
void MainWindow::OnPlus()
{
int val = label->text().toInt();
val++;
label->setText(QString::number(val));
}
void MainWindow::OnMinus()
{
int val = label->text().toInt();
val--;
label->setText(QString::number(val));
}
MainWindow::~MainWindow()
{
delete ui;
}
main.cpp
#include <QtGui/QApplication>
#include "mainwindow.h"
#include <QPushButton>
#include <QLabel>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
Your problem is with this line:
ui->setupUi(this);
It creates an invisible central widget for your main window, which blocks all events destined for your buttons, which is why they don't depress when you click them. Move this line to the beginning of your constructor for MainWindow and the problem will go away.