I'm in the process of transitioning from PyQt5 to Qt5 in C++ and I'm having a bit of a tough time. I created a simple UI that contains a Qwidget called logo. I'm trying to make this widget an SVG rendering widget with this code:
QSvgRenderer renderer(QString(":/LogoSVG.svg"));
QImage image(500, 200, QImage::Format_ARGB32);
image.fill(0x000000);
QPainter painter(&image);
renderer.render(&painter);
In Python, I'd create a simple widget class that renders the SVG then in the UI form loader class I'd do
self.logo = SVGRender(self)
I'm trying to do the same thing in C++ Qt, so here's what I have so far and it's returning the error error: cannot convert ‘logoW’ to ‘QWidget*’ in assignment
example.h
#ifndef EXAMPLE_H
#define EXAMPLE_H
#include "ui_example.h"
class example : public QWidget
{
Q_OBJECT
public:
example(QWidget *parent = 0);
private:
Ui::example ui;
};
class logoW: public QWidget
{
Q_OBJECT
public:
logoW(QWidget *parent = 0);
};
#endif
example.cpp
#include <QtGui>
#include <QScreen>
#include <QApplication>
#include <QDesktopWidget>
#include <QCoreApplication>
#include <QSvgRenderer>
#include <QPainter>
#include <QImage>
#include <iostream>
#include "example.h"
using namespace std;
example::example(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
ui.logo = logoW(this)
}
logoW :: logoW(QWidget * parent = 0){
QSvgRenderer renderer(QString(":resources/LogoSvg.svg"));
QImage image(500, 200, QImage::Format_ARGB32);
image.fill(0xaaA08080);
QPainter painter(&image);
renderer.render(&painter);
}
Can someone show me what I'm doing wrong?
The variable ui.logo requires a pointer of the object, in your case it changes:
ui.logo = logoW(this);
to:
ui.logo = new logoW(this);
I also understand that you want to display the image in the logo widget. To do this you must implement the paintEvent method:
*.h
class logoW: public QWidget
{
Q_OBJECT
public:
logoW(QWidget *parent = 0);
protected:
void paintEvent(QPaintEvent *event);
};
*.cpp
logoW::logoW(QWidget *parent):QWidget(parent)
{
}
void logoW::paintEvent(QPaintEvent *event){
Q_UNUSED(event)
QSvgRenderer renderer(QString(":resources/LogoSvg.svg"));
QPainter painter(this);
renderer.render(&painter);
}
Related
I am trying to implement an image editor with some customized image edition tools not present in the Qt image classes. When the user clicks on the image scene to perform some operation, I want the image to be instantly updated in the GUI application, showing in real time to the user the changes (drawing pixels, zooming...). The problem is that the actions to edit the image when clicking can only be done (at least to my knowledge) inside a separate class (in the example I show below, such class is called GraphicsScene), and thus I don't know how to transfer the edited image to the MainWindow class.
In short, I would like to "send" the edited image from the GraphicsScene class to the MainWindow class immediately after the user performs an action to edit the image, and then make the latter one execute the code to update the screen in real time after each user action is performed on the image.
For the sake of clarity, I next show the scheme of the code I have for now.
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>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
Ui::MainWindow *ui;
private slots:
private:
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QApplication>
#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>
#include "graphicsscene.h"
extern QImage Image_original, Image_modified;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionOpen_Image_triggered()
{
QDir dir;
QString filename=QFileDialog::getOpenFileName(this,
tr("Open Background"),
path,
tr("Images (*.png *.bmp *.jpg *.jpeg);;All files (*.*)"));
Image_original.load(filename);
GraphicsScene * img = new GraphicsScene( this );
img->addPixmap(QPixmap::fromImage(Image_original));
ui->preview->setScene(img);
}
In order to be able to track the coordinates when clicking, and following some suggestions around the net, I created a subclass of QGraphicsScene called GraphicsScene, whose header file is:
graphicsscene.h
#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 mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent);
signals:
public slots:
private:
int x, y;
};
#endif // GRAPHICSSCENE_H
Finally, to perform the image editions, the source file associated is:
graphicsscene.cpp
#include "graphicsscene.h"
#include <iostream>
using namespace std;
extern QImage Image_original, Image_modified;
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
this->setBackgroundBrush(Qt::gray);
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent * mouseEvent)
{
QGraphicsScene::mousePressEvent(mouseEvent);
if (mouseEvent->button()==Qt::LeftButton)
{
x=mouseEvent->scenePos().x();
y=mouseEvent->scenePos().y();
}
Image_modified=some_custom_image_editing_code(Image_original, x, y);
}
Ideally, I would like to execute the following action in MainWindow after the mousePressEvent is performed:
img->addPixmap(QPixmap::fromImage(Image_modified));
ui->preview->setScene(img);
I would highly appreciate any idea.
Since you want to click the item containing the pixmap it is not necessary to overwrite the QGraphicsScene mousePressEvent method, since you could click outside the image, it is better to overwrite that method in QGraphicsPixmapItem.
Instead of using extern to access the images, in Qt is better signals and slot, but only the classes that inherit from QObject can have these attributes, unfortunately QGraphicsPixmapItem does not inherit from this, but we can use it as interface.
graphicspixmapitem.h
#ifndef GRAPHICSPIXMAPITEM_H
#define GRAPHICSPIXMAPITEM_H
#include <QGraphicsPixmapItem>
#include <QObject>
class GraphicsPixmapItem : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
explicit GraphicsPixmapItem(QObject *parent=0);
protected:
void mousePressEvent(QGraphicsSceneMouseEvent * event);
signals:
void newPixmap(const QPixmap p);
};
#endif // GRAPHICSPIXMAPITEM_H
graphicspixmapitem.cpp
#include "graphicspixmapitem.h"
#include <QGraphicsSceneMouseEvent>
GraphicsPixmapItem::GraphicsPixmapItem(QObject * parent):QObject(parent)
{
}
void GraphicsPixmapItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPoint p = QPoint(event->pos().x(), event->pos().y());
QPixmap pix = pixmap();
if(!pix.isNull()){
QRect rect(QPoint(), pix.rect().size()/2);
rect.moveCenter(p);
QPixmap modified = pix.copy(rect);
modified = modified.scaled(pix.rect().size(), Qt::KeepAspectRatioByExpanding);
emit newPixmap(modified);
}
QGraphicsPixmapItem::mousePressEvent(event);
}
In the previous code we created the signal newPixmap, this connected it with a slot called onNewPixmap in MainWindow.
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "graphicsscene.h"
#include "graphicspixmapitem.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_actionOpen_triggered();
void onNewPixmap(const QPixmap pixmap);
private:
Ui::MainWindow *ui;
GraphicsPixmapItem *item;
GraphicsScene *scene;
QPixmap original_pixmap;
QPixmap new_pixmap;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QGraphicsView>
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new GraphicsScene(this);
ui->preview->setScene(scene);
item = new GraphicsPixmapItem;
/*ui->preview->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
ui->preview->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);*/
scene->addItem(item);
connect(item, &GraphicsPixmapItem::newPixmap, this, &MainWindow::onNewPixmap);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_actionOpen_triggered()
{
QString path = QDir::homePath();
QString filename=QFileDialog::getOpenFileName(this,
tr("Open Background"),
path,
tr("Images (*.png *.bmp *.jpg *.jpeg);;All files (*.*)"));
original_pixmap = QPixmap(filename);
item->setPixmap(original_pixmap);
}
void MainWindow::onNewPixmap(const QPixmap pixmap)
{
new_pixmap = pixmap;
QFile file("new_file.png");
file.open(QIODevice::WriteOnly);
new_pixmap.save(&file, "PNG");
}
In that slot as test I save the image in the folder where the executable is generated.
In your code I see that you use QImage, if you want to continue using it you can convert QPixmap to QImage with:
new_pixmap.toImage()
The complete example is found here
I am new to qt and I am trying to create a program where the MainWindow calls a QDialog to enter some data.
The problem is that the parent() at my QDialog does not have any access to the public methods of the MainWindow in our case the
void save_city(const City *city); //public method of MainWindow
The code is actually big so here is some of the code.Thanks.
mainwindow.h
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QMainWindow>
#include <QTextStream>
#include <QVector>
#include <QDebug>
#include <QFile>
#include "dialog_add_city.h"
#include "street.h"
#include "city.h"
#include "map.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
//main Window constructor
explicit MainWindow(QWidget *parent = 0);
//main Window deconstructor
~MainWindow();
/*utility function to save the city
*the function is public so that also QDialogs
*data saves can */
//////////////
//here is the public function
void save_city(const City *city);
private slots:
private:
Map mainMap;
Ui::MainWindow *ui;
QGraphicsView view;
QGraphicsScene scene;
};
dialog_add_city.h
#ifndef DIALOG_ADD_CITY_H
#define DIALOG_ADD_CITY_H
#include <QDialog>
#include "mainwindow.h"
#include "City.h"
namespace Ui {
class Dialog_Add_City;
}
class Dialog_Add_City : public QDialog
{
Q_OBJECT
public:
explicit Dialog_Add_City(QWidget *parent = 0);
~Dialog_Add_City();
private slots:
//Add New City Button clicked-Adds an new city to our city_locations.txt
void on_PushButton_Add_New_City_clicked();
private:
Ui::Dialog_Add_City *ui;
};
#endif // DIALOG_ADD_CITY_H
dialog_add_city.cpp
#include "dialog_add_city.h"
#include "ui_dialog_add_city.h"
Dialog_Add_City::Dialog_Add_City(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog_Add_City)
{
ui->setupUi(this);
}
Dialog_Add_City::~Dialog_Add_City()
{
delete ui;
}
void Dialog_Add_City::on_PushButton_Add_New_City_clicked()
{
City *city=new City(ui->lineEdit_cityName->text(),
ui->lineEdit_X_Ko->text().toDouble(),
ui->lineEdit_Y_Ko->text().toDouble());
qDebug() << ui->lineEdit_cityName->text()
<< ui->lineEdit_X_Ko->text()
<< ui->lineEdit_Y_Ko->text();
/////////////////////////////
//HERE IS THE PROBLEM
parent()->save_city(city);
}
Any other suggestions are welcomed!
The Problem is that parent() will return a pointer the parent object as QObject.
QObject Documentation
As dreschrjm pointed out you could try to cast the object via
MyWidget *myWidget = qobject_cast<MyWidget *>(obj);
from The Meta-Object System
Suggestion: Use Qt's signal/slot mechanism to avoid a backward reference to the parent.
Declare save_city as signal in Dialog_Add_City.
Declare save_city in MainWindow as slot
Connect both where the dialog is created:
e.g.
void MainWindow::show_add_city_dialog()
{
Dialog_Add_city dialog;
connect(&dialog, &Dialog_Add_city::save_city, this, &MainWindow::save_city);
dialog.exec();
}
Replace parent()->save_city(city); in Dialog_Add_City with emit save_city(city);
Ensure that the new city object doesn't leak, I think a better design would be to create the City object elsewhere not in the dialog.
so
emit save_city(ui->lineEdit_cityName->text(),
ui->lineEdit_X_Ko->text().toDouble(),
ui->lineEdit_Y_Ko->text().toDouble());
and the slot
void MainWindow::save_city(const QString &cityName, double x, double y)
{
City *city=new City(cityName, x, y);
// do some interresting things with city.
}
When I add QGraphicsPixmapItem to scene and after first mouse click program freeze for long. Why? Or how i can exclude this from Qt's inner computations (if only i know what happens behind..)
*.h
#include <QtWidgets/QMainWindow>
#include "ui_bigqgraphicsscene.h"
class BigQGraphicsScene : public QMainWindow
{
Q_OBJECT
public:
BigQGraphicsScene(QWidget *parent = 0);
~BigQGraphicsScene();
private slots:
void on_pushButton_clicked();
private:
Ui::BigQGraphicsSceneClass ui;
QImage imgOrig;
};
*.cpp
#include "bigqgraphicsscene.h"
#include <QFileDialog>
#include <QSet>
#include <QDebug>
#include <QGraphicsPixmapItem>
BigQGraphicsScene::BigQGraphicsScene(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
ui.graphicsView->setScene(new QGraphicsScene());
}
BigQGraphicsScene::~BigQGraphicsScene(){}
void BigQGraphicsScene::on_pushButton_clicked()
{
QString s = "d:/!Qt/ImageNumber/BigQGraphicsScene/TestPic/fastole_bdr.png";
if (s.length())
{
imgOrig.load(s);
QGraphicsPixmapItem *itm = new QGraphicsPixmapItem();
itm->setPixmap(QPixmap::fromImage(imgOrig));
ui.graphicsView->scene()->setItemIndexMethod(QGraphicsScene::NoIndex);
ui.graphicsView->scene()->addItem(itm);
ui.graphicsView->scene()->setSceneRect( imgOrig.rect() );
}
}
scene()->setItemIndexMethod(QGraphicsScene::NoIndex); - not help...
almost transparent pix for example - fastole_bdr.png
Can you background load your image? You're reading from disk and then processing the image into whatever format QT uses internally on the UI thread, so it's not particularly surprising that the application becomes unresponsive for larger images.
I want to make a program that shows the info of a QGraphicsItem (width and height) by clicking the option "info" inside a context menu I created with the QGraphicsSceneContextMenuEvent. Right now I´m just trying to call a function with a qDebug in it called info.
Here's my code
dialog.h:
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include "QtCore"
#include "QtGui"
#include "mysquare.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
private:
Ui::Dialog *ui;
QGraphicsScene *scene;
MySquare *square;
};
#endif // DIALOG_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
#include <QWidget>
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
square=new MySquare();
scene->addItem(square);
}
Dialog::~Dialog()
{
delete ui;
}
mysquare.h
#ifndef MYSQUARE_H
#define MYSQUARE_H
#include <QPainter>
#include <QGraphicsItem>
#include <QDebug>
#include <QMenu>
class MySquare: public QGraphicsItem
{
public:
MySquare();
QRectF boundingRect() const;
void paint (QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QMenu *menu;
QAction *heightAct;
QAction *widthAct;
QAction *color;
private slots:
void info();
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event);
};
#endif // MYSQUARE_H
mysquare.cpp
#include "mysquare.h"
#include<QMenu>
#include <string>
using namespace std;
MySquare::MySquare()
{
}
QRectF MySquare::boundingRect() const
{
return QRectF(100,100,50,50);
}
void MySquare::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
QRectF rec = boundingRect();
QBrush brushy(Qt::green);
painter->fillRect(rec,brushy);
painter->drawRect(rec);
}
void MySquare::info()
{
qDebug()<<"HERE'S MY INFO!!!";
}
void MySquare::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QString height = "Height: "+QString::number(boundingRect().height());
QString width = "Width: "+QString::number(boundingRect().width());
menu = new QMenu();
heightAct = menu->addAction(height);
widthAct = menu->addAction(width);
color = menu->addAction("Change color");
menu->exec(QCursor::pos());
}
To make a "link" between a click on an action in your menu and your slot info(), you need to use the signal/slot mechanism.
You only have to add a QObject::connect(...) in your QMenu initialization.
void MySquare::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
QString height = "Height: "+QString::number(boundingRect().height());
QString width = "Width: "+QString::number(boundingRect().width());
menu = new QMenu();
heightAct = menu->addAction(height);
widthAct = menu->addAction(width);
color = menu->addAction("Change color");
QObject::connect(heightAct, SIGNAL(triggered()), this, SLOT(info()));
menu->exec(QCursor::pos());
}
However, the above code will not compile because signal/slot mechanism work only with subclasses of QObject and QGraphicsItem isn't. So you have to change it to a QGraphicsObject. (Don't forget the Q_OBJECT macro though)
Also, a little out of subject:
Use
#include <QtCore>
instead of
#include "QtCore"
but I really advise you to just include what you need, not the whole QtCore library.
Also, put your includes in your source files instead of your header files except when it's impossible.
Don't mix standard C++ library such as
#include <string>
except when it's absolutely needed. In this case you have to include
#include <QString>
And just simply remove
using namespace std;
I'm writing simple application by using QPixmap and QPainter. In my programm I need to load some images and resize them. I used QPixmap::scaled(), but images does not scaled. What I did wrong?
This is my code:
chesstile.cpp
#include "chesstile.h"
ChessTile::ChessTile(QWidget *parent) :
QLabel(parent)
{
}
void ChessTile::paintEvent(QPaintEvent *)
{
const QString &fileName = "images/white_king.png";
QPixmap bgPixmap(fileName);
bgPixmap.scaled(QSize(64, 64));
QPainter painter(this);
painter.drawPixmap(0, 0, bgPixmap);
}
chesstile.h
#ifndef CHESSTILE_H
#define CHESSTILE_H
#include <QLabel>
#include <QString>
#include <QPainter>
#include <QPixmap>
#include <QSize>
class ChessTile : public QLabel
{
Q_OBJECT
public:
ChessTile(QString fileName,
QString tileColor,
QWidget *parent = 0);
void paintEvent(QPaintEvent *);
private:
signals:
public slots:
};
#endif // CHESSTILE_H
You'll notice from the docs that the QPixmap::scaled member function is const - i.e. it doesn't change the object itself.
The scaled object is returned by that method, it doesn't change the original pixmap.
Try something like:
QPixmap bgPixmap(fileName);
QPixmap scaled = bgPixmap.scaled(QSize(64, 64));
QPainter painter(this);
painter.drawPixmap(0, 0, scaled)