Custom QGraphicsPixmapItem doesn't display pixmap - c++

I have made a custom QGraphicsPixMap QGraphicsItem as I need to have functions that trigger when someone clicks on it! The header for this is seen below:
#ifndef NEWGPIXMAP_H
#define NEWGPIXMAP_H
#include <QObject>
#include <QGraphicsPixmapItem>
#include <QGraphicsSceneMouseEvent>
class NewGPixmap : public QObject, public QGraphicsPixmapItem
{
Q_OBJECT
public:
NewGPixmap();
void mousePressEvent(QGraphicsSceneMouseEvent *event);
// void mouseMoveEvent(QGraphicsSceneMouseEvent *event);
// void mouseReleaseEvent(QGraphicsSceneMouseEvent *event);
};
#endif // NEWGPIXMAP_H
And the .cpp for this can be seen here:
#include "newgpixmap.h"
#include <iostream>
#include <QPointF>
NewGPixmap::NewGPixmap()
{
}
void NewGPixmap::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QPointF pos = event->pos();
int x = pos.x();
int y = pos.y();
std::cout<<x<<" "<<y<<std::endl;
}
When I try and update the pixmap in the QGraphicsScene (stored in a variable called "scene") I get no errors however the PixMap isn't displayed.
This is the code I used prior to implementing my own QGraphicsPixMap which worked fine:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
QGraphicsPixmapItem* item = new QGraphicsPixmapItem(QPixmap::fromImage(image));
scene->clear();
scene->addItem(item);
}
And now that I am using my own QGraphicsPixMap implementation, this is what code I have:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
NewGPixmap item;
item.setPixmap(QPixmap::fromImage(image));
scene->clear();
scene->addItem(&item);
}
The problem is that the pixmap wont load into the QGraphicsScene.
Thanks for your help!

Variables are destroyed when their scope ends, in your case "NewGPixmap item;" it is a local variable so it will be deleted when finished running on_openImage_triggered. If you want the object to not depend on the life cycle of the variable then you must use a pointer like your example with QGraphicsPixmapItem:
void MainWindow::on_openImage_triggered()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Choose File"));
QImage image(fileName);
NewGPixmap *item = new NewGPixmap;
item->setPixmap(QPixmap::fromImage(image));
scene->clear();
scene->addItem(item);
}

Related

Is there a Qt widget that looks like a label to display text but can also be edited if double-clicked?

