Starting with Qt - QGraphicsView and QGraphicsScene - c++

I'm a beginner in using Qt and I have a problem. I want to display red background using QGraphicsView and QGraphicsScene. Instead of red, I'm still displaying the white one. I don't know, where the problem exists.
MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QBrush>
class Screen:public QGraphicsView
{
Q_OBJECT
public:
Screen();
};
#endif // MAINWINDOW_H
MainWindow.cpp
#include "mainwindow.h"
Screen::Screen()
{
QGraphicsView *view = new QGraphicsView(this);
QGraphicsScene *scene = new QGraphicsScene();
QBrush redBrush(Qt::red);
scene->setBackgroundBrush(redBrush);
view->setScene(scene);
}
Main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Screen scr;
scr.show();
return a.exec();
}

The problem with the code you posted is there there are two different QGraphicsView objects being created -- one is the Screen object (scr), which is a subclass of QGraphicsView and therefore is a QGraphicsView object, and the other is the (view) object that you allocated with 'new' in the Screen constructor.
You're setting the scene attribute of the second one, but never showing it or doing anything with it. You're seeing the first one displayed on screen (since that is the one you call show() on inside main()), but since you never set its scene attribute, it remains blank/white.
The easiest fix is to get rid of the unnecessary second QGraphicsView object. I changed the Scene constructor to this:
Screen::Screen()
{
QGraphicsScene *scene = new QGraphicsScene();
scene->setBackgroundBrush(Qt::red);
setScene(scene);
}
... and having done that, the program now displays the red window that you would expect.

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

Why does my toolbar dock to the incorrect location?

I have a weird scenario. I create a QMainWindow that is embedded in a QGraphicsScene. I want to have multiple QMainWindows each with a toolbar inside the scene. I'm simulating an MDI Area, without using the QMdiArea class.
Here is the MainWindow.cpp
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent){
resize(1000, 750);
qApp->setStyle(QStyleFactory::create("Fusion"));
QGraphicsView* view = new QGraphicsView;
QGraphicsScene* scene = new QGraphicsScene;
view->setFixedSize(1000, 750);
view->setScene(scene);
view->scene()->setSceneRect(-150, -150, view->size().width(), view->size().height());
setCentralWidget(view);
QWidget* widget = new QWidget;
widget->resize(300, 300);
QVBoxLayout* vLay = new QVBoxLayout;
widget->setLayout(vLay);
QMainWindow* testWindow = new QMainWindow;
testWindow->resize(300, 300);
QToolBar* toolbar = new QToolBar;
toolbar->setFloatable(false);
toolbar->setStyleSheet("border: 1px solid red"); //For better seeing the issue
toolbar->addAction("Test");
testWindow->addToolBar(toolbar);
vLay->addWidget(testWindow);
scene->addWidget(widget);
}
What happens is the QToolBar will spawn in the correct location on the embedded QMainWindow, but when it's moved and docked anywhere, it will snap too far up and too far to the left. I've added outliner code to outline the toolbar so you can see the toolbar box.
Here is the MainWindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QToolBar>
#include <QVBoxLayout>
class MainWindow : public QMainWindow{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
};
#endif // MAINWINDOW_H
Why does the toolbar do this weird snapping effect? I added the QMainWindow into a QWidget on purpose, as it's needed for something I'm doing. I realize that embedding just the QMainWindow has the desired interaction, but I need it embedded in the QWidget. I also realize that not having parents are bad for memory management, but I handle that as well.
I'm on Qt Version 5.10.1 and I'm using Redhat as my OS.

Qt window wont close using "this->close()" from other class

