Имеет пользовательский класс MouseDraw
, полученный от QGraphicsItem
. Существует QGraphicsPathItem
, который обрабатывает все это для вас, правильно.
Концептуально некорректно обрабатывать взаимодействие с мышью внутри создаваемого элемента - ваш большой ограничивающий прямоугольник - это хак, который необходим для его работы, но это неправильный подход. Вы не хотите, чтобы элемент взаимодействовал с мышью. Вы хотите, чтобы сцена взаимодействовала с мышью и создала элемент на лету. Только когда редактирует существующий элемент, который вы хотите связать с мышью, но даже тогда лучше создать отдельный элемент редактора, наложенный на редактируемый элемент для обработки взаимодействия редактирования.
Кликните на окне правой кнопкой мыши, чтобы получить контекстное меню с действием, чтобы очистить изображение. Вы также можете переключать, будет ли следующий путь присоединен к предыдущему. Этот код тестируется как с Qt 4.8.5, так и с 5.2.
Когда сцена меньше, чем на вид, точка зрения настаивает на ее центрировании (с использованием свойства alignment
). В качестве обхода этой «функции» используется EmptyItem
, чтобы ограничить местоположение сцены в представлении, когда сцена меньше, чем вид (в том числе, когда сцена «пуста»).
Код создает отдельный элемент для каждого непересекающегося пути - QGraphicsScene
обычно будет выполнять лучшее с несколькими неперекрывающимися элементами.Разумеется, вы можете сохранить только один элемент и добавлять к нему новые сегменты при каждом нажатии на кнопку мыши, но это в конечном итоге будет иметь последствия для производительности - особенно если вы увеличите масштаб сцены, где вы ожидаете, что производительность станет лучше, чем меньше Показано.
// https://github.com/KubaO/stackoverflown/tree/master/questions/gscene-paint-20632209
#include <QtGui>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <QtWidgets>
#endif
class EmptyItem : public QGraphicsItem
{
public:
EmptyItem(QGraphicsItem * parent = nullptr) : QGraphicsItem{parent} {}
QRectF boundingRect() const override { return {0, 0, 1, 1}; }
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {}
};
class Scene : public QGraphicsScene
{
Q_OBJECT
Q_PROPERTY(bool joinFigures READ joinFigures WRITE setJoinFigures)
bool m_joinFigures = false;
QGraphicsPathItem * m_item = nullptr;
QPainterPath m_path;
void newItem() {
addItem(m_item = new QGraphicsPathItem);
m_item->setPen(QPen{{qrand() % 256, qrand() % 256, qrand() % 256}});
m_path = QPainterPath{}; // using std::swap; swap(m_path, QPainterPath());
}
void newPoint(const QPointF& pt) {
if (! m_item) {
newItem();
m_path.moveTo(pt);
} else {
m_path.lineTo(pt);
m_item->setPath(m_path);
}
}
void mousePressEvent(QGraphicsSceneMouseEvent * ev) override {
if (ev->buttons() != Qt::LeftButton) return;
if (! m_joinFigures) m_item = nullptr;
newPoint(ev->scenePos());
}
void mouseMoveEvent(QGraphicsSceneMouseEvent *ev) override {
if (ev->buttons() != Qt::LeftButton) return;
newPoint(ev->scenePos());
}
void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override {
if (! m_path.isEmpty()) return;
delete m_item; // Empty items are useless
m_item = nullptr;
}
public:
Scene(QObject *parent = nullptr) : QGraphicsScene{parent}
{
addItem(new EmptyItem{});
}
Q_SLOT void setJoinFigures(bool j) { m_joinFigures = j; }
bool joinFigures() const { return m_joinFigures; }
};
class Window : public QWidget
{
Q_OBJECT
QGridLayout m_layout{this};
QGraphicsView m_view;
QCheckBox m_join{"Join Figures (toggle with Spacebar)"};
QAction m_toggleJoin{this};
public:
Window(QWidget * parent = 0) : QWidget{parent}
{
m_layout.addWidget(&m_view);
m_layout.addWidget(&m_join);
m_view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
m_toggleJoin.setShortcut(QKeySequence(Qt::Key_Space));
connect(&m_toggleJoin, SIGNAL(triggered()), &m_join, SLOT(toggle()));
addAction(&m_toggleJoin);
m_view.addAction(new QAction{"Clear", this});
m_view.setContextMenuPolicy(Qt::ActionsContextMenu);
connect(m_view.actions().at(0), SIGNAL(triggered()), SLOT(newScene()));
// Create a new scene instead of clear()-ing it, since scenes can only grow their
// sceneRect().
newScene();
}
Q_SLOT void newScene() {
if (m_view.scene()) m_view.scene()->deleteLater();
m_view.setScene(new Scene);
m_view.scene()->connect(&m_join, SIGNAL(toggled(bool)), SLOT(setJoinFigures(bool)));
}
};
int main(int argc, char *argv[])
{
QApplication a{argc, argv};
Window w;
w.show();
return a.exec();
}
#include "main.moc"
Вы должны переопределить '' QGraphicsScene' или события мыши QGraphicsView', а не родитель для виджета из них – dvvrd
Кроме того, 'setMouseTracking (истина)' должна вызываться один раз в конструкторе. И это необходимо, только если вы хотите отслеживать движения мыши, не нажимая кнопки мыши. –
Нет, я не хочу подключения, это моя проблема, но я не знаю, как это решить. Все рисунки нужно сделать за один ход, проблема в том, что, например, рисование квадрата, рисование сначала слева направо , затем справа на верх, и если вы затем отпустите кнопку мыши и щелкните ее еще раз в левом нижнем углу, чтобы нарисовать линию, например, линия также нарисована справа внизу слева. – user3110781