I want a widget in Qt that will act like a spreadsheet cell does. It can display text, then when the user double-clicks on it, it becomes editable. Once the user is done with editing and presses Enter, the text gets saved and the control is not editable anymore. If the user hits Escape while editing, then the control returns to its previous value.
One possible solution is sub-classing QWidget, QLabel and QLineEdit. Are there any other solutions available in Qt?
The following version also implements the same functionalities of your answer but instead of subclassing the QLineEdit and the QLabel only use eventFilter() and instead of managing the visibility manually let QStackedWidget do it.
#include <QApplication>
#include <QFormLayout>
#include <QKeyEvent>
#include <QLabel>
#include <QLineEdit>
#include <QStackedWidget>
#include <QVBoxLayout>
class MyEditableLabel: public QWidget{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
MyEditableLabel(QWidget *parent=nullptr):
QWidget(parent),
mLabel(new QLabel),
mLineEdit(new QLineEdit)
{
setLayout(new QVBoxLayout);
layout()->setMargin(0);
layout()->setSpacing(0);
layout()->addWidget(&stacked);
stacked.addWidget(mLabel);
stacked.addWidget(mLineEdit);
mLabel->installEventFilter(this);
mLineEdit->installEventFilter(this);
setSizePolicy(mLineEdit->sizePolicy());
connect(mLineEdit, &QLineEdit::textChanged, this, &MyEditableLabel::setText);
}
bool eventFilter(QObject *watched, QEvent *event){
if (watched == mLineEdit) {
if(event->type() == QEvent::KeyPress){
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_Return ||
keyEvent->key() == Qt::Key_Escape ||
keyEvent->key() == Qt::Key_Enter)
{
mLabel->setText(mLineEdit->text());
stacked.setCurrentIndex(0);
}
}
else if (event->type() == QEvent::FocusOut) {
mLabel->setText(mLineEdit->text());
stacked.setCurrentIndex(0);
}
}
else if (watched == mLabel) {
if(event->type() == QEvent::MouseButtonDblClick){
stacked.setCurrentIndex(1);
mLineEdit->setText(mLabel->text());
mLineEdit->setFocus();
}
}
return QWidget::eventFilter(watched, event);
}
QString text() const{
return mText;
}
void setText(const QString &text){
if(text == mText)
return;
mText == text;
emit textChanged(mText);
}
signals:
void textChanged(const QString & text);
private:
QLabel *mLabel;
QLineEdit *mLineEdit;
QStackedWidget stacked;
QString mText;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QWidget w;
QFormLayout *lay = new QFormLayout(&w);
MyEditableLabel el;
lay->addRow("MyEditableLabel: ", &el);
lay->addRow("QLineEdit: ", new QLineEdit);
w.show();
return a.exec();
}
#include "main.moc"
this solution is not as sexy but probably one of the more performant solutions available to you is to use a QInputdialog to change QLabel and override the mouseDoubleClickEvent to trigger the input dialog. I as some here have learned that there is no means to Pull edited text from a QLabel. Not without changing QLabels internal code. Here's an example using a QInputDialog as means.
//intrlbl.h
#ifndef INTRLBL_H
#define INTRLBL_H
#include <QWidget>
#include <QLabel>
#include <QMouseEvent>
class intrLbl: public QLabel
{
Q_OBJECT
public:
intrLbl(QWidget *parent);
void mouseDoubleClickEvent(QMouseEvent *event) override;
QString text;
};
#endif // INTRLBL_H
//intrlbl.cpp file
#include "intrlbl.h"
#include <QDebug>
#include <QInputDialog>
intrLbl::intrLbl(QWidget *parent)
{
this->setText("Text Changeable Via Double Click QInput Dialog");
this->setFocusPolicy(Qt::ClickFocus);
this->setWordWrap(false);
}
void intrLbl::mouseDoubleClickEvent(QMouseEvent *event)
{
QString title
= QInputDialog::getText(this,
tr("Enter your Idea Title:"),
tr("Title:"), QLineEdit::Normal,
tr("enter your title here"));
if(!title.isEmpty())
{
qDebug() << "Title set to:" << title;
this->setText(title);
}
else
{
title = "Title";
this->setText(title);
}
}
One of the solutions is to have a QLineEdit and set it to read-only and style it in a way that it will look like a label. I personally do not like this solution, because it's more of a hacking approach. I have come up with something that in my opinion is pretty cool, which includes sub-classing QWidget, QLabel and QLineEdit:
Let's first introduce a model, which will be created in the sub-classed version of our QWidget and this model will be passed to its child widgets, the sub-classed versions of QLabel and QLineEdit:
Model header - mymodel.h:
#ifndef MYMODEL_H
#define MYMODEL_H
#include <QObject>
class MyModel : public QObject {
Q_OBJECT
Q_PROPERTY(Mode mode READ getMode WRITE setMode NOTIFY modeChanged)
Q_PROPERTY(QString text READ getText WRITE setText NOTIFY textChanged)
public:
enum class Mode {
ReadOnly = 0,
Edit = 1,
};
explicit MyModel(QObject* parent = nullptr);
Mode getMode() const {
return _mode;
}
const QString& getText() const {
return _text;
}
signals:
void modeChanged(Mode mode);
void textChanged(const QString& text);
public slots:
void setMode(Mode mode);
void setText(const QString& text);
private:
Mode _mode;
QString _text;
};
#endif // MYMODEL_H
Model implementation - mymodel.cpp
#include "mymodel.h"
MyModel::MyModel(QObject *parent)
: QObject(parent)
, _mode(MyModel::Mode::ReadOnly)
, _text(QString()) {
}
void MyModel::setMode(MyModel::Mode mode) {
if (_mode != mode) {
_mode = mode;
emit modeChanged(_mode);
}
}
void MyModel::setText(const QString &text) {
if (_text != text) {
_text = text;
emit textChanged(text);
}
}
As we see the model has the text, which is common for both the QLabel and the QLineEdit, and it has a mode, which can be either read only or edit mode.
The label implementation is a sub-class of Label.
Header - mylabel.h:
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
#include <QSharedPointer>
#include "mymodel.h"
class MyLabel : public QLabel {
Q_OBJECT
public:
explicit MyLabel(QWidget *parent = 0);
void setModel(QSharedPointer<MyModel> model);
protected:
void mouseDoubleClickEvent(QMouseEvent *) override;
private:
QSharedPointer<MyModel> _model;
};
#endif // MYLABEL_H
Implementation - mylabel.cpp:
#include "mylabel.h"
#include <QMouseEvent>
MyLabel::MyLabel(QWidget *parent)
: QLabel(parent) {
}
void MyLabel::setModel(QSharedPointer<MyModel> model) {
_model = model;
}
void MyLabel::mouseDoubleClickEvent(QMouseEvent *) {
_model->setText(text());
_model->setMode(MyModel::Mode::Edit);
}
As we our class MyLabel has a setModel() method, which will take the model from its parent. We are overriding the mouseDoubleClickEvent(), though which we are setting the text of the model to whatever text there is in the label, and setting the mode to edit, because when double-clicking we want to edit the text.
Now let's take a look at the QLineEdit. Our version of QLineEdit, called MyLineEdit, is listening to keyboard events and when Enter and Esc keys are pressed it either saves the text to the model, or discards it. Then it changes the mode to read-only.
MyLineEdit.h:
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QLineEdit>
#include <QSharedPointer>
#include "mymodel.h"
class MyLineEdit : public QLineEdit {
Q_OBJECT
public:
MyLineEdit(QWidget* parent = nullptr);
void setModel(QSharedPointer<MyModel> model);
protected:
void keyPressEvent(QKeyEvent* event) override;
void focusOutEvent(QFocusEvent*);
private:
QSharedPointer<MyModel> _model;
};
#endif // MYLINEEDIT_H
And here's the implementation - MyLineEdit.cpp:
#include "mylineedit.h"
#include <QKeyEvent>
MyLineEdit::MyLineEdit(QWidget *parent)
: QLineEdit(parent) {
}
void MyLineEdit::setModel(QSharedPointer<MyModel> model) {
_model = model;
}
void MyLineEdit::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Enter) {
_model->setText(text());
_model->setMode(MyModel::Mode::ReadOnly);
} else if (event->key() == Qt::Key_Escape) {
_model->setMode(MyModel::Mode::ReadOnly);
} else {
QLineEdit::keyPressEvent(event);
}
}
void MyLineEdit::focusOutEvent(QFocusEvent *) {
_model->setText(text());
_model->setMode(MyModel::Mode::ReadOnly);
}
So now we have the model, we have our version of QLabel and our version of QLineEdit. What we want now is a parent widget that will contain both of them, listen to signals from the model and change its appearance based on the signals. That class is derived from QWidget and is called MyEditableLabel:
MyEditableLabel.h:
#ifndef MYEDITABLELABEL_H
#define MYEDITABLELABEL_H
#include <QSharedPointer>
#include <QWidget>
#include "mylabel.h"
#include "mylineedit.h"
class MyEditableLabel : public QWidget {
Q_OBJECT
public:
explicit MyEditableLabel(QWidget *parent = nullptr);
QString getText() const {return _text;}
private:
MyLabel *_label;
MyLineEdit *_lineEdit;
QSharedPointer<MyModel> _model;
private slots:
void onModeChanged(MyModel::Mode mode);
void onTextChanged(const QString &text);
private:
QString _text;
};
#endif // MYEDITABLELABEL_H
MyEditableLabel.cpp:
#include "myeditablelabel.h"
#include <QHBoxLayout>
MyEditableLabel::MyEditableLabel(QWidget *parent)
: QWidget(parent) {
_model = QSharedPointer<MyModel>(new MyModel());
_model->setText("Click me!");
_label = new MyLabel(this);
_label->setModel(_model);
_lineEdit = new MyLineEdit(this);
_lineEdit->setModel(_model);
_lineEdit->setReadOnly(false);
QHBoxLayout *mainLayout = new QHBoxLayout();
mainLayout->setMargin(0);
mainLayout->setSpacing(0);
mainLayout->addWidget(_label);
mainLayout->addWidget(_lineEdit);
setLayout(mainLayout);
connect(_model.data(), &MyModel::modeChanged, this, &MyEditableLabel::onModeChanged);
onModeChanged(_model->getMode());
connect(_model.data(), &MyModel::textChanged, this, &MyEditableLabel::onTextChanged);
onTextChanged(_model->getText());
}
void MyEditableLabel::onModeChanged(MyModel::Mode mode) {
_lineEdit->setVisible(mode == MyModel::Mode::Edit);
_lineEdit->selectAll();
_label->setVisible(mode == MyModel::Mode::ReadOnly);
}
void MyEditableLabel::onTextChanged(const QString &text) {
_lineEdit->setText(text);
_label->setText(text);
_text = text;
}
Usage:
Using this is pretty straightforward. If you're using the Qt Creator designer, then you want to draw a QWidget and the right click on it and promote it to MyEditableLabel and you're done. If you're not using the Qt Creator designer then you just have to create and instance of MyEditableLabel and you're in business.
Improvements:
It probably is a better idea to not create the model in the constructor of MyEditableLabel, but outside of it and have a setModel method in MyEditableLabel.