I will start off by explaining my main goal. I have a main window with 7 buttons on it(amongst other things), when you hit each button, it closes out the current window and opens up a new window. All the windows will have the same 7 buttons, so you can go between each window. With all windows having the exact same 7 buttons, I wanted to set up a function that each class can call to set up each button and connect to a slot() in my mainwindow.cpp(called setupSubsystemButtons in example below). However, I can't seem to get the window to close using the standard "this->close()"...it works when I go from the main window to another window(the main window closes) but when I go from a different window to say the home window, the different window doesn't close. Suggestions would be greatly appreciated. My guess is that my understanding of "this" when it comes to calling slots in another class is wrong.
mainwindow.cpp( the parts that are relevant)
void MainWindow::ECSgeneralScreen()
{
ECSgeneralCommand *ECSgeneral = new ECSgeneralCommand;
this->close();
ECSgeneral->show();
//opens up the ECS screen
}
void MainWindow::homeScreen()
{
MainWindow *home = new MainWindow;
this->close();
home->show();
//opens up the ECS screen
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::setupSubsystemButtons(QGridLayout *layout)
{
//Push Button Layout
homeScreenButton = new QPushButton("Home");
layout->addWidget(homeScreenButton, 3, 11);
connect(homeScreenButton, SIGNAL(clicked()), this, SLOT(homeScreen()));
ECSgeneralScreenButton = new QPushButton("General");
layout->addWidget(ECSgeneralScreenButton,5,11);
connect(ECSgeneralScreenButton, SIGNAL(clicked()), this, SLOT(ECSgeneralScreen()));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtWidgets>
#include <QDialog>
namespace Ui {
class MainWindow;
}
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
QWidget *window;
void setupSubsystemButtons(QGridLayout *layout);
~MainWindow();
private slots:
public slots:
void ECSgeneralScreen();
void homeScreen();
};
#endif // MAINWINDOW_H
ecsgeneralcommandWindow
include "ecsgeneralcommand.h"
#include "mainwindow.h"
#include <QtWidgets>
#include <QtCore>
ECSgeneralCommand::ECSgeneralCommand(MainWindow *parent) : QDialog(parent)
{
QGridLayout *layout = new QGridLayout;
QWidget::setFixedHeight(600);
QWidget::setFixedWidth(650);
...
//Setup Subsystem Buttons
test.setupSubsystemButtons(layout);
setLayout(layout);
}
ecsgeneralcommandWindow header
#ifndef ECSGENERALCOMMAND_H
#define ECSGENERALCOMMAND_H
#include <QDialog>
#include <QMainWindow>
#include <QtWidgets>
#include <QObject>
#include "mainwindow.h"
class ECSgeneralCommand : public QDialog
{
Q_OBJECT
public:
explicit ECSgeneralCommand(MainWindow *parent = 0);
private:
MainWindow test;
public slots:
};
#endif // ECSGENERALCOMMAND_H
Slots are just normal functions. When Qt invokes a slot, it ends up calling the appropriate receiver's method. In other words, this equals to the value of the 3rd argument of your connect statements. You passed this there, so the receiver is MainWindow object. E.g. MainWindow::homeScreen method always tries to close MainWindow. If it is already hidden, this action takes no effect.
You should either have a slot in each window class and connect buttons to appropriate receivers, or use a pointer to the currently active window instead of this when calling close(). But your architecture is strange in the first place. Why would you need to create these buttons for each window? It is reasonable to create them once and use in all windows. Also hiding and showing windows is not necessary. You can create one main window with buttons and a QStackedWidget that will contain the content of all other windows. Maybe you can even use QTabWidget instead of these buttons.

QML, Qt 4.8: How to enable openGl and Chromeless at the same time?

So here is my main
#include <QtGui/QApplication>
#include <QtOpenGL>
#include <QDeclarativeView>
#include <QDeclarativeEngine>
#include "mainwindow.h"
int main(int argc, char *argv[])
{
// Depending on which is the recommended way for the platform, either use
// opengl graphics system or paint into QGLWidget.
#ifdef SHADEREFFECTS_USE_OPENGL_GRAPHICSSYSTEM
QApplication::setGraphicsSystem("opengl");
#endif
QApplication a(argc, argv);
#ifndef SHADEREFFECTS_USE_OPENGL_GRAPHICSSYSTEM
QGLFormat format = QGLFormat::defaultFormat();
format.setSampleBuffers(false);
format.setSwapInterval(1);
QGLWidget* glWidget = new QGLWidget(format);
glWidget->setAutoFillBackground(false);
#endif
MainWindow w(glWidget);
w.show();
return a.exec();
}
and files I use to open QML
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
setAttribute(Qt::WA_OpaquePaintEvent);
setAttribute(Qt::WA_NoSystemBackground);
setAttribute(Qt::WA_TranslucentBackground);
setStyleSheet("background:transparent;");
qmlRegisterType<QGraphicsBlurEffect>("Effects",1,0,"Blur");
/* turn off window decorations */
setWindowFlags(Qt::FramelessWindowHint);
ui = new QDeclarativeView;
ui->setSource(QUrl("qrc:/assets/ui.qml"));
// ui->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
setCentralWidget(ui);
}
MainWindow::~MainWindow()
{
delete ui;
}
and
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QtDeclarative>
#include <QtDeclarative/QDeclarativeView>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QDeclarativeView *ui;
};
#endif // MAINWINDOW_H
I try to enable Open GL But I see nothing, when I comment lines in main that in my opinion had to do the job i SEE MY CHROMELESS WINDOW BUT also
Qml debugging is enabled. Only use this in a safe environment!
ShaderEffectItem::paint - OpenGL not available
What do I do wrong?
I have been struggling with the same issue, but it doesn't seem to be possible. When the parent window is transparent, OpenGL elements never seem to draw, it looks like OpenGL elements can only be rendered to a visible portion in a window, I haven't tried this yet but it might be possible to work around the issue by painting the main window with an almost fully transparent layer:
void MainWindow::paintEvent(QPaintEvent *event)
{
QPainter painter;
painter.begin(this);
painter.fillRect(event->rect(), QBrush(QColor(0, 0, 0, 1)));
painter.end();
}
In-theory this should provide OpenGL with a visible parent to render onto.
In your code your calling QWidget->setAttribute multiple times, as this sets a single property, each time you set the property it's overwriting the previous value. You should merge the flags into one call:
setAttribute(Qt::WA_TranslucentBackground | Qt::WA_NoSystemBackground | Qt::WA_OpaquePaintEvent);
According to this: http://qt-project.org/faq/answer/opengl_and_translucent_background_do_not_work_together_due_to_a_limitation
It seems impossible.

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