Реклама

Тег → QGraphicsScene

  • EVILEG
  • Статья
  • 22 октября 2017 г. 14:54

Qt/C++ - Урок 072. Пример векторного редактора на Qt

QGraphicsItem, QGraphicsScene, QGraphicsView, Vector Editor, QGraphicsObject

Довольно часто появляются вопросы так или иначе связанные с работой графической сцены, с кастомными фигурами, с рисованием линий на графической сцене, причём даже всяких ломаных линий. И тут я вспомнил про один проект, который делал в качестве тестового задания.

А именно это был векторный редактор, который может:

  • Создавать прямоугольники
  • Изменять размер этих прямоугольников
  • Крутить прямоугольники вокруг центра
  • Делать заливку прямоугольников
  • Делать заливку прямоугольников градиентом
  • Изменять ширину абриса прямоугольника
  • Устанавливать цвет абриса прямоугольника
  • Создавать линии
  • Задавать ширину и цвет создаваемой линии
  • Делать ломанные линии из линий по двойному щелчку добавляя на линии точки излома
  • Выделять все графические объекты и перетаскивать их кучкой
  • Сохранять полученное изображение в SVG файл, а также восстанавливать все графические объекты из этого файла

На выполнение этого проекта в своё время (1,5 года назад) я потратил порядка 36 часов рабочего времени... сейчас на это ушло бы поменьше времени.

  • Arrow
  • Вопрос
  • 1 июня 2017 г. 19:08

Обрезать изображение

QGraphicsScene, изображение

Добрый день!

Подскажите как возможно реализовать возможность обрезания изображения как это делается во всех редакторах изображений (Paint, GIMP, PhotoShop и др.).

Изображение загружено в QGraphicsScene.

Планирую отрисовывать квадрат на сцене с возможностью изменения его размеров, а затем после нажатия пользователем кнопки подтверждения копировать выделенную часть изображения.

И второй вопрос как сделать объект на QGraphicsScene перемещаемым. Так не выходит:

QGraphicsLineItem *line = new QGraphicsLineItem();
line->setFlag(QGraphicsItem::ItemIsSelectable, true);
line->setFlag(QGraphicsItem::ItemIsMovable, true);

Отрисовка графика в QGraphicsView

Qt QGraphicsView QGraphicsScene

Задача такая. У меня есть "графическое окно" в котором должны рисоваться графики вертикально(пока 2)-как показано на рисунке. Подскажите пожалуйста как это сделать? Я излазил всю библиотекуQGraphicsScene и нашёл функцию -> QGraphicsScene::addLine(она рисует только линии по 2-м точкам) Помогите пожалуйста. Заранее спасибо.

  • Arrow
  • Вопрос
  • 16 мая 2017 г. 20:20

Курсор ввода текста в графическом режиме

Курсор ввода текста, Qt, QGraphicsScene

Реализовал я ввод текста пользователем при клике мышью в QGraphicsScene. Остался только один вопрос: как реализовать курсор ввода текста? Без него все выглядит не привычно. Ввод самого текста реализовал так:

void mousePressEvent(QGraphicsSceneMouseEvent * event) override;
void keyPressEvent(QKeyEvent *event) override;

void textTyping(const QString text);

bool m_textTyping;
QString m_text;

// ----------------------------

void PaintScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{  
        if (m_textTyping) {
            m_textTyping = !m_textTyping;
            m_text.clear();
            return;
        }
        m_textTyping = true;

    // Сохранить координаты точки нажатия
    setPrevPos(event->scenePos());
}

void PaintScene::keyPressEvent(QKeyEvent *event)
{
    if (m_textTyping) {
        emit textTyping(event->text());
    }
    QGraphicsScene::keyPressEvent(event);
}

void PaintScene::typingText(const QString text)
{
    // Отображение текста
    if (m_text.isEmpty()) { 
        m_text.append(text);
        QGraphicsTextItem *textItem = new QGraphicsTextItem(m_text);
        currentItem = textItem;
        addItem(currentItem);
        textItem->setPos(m_prevPos);
        textItem->setDefaultTextColor(currentColor);
        textItem->setFont(QFont("Arial", 14));
        textItem->setSelected(true);
    }
    else {
        m_text.append(text);
        QGraphicsTextItem *textIt = qgraphicsitem_cast<QGraphicsTextItem *>(currentItem);
        textIt->setPlainText(m_text);
    }
}
Удаления и текста и навигации по нему пока не реализовывал. Мысль по реализации такая: 1. Выводить в качестве курсора вертикальную черту " | " и по таймеру реализовать ее скрытие и показ. Возможно добавлять ее до введенного текста и удалять; (Мысль плохая) 2. По таймеру выводить рисованный курсор в конце строки и организовать его мигание по таймеру. Или другим способом будет правильнее? Может ввод текста вообще реализовывается по другому? С такими вещами ранее не работал вообще.
  • Arrow
  • Вопрос
  • 5 мая 2017 г. 20:04

Рисование на QGraphicsScene при зажатой кнопке мыши

QGraphicsScene