Converting a list of items in qt listwidget to radio buttons

I have created an application where files from a directory are being displayed in the qlistwidget.
Now the problem is that I want this list to be shown as a list of radio buttons so that the user can select a radio button and the address of the selected file can be saved. Also an error need to be shown if the user doesn't select a radio button and clicks next.
I'm using Visual Studio for coding the gui instead of qt creator.
My code so far is:
.hpp file
#pragma once
#include <QWidget>
#include "ui_secondform.h"
#include "thirdform.hpp"
#include <QRegExp>
#include <QDir>
#include <QDebug>
class SecondForm : public QWidget {
Q_OBJECT
public:
SecondForm(QWidget * parent = Q_NULLPTR);
~SecondForm();
QString processText();
signals:
void firstform();
public slots:
void on_pushButton_next2_clicked();
void on_pushButton_back2_clicked();
void on_lineEdit_textChanged(const QString &arg1);
//void onNewTextEntered(const QString &text);
//void on_lineEdit_textChanged(const QString &arg1);
private:
Ui::SecondForm ui;
ThirdForm *third;
QStringList fileList;
};
.cpp file:
#include "secondform.hpp"
#include "firstform.h"
SecondForm::SecondForm(QWidget * parent) : QWidget(parent) {
ui.setupUi(this);
third = new ThirdForm();
// connected to the slot start the main window on the button in the second window
connect(third, &ThirdForm::secondform, this, &SecondForm::show);
//QString dir = processText();
QDir testPath("D://");
testPath.setFilter(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
fileList = testPath.entryList();
ui.listWidget->addItems(fileList);
}
SecondForm::~SecondForm() {
}
void SecondForm::on_pushButton_back2_clicked() {
this->hide();
emit firstform();
}
void SecondForm::on_pushButton_next2_clicked() {
this->close();
third->show();
}
void SecondForm::on_lineEdit_textChanged(const QString &arg1) {
QRegExp regExp(arg1, Qt::CaseInsensitive, QRegExp::Wildcard);
ui.listWidget->clear();
ui.listWidget->addItems(fileList.filter(regExp));
}
QString SecondForm::processText()
{
FirstForm first;
const QString dir = first.lineEdit()->text();
return dir;
// do something with the text
}
Output:

How to open SVG using QT c++

I'm trying to create and save QGraphicsScene to .svg file and my code works properly. Which creates rectangle,circle and save it into .svg But problem is which can only open rectangles only,how can I implement this to open circle(ellipse too) Please help me.
here are my codes.
readsvg.h
#ifndef READSVG_H
#define READSVG_H
#include <QList>
#include <QGraphicsRectItem>
class ReadSVG
{
public:
ReadSVG();
static QList<QGraphicsRectItem *> getElements(const QString filename);
static QRectF getSizes(const QString filename);
//static QList<QGraphicsEllipseItem *> getElements(const QString filename);
//static QRectF getSizes(const QString filename);
};
#endif // READSVG_H
readsvg.cpp
#include "readsvg.h"
#include <QPen>
#include <QFile>
#include <QMessageBox>
#include <QDomDocument>
#include <QStringList>
ReadSVG::ReadSVG()
{
}
QList<QGraphicsRectItem *> ReadSVG::getElements(const QString filename)
{
QList<QGraphicsRectItem *> rectList; // We declare in the stack a list of rectangles
QDomDocument doc; // document object
QFile file(filename); // Open our SVG file
// If it did not open or could not transfer content to QDocDocument
if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
return rectList; // then return the list, but empty
// Look in the document for all objects with the tag g
QDomNodeList gList = doc.elementsByTagName("g");
// We start to sort them out
for (int i = 0; i < gList.size(); i++) {
QDomNode gNode = gList.item(i); // Select the node from the list
QDomElement rectangle = gNode.firstChildElement("rect"); // And we search in it for an element with the tag rect
// If the resulting elements are not zero, then
if (rectangle.isNull()){
continue;
} else {
// begin to form a rectangle
QGraphicsRectItem *rect = new QGraphicsRectItem();
// This flag makes the object moveable, it will be required for verification
rect->setFlag(QGraphicsItem::ItemIsMovable);
// We take sizes from the rect tag
QDomElement gElement = gNode.toElement();
rect->setRect(rectangle.attribute("x").toInt(),
rectangle.attribute("y").toInt(),
rectangle.attribute("width").toInt(),
rectangle.attribute("height").toInt());
/*
We take the parameters of the colors gNode from the node element
yes yes yes ... it's from gNode, not from rectangle. These parameters are stored in the tag g
* */
QColor fillColor(gElement.attribute("fill", "#ffffff")); // fill color
fillColor.setAlphaF(gElement.attribute("fill-opacity","0").toFloat());
rect->setBrush(QBrush(fillColor));
// as well as the color and thickness of the outline
QColor strokeColor(gElement.attribute("stroke", "#000000"));
strokeColor.setAlphaF(gElement.attribute("stroke-opacity").toFloat());
rect->setPen(QPen(strokeColor,gElement.attribute("stroke-width", "0").toInt()));
rectList.append(rect); // add a rectangle to the list
}
}
file.close();
return rectList;
}
QRectF ReadSVG::getSizes(const QString filename)
{
QDomDocument doc; // initialize the QDomDocument object on the stack
QFile file(filename); // Open our SVG file
// If it did not open or could not transfer content to QDocDocument
if (!file.open(QIODevice::ReadOnly) || !doc.setContent(&file))
return QRectF(0,0,200,200); // then return the values ​​for the default scene
/* Next, we take the list of elements with the tag svg.
* In case the list of elements is not empty,
* then we will take the dimensions of the graphic scene.
* */
QDomNodeList list = doc.elementsByTagName("svg");
if(list.length() > 0) {
QDomElement svgElement = list.item(0).toElement();
QStringList parameters = svgElement.attribute("viewBox").split(" ");
return QRectF(parameters.at(0).toInt(),
parameters.at(1).toInt(),
parameters.at(2).toInt(),
parameters.at(3).toInt());
}
return QRectF(0,0,200,200);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QWidget>
#include <QtCore>
#include <QtGui>
#include <QSvgGenerator>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots:
void on_pushButton_clicked();
void on_btnSave_clicked();
void on_btnOpen_clicked();
private:
Ui::Widget *ui;
QGraphicsScene *scene;
QGraphicsEllipseItem *elipse;
QGraphicsRectItem *rect;
QString path;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "readsvg.h"
#include <QCursor>
#include <QFileDialog>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
QBrush redBrush(Qt::red);
QBrush blueBrush(Qt::blue);
QPen blackPen(Qt::black);
blackPen.setWidth(6);
elipse = scene->addEllipse(10,10,100,100,blackPen,redBrush);
rect = scene->addRect(-10,-10,100,100,blackPen,blueBrush);
rect->setFlag(QGraphicsItem::ItemIsMovable, true);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
QString fileName= QFileDialog::getSaveFileName(this, "Save image", QCoreApplication::applicationDirPath(), "BMP Files (*.bmp);;JPEG (*.JPEG);;PNG (*.png)" );
if (!fileName.isNull())
{
QPixmap pixMap = this->ui->graphicsView->grab();
pixMap.save(fileName);
}
}
void Widget::on_btnSave_clicked()
{
// Заберём путь к файлу и его имененем, который будем создавать
QString newPath = QFileDialog::getSaveFileName(this, trUtf8("Save SVG"),
path, tr("SVG files (*.svg)"));
if (newPath.isEmpty())
return;
path = newPath;
QSvgGenerator generator;
generator.setFileName(path);
generator.setSize(QSize(scene->width(), scene->height()));
generator.setViewBox(QRect(0, 0, scene->width(), scene->height()));
generator.setTitle(trUtf8("SVG Example"));
generator.setDescription(trUtf8("File created by SVG Example"));
QPainter painter;
painter.begin(&generator);
scene->render(&painter);
painter.end();
}
void Widget::on_btnOpen_clicked()
{
QString newPath = QFileDialog::getOpenFileName(this, trUtf8("Open SVG"),
path, tr("SVG files (*.svg)"));
if (newPath.isEmpty())
return;
path = newPath;
scene->clear();
scene->setSceneRect(ReadSVG::getSizes(path)); // Set the size of the graphic scene
// Install the objects on the graphical scene, get them using the getElements
foreach (QGraphicsRectItem *item, ReadSVG::getElements(path)) {
QGraphicsRectItem *rect = item;
scene->addItem(rect);
}
}
You can continue with the approach that you have started. Look for elements with the tag names that you want. Start with the "circle" tag. Here's what a ciricle tag might look like;
<circle cx="5" cy="5" r="3" fill="#0f0"/>

How to draw a line on a QPixmap using points

I have a label in my GUI that displays an image as a QPixmap. I want to be able to draw a continuous line on my image by simply clicking anywhere on the image to select the start point and then make a second point somewhere else by clicking on a other part of the image. The two points should connect immediately after placing the second point and I want to be able to continue that same line by placing more points on the image.
While I know how to draw something on a QPixmap, the mouse event which I need to use to get the coordinates for the points is really confusing me as I’m still fairly new to Qt.
Any examples for a solution would be much appreciated.
I suggest you to use QGraphicsView for this purpose. Use my code snippet which works perfectly.
Subclass QGraphicsScene:
#ifndef GRAPHICSSCENE_H
#define GRAPHICSSCENE_H
#include <QGraphicsScene>
#include <QPoint>
#include <QMouseEvent>
class GraphicsScene : public QGraphicsScene
{
Q_OBJECT
public:
explicit GraphicsScene(QObject *parent = 0);
signals:
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent);
public slots:
private:
QPolygon pol;
};
#endif // GRAPHICSSCENE_H
.cpp file:
#include "graphicsscene.h"
#include <QDebug>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
GraphicsScene::GraphicsScene(QObject *parent) :
QGraphicsScene(parent)
{
addPixmap(QPixmap("G:/2/qt.jpg"));//your pixmap here
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
//qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QPoint pos = mouseEvent->scenePos().toPoint();
pol.append(pos);
if(pol.size() > 1)
{
QPainterPath myPath;
myPath.addPolygon(pol);
addPath(myPath,QPen(Qt::red,2));
}
}
}
Usage:
#include "graphicsscene.h"
//...
GraphicsScene *scene = new GraphicsScene(this);
ui->graphicsView->setScene(scene);
ui->graphicsView->show();
Result:
If you want save new pixmap (or just get pixmap) as image, use this code:
QPixmap pixmap(ui->graphicsView->scene()->sceneRect().size().toSize());
QString filename("example.jpg");
QPainter painter( &pixmap );
painter.setRenderHint(QPainter::Antialiasing);
ui->graphicsView->scene()->render( &painter, pixmap.rect(),pixmap.rect(), Qt::KeepAspectRatio );
painter.end();
pixmap.save(filename);
With render() you can also grab different areas of your scene.
But this code can be better: we create and paint same polygon. If we can remember last painted point, then we can paint line by line (begin of line is end of last line). In this case we don't need all points, we need just last point.
As I promised(Code improvement):just provide additional variable QPoint last; instead of QPolygon pol; and use next code:
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
{
//qDebug() << "in";
if (mouseEvent->button() == Qt::LeftButton)
{
QPoint pos = mouseEvent->scenePos().toPoint();
if(last.isNull())
{
last = pos;
}
else
{
addLine(QLine(last,pos),QPen(Qt::red,2));
last = pos;
}
}
}
As you can see, you store only last point and paint only last line. User can clicks thousands time and now you not need to store this unnecessary points and do this unnecessary repainting.

