What would the syntax look like if I wanted to even use QGraphicsView::scene() in the first place? My goal is to change the scale of a pixmap in my graphics view object with sliders. I want to use QgraphicsView::scene() and QScene::itemsAt() etc. to find the original pixmap and then use QPixmap::scaled() (this I found would be the only way to ensure my cosmetic property set for the pixmap holds true). However I am having issues with the syntax of QGraphicsView::scene(). My attempt is below. I am also creating a Qt widget application for context.
QGraphicsViewScene graphicsScene = ui->PixmapView->scene();
QGraphicsPixmapItem graphicsPixmapItem = graphicsScene.itemAt(0, 0);
edit
If I was to store my QPixmap pixmap* as a member variable I am not entirely sure how to implement that where it remains in scope for my slots.
edit
static member variables?
You can make your QGraphicsPixmapItem object a member variable of your class. Then you would be able to access it from any of your class member functions.
Here is a quick example:
class MyClass : public QWidget
{
Q_OBJECT
public:
MyClass(QWidget *parent = nullptr) : QWidget(parent)
{
// create graphics view, scene, etc..
}
public slots:
void openActionTriggered()
{
...
myItem = scene->addPixmap(myPixmap); // you can create your item however you want.. this is just an example
}
void mySlot()
{
if(myItem)
{
// do something with myItem
}
}
private:
QGraphicsPixmapItem *myItem = nullptr; // myItem is a member variable of
QGraphicsScene *scene = nullptr; // I made scene a member variable so it can be accessed from any member functions
}
Related
I have the following problem in Qt, I'm trying to make a chess-game and I'm encountering some problems:
In the class mainwindow I have the following function:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
scene = new ChessBoard;
QGraphicsView *view = new QGraphicsView(scene);
setCentralWidget(view);
connect(scene,SIGNAL(clicked(int,int)),this,SLOT(clicked(int,int)));
//!!!!!!!!!!
scene->setInitialPositions();
}
I have a variable scene, scene is an object of the class ChessBoard.
In the whole class mainwindow I can use the scene-variable to use functions declared in ChessBoard.
However, I have another class called game.
In game I have this function
void game::setStartBord() {
scene->setInitialPositions();
}
It simply needs to launch scene->setInitialPositions();
However, I don't have access to the 'scene-variable' there. I tried to inherit the ChessBoard and MainWindow class, tried to make scene global, but none really were a good solution.
How would I do that?
Full code is visibly here:
https://github.com/UA-Niel/chess
You can use signal and slot technique. Connect your game class object to scene object.
connect(game, &Game::mySignal, scene, &ChessBoard::setInitialPositions);
Define in your Game-Class the signal.
class Game .. {
..
signals:
void mySignal();
..
};
Then define setInitialPositions in your ChessBorard class in public slots.
class ChessBoard {
...
public slots:
<datatype> setInitialPositions();
};
Then use
emit mySignal(); from Game class
to execute setIntialPositions() in your ChessBoad class.
You need to design your code that you have access to both objects at some point. Mostly this is MainWindow because you intialize classes upon program start.
If your code does not depend on the intialized class.
You can simply do a new ChessBoard object in Game class
ChessBoard myObject;
myObject.setIntialPositions();
I'm having a question about a weird (At least it was unexpected for me) behavior (It crashes) of qt when initializing pointers on a member class different than the constructor. I am attaching part of my code:
In mainwindow.h:
class MainWindow : public QMainWindow
{
...
private:
QPixmap *qpm_s1_yaw;
QPainter *s1_yaw_painter;
...
}
In mainwindow.cpp:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
...
initGraph(qpm_s1_yaw, s1_yaw_painter, ui->YAW1);
...
}
void MainWindow::initGraph(QPixmap *map, QPainter *painter, QLabel *label)
{
map = new QPixmap(label->size());
map->fill(Qt::white);
painter = new QPainter(map);
... doing some stuff ...
label->setPixmap(*map); // ++(Remember this LINE)++
}
That actually works, but when I comment the line:
label->setPixmap(*map)
and instead set the Pixmap in the constructor (MainWindow::MainWindow) by writing:
ui->YAW1->setPixmap(*qpm_s1_yaw)
I got a segmentation Fault.
Could someone explain what is wrong with it? To make it work I had to initialize all the pointers in the constructor (and commenting those line in the classs member initGraph), like this:
qpm_s1_yaw = new QPixmap(ui->YAW1->size());
s1_yaw_painter = new QPainter(qpm_s1_yaw);
initGraph(qpm_s1_yaw, s1_yaw_painter, ui->YAW1);
ui->YAW1->setPixmap(*qpm_s1_yaw);
Thanks
This is a trivial misunderstanding of how C++ works, nothing to do with Qt.
Your code lies to you: you can equally well write: initGraph(0, 0, ui->YAW1). You're initializing local variables instead of class members. The values you pass as the first two arguments are not used for anything.
It's also completely unnecessary to hold the pixmap and the painter by pointer. Hold the pixmap by value, and only instantiate a painter for it when you do the painting.
Holding a painter to a pixmap when you're not painting on it can cause unnecessary copies of the pixmap to be made when the pixmap is consumed (read from): a pixmap with an active painter is considered "dirty".
What you should do then is to hold pixmaps by value and you can return the new value from initGraph - this decouples initGraph from the detail of the surrounding class where the pixmaps are stored. The user of initGraph has an option of not storing the pixmap, and e.g. querying the label itself for it.
class MainWindow : public QMainWindow
{
Ui::MainWindow ui; // hold by value
...
QPixmap qpm_s1_yaw; // hold by value
QPixmap initGraph(QLabel *label) {
QPixmap pixmap{label->size()};
pixmap.fill(Qt::white);
QPainter painter{&pixmap};
//... doing some stuff ...
label->setPixmap(pixmap);
return pixmap;
}
public:
explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
ui.setupUi(this);
gpm_s1_yaw = initGraph(ui.YAW1);
}
};
I am trying to make a class that will make a dot graphic. The class inherits from QWidget. I want it to draw lines and dots on a QPixmap that will be displayed in a QLabel.
The constructor of the class looks like this:
MyClass::MyClass()
{
calcul_proprietes(); // Function that makes calculation of what to draw.
pix = new QPixmap(760,350);
dessiner_graphique(); // Function that does the drawing.
//Displaying the qpixmap
layout_principal = new QVBoxLayout(this);
label_pix = new QLabel(this);
label_pix->setPixmap(*pix);
layout_principal->addWidget(label_pix);
this->setLayout(layout_principal);
}
And a short part of the function that does the drawing
void MyClass::dessiner_graphique()
{
// ...
QPainter painter(pix);
QRect contour(x_depart,y_depart,largeur_grille,hauteur_grille);
painter.drawRect(contour);
// ...
}
I don't want to use the paintEvent function because it gets called all the time and i only need my graphic to be painted once. What do i do wrong?
Did you call the default base class constructor before Your class constructor ?
MyClass( QObject *parent )
: QWidget( parent )
{
// Your posted code.
}
In Qt Creator, I have a couple of widgets declared like so:
Header File:
class MapViewer : public QGraphicsView
{
Q_OBJECT
public:
explicit MapViewer(QGraphicsScene *scene, QWidget *parent = 0);
~MapViewer();
public slots:
void mousePressEvent(QMouseEvent *event);
};
// Declaration for the map editor window.
class MapEditor : public QMainWindow
{
Q_OBJECT
public:
explicit MapEditor(QWidget *parent = 0);
~MapEditor();
public:
QLayout *editorLayout;
QPushButton *btn;
QGraphicsScene *mapScene;
MapViewer *mapView;
private:
Ui::MapEditor *ui;
};
CPP File:
MapEditor::MapEditor(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MapEditor)
{
ui->setupUi(this);
this->setWindowTitle("2DXY :: Map Editor");
this->setGeometry(10,10,1170,750);
editorLayout = new QVBoxLayout; // Create a new layout
this->setLayout(editorLayout); // Set the widget's layout to our newly created layout.
mapScene = new QGraphicsScene(); // Create a new graphics scene to draw upon.
mapView = new MapViewer(mapScene,this); // Create a new graphics view to display our scene - set its parent to 'this' so that it doesn't open in a new window.
mapView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mapView->setGeometry(20,20,1178,546); // Width first, then height.
AND:
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// Some how access the same QGraphicsScene and View (mapScene, mapView) as above, so
// I can update their contents on the open form / window.
}
And as you can see, I wish to access the Graphics Scene again to update it, then redraw it (or whatever). But I'm not able to access the graphics scene at all, despite a few hours of trial and error with declaring widgets in different ways.
I know that the listener itself works, because if it's set to open a new message box, or output to the debug window, then it works, it's just that I can't access the widgets I've already defined.
I feel that there is a (relatively) easy solution to this problem, and that I'm just missing something obvious.
You passed the QGraphicsScene to your MapRender object's constructor. What do you do with the scene within its constructor? Ideally, you should be storing it as a data member of MapRender. For example:
class MapRender {
public:
MapRender(QGraphicsScene* scene)
: scene_(scene)
{
}
public slots:
void mousePressEvent(QMouseEvent *event);
private:
QGraphicsScene* scene_;
}
Now in your implementation of mousePressEvent, you can access to the scene member:
void MapRender::mousePressEvent(QMouseEvent *event) {
int CursorX = event->globalX();
int CursorY = event->globalY();
QGraphicsRectItem *clickedBox = new QGraphicsRectItem(40,40,32,32);
clickedBox->setBrush(QBrush(Qt::blue));
scene_->addItem(clickedBox);
}
Keep in mind you should ideally be putting the implementation of the constructor in your cpp file, but my example does it in the declaration for brevity.
void MapViewer::mousePressEvent(QMouseEvent *event)
{
// Show an empty message box, just to check that the event handler works!
QMessageBox *notification = new QMessageBox();
notification->show();
notification->exec();
// To add something whenever the user clicks, you don't need the view,
// just the scene.
scene()->addItem( new MyItem() );
}
Remember MapViewer derives from QGraphicsView and the view must know about the scene it belongs to - so it has a scene() method to return it, which you inherited.
//clposter.h
class CLPoster : public QMainWindow
{
Q_OBJECT
public:
CLPoster();
private slots:
QWidget createCentralWidget();
void createActions();
void createMenu();
void createStatusBar();
void loadSavedPosts();
};
//clposter.cpp
CLPoster::CLPoster()
{
setWindowTitle("Craigslist Poster");
QWidget mainWidget = createCentralWidget();
setCentralWidget(mainWidget);
// createActions();
// createMenu();
// createStatusBar();
// loadSavedPosts();
// checkForActionsNeeded(); //May want to break up into more functions
}
The error I'm getting is this:
/usr/include/qt4/QtGui/qwidget.h:: In constructor ‘CLPoster::CLPoster()’:
/usr/include/qt4/QtGui/qwidget.h:787: error: ‘QWidget::QWidget(const QWidget&)’ is private
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:9: error: within this context
/home/brett/projects/CLPoster/CLPoster-build-desktop/../CLPoster/clposter.cpp:10: error: no matching function for call to ‘CLPoster::setCentralWidget(QWidget&)’
/usr/include/qt4/QtGui/qmainwindow.h:141: candidates are: void QMainWindow::setCentralWidget(QWidget*)
I'm having trouble interpreting the error message. It says there is no matching function call, but it should be inheriting it from QMainWindow. It could just be a lack of understanding C++ more so than QT, first time I've used it, but dunno. Thanks for the help.
All QWidget items must be allocated in the free-store (new) since they all have to have "parents". In Qt a parent will delete its children (with delete). This is why any function returning, accepting, whatever a widget is going to do so on a pointer to a widget, not the widget itself; you need to do the same.
The setCentralWidget function expects that you are sending a pointer to a QWidget (QWidget*), whereas you are trying to send the actual object (or a reference to the object, QWidget&, as implied by the compiler error) in your code. If you create your central widget as a pointer (change the member function to QWidget* createCentralWidget()) and pass the pointer to the setCentralWidget function you should be good to go.
e.g.
QWidget* CLPoster::createCentralWidget()
{
QWidget* w = new QWidget;
// Do stuff..
return w;
}
Then in your constructor, you can just call setCentralWidget(createCentralWidget()). The QMainWindow destructor will ensure that your central widget is deleted.
Don't you need to allocate the Widget on the heap and pass a pointer to setCentralWidget()