Есть QGraphicsScene в которой происходит рисование на загруженной в нее картинке. Нужно дать пользователю возможность рисовать линию из точки А в точку В только при зажатой левой кнопке мыши. Рисование линии должно быть похоже на рисование линии в Paint. Как можно это организовать в Qt.

  • born66613
  • Вопрос
  • 15 марта 2017 г. 6:15

Проблема при перерисовке сцены - "скакание" элементов сцены по вертикали

QGraphicsView, QGraphicsScene, QWidget

Здравствуйте. Использую Qt 5.6.1.
В общем, имеется клиентское приложение, которое связывается с сервером, получает от него данные - координаты узлов сети системы управления и данные с них, и отрисовывает местоположение узлов на QGraphicsView. На сцене рисую координатную сетку, которое можно "зуммировать" колесиком мыши, "скролить" правой кнопкой мыши. Возникает интересная вещь - при скроллинге по горизонтали все отлично, при скроллинге по вертикали начинают скакать горизонтальные линии координатной сетки, подписи к оси Х. Такое ощущение, что выключена какая нибудь "вертикальная привязка" или еще что-то в этом роде. Ничего похожего в интернете не нашел.
Выкладываю 2 класса - главного окна (myclient.h, myclient.cpp) и виджета, на котором происходит рисование (mygraphicview.cpp, mygraphicview.h).
Также для лицезрения сего чуда прикрепляю папку с проектом - сначала сделайте Zoom колесиком мыши и попробуйте правой кнопкой мыши поскроллить. Увидите, что горизонтальная линия зеленого цвета начнем прыгать то в одну сторону, то в другую (в зависимости от направления скролла).
p.s. При компиляции укажите путь к БД (database.cpp).

myclient.h

#ifndef MYCLIENT_H
#define MYCLIENT_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QGraphicsScene>
#include <QLabel>
#include <QStatusBar>
#include <database.h>
#include <stdlib.h>
#include <QSqlTableModel>
#include <QMessageBox>
#include <mypoint.h>
#include "mygraphicview.h"
#include <QKeyEvent>
#include <QProgressBar>

namespace Ui {
class MyClient;
}
class MyClient : public QMainWindow
{
    Q_OBJECT

public:
    explicit MyClient(QWidget *parent = 0);
    ~MyClient();
    Ui::MyClient *ui;

private:
    QProgressBar *pBar;
    MyPoint *point;
    QTcpSocket* pTcpSocket;             // Объявляем сокет
    bool Connect = false;               // Объявляем переменную, отвечающую за наличие соединения
    QGraphicsScene  *scene;             // Объявляем графическую сцену
    MyGraphicView   *myPicture;         // Наш кастомный виджет
    DataBase        *db;                // Объявляем переменную для доступа к БД
    QSqlTableModel  *model;             // Объект для взаимодействия с моделью представления таблицы БД
    // Объявяем метод для парсинга входящего сообщения
    void parsingRecMsg(const QString &RecMsg);
    // Метод для формирования модели представления таблицы БД
    void setupModel(const QString &tableName, const QStringList &headers);
    // Метод для отрисовки медели представления таблицы БД
    void createModel();
    //QLabel *mouseTracker;

protected:
    //void mouseMoveEvent(QMouseEvent* pe);
    QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const;

signals:
    void signalRepaint();

private slots:
    void slotReadyRead();
    void slotError(QAbstractSocket::SocketError);
    void slotConnected();
    void slotDisconnected();
    void on_Button_Connect_clicked();
    void on_Button_Send_clicked();


    void on_Button_AddNode_clicked();

public slots:
    void slotSelectRow(int idRow);
};

#endif // MYCLIENT_H

myclient.cpp
#include "myclient.h"
#include "ui_myclient.h"

// Конструктор:
MyClient::MyClient(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MyClient)
{
    qDebug()<<"startMakeUI";
    ui->setupUi(this);
    this->resize(732,694);                                                  // Задаем размеры окна
    this->setFixedSize(732,694);                                            // Фиксируем размеры окна
    ui->graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);   // Отключаем скроллбар по вертикали
    ui->graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // Отключаем скроллбар по горизонтали
    this->setWindowTitle("Monitoring control system");
    // Подключаемся к БД:
    db = new DataBase();
    db->connectToDataBase();
    //this->setMouseTracking(true);
    // Инициализируем виджет с графикой
    myPicture = new MyGraphicView();
    // и добавляем его на слой
    scene = new QGraphicsScene();                                           // Инициализируем графическую сцену
    ui->graphicsView->setScene(scene);                                      // Устанавливаем графическую сцену в graphicsView
    scene->addWidget(myPicture);
    /*/ Для отображения координат указателя мыши в StatusBar
    mouseTracker = new QLabel(this);
    statusBar()->addWidget(mouseTracker);*/
    connect(this,&MyClient::signalRepaint, myPicture, &MyGraphicView::slotAlarmTimer);
    connect(myPicture,&MyGraphicView::signalSelectRow,this,&MyClient::slotSelectRow);
    // Инициализируем модель для представления данных с заданием названий колонок
    this->setupModel(TABLE, QStringList() << trUtf8("NodeID")
                                          << trUtf8("Х")
                                          << trUtf8("Y")
                                          << trUtf8("Z")
                                          << trUtf8("Data 1")
                                          << trUtf8("Data 2")
                                          << trUtf8("Data 3")
                                          << trUtf8("State"));
    this->createModel();
}