Qt send data from form1 into form2 treeview component

I am pretty new to Qt, but I guess that I need to use signals and slots to send/receive data, at least in tutorials and other posts it's always like that.
This should be working:
Push Import button, select xls file -> right after we've selected it. We are running through the file and get the same sheet name and sheet table column headers for each sheet (then the user selects the column and all what that column contains; we are inserting into a database, etc)
I want to make a GUI application like this in my "excel-2-some-db" module:
I got two classes. First one - import_module:
import_module.h:
#ifndef IMPORTDB_MODULE_H
#define IMPORTDB_MODULE_H
#include <QtGui/QMainWindow>
#include <QAxObject>
#include <QAxWidget>
#include "ui_importdb_module.h"
#include "headers_selection.h"//select form
class importdb_module : public QMainWindow
{
Q_OBJECT
public:
importdb_module(QWidget *parent = 0, Qt::WFlags flags = 0);
~importdb_module();
//...
private:
Ui::importdb_moduleClass ui;
//...
headers_selection* select_form;
public slots:
void on_getExcelPath_clicked();
void on_pushButton1_clicked();
//signal we will send after read some sheets columns
signals:
void sendTreeViewData(QString &sheet_name, QStringList &sheet_headers);
};
#endif // IMPORTDB_MODULE_H
import_module.cpp
#include <QtGui>
#include <QApplication>
#include "importdb_module.h"
importdb_module::importdb_module(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
select_form = new headers_selection();
//to show form on click
connect(ui.pushButton1, SIGNAL(clicked()), select_form, SLOT(show()));
connect(this,
SIGNAL(sendTreeViewData(QString &sheet_name, QStringList &sheet_headers)),
select_form,
SLOT(recieveTreeViewData(QString &sheet_name, QStringList &sheet_headers)));
}
importdb_module::~importdb_module()
{
}
//....
//all file headers
void importdb_module::readSheetsHeaders(QAxObject* &_workbook, QAxObject* _worksheets, QAxObject* &_excel){
QAxObject* sheet_i;
int sheets_count = _worksheets->property("Count").toInt(); //get how much lists there, gonna choose one to import data
QString sheet_name;
QStringList sheet_headers;//sheet headers will store here
//sheets num starts from 1
for(int i=1; i<= sheets_count; i++){
sheet_i = _workbook->querySubObject("Worksheets(int)", i);//get teh list
sheet_name = sheet_i->property("Name").toString();//get teh name
//...
getTableHeaders(sheet_i, sheet_headers);
//says that we've send tree data into the form
emit sendTreeViewData(sheet_name, sheet_headers);
sheet_i->clear();
sheet_headers.clear();
}
delete sheet_i;
};
//...
headers_selection.h
#ifndef HEADERS_SELECTION_H
#define HEADERS_SELECTION_H
#include <QWidget>
#include "ui_headers_selection.h"
class headers_selection : public QWidget
{
Q_OBJECT
public:
headers_selection(QWidget *parent = 0);
~headers_selection();
private:
Ui::headers_selection ui;
public slots:
void recieveTreeViewData(QString &sheet_name, QStringList &sheet_headers);
};
#endif // HEADERS_SELECTION_H
headers_selection.cpp
#include "headers_selection.h"
headers_selection::headers_selection(QWidget *parent)
: QWidget(parent)
{
ui.setupUi(this);
QStandardItemModel *model = new QStandardItemModel;
}
headers_selection::~headers_selection()
{
}
void headers_selection::recieveTreeViewData(QString &sheet_name, QStringList &sheet_headers)
{
//just test
QStandardItemModel *model = new QStandardItemModel;
model->setColumnCount(1);
model->setRowCount(5);
model->setData(model->index(0, 0), "some data0");
model->setData(model->index(1, 0), "some data1");
model->setData(model->index(2, 0), "some data2");
model->setData(model->index(3, 0), "some data3");
model->setData(model->index(4, 0), "some data4");
ui.treeView->setModel(model);
}
And after I import .xls and opening treeview selection windows - it's empty!
So I got two possible problems here
maybe sendTreeViewData does not invoke recieveTreeViewData or maybe I do something wrong with tree view inside recieveTreeViewData method.
Could somebody help me to fix it, please?
UPDATE
Well, I made a little changes (thanks to thomas_b, his answer shown me the way) in code and now it works!
//impordb_module.h
signals:
void sendTreeViewData(QString &sheet_name, QStringList &sheet_headers);
//heaqders_selection.h
public slots:
void recieveTreeViewData(QString &sheet_name, QStringList &sheet_headers);
//heaqders_selection.cpp
void headers_selection::recieveTreeViewData(QString &sheet_name, QStringList &sheet_headers)
{
qDebug()<<sheet_name<<" gotcha! ";
}
//in impordb_module.cpp
importdb_module::importdb_module(QWidget *parent, Qt::WFlags flags): QMainWindow(parent, flags){
connect(this, SIGNAL(sendTreeViewData(QString &,QStringList &)), select_form, SLOT(recieveTreeViewData(QString &,QStringList &)));
}
//...
void importdb_module::readSheetsHeaders(QAxObject* &_workbook, QAxObject* _worksheets, QAxObject* &_excel){
//...
getTableHeaders(sheet_i, sheet_headers);
//says that we've send tree data into the form
emit sendTreeViewData(sheet_name, sheet_headers);
//...
};
Maybe your connection failed because of the parameter names in your connect statement. Try change it to:
connect(this, SIGNAL(sendTreeViewData(QString,QStringList)),
select_form, SLOT(recieveTreeViewData(QString,QStringList)));