Creating Paint Application in CPP using QT
Create QT Widget application
Give Project Name and Select the location to save the project
Build System: qmake
Let it be same and click on next.
Click on Finish to create project
After creation of project the file structure will like this.
Create new Header File inside the header Folder:-
Project File Structure and code inside them
EditPaint.pro code
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
mainwindow.cpp \
scribblearea.cpp
HEADERS += \
mainwindow.h \
scribblearea.h
FORMS += \
mainwindow.ui
TRANSLATIONS += \
EditPaint_en_IO.ts
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
Code inside the mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QList>
#include <QMainWindow>
// ScribbleArea used to paint the image
class ScribbleArea;
class MainWindow : public QMainWindow
{
// Declares our class as a QObject which is the base class
// for all Qt objects
// QObjects handle events
Q_OBJECT
public:
MainWindow();
protected:
// Function used to close an event
void closeEvent(QCloseEvent *event) override;
// The events that can be triggered
private slots:
void open();
void save();
void penColor();
void penWidth();
void about();
private:
// Will tie user actions to functions
void createActions();
void createMenus();
// Will check if changes have occurred since last save
bool maybeSave();
// Opens the Save dialog and saves
bool saveFile(const QByteArray &fileFormat);
// What we'll draw on
ScribbleArea *scribbleArea;
// The menu widgets
QMenu *saveAsMenu;
QMenu *fileMenu;
QMenu *optionMenu;
QMenu *helpMenu;
// All the actions that can occur
QAction *openAct;
// Actions tied to specific file formats
QList<QAction *> saveAsActs;
QAction *exitAct;
QAction *penColorAct;
QAction *penWidthAct;
QAction *printAct;
QAction *clearScreenAct;
QAction *aboutAct;
QAction *aboutQtAct;
};
#endif
Code inside scribblearea.h
#ifndef SCRIBBLEAREA_H
#define SCRIBBLEAREA_H
#include <QColor>
#include <QImage>
#include <QPoint>
#include <QWidget>
class ScribbleArea : public QWidget
{
// Declares our class as a QObject which is the base class
// for all Qt objects
// QObjects handle events
Q_OBJECT
public:
ScribbleArea(QWidget *parent = 0);
// Handles all events
bool openImage(const QString &fileName);
bool saveImage(const QString &fileName, const char *fileFormat);
void setPenColor(const QColor &newColor);
void setPenWidth(int newWidth);
// Has the image been modified since last save
bool isModified() const { return modified; }
QColor penColor() const { return myPenColor; }
int penWidth() const { return myPenWidth; }
public slots:
// Events to handle
void clearImage();
void print();
protected:
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
// Updates the scribble area where we are painting
void paintEvent(QPaintEvent *event) override;
// Makes sure the area we are drawing on remains
// as large as the widget
void resizeEvent(QResizeEvent *event) override;
private:
void drawLineTo(const QPoint &endPoint);
void resizeImage(QImage *image, const QSize &newSize);
// Will be marked true or false depending on if
// we have saved after a change
bool modified;
// Marked true or false depending on if the user
// is drawing
bool scribbling;
// Holds the current pen width & color
int myPenWidth;
QColor myPenColor;
// Stores the image being drawn
QImage image;
// Stores the location at the current mouse event
QPoint lastPoint;
};
#endif
Code inside main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
// The main application
QApplication app(argc, argv);
// Create and open the main window
MainWindow window;
window.show();
// Display the main window
return app.exec();
}
Code inside mainwindow.cpp
#include <QtWidgets>
#include "mainwindow.h"
#include "scribblearea.h"
// MainWindow constructor
MainWindow::MainWindow()
{
// Create the ScribbleArea widget and make it
// the central widget
scribbleArea = new ScribbleArea;
setCentralWidget(scribbleArea);
// Create actions and menus
createActions();
createMenus();
// Set the title
setWindowTitle(tr("Paint Application"));
// Size the app
resize(500, 500);
}
// User tried to close the app
void MainWindow::closeEvent(QCloseEvent *event)
{
// If they try to close maybeSave() returns true
// if no changes have been made and the app closes
if (maybeSave()) {
event->accept();
} else {
// If there have been changes ignore the event
event->ignore();
}
}
// Check if the current image has been changed and then
// open a dialog to open a file
void MainWindow::open()
{
// Check if changes have been made since last save
// maybeSave() returns true if no changes have been made
if (maybeSave()) {
// Get the file to open from a dialog
// tr sets the window title to Open File
// QDir opens the current dirctory
QString fileName = QFileDialog::getOpenFileName(this,
tr("Open File"), QDir::currentPath());
// If we have a file name load the image and place
// it in the scribbleArea
if (!fileName.isEmpty())
scribbleArea->openImage(fileName);
}
}
// Called when the user clicks Save As in the menu
void MainWindow::save()
{
// A QAction represents the action of the user clicking
QAction *action = qobject_cast<QAction *>(sender());
// Stores the array of bytes of the users data
QByteArray fileFormat = action->data().toByteArray();
// Pass it to be saved
saveFile(fileFormat);
}
// Opens a dialog to change the pen color
void MainWindow::penColor()
{
// Store the chosen color from the dialog
QColor newColor = QColorDialog::getColor(scribbleArea->penColor());
// If a valid color set it
if (newColor.isValid())
scribbleArea->setPenColor(newColor);
}
// Opens a dialog that allows the user to change the pen width
void MainWindow::penWidth()
{
// Stores button value
bool ok;
// tr("Scribble") is the title
// the next tr is the text to display
// Get the current pen width
// Define the min, max, step and ok button
int newWidth = QInputDialog::getInt(this, tr("Scribble"),
tr("Select pen width:"),
scribbleArea->penWidth(),
1, 50, 1, &ok);
// Change the pen width
if (ok)
scribbleArea->setPenWidth(newWidth);
}
// Open an about dialog
void MainWindow::about()
{
// Window title and text to display
QMessageBox::about(this, tr("About Scribble"),
tr("<p>The <b>Scribble</b> example is awesome</p>"));
}
// Define menu actions that call functions
void MainWindow::createActions()
{
// Create the action tied to the menu
openAct = new QAction(tr("&Open..."), this);
// Define the associated shortcut key
openAct->setShortcuts(QKeySequence::Open);
// Tie the action to MainWindow::open()
connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
// Get a list of the supported file formats
// QImageWriter is used to write images to files
foreach (QByteArray format, QImageWriter::supportedImageFormats()) {
QString text = tr("%1...").arg(QString(format).toUpper());
// Create an action for each file format
QAction *action = new QAction(text, this);
// Set an action for each file format
action->setData(format);
// When clicked call MainWindow::save()
connect(action, SIGNAL(triggered()), this, SLOT(save()));
// Attach each file format option menu item to Save As
saveAsActs.append(action);
}
// Create print action and tie to MainWindow::print()
printAct = new QAction(tr("&Print..."), this);
connect(printAct, SIGNAL(triggered()), scribbleArea, SLOT(print()));
// Create exit action and tie to MainWindow::close()
exitAct = new QAction(tr("E&xit"), this);
exitAct->setShortcuts(QKeySequence::Quit);
connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
// Create pen color action and tie to MainWindow::penColor()
penColorAct = new QAction(tr("&Pen Color..."), this);
connect(penColorAct, SIGNAL(triggered()), this, SLOT(penColor()));
// Create pen width action and tie to MainWindow::penWidth()
penWidthAct = new QAction(tr("Pen &Width..."), this);
connect(penWidthAct, SIGNAL(triggered()), this, SLOT(penWidth()));
// Create clear screen action and tie to MainWindow::clearImage()
clearScreenAct = new QAction(tr("&Clear Screen"), this);
clearScreenAct->setShortcut(tr("Ctrl+L"));
connect(clearScreenAct, SIGNAL(triggered()),
scribbleArea, SLOT(clearImage()));
// Create about action and tie to MainWindow::about()
aboutAct = new QAction(tr("&About"), this);
connect(aboutAct, SIGNAL(triggered()), this, SLOT(about()));
// Create about Qt action and tie to MainWindow::aboutQt()
aboutQtAct = new QAction(tr("About &Qt"), this);
connect(aboutQtAct, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
}
// Create the menubar
void MainWindow::createMenus()
{
// Create Save As option and the list of file types
saveAsMenu = new QMenu(tr("&Save As"), this);
foreach (QAction *action, saveAsActs)
saveAsMenu->addAction(action);
// Attach all actions to File
fileMenu = new QMenu(tr("&File"), this);
fileMenu->addAction(openAct);
fileMenu->addMenu(saveAsMenu);
fileMenu->addAction(printAct);
fileMenu->addSeparator();
fileMenu->addAction(exitAct);
// Attach all actions to Options
optionMenu = new QMenu(tr("&Options"), this);
optionMenu->addAction(penColorAct);
optionMenu->addAction(penWidthAct);
optionMenu->addSeparator();
optionMenu->addAction(clearScreenAct);
// Attach all actions to Help
helpMenu = new QMenu(tr("&Help"), this);
helpMenu->addAction(aboutAct);
helpMenu->addAction(aboutQtAct);
// Add menu items to the menubar
menuBar()->addMenu(fileMenu);
menuBar()->addMenu(optionMenu);
menuBar()->addMenu(helpMenu);
}
bool MainWindow::maybeSave()
{
// Check for changes since last save
if (scribbleArea->isModified()) {
QMessageBox::StandardButton ret;
// Scribble is the title
// Add text and the buttons
ret = QMessageBox::warning(this, tr("Scribble"),
tr("The image has been modified.\n"
"Do you want to save your changes?"),
QMessageBox::Save | QMessageBox::Discard
| QMessageBox::Cancel);
// If save button clicked call for file to be saved
if (ret == QMessageBox::Save) {
return saveFile("png");
// If cancel do nothing
} else if (ret == QMessageBox::Cancel) {
return false;
}
}
return true;
}
bool MainWindow::saveFile(const QByteArray &fileFormat)
{
// Define path, name and default file type
QString initialPath = QDir::currentPath() + "/untitled." + fileFormat;
// Get selected file from dialog
// Add the proper file formats and extensions
QString fileName = QFileDialog::getSaveFileName(this, tr("Save As"),
initialPath,
tr("%1 Files (*.%2);;All Files (*)")
.arg(QString::fromLatin1(fileFormat.toUpper()))
.arg(QString::fromLatin1(fileFormat)));
// If no file do nothing
if (fileName.isEmpty()) {
return false;
} else {
// Call for the file to be saved
return scribbleArea->saveImage(fileName, fileFormat.constData());
}
}
Code inside scribblearea.cpp
#include <QtWidgets>
#if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printdialog)
#include <QPrinter>
#include <QPrintDialog>
#endif
#endif
#include "scribblearea.h"
ScribbleArea::ScribbleArea(QWidget *parent)
: QWidget(parent)
{
// Roots the widget to the top left even if resized
setAttribute(Qt::WA_StaticContents);
// Set defaults for the monitored variables
modified = false;
scribbling = false;
myPenWidth = 1;
myPenColor = Qt::blue;
}
// Used to load the image and place it in the widget
bool ScribbleArea::openImage(const QString &fileName)
{
// Holds the image
QImage loadedImage;
// If the image wasn't loaded leave this function
if (!loadedImage.load(fileName))
return false;
QSize newSize = loadedImage.size().expandedTo(size());
resizeImage(&loadedImage, newSize);
image = loadedImage;
modified = false;
update();
return true;
}
// Save the current image
bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat)
{
// Created to hold the image
QImage visibleImage = image;
resizeImage(&visibleImage, size());
if (visibleImage.save(fileName, fileFormat)) {
modified = false;
return true;
} else {
return false;
}
}
// Used to change the pen color
void ScribbleArea::setPenColor(const QColor &newColor)
{
myPenColor = newColor;
}
// Used to change the pen width
void ScribbleArea::setPenWidth(int newWidth)
{
myPenWidth = newWidth;
}
// Color the image area with white
void ScribbleArea::clearImage()
{
image.fill(qRgb(255, 255, 255));
modified = true;
update();
}
// If a mouse button is pressed check if it was the
// left button and if so store the current position
// Set that we are currently drawing
void ScribbleArea::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
lastPoint = event->pos();
scribbling = true;
}
}
// When the mouse moves if the left button is clicked
// we call the drawline function which draws a line
// from the last position to the current
void ScribbleArea::mouseMoveEvent(QMouseEvent *event)
{
if ((event->buttons() & Qt::LeftButton) && scribbling)
drawLineTo(event->pos());
}
// If the button is released we set variables to stop drawing
void ScribbleArea::mouseReleaseEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton && scribbling) {
drawLineTo(event->pos());
scribbling = false;
}
}
// QPainter provides functions to draw on the widget
// The QPaintEvent is sent to widgets that need to
// update themselves
void ScribbleArea::paintEvent(QPaintEvent *event)
{
QPainter painter(this);
// Returns the rectangle that needs to be updated
QRect dirtyRect = event->rect();
// Draws the rectangle where the image needs to
// be updated
painter.drawImage(dirtyRect, image, dirtyRect);
}
// Resize the image to slightly larger then the main window
// to cut down on the need to resize the image
void ScribbleArea::resizeEvent(QResizeEvent *event)
{
if (width() > image.width() || height() > image.height()) {
int newWidth = qMax(width() + 128, image.width());
int newHeight = qMax(height() + 128, image.height());
resizeImage(&image, QSize(newWidth, newHeight));
update();
}
QWidget::resizeEvent(event);
}
void ScribbleArea::drawLineTo(const QPoint &endPoint)
{
// Used to draw on the widget
QPainter painter(&image);
// Set the current settings for the pen
painter.setPen(QPen(myPenColor, myPenWidth, Qt::SolidLine, Qt::RoundCap,
Qt::RoundJoin));
// Draw a line from the last registered point to the current
painter.drawLine(lastPoint, endPoint);
// Set that the image hasn't been saved
modified = true;
int rad = (myPenWidth / 2) + 2;
// Call to update the rectangular space where we drew
update(QRect(lastPoint, endPoint).normalized()
.adjusted(-rad, -rad, +rad, +rad));
// Update the last position where we left off drawing
lastPoint = endPoint;
}
// When the app is resized create a new image using
// the changes made to the image
void ScribbleArea::resizeImage(QImage *image, const QSize &newSize)
{
// Check if we need to redraw the image
if (image->size() == newSize)
return;
// Create a new image to display and fill it with white
QImage newImage(newSize, QImage::Format_RGB32);
newImage.fill(qRgb(255, 255, 255));
// Draw the image
QPainter painter(&newImage);
painter.drawImage(QPoint(0, 0), *image);
*image = newImage;
}
// Print the image
void ScribbleArea::print()
{
// Check for print dialog availability
}