Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

scribble area add scrollbar and scroll mechanism



  • I would like to add a scrollbar to the scribble area.

    I am using the scribble example and I would like to keep all the functionalities of the scribble example. I'd just like to be able to scroll down the image if the image is too big to fit the screen. (Since I added zoom in and out functions).

    This is my code:

    MainWindow.h:

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QList>
    #include <QMainWindow>
    
    class ScribbleArea;
    
    //! [0]
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow();
    
    protected:
        void closeEvent(QCloseEvent *event) Q_DECL_OVERRIDE;
    
    private slots:
        void open();
        void save();
        void penColor();
        void penWidth();
    
    private:
        void createActions();
        void createMenus();
        bool maybeSave();
        bool saveFile(const QByteArray &fileFormat);
    
        ScribbleArea *scribbleArea;
    
        QMenu *fileMenu;
        QMenu *optionMenu;
    
        QAction *openAct;
        QAction *exitAct;
        QAction *clearScreenAct;
        QAction *undoAct;
        QAction *redoAct;
        QAction *addRoomAct;
        QAction *zoomInAct;
        QAction *zoomOutAct;
    };
    //! [0]
    
    #endif
    
    

    this is my MainWindow.cpp:

    #include <QtWidgets>
    
    #include "mainwindow.h"
    #include "scribblearea.h"
    
    //! [0]
    MainWindow::MainWindow()
    {
        scribbleArea = new ScribbleArea;
        setCentralWidget(scribbleArea);
        
        scribbleArea->
    
        createActions();
        createMenus();
    
        setWindowTitle(tr("Scribble"));
        resize(500, 500);
    }
    //! [0]
    
    //! [1]
    void MainWindow::closeEvent(QCloseEvent *event)
    //! [1] //! [2]
    {
        if (maybeSave())
        {
            event->accept();
        } else
        {
            event->ignore();
        }
    }
    //! [2]
    
    //! [3]
    void MainWindow::open()
    //! [3] //! [4]
    {
        if (maybeSave()) {
            QString fileName = QFileDialog::getOpenFileName(this,
                                       tr("Open File"), QDir::currentPath());
            if (!fileName.isEmpty())
                scribbleArea->openImage(fileName);
        }
    }
    //! [4]
    
    //! [5]
    void MainWindow::save()
    //! [5] //! [6]
    {
        QAction *action = qobject_cast<QAction *>(sender());
        QByteArray fileFormat = action->data().toByteArray();
        saveFile(fileFormat);
    }
    //! [6]
    
    //! [7]
    void MainWindow::penColor()
    //! [7] //! [8]
    {
        QColor newColor = QColorDialog::getColor(scribbleArea->penColor());
        if (newColor.isValid())
            scribbleArea->setPenColor(newColor);
    }
    //! [8]
    
    //! [9]
    void MainWindow::penWidth()
    //! [9] //! [10]
    {
        bool ok;
        int newWidth = QInputDialog::getInt(this, tr("Scribble"),
                                            tr("Select pen width:"),
                                            scribbleArea->penWidth(),
                                            1, 50, 1, &ok);
        if (ok)
            scribbleArea->setPenWidth(newWidth);
    }
    //! [10]
    
    //! [13]
    void MainWindow::createActions()
    //! [13] //! [14]
    {
        openAct = new QAction(tr("&Open..."), this);
        openAct->setShortcuts(QKeySequence::Open);
        connect(openAct, SIGNAL(triggered()), this, SLOT(open()));
    
        exitAct = new QAction(tr("&Exit"), this);
        exitAct->setShortcuts(QKeySequence::Quit);
        connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
    
        //penColorAct = new QAction(tr("&Pen Color..."), this);
        //connect(penColorAct, SIGNAL(triggered()), this, SLOT(penColor()));
    
        //penWidthAct = new QAction(tr("Pen &Width..."), this);
        //connect(penWidthAct, SIGNAL(triggered()), this, SLOT(penWidth()));
    
        clearScreenAct = new QAction(tr("&Clear Screen"), this);
        clearScreenAct->setShortcut(tr("Ctrl+L"));
        connect(clearScreenAct, SIGNAL(triggered()),
                scribbleArea, SLOT(clearImage()));
    
        undoAct = new QAction(tr("&Undo"), this);
        undoAct->setShortcut(tr("Ctrl+Z"));
        connect(undoAct, SIGNAL(triggered()), scribbleArea, SLOT(undoAction()));
    
        redoAct = new QAction(tr("&Redo"), this);
        redoAct->setShortcut(tr("Ctrl+Y"));
        connect(redoAct, SIGNAL(triggered()),scribbleArea, SLOT(redoAction()));
    
        addRoomAct = new QAction(tr( "&Add Room"), this);
        addRoomAct->setShortcut(tr("Ctrl+N"));                             //addd shortcut if you would like
        connect(addRoomAct, SIGNAL(triggered()), scribbleArea, SLOT(addRoomAction()));
    
        zoomInAct = new QAction(tr("&Zoom In"), this);
        zoomInAct->setShortcut(QKeySequence::ZoomIn);
        connect(zoomInAct, SIGNAL(triggered()), scribbleArea, SLOT(zoomIn()));
    
        zoomOutAct = new QAction(tr("&Zoom Out"), this);
        zoomOutAct->setShortcut(QKeySequence::ZoomOut);
        connect(zoomOutAct, SIGNAL(triggered()), scribbleArea, SLOT(zoomOut()));
    }
    //! [14]
    
    //! [15]
    void MainWindow::createMenus()
    //! [15] //! [16]
    {
        //saveAsMenu = new QMenu(tr("&Save As"), this);
    
        fileMenu = new QMenu(tr("&File"), this);
        fileMenu->addAction(openAct);
    
        optionMenu = new QMenu(tr("&Options"), this);
        optionMenu->addAction(undoAct);
        optionMenu->addAction(redoAct);
        optionMenu->addAction(clearScreenAct);
        optionMenu->addAction(addRoomAct);
        optionMenu->addAction(zoomInAct);
        optionMenu->addAction(zoomOutAct);
    
        menuBar()->addMenu(fileMenu);
        menuBar()->addMenu(optionMenu);
    }
    //! [16]
    
    //! [17]
    bool MainWindow::maybeSave()
    //! [17] //! [18]
    {
        if (scribbleArea->isModified()) {
           QMessageBox::StandardButton ret;
           ret = QMessageBox::warning(this, tr("Scribble"),
                              tr("Any changes will be gone.\n"
                                 "Are you sure you want to exit?"),
                              QMessageBox::Ok | QMessageBox::Cancel);
            if (ret == QMessageBox::Ok) {
                return saveFile("png");
            } else if (ret == QMessageBox::Cancel) {
                return false;
            }
        }
        return true;
    }
    //! [18]
    
    //! [19]
    bool MainWindow::saveFile(const QByteArray &fileFormat)
    //! [19] //! [20]
    {
        QString initialPath = QDir::currentPath() + "/untitled." + fileFormat;
    
        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 (fileName.isEmpty()) {
            return false;
        } else {
            return scribbleArea->saveImage(fileName, fileFormat.constData());
        }
    }
    //! [20]
    
    

    ScribbleArea.h:

    #ifndef SCRIBBLEAREA_H
    #define SCRIBBLEAREA_H
    
    #include <QColor>
    #include <QImage>
    #include <QPoint>
    #include <QWidget>
    #include <QGraphicsItem>
    
    #define GREEN_50    QColor(27, 163, 0, 128)
    #define YELLOW_50   QColor(232, 189, 0, 128)
    #define RED_50      QColor(232, 0, 0, 128)
    
    #define GREEN_67    QColor(27, 163, 0, 169)
    #define YELLOW_67   QColor(232, 189, 0, 169)
    #define RED_67      QColor(232, 0, 0, 169)
    
    #define GREEN_75    QColor(27, 163, 0, 192)
    #define YELLOW_75   QColor(232, 189, 0, 192)
    #define RED_75      QColor(232, 0, 0, 192)
    //! [0]
    class ScribbleArea : public QWidget
    {
        Q_OBJECT
    
    public:
        ScribbleArea(QWidget *parent = 0);
    
        bool openImage(const QString &fileName);
        bool saveImage(const QString &fileName, const char *fileFormat);
        void setPenColor(const QColor &newColor);
        void setPenWidth(int newWidth);
    
        bool isModified() const { return modified; }
        QColor penColor() const { return myPenColor; }
        int penWidth() const { return myPenWidth; }
    
    
    public slots:
        void clearImage();
        void undoAction();
        void redoAction();
        void addRoomAction();
        void zoomIn();
        void zoomOut();
    
    protected:
        void mousePressEvent(QMouseEvent *event) override;
        void mouseReleaseEvent(QMouseEvent *event) override;
        void paintEvent(QPaintEvent *event) override;
        void resizeEvent(QResizeEvent *event) override;
        void dragMoveEvent(QDragMoveEvent *event) override;
        void dropEvent(QDropEvent *event) override;
    
    private:
        void resizeImage(QImage *image, const QSize &newSize);
    
        bool modified;
        bool scribbling;
        bool finalItem;
        int myPenWidth;
        QColor myPenColor;
        QImage image;
        QPoint lastPoint;
        QVector<QPoint> qv_points;
        QVector<QPoint> redo_points;
        QVector<QVector<QPoint>> qv_rooms;
        QVector<QString> qv_roomnames;
    
        bool stopUndo, stopRedo = false;
        qreal scale;
    };
    //! [0]
    
    #endif
    
    

    scribblearea.cpp:

    #include <QtWidgets>
    #include "scribblearea.h"
    #include <QFile>
    #include <QStringList>
    #include <QGraphicsItem>
    
    //! [0]
    ScribbleArea::ScribbleArea(QWidget *parent)
        : QWidget(parent)
    {
        setAttribute(Qt::WA_StaticContents);
        modified = false;
        scribbling = false;
        myPenWidth = 1;
        myPenColor = Qt::blue;
        scale = 1;
    }
    //! [0]
    
    //! [1]
    bool ScribbleArea::openImage(const QString &fileName)
    //! [1] //! [2]
    {
        QImage loadedImage;
        if (!loadedImage.load(fileName))
            return false;
    
        QSize newSize = loadedImage.size().expandedTo(size());
        resizeImage(&loadedImage, newSize);
        image = loadedImage;
        modified = false;
        update();
        return true;
    }
    //! [2]
    
    //! [3]
    bool ScribbleArea::saveImage(const QString &fileName, const char *fileFormat)
    //! [3] //! [4]
    {
        QImage visibleImage = image;
        resizeImage(&visibleImage, size());
    
        if (visibleImage.save(fileName, fileFormat)) {
            modified = false;
            return true;
        } else {
            return false;
        }
    }
    //! [4]
    
    //! [5]
    void ScribbleArea::setPenColor(const QColor &newColor)
    //! [5] //! [6]
    {
        myPenColor = newColor;
    }
    //! [6]
    
    //! [7]
    void ScribbleArea::setPenWidth(int newWidth)
    //! [7] //! [8]
    {
        myPenWidth = newWidth;
    }
    //! [8]
    
    //! [9]
    void ScribbleArea::clearImage()
    //! [9] //! [10]
    {
        qv_points.clear();
        qv_rooms.clear();
        qv_roomnames.clear();
        update();
    }
    //! [10]
    
    //! [11]
    void ScribbleArea::mousePressEvent(QMouseEvent *event)
    //! [11] //! [12]
    {
        QGraphicsEllipseItem *ellipse = new QGraphicsEllipseItem();
        //ellipse = addEllipse(x, y, 5, 5, QPen(Qt::NoPen), QBrush(Qt::red));
        ellipse->setFlag(QGraphicsItem::ItemIsMovable);
    
        if (event->button() == Qt::LeftButton) {
            lastPoint = event->pos()/scale;
            qDebug() << lastPoint;
            qv_points << lastPoint;
    
            stopUndo = false;
            stopRedo = true;
            redo_points.clear();
        }
        this->update();
    }
    
    void ScribbleArea::mouseReleaseEvent(QMouseEvent *event)
    {
        if (event->button() == Qt::LeftButton && scribbling) {
            //drawLineTo(event->pos());
            scribbling = false;
        }
    }
    
    //! [12] //! [13]
    void ScribbleArea::paintEvent(QPaintEvent *event)
    //! [13] //! [14]
    {
        QPainter painter(this);
        painter.scale(scale,scale);
        QRect dirtyRect = event->rect();
        painter.drawImage(dirtyRect, image, dirtyRect);
        painter.setPen(QPen(Qt::black, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        //define polygon, add all existing points to it
        QPolygon polygon;
        polygon << qv_points;
        painter.drawPolygon(polygon);
    
        painter.setPen(QPen(Qt::red, 4, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
        painter.drawPoints(qv_points);
    
        for(int i = 0; i < qv_rooms.size(); i++)
        {
            painter.setPen(QPen(YELLOW_50, 0, Qt::NoPen, Qt::RoundCap, Qt::RoundJoin));
            QPolygon polygon_existing;
            QGraphicsScene scene;
    //        QGraphicsPolygonItem polyItem;
    //        polyItem.setPolygon(polygon_existing);
            polygon_existing << qv_rooms.at(i);
            QPainterPath polyPath_exitsting;
            polyPath_exitsting.addPolygon(polygon_existing);
            painter.fillPath(polyPath_exitsting, QBrush(GREEN_50));
            painter.drawPolygon(polygon_existing);
        }
    }
    //! [14]
    
    //! [15]
    void ScribbleArea::resizeEvent(QResizeEvent *event)
    //! [15] //! [16]
    {
        if (width() > image.width() || height() > image.height()) {
            int newWidth = qMax(width() + 10, image.width());
            int newHeight = qMax(height() + 10, image.height());
            resizeImage(&image, QSize(newWidth, newHeight));
            update();
        }
        QWidget::resizeEvent(event);
    }
    //! [16]
    
    void ScribbleArea::dragMoveEvent(QDragMoveEvent *event)
    {
        if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
            if (event->source() == this) {
                event->setDropAction(Qt::MoveAction);
                event->accept();
            } else {
                event->acceptProposedAction();
            }
        } else {
            event->ignore();
        }
    }
    
    void ScribbleArea::dropEvent(QDropEvent *event)
    {
        if (event->mimeData()->hasFormat("application/x-dnditemdata")) {
            QByteArray itemData = event->mimeData()->data("application/x-dnditemdata");
            QDataStream dataStream(&itemData, QIODevice::ReadOnly);
    
            QPixmap pixmap;
            QPoint offset;
            dataStream >> pixmap >> offset;
    
            QLabel *newIcon = new QLabel(this);
            newIcon->setPixmap(pixmap);
            newIcon->move(event->pos() - offset);
            newIcon->show();
            newIcon->setAttribute(Qt::WA_DeleteOnClose);
    
            if (event->source() == this) {
                event->setDropAction(Qt::MoveAction);
                event->accept();
            } else {
                event->acceptProposedAction();
            }
        } else {
            event->ignore();
        }
    }
    //! [19]
    void ScribbleArea::resizeImage(QImage *image, const QSize &newSize)
    //! [19] //! [20]
    {
        if (image->size() == newSize)
            return;
    
        QImage newImage(newSize, QImage::Format_RGB32);
        newImage.fill(qRgb(255, 255, 255));
        QPainter painter(&newImage);
        painter.drawImage(QPoint(0, 0), *image);
        *image = newImage;
    }
    //! [20]
    
    void ScribbleArea::undoAction()
    { 
        if(!stopUndo)
        {
            stopRedo = false;
            if(qv_points.first() == qv_points.last())
            {
                redo_points << qv_points.last();
                qv_points.clear();
                stopUndo = true;
            }
            else
            {
                redo_points << qv_points.takeLast();
            }
            update();
        }
        else
        {
        }
    
    }
    
    void ScribbleArea::redoAction()
    {
        if(!stopRedo)
        {
            stopUndo=false;
            if(redo_points.first() == redo_points.last())
            {
                qv_points << redo_points.last();
                redo_points.clear();
                stopRedo = true;
            }
            else
            {
                qv_points << redo_points.takeLast();
            }
            update();
        }
        else
        {
        }
    }
    
    void ScribbleArea::addRoomAction()
    {
        QString text = QInputDialog::getText(this, tr("Save Room As"), tr("Please enter a roomname: "), QLineEdit::Normal);
        if(text != "" && !text.contains(","))
        {
            qDebug() << text;
            for(int i = 0; i < qv_points.size(); i++)
            {
                qDebug() << qv_points.at(i);
    
                //qv_rooms.at(i).
            }
            qv_rooms << qv_points;
            qv_roomnames << text;
            qv_points.clear();
            update();
        }
        else
        {
            QMessageBox warning;
            if(text == "")
            {
                warning.setIcon(QMessageBox::Critical);
                warning.setText("The roomname cannot be empty");
                warning.exec();
                addRoomAction();
            }
            else if(text.contains(","))
            {
                warning.setIcon(QMessageBox::Critical);
                warning.setText("The roomname connot contain a comma\n");
                warning.exec();
                addRoomAction();
            }
            update();
        }
    }
    
    void ScribbleArea::zoomIn()
    {
        qDebug() << "Zoom in...";
        scale = scale + 0.2;
        update();
    }
    
    void ScribbleArea::zoomOut()
    {
        qDebug() << "Zoom out...";
        scale = scale - 0.2;
        update();
    }
    
    


  • I feel like it should work if I'd added a QSrollArea to the MainWindow and upgrade it to a ScribbleArea, but I don't know how to do that programmatically.



  • @hobbyProgrammer please try not to double post...


Log in to reply