// Диструктор:
MyClient::~MyClient()
{
    qDebug()<<"startDeleteUI";
    delete ui;
}

// Обработчик нажатия кнопки Connect:
void MyClient::on_Button_Connect_clicked()
{
    qDebug()<<"on_Button_Connect_clicked()";
    if (Connect==false){ // если соединения нет
        qDebug()<<"on_Button_Connect_clicked(): connecting...";
        bool PortNumber_ok;
        const QString IP = this->ui->LEdit_IPAdress->text();
        const ushort port = this->ui->LEdit_PortNumber->text().toUShort(&PortNumber_ok);
        if (!PortNumber_ok)
        {
            QMessageBox msgBox;
            msgBox.setText("The port is not valid.");
            msgBox.exec();
            return;
        }
        pTcpSocket = new QTcpSocket(this);
        pTcpSocket->connectToHost(IP, port);
        connect(pTcpSocket, SIGNAL(connected()), SLOT(slotConnected()));
        connect(pTcpSocket, SIGNAL(disconnected()), SLOT(slotDisconnected()));
        connect(pTcpSocket, SIGNAL(readyRead()), SLOT(slotReadyRead()));
        connect(pTcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
                this,         SLOT(slotError(QAbstractSocket::SocketError))
               );
    }
    else { // если соединения есть
        qDebug()<<"on_Button_Connect_clicked(): disconnecting...";
        pTcpSocket->disconnectFromHost();
    }
}

// Слот успешного соединения клиента с сервером:
void MyClient::slotConnected()
{
    qDebug()<<"slotConnected(): connected";
    Connect=true;
    ui->TEdit_RMsg->append("State: Connected");
    ui->LEdit_IPAdress->setEnabled(false);
    ui->LEdit_PortNumber->setEnabled(false);
    ui->Button_Connect->setText("Disconnect");
    ui->Button_Send->setEnabled(true);
}

// Слот отсоединения клиента с сервером:
void MyClient::slotDisconnected()
{
    qDebug()<<"slotDisconnected(): disconnected";
    Connect = false;
    ui->TEdit_RMsg->append("State: Disconnected");
    ui->LEdit_IPAdress->setEnabled(true);
    ui->LEdit_PortNumber->setEnabled(true);
    ui->Button_Connect->setText("Connect");
    ui->Button_Send->setEnabled(false);
}

// Слот приема данных от сервера:
void MyClient::slotReadyRead()
{
    qDebug()<<"slotReadyRead(): StartReceiveData";
    QString line = "";
    // Определяем размер входящего пакета:
    int bytesAvail = pTcpSocket->bytesAvailable();
    qDebug()<<"waitForInput(): Receive " << bytesAvail << "bytes";
    int cnt = 0;
    bool endOfStream = false;
    while (cnt < bytesAvail && (!endOfStream)) {
        char ch;
        int bytesRead = pTcpSocket->read(&ch, sizeof(ch));
        if (bytesRead == sizeof(ch)) {
            cnt++;
            line.append( ch );
        }
        else {
            endOfStream = true;
        }
    }
    ui->TEdit_RMsg->append("Receive: "+line);
    parsingRecMsg(line);

}

// Слот обработки ошибок в соединении клиента с сервером:
void MyClient::slotError(QAbstractSocket::SocketError err)
{
    qDebug()<<"slotError";
    QString strError =
        "Error: " + (err == QAbstractSocket::HostNotFoundError ?
                     "The host was not found." :
                     err == QAbstractSocket::RemoteHostClosedError ?
                     "The remote host is closed." :
                     err == QAbstractSocket::ConnectionRefusedError ?
                     "The connection was refused." :
                     QString(pTcpSocket->errorString())
                    );
    ui->TEdit_RMsg->append(strError);
}

// Обработчик нажатия кнопки Send:
void MyClient::on_Button_Send_clicked()
{
    qDebug()<<"on_Button_Send_clicked(): send...";
    QByteArray  arrBlock;
    arrBlock.append(QString(ui->LEdit_TMsg->text()));
    pTcpSocket->write(arrBlock);
    ui->TEdit_RMsg->append("Send: "+QString(arrBlock));
}

/*void MyClient::mouseMoveEvent(QMouseEvent* pe)
{
    QPoint bsc = myPicture->pos();
    int x = pe->x() - bsc.x();
    int y = pe->y() - bsc.y();
    if((x < 0)||(x > scene->width())||(y < 0)||(y > scene->height()))
    {
        mouseTracker->setText("out of scene");
        return;
    }
    mouseTracker->setText(QString::number(x) + "  " + QString::number(y));
}*/

