[1/2]背景
您好! Qt爲我們提供了創建高度定製圖形項目的意義。我們所需要做的就是繼承QGraphicsItem並覆蓋純虛擬boundingRect()函數。此外,我們可以選擇性地覆蓋虛擬shape()函數以(除其他之外)爲項目提供更精確的形狀...Qt - QGraphics(異形)的選擇項目
現在讓我們看看下面的圖表我繪製了一個軟件(個人學生項目)用C++進行開發。
然後讓灰度突出上述描繪圖內每個邊緣的邊界矩形。
[2/2]問題&備註
我想要的物品可以進行選擇,所以我能夠選擇標誌:
setFlag(ItemIsSelectable, true);
它的工作原理像長方形的一個夢想,圈子項目。它也適用於邊緣,但不像魅力。如果我點擊由邊界矩形定義的區域(上圖中的灰色區域),仍然會選中邊緣。 只有當我們點擊定義項目形狀的曲線時,纔有辦法確保只點擊鼠標的事件?
我已經重寫了所有的鼠標*事件並返回如果shape()不與event.scenePos()相交,但結果不是更好。有沒有辦法實現我想要做的事情? 是否有Qt-ish的方式檢查鼠標位置是否在曲線路徑內?
其實我終於結束了設置標誌,以便邊緣忽略鼠標按鈕:
setAcceptedMouseButtons(Qt::NoButton);
但是,如果有人遇到類似的問題,有一個解決方案,分享我會很高興。
編輯
這是您可以編譯和執行的代碼的一部分。提醒一下,我只想在定義其形狀的路徑上單擊時選擇邊(曲線)。
/**
* 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
哇https://translate.google.fr/#ja/en/subarashi!它像夢一樣運作。非常感謝。 但是(是的,有一個但是),讓我們說用於繪製路徑的筆被賦予了一個非默認的樣式,就像'pen.setStyle(Qt :: DashLine);'一樣。然後選擇曲線(以便畫家的筆寬增加)。現在選擇一個控制點並移動它。您會注意到繪製的路徑有點奇怪:它不同於'shape'函數只是'return buildPath()'而不使用'QPainterPathStroker'的情況。 任何提示去解決這個問題? – misterFad