Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Unsolved scribble area add scrollbar and scroll mechanism

    General and Desktop
    2
    3
    92
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • H
      hobbyProgrammer last edited by

      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();
      }
      
      
      1 Reply Last reply Reply Quote 0
      • H
        hobbyProgrammer last edited by

        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.

        Pablo J. Rogina 1 Reply Last reply Reply Quote 0
        • Pablo J. Rogina
          Pablo J. Rogina @hobbyProgrammer last edited by

          @hobbyProgrammer please try not to double post...

          Upvote the answer(s) that helped you solve the issue
          Use "Topic Tools" button to mark your post as Solved
          Add screenshots via postimage.org
          Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

          1 Reply Last reply Reply Quote 1
          • First post
            Last post