// Метод для парсинга входящего сообщения:
void MyClient::parsingRecMsg(const QString &RecMsg){
    qDebug()<<"parsingRecMsg()";
    if (RecMsg.length()==22){
        int id = strtol(RecMsg.mid(0,2).toUtf8().data(),NULL,16);
        int x = strtol(RecMsg.mid(2,4).toUtf8().data(),NULL,16);
        int y = strtol(RecMsg.mid(6,4).toUtf8().data(),NULL,16);
        int z = strtol(RecMsg.mid(10,4).toUtf8().data(),NULL,16);
        int data1 = strtol(RecMsg.mid(14,2).toUtf8().data(),NULL,16);
        int data2 = strtol(RecMsg.mid(16,2).toUtf8().data(),NULL,16);
        int data3 = strtol(RecMsg.mid(18,2).toUtf8().data(),NULL,16);
        int state = strtol(RecMsg.mid(20,2).toUtf8().data(),NULL,16);
        QString state_s;
        if(state == 1) state_s = "work_ON";
        else state_s = "work_OFF";
        QVariantList data;
        data.append(id);
        data.append(x);
        data.append(y);
        data.append(z);
        data.append(data1);
        data.append(data2);
        data.append(data3);
        data.append(state_s);
        QSqlQuery query;
        query.prepare("SELECT * FROM TableSystNode WHERE NodeID=:NodeID");
        query.bindValue(":NodeID", id);
        query.exec();
        if(query.next()==false){
            // Вставляем данные в БД
            db->inserIntoTable(data);
            model->select();
            emit signalRepaint();
        }
        else{
            // Изменяем данные в БД
            db->updateTable(data);
            model->select();
            emit signalRepaint();
        }
    }
    else{
        qDebug()<<"parsingRecMsg(): bad RecMsg: "<<RecMsg;
    }

}

// Метод для инициализации модели представления таблицы БД:
void MyClient::setupModel(const QString &tableName, const QStringList &headers)
{
    /* Производим инициализацию модели представления данных
     * с установкой имени таблицы в базе данных, по которому
     * будет производится обращение в таблице
     * */
    model = new QSqlTableModel(this);
    model->setTable(tableName);
    // Устанавливаем названия колонок в таблице с сортировкой данных
    for(int i = 0, j = 0; i < model->columnCount(); i++, j++){
        model->setHeaderData(i,Qt::Horizontal,headers[j]);

    }
    // Устанавливаем сортировку по возрастанию данных по нулевой колонке
    model->setSort(0,Qt::AscendingOrder);

}

// Метод для отрисовки модели представления таблицы БД:
void MyClient::createModel()
{
    ui->tableView->setModel(model);             // Устанавливаем модель на TableView
    //ui->tableView->setColumnHidden(0, true);    // Скрываем колонку с id записей
    ui->tableView->verticalHeader()->hide();

    // Разрешаем выделение строк
    ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
    // Устанавливаем режим выделения лишь одно строки в таблице
    ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection);
    // Устанавливаем размер колонок по содержимому
    ui->tableView->resizeColumnsToContents();
    ui->tableView->setColumnWidth(1,50);
    ui->tableView->setColumnWidth(2,50);
    ui->tableView->setColumnWidth(3,50);
    ui->tableView->setColumnWidth(4,50);
    ui->tableView->setColumnWidth(5,50);
    ui->tableView->setColumnWidth(6,50);
    ui->tableView->setUpdatesEnabled(true);
    ui->tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);

    ui->tableView->horizontalHeader()->setStretchLastSection(true);
    model->select(); // Делаем выборку данных из таблицы
}

// Слот для выделения строки в таблице БД:
void MyClient::slotSelectRow(int idRow)
{
    // Выделяем нужную строку
    ui->tableView->selectRow(idRow);
    // Имитируем нажатие кнопки Tab, чтобы выделить строку
    QKeyEvent* pe = new QKeyEvent(QEvent::KeyPress,
            Qt::Key_Tab,Qt::NoModifier, "Tab");
    QApplication::sendEvent(this, pe);
}


void MyClient::on_Button_AddNode_clicked()
{
    pBar = new QProgressBar();
    pBar->setRange(0,0);
    pBar->setTextVisible(true);
    pBar->setFormat("Loading...");
    pBar->setAlignment(Qt::AlignCenter);
    pBar->show();
}


mygraphicview.h
#ifndef MYGRAPHICVIEW_H
#define MYGRAPHICVIEW_H

#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QWheelEvent>
#include <qmath.h>
#include <math.h>
#include <QDebug>
#include <QRect>
#include <QScrollBar>
#include <QApplication>
#include <mypoint.h>
#include <QMessageBox>
#include <QtSql>
#include <database.h>
#include <QObject>

class MyGraphicView : public QGraphicsView
{
    Q_OBJECT
public:
    explicit MyGraphicView(QWidget *parent = 0);
       ~MyGraphicView();
    double CurZoom=1.0;
    bool FirstStart = true;

private:
    QGraphicsScene      *scene;     // Объявляем сцену для отрисовки
    QGraphicsItemGroup  *group_1;   // Объявляем первую группу элементов
    QGraphicsItemGroup  *group_2;   // Объявляем вторую группу элементов
    MyPoint *point;                 // Объявляем переменную для создания объектов на сцене
    DataBase *db;                   // Объявляем переменную для доступа к БД
    double minX = -250.0;              // Минимальное значение по оси Х
    double maxX = 250.0;            // Максимальное значение по оси Х
    int numXTicks = 10;             // Количество рисок по оси Х
    double minY = -250.0;              // Минимальное значение по оси Y
    double maxY = 250;              // Максимальное значение по оси Y
    int numYTicks = 10;             // Количество рисок по оси Y
    double spanX() const { return fabs(maxX - minX); }  // Разница по между макс и мин X
    double spanY() const { return fabs(maxY - minY); }  // Разница по между макс и мин Y
    double currentX;                // Текущее значение Х
    double currentY;                // Текущее значение Y
    bool StartDraw = false;         // Переменная для разрешения перерисовки сцены
    double pXmin;                   // Временная переменная для хранение мин значения оси Х
    double pYmax;                   // Временная переменная для хранение мин значения оси Y
    void clearScene();              // Метод для удаления всех элементов со сцены
    void adjustAxis(double &min, double &max, int &numTicks);// Метод для выбора оптимальных значений осей и рисок сцены

protected:
    void wheelEvent(QWheelEvent* event);
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);

private slots:
    void slotFromPoint(int numberPoint, int pX, int pY);       // Слот для обработки сигнала из точки

public slots:
    void slotAlarmTimer();      // Cлот для обработчика переполнения таймера (в нем происходит рисование сцены)
    //void slotSelectedItem();

signals:
    void signalSelectRow(int numRow);
};

#endif // MYGRAPHICVIEW_H

mygraphicview.cpp
#include "mygraphicview.h"

MyGraphicView::MyGraphicView(QWidget *parent)
    : QGraphicsView(parent)
{
    qDebug()<<"MyGraphicView(): start";
    // Настраиваем отображение виджета и его содержимого:
    this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);             // Отключим скроллбар по горизонтали
    this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);               // Отключим скроллбар по вертикали
    this->setAlignment(Qt::AlignCenter);                                    // Делаем привязку содержимого к центру
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);    // Растягиваем содержимое по виджету
    this->setTransformationAnchor(QGraphicsView::AnchorUnderMouse);         // В качестве якоря используется точка под курсором мышки.
    this->setRenderHint(QPainter::Antialiasing);                            // Устанавливаем сглаживание
    //this->setFocusPolicy(Qt::StrongFocus);
    scene = new QGraphicsScene();                                           // Инициализируем сцену для отрисовки
    scene->setItemIndexMethod(QGraphicsScene::NoIndex);                     // Линейный поиск элементов
    this->setScene(scene);                                                  // Устанавливаем сцену в виджет
    slotAlarmTimer();


    //timer = new QTimer();                   // Инициализируем Таймер
    // Подключаем СЛОТ для отрисовки к таймеру
    //connect(timer, SIGNAL(timeout()), this, SLOT(slotAlarmTimer()));
    //timer->start(50);                   // Стартуем таймер на 50 миллисекунд
    FirstStart = false;
}

MyGraphicView::~MyGraphicView()
{

}

// Метод отвечающий за перерисовку сцены
void MyGraphicView::slotAlarmTimer()
{
    // Запрещаем перерисование сцены
    StartDraw = true;
    qDebug()<<"slotAlarmTimer(): start";
    /* Удаляем все элементы со сцены,
     * если они есть перед новой отрисовкой
     * */
    clearScene();
    /* Устанавливаем размер сцены по размеру виджета
     * Первая координата - это левый верхний угол,
     * а Вторая - это правый нижний угол
     * */
    scene->setSceneRect(-250,-250,500,500);
    // Создаем кисти для рисования на сцене
    QPen penGreen(Qt::green);       // Задаём чёрную кисть
    QPen penRed(Qt::red);           // Задаём красную кисть
    QPen penGray(Qt::lightGray);         // Задаем серую кисть
    QPen penDarkGray(Qt::green); // Задаем темно-серую кисть
    penGray.setCosmetic(true);
    penDarkGray.setCosmetic(true);
    // Получаем текущее значение минимальных значений осей координат
    QPolygon pView = mapFromScene(QRect(0, 0, this->viewport()->width(), this->viewport()->height()));
    if (CurZoom < 2.0) {
        pXmin = 0;
        pYmax = 0;
    }
    else
    {
        pXmin = -pView.at(0).x()/CurZoom;
        pYmax = 500 / CurZoom + minY;
    }

    // Рисуем координатную ось Х:
    QRect rect(minX,minY,spanX(),spanY());
    for (int i = 0; i <= numXTicks; ++i) {
        int x = rect.left() + (i * (rect.width() - 1)/numXTicks);
        double label = minX + (i * spanX()/numXTicks);
        if (label == 0) scene->addLine(x+1,rect.top(),x+1,rect.bottom(),penDarkGray);
        else scene->addLine(x+1,rect.top(),x+1,rect.bottom(),penGray);
        //qDebug()<<"add line X:"<<x<<" "<<rect.top()<<" "<<x<< " "<< rect.bottom();
        QGraphicsSimpleTextItem *name = NULL;
        name = scene->addSimpleText(QString::number(label));
        name->setBrush(Qt::gray);
        name->setScale(1/CurZoom);
        int kname = spanX()/numXTicks;
        name->setPos(minX+i*kname+3/CurZoom, pYmax-14/CurZoom);
    }
    // Рисуем координатную ось Y:
    for (int j = 0; j <= numYTicks; ++j) {
        int y = rect.bottom() - (j * (rect.height() - 1)/numYTicks);
        double label = -(minY + (j * spanY()/numYTicks));
        if ((unsigned int)label == 0)
        {
            scene->addLine(rect.left(), y, rect.right(), y,penDarkGray);
            //qDebug()<<"LABEL:"<<label;
        } else scene->addLine(rect.left(), y, rect.right(), y,penGray);
        //qDebug()<<"add line Y:"<<rect.left()<<" "<<y<<" "<<rect.right()<< " "<< y;
        QGraphicsSimpleTextItem *name = NULL;
        name = scene->addSimpleText(QString::number(label));
        name->setBrush(Qt::gray);
        int kname = spanY()/numYTicks;
        name->setPos(pXmin+3/CurZoom, minY+j*kname-0.7*CurZoom);
        name->setScale(1/CurZoom);
    }
    scene->addRect(rect,penGray);

    // Рисуем местоположение абонентов системы:
    QSqlQuery query;
    db->selectTable(query);
    while (query.next()) {
         int numberP = query.value(0).toInt();
         int pX = query.value(1).toInt();
         int pY = query.value(2).toInt();
         qDebug()<<"slotAlarmTimer(): new point with cord X = "<<pX<<" Y = "<<pY;
         point = new MyPoint(pX,-pY,5.0,5.0,Qt::green,numberP);
         scene->addItem(point);
         point->setPos(pX,-pY);
         // Подключаем сигнал из точки к СЛОТу в главном классе
         connect(point,&MyPoint::signal1, this, &MyGraphicView::slotFromPoint);

    }
    // Разрешаем перерисование сцены
    StartDraw = false; 
}

/* // Методом перехватываем событие изменения размера виджет
void MyGraphicView::resizeEvent(QResizeEvent *event)
{
    timer->start(50);   // Как только событие произошло стартуем таймер для отрисовки
    QGraphicsView::resizeEvent(event);  // Запускаем событие родителького класса
}
*/

// Метод для удаления всех элементов со сцены:
void MyGraphicView::clearScene()
{
    // Перебираем все элементы сцены и удаляем их
    QList<QGraphicsItem*> all = items();
    for (int i = 0; i < all.size(); i++)
    {
        QGraphicsItem *gi = all[i];
        if(gi->parentItem()==NULL) {
            delete gi;
        }
    }
}

// Метод вращения колесика мыши:
void MyGraphicView::wheelEvent(QWheelEvent *event)
{
    // Scale the view / do the zoom
    const double scaleFactor = 1.15;
    if(event->delta() > 0)
    {
        // Zoom in
        if(CurZoom < 6.0){
            CurZoom = CurZoom*scaleFactor;
            qDebug()<<"wheelEvent(): CurZoom = " << CurZoom;
            scale(scaleFactor, scaleFactor);
            centerOn(mapToScene(event->pos()));
            QPolygon pView = mapFromScene(QRect(0, 0, this->viewport()->width(), this->viewport()->height()));
            qDebug()<<pView;
            minX = -pView.at(0).x()/CurZoom;
            maxX = 500 / CurZoom + minX;
            minY = -pView.at(0).y()/CurZoom;
            maxY = 500 / CurZoom + minY;
            adjustAxis(minX, maxX, numXTicks);
            adjustAxis(minY, maxY, numYTicks);
            qDebug()<<"numXTicks = "<<numXTicks;
            qDebug()<<"numYTicks = "<<numYTicks;
            qDebug()<<"minX = "<< minX << "; minY = " << minY;
            qDebug()<<"maxX = "<< maxX << "; maxY = " << maxY;
            slotAlarmTimer();
        } else qDebug()<<"wheelEvent(): posX = "<<event->pos().x()/CurZoom<< "posY = "<<event->pos().y()/CurZoom;
    }
    else
    {
        // Zooming out
        if (CurZoom > 1.10) {
            CurZoom = CurZoom/scaleFactor;
            qDebug()<<"wheelEvent(): CurZoom = " << CurZoom;
            scale(1.0 / scaleFactor, 1.0 / scaleFactor);
            centerOn(mapToScene(event->pos()));
            QPolygon pView = mapFromScene(QRect(0, 0, this->viewport()->width(), this->viewport()->height()));
            qDebug()<<pView;
            minX = -pView.at(0).x()/CurZoom;
            maxX = 500 / CurZoom + minX;
            minY = -pView.at(0).y()/CurZoom;
            maxY = 500 / CurZoom + minY;
            adjustAxis(minX, maxX, numXTicks);
            adjustAxis(minY, maxY, numYTicks);
            qDebug()<<"numXTicks = "<<numXTicks;
            qDebug()<<"numYTicks = "<<numYTicks;
            qDebug()<<"minX = "<< minX << "; minY = " << minY;
            qDebug()<<"maxX = "<< maxX << "; maxY = " << maxY;
            slotAlarmTimer();
        } else {
            minX = -250;
            maxX = 250;
            minY = -250;
            maxY = 250;
            numXTicks = 10;
            numYTicks = 10;
            qDebug()<<"wheelEvent(): posX = "<<event->pos().x()/CurZoom<< "posY = "<<event->pos().y()/CurZoom;
            slotAlarmTimer();
        }
    }
}

// Метод для определения оптимыльных значений рисок координатных осей:
void MyGraphicView::adjustAxis(double &min, double &max, int &numTicks)
{
    const int MinTicks = 5;
    double grossStep = (max - min) / MinTicks;
    double step = pow(10, floor(log10(grossStep)));
    qDebug()<<"Step = "<<step;
    if (5 * step < grossStep) step *= 5;
    else if (4 * step < grossStep) step *= 4;
    else if (3 * step < grossStep) step *= 3;
    else if (2 * step < grossStep) step *= 2;
    numTicks = (int)(ceil(max / step) - floor(min / step));
    if(CurZoom<1.10) numTicks = 10;
    if (CurZoom > 6.0) numTicks = 10;
    min = floor(min / step) * step;
    max = ceil(max / step) * step;
}

// Метод нажатия кнопки мыши:
void MyGraphicView::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::RightButton){
        QApplication::setOverrideCursor(QCursor(Qt::ClosedHandCursor));
        //this->viewport()->setCursor(Qt::ClosedHandCursor);
        // Store original position.
        currentX = event->x();
        currentY = event->y();
        //event->accept();
        qDebug()<<"mousePressEvent(): originX = "<<currentX<<"; originY = "<<currentY;
        return;
    }
    if (event->button() == Qt::LeftButton){
        slotAlarmTimer();
    }
    //event->ignore();
}

// Метод перемещения указателя мыши:
void MyGraphicView::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::RightButton) {
        this->horizontalScrollBar()->setValue(horizontalScrollBar()->value() - (event->x() - currentX));
        this->verticalScrollBar()->setValue(verticalScrollBar()->value() - (event->y() - currentY));
        currentX = event->x();
        currentY = event->y();
        qDebug()<<"mouseMoveEvent(): originX = "<<currentX<<"; originY = "<<currentY;
        event->accept();
        if(StartDraw == false && CurZoom != 1.0){
            QPolygon pView = mapFromScene(QRect(0, 0, this->viewport()->width(), this->viewport()->height()));
            qDebug()<<pView;
            minX = -pView.at(0).x()/CurZoom;
            maxX = 500 / CurZoom + minX;
            minY = -pView.at(0).y()/CurZoom;
            maxY = 500 / CurZoom + minY;
            qDebug()<<"minX = "<< minX << "; minY = " << minY;
            qDebug()<<"maxX = "<< maxX << "; maxY = " << maxY;
            adjustAxis(minX, maxX, numXTicks);
            adjustAxis(minY, maxY, numYTicks);
            qDebug()<<"numXTicks = "<<numXTicks;
            qDebug()<<"numYTicks = "<<numYTicks;
            qDebug()<<"minX = "<< minX << "; minY = " << minY;
            qDebug()<<"maxX = "<< maxX << "; maxY = " << maxY;
            slotAlarmTimer();
        }
        return;
    }
    event->ignore();
}

// Метод отпускания кнопки мыши:
void MyGraphicView::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button()==Qt::RightButton)
    {
        qDebug()<<"mouseReleaseEvent(): RightButton was released";
        QApplication::setOverrideCursor(QCursor(Qt::ArrowCursor));
        event->accept();
        if(StartDraw == false && CurZoom != 1.0){
            QPolygon pView = mapFromScene(QRect(0, 0, this->viewport()->width(), this->viewport()->height()));
            qDebug()<<pView;
            minX = -pView.at(0).x()/CurZoom;
            maxX = 500 / CurZoom + minX;
            minY = -pView.at(0).y()/CurZoom;
            maxY = 500 / CurZoom + minY;
            adjustAxis(minX, maxX, numXTicks);
            adjustAxis(minY, maxY, numYTicks);
            qDebug()<<"numXTicks = "<<numXTicks;
            qDebug()<<"numYTicks = "<<numYTicks;
            qDebug()<<"minX = "<< minX << "; minY = " << minY;
            qDebug()<<"maxX = "<< maxX << "; maxY = " << maxY;
            slotAlarmTimer();
        }
    }
    event->ignore();
}

void MyGraphicView::slotFromPoint(int numberPoint, int pX, int pY)
{
    qDebug()<<"slotFromPoint(): click "<<numberPoint<<" node";
    QList<QGraphicsItem *> itemsSelected = scene->items(QPolygonF()
                                                        << QPointF(pX, pY)
                                                        << QPointF(pX, pY)
                                                        << QPointF(pX, pY)
                                                        << QPointF(pX, pY));
    foreach (QGraphicsItem *item, itemsSelected) {
        if(item->pos().x()!=0 && item->pos().y()!=0)
        {
            qDebug()<<"Item = "<<item;
        }
    }

    emit signalSelectRow(numberPoint);
}

  • den141280
  • Вопрос
  • 17 января 2017 г. 17:17

Смена цвета объекта при клике мышью

Qt, QGraphicsItem, QGraphicsScene

Вот проект. При нажатии на квадрат он меняет цвет. Хотелось бы, чтобы он цвет менял, но не двигался. Мне зафиксировать сцену нужно или что сделать? Может кто-нибудь изменить код, чтобы квадрат не двигался, а лишь изменял цвет.

  • Julia
  • Вопрос
  • 18 апреля 2016 г. 20:15

Построение схем из графических элементов

QGraphicsScene, GridLayout, Qt, scheme

Добрый день!
Прошу, пожалуйста, помочь с таким вопросом.
Создаю программу, которая рассчитывает электрические или комбинационые схемы (точно пока не определилась, но это не особо влияет на суть вопроса). Целью задачи есть сложить эту схему.
Нажимая на кнопку, мы поучаем нужный элемент и перетаскиваем в нужную позицию.
На этом сайте нашла урок о графической сцене и перетаскиванию по ней элементов, он очень помог, но осталось два вопроса:
1) как сделать так, чтобы элемент становился не в произвольную позицию, а как будто разбить поле на прямоугольные участки;
2) приоритетный в решении момент. Как понять, что два элемента стоят рядом, то есть соединены в цепь или что выходы одного элемента подключены ко входам второго.
  • EVILEG
  • Статья
  • 1 апреля 2016 г. 22:51

Qt/C++ - Урок 045. SvgReader на Qt. Восстановление данных из файла SVG в QGraphicsScene

QGraphicsScene, Qt, SVG, Svg Reader

В прошлой статье был рассмотрен пример того, как сохранить объекты графической сцены в файл SVG, а потом мы смогли открыть его в CorelDraw. А теперь попробуем этот же самый файл открыть и восстановить графические объекты в QGraphicsScene .

Отмечу, что мы не будем использовать класс QSvgRenderer для этого по той причине, что он без проблем поместит содержимое файла SVG на графическую сцену, НО это будет один единый графический объект, а если Вам нужно, чтобы он восстановился в качестве отдельных графических объектов, например, QGraphicsItem , то необходимо будет парсить файл SVG изготавливать из него все графические объекты.

Поскольку файл SVG имеет структуру XML-формата, то разобрать его не представит никакого труда с помощью классов семейства QDomDocument.

  • EVILEG
  • Статья
  • 20 марта 2016 г. 22:31

Qt/C++ - Урок 044. Сохранение объектов QGraphicsScene в файл векторной графики SVG

CorelDraw, QGraphicsScene, Qt, SVG

С помощью библиотеки Qt можно сохранять содержимое графической сцены QGraphicsScene в файлы векторной графики формата SVG, которые после без проблем открываются в таких редакторах, как CorelDraw. Предлагаю написать небольшое приложение, которое позволит сохранить содержимое графической сцены в файл формата SVG, а потом откроем его с помощью CorelDraw .

Структура проекта

  • SvgExample.pro - профайла проекта;
  • mainwindow.h - заголовочного файла главного окна приложения;
  • mainwindow.cpp - файла исходных кодов главного окна приложения, в котором и будет происходить всё действо;
  • mainwindow.ui - файл формы главного окна приложения;
  • main.cpp - основного стартового файла исходных кодов.
Реклама

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 50 баллов
  • Очки рейтинга -4

C++ - Тест 004. Указатели, Массивы и Циклы

  • Результат 80 баллов
  • Очки рейтинга 4

C++ - Тест 001. Первая программа и типы данных

  • Результат 6 баллов
  • Очки рейтинга -10
Последние комментарии

QML - Урок 002. Custom Button in QML Android

Нашел http://doc.qt.io/Qt-5/qtquickcontrols2-customize.html#customizing-button

QML - Урок 002. Custom Button in QML Android

А как кастомайзить Button если использовать QtQuick.Controls 2.0 ? В этом случае пишет Cannot assign to non-existent property "style"

  • EVILEG
  • 15 ноября 2017 г. 13:56

Qt/C++ - Урок 072. Пример векторного редактора на Qt

You need add common QWidget to form, after that you need right-click on this QWidget in the form and select "Promote to..." in Context Menu. After that You will see dialog. In dialog choose Ba...

  • cordsac
  • 15 ноября 2017 г. 3:33

Qt/C++ - Урок 072. Пример векторного редактора на Qt

Sir,In this form design how did you add verectanglesettings.ui,vepolylinesettings.ui UI's to this mainwindow.ui ? have any QT tool to add so. this image shows what I meaning.

Сейчас обсуждают на форуме
  • Docent
  • 21 ноября 2017 г. 19:39

Видео на сцене QGraphicsScene, как правильно сделать?

Ситуация такая: имеется область в памяти в которую пишутся кадры с камеры. Каким наиболее оптимальным образом отобразить их на сцене. У меня это реализовано таким образом, но подозреваю что мо...

Многопоточность. Ошибки при обращении к переменной

Не будет вызываться, оно вызывается ниже по коду. Но какая разница в каком классе хранить данные, если в этой функции я только их выгружаю. Но можно ли все таки выгружать данные из ...

как отключить событие при открытии формы?

как обойти проблему: см. комментарий кода - может кто подскажет. TableView { id: table model: tableModel anchors.fill: parent focus: true Component.onComple...

  • EVILEG
  • 21 ноября 2017 г. 14:40

QGraphicsItem конструктор с параметрами

За что именно отвечают x_c , y_c ? Это положение объекта на графической сцене? Тогда лучше не в методе paint их применять, а через метод setPo...

  • EVILEG
  • 21 ноября 2017 г. 1:36

QGraphicsItem

Я так понимаю, вы каким-то образом передаёте указатель на отрисовываемый текст, то есть на QString. Но лучше добавить переменную в объявление класса, которая будет отвечать за текст, и п...