[1/2] Контекст
Hello! Qt дает нам возможность создавать высоко настраиваемые графические элементы. Все, что нам нужно сделать, это наследовать от QGraphicsItem и переопределить чистую виртуальную функцию boundingRect(). Более того, мы можем опционально переопределить функцию виртуальной формы(), чтобы (среди прочих) дать деталям более точную форму ...Qt - Выбор QGraphics (Shaped) Товар
Теперь давайте посмотрим график ниже. Я рисовал с помощью программного обеспечения (личный студенческий проект). Я был разработка с Qt в C++.
Тогда давайте серо-выделить ограничивающий прямоугольник каждого края в пределах выше изображен график.
[2/2] Вопросы & Замечания
Я хочу, чтобы элементы, чтобы быть по выбору, так что я включить флаг выбора:
setFlag(ItemIsSelectable, true);
Он работает как сон для прямоугольных и круглые предметы. Он тоже работает для краев, но не как шарм. Действительно, ребра по-прежнему выбраны, если я щелкнул в области, заданной ограничивающим прямоугольником (серый на предыдущем графике). Есть ли способ обеспечить, чтобы событие с щелчком мыши учитывалось, только если мы нажали на кривую, определяющую форму элемента?
Я переопределил всю мышь * Событие и возвращение, если shape() не пересекается с event.scenePos(), но результат не был лучше. Есть ли способ достичь того, что я хочу сделать? Есть ли способ Qt-ish проверить, находится ли положение мыши в пределах кривой?
На самом деле я, наконец, в конечном итоге установив флаг так, чтобы края игнорировать кнопки мыши:
setAcceptedMouseButtons(Qt::NoButton);
Но я был бы рад, если бы кто-нибудь сталкивался с аналогичной проблемой и имеет решение, чтобы разделить.
EDIT
Вот часть кода, который вы можете скомпилировать и выполнить. В качестве напоминания я хочу, чтобы ребра (кривые) выбирались только в том случае, если мы нажимаем на путь, определяющий его форму.
/**
* It was really hard to come up with the little snippet below,
* since the real code is more complex.
* Hope someone'll be able to provide me with a solution.
*
* All you need to do is to copy and paste the code to a main.cpp file.
*/
#include <QApplication>
#include <QGraphicsItem>
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QScrollBar>
/**
* Nothing special about this class.
* Note View instances handle rubber band selection (you can try it).
*/
class View : public QGraphicsView {
public:
View(QWidget *parent = nullptr)
: QGraphicsView(parent)
{
customize();
}
private:
void customize() // just customization
{
horizontalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu);
verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu);
setBackgroundBrush(QBrush(Qt::lightGray, Qt::CrossPattern));
setRenderHint(QPainter::Antialiasing);
setDragMode(RubberBandDrag);
setRubberBandSelectionMode(Qt::ContainsItemShape);
}
};
/**
* Nothing special about this class, just a helper class.
*
* A rect item has the QGraphicsItem::ItemIsSelectable QGraphicsItem::ItemIsMovable enabled.
* So you can select and move it around.
*/
class RectItem : public QGraphicsRectItem {
public:
RectItem(QGraphicsItem *parent = nullptr)
: QGraphicsRectItem(parent)
{
const double length = 10;
setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges);
setRect(-length/2.0, -length/2.0, length, length);
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) override
{
setBrush(isSelected() ? QBrush(Qt::gray) : Qt::NoBrush);
QGraphicsRectItem::paint(painter, option, widget);
}
protected:
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
{
switch(change) {
case ItemPositionChange: case ItemSelectedChange:
if(scene()) {
scene()->update(); // just to avoid some ugly effect occuring on the scene.
}
break;
default:
break;
}
return QGraphicsRectItem::itemChange(change, value);
}
};
/**
* A quite simple version of what a cubic Bezier curve is:
* it starts at a given point "from",
* ends at some point "to",
* having two control points (let's say "ctrlPt1" and ctrlPt2").
*
* A curve has the QGraphicsItem::ItemIsSelectable enabled.
* So you can select it.
*/
class Curve : public QGraphicsItem {
protected:
RectItem from;
RectItem ctrlPt1;
RectItem ctrlPt2;
RectItem to;
public:
Curve(QGraphicsItem *parent = nullptr)
: QGraphicsItem(parent)
{
// simple customization
setFlags(ItemIsSelectable);
// set positions
const qreal h = 100.;
const qreal d = 100.;
from.setPos(-150, 0);
ctrlPt1.setPos(from.pos() + QPointF(d, -h));
ctrlPt2.setPos(ctrlPt1.pos() + QPointF(d, 0));
to.setPos(ctrlPt2.x()+d, ctrlPt2.y()+h);
}
// Should be called after scene is defined for this item.
void addPoints() {
QList<QGraphicsRectItem*> list;
list << &from << &ctrlPt1 << &ctrlPt2 << &to;
for(auto *item : list) {
scene()->addItem(item);
}
}
QRectF boundingRect() const override
{
QPolygonF poly;
poly << from.pos() << ctrlPt1.pos() << ctrlPt2.pos() << to.pos();
return poly.boundingRect()
.normalized();
}
QPainterPath shape() const override
{
QPainterPath path;
path.moveTo(from.pos());
path.cubicTo(ctrlPt1.pos(), ctrlPt2.pos(), to.pos());
return path;
}
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR) override
{
Q_UNUSED(option)
Q_UNUSED(widget)
// Draw curve
QPen pen = QPen(Qt::darkBlue);
pen.setWidthF(isSelected() ? 3. : 1.);
painter->setPen(pen); // curve pen
painter->setBrush(Qt::green); // curve brush
painter->drawPath(shape());
// Tie ctrl points
const bool tieCtrlPoints = from.isSelected() || ctrlPt1.isSelected() || ctrlPt2.isSelected() || to.isSelected();
if(tieCtrlPoints) {
painter->setPen(Qt::black);
painter->setBrush(Qt::black);
painter->drawLine(from.pos(), ctrlPt1.pos());
painter->drawLine(ctrlPt1.pos(), ctrlPt2.pos());
painter->drawLine(ctrlPt2.pos(), to.pos());
}
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QGraphicsScene scene;
scene.setSceneRect(-300, -300, 600, 600);
View view;
view.setScene(&scene);
Curve curve;
scene.addItem(&curve);
curve.addPoints();
view.show();
return a.exec();
}
Действительно, вы правы: моя функция фигуры была неправильной. Я меняю его так, чтобы он возвращал тот же путь, что и тот, который был обращен к экрану. ** Но это ничего не меняет **. Может быть, мне что-то не хватает ... Затем я редактирую исходное сообщение, чтобы добавить фрагмент, чтобы вы могли компилировать, выполнять и видеть, о чем я говорю сам. Было очень сложно придумать этот маленький фрагмент, поскольку реальный код более сложный. Надеюсь, кто-то сможет предоставить мне решение. – misterFad
Ответ отредактирован выше для обеспечения исправления. И спасибо за отличный пример кода. Я не сомневаюсь, что это было сложно создать, но то, что вы предоставили, было совершенным. – goug
Wow https://translate.google.fr/#ja/en/subarashi! Он работает как сон. Большое спасибо. Но (да, есть, но), скажем, перо, используемое для рисования пути, получает нестандартный стиль, например, в 'pen.setStyle (Qt :: DashLine);' например. Затем выберите кривую (так, чтобы ширина пера художника увеличивалась). Теперь выберите одну из контрольных точек и передвиньте ее. Вы заметите, что пройденный путь немного странный: он отличается от того, который был бы нарисован, если бы функция 'shape' просто« возвращала buildPath() », не используя' QPainterPathStroker'. Любой совет, чтобы обойти это? – misterFad