绘制节点联系

This commit is contained in:
codeboss 2025-07-03 17:37:20 +08:00
parent 8a27ca60e5
commit be67b5ef03
2 changed files with 155 additions and 23 deletions

View File

@ -8,7 +8,9 @@ NodePresent::NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::sha
QRectF NodePresent::contentMeasure() const
{
auto metrics = this->_widget_p->fontMetrics();
return metrics.boundingRect(this->_node_bind->rtName());
auto rect = metrics.boundingRect(this->_node_bind->rtName());
rect.moveTopLeft(QPoint(0, 0));
return rect;
}
#include <QDebug>
@ -21,7 +23,7 @@ AcceptType NodePresent::testAccept(const QPointF& local_pos, const QString& kind
auto left_rect = QRectF(origin + QPointF(0, 0), QSizeF(width / 3, outline.height()));
auto right_rect = QRectF(origin + QPointF(width * 2 / 3, 0), QSizeF(width / 3, outline.height()));
auto top_rect = QRectF(origin + QPointF(width / 3, outline.height() / 2), QSizeF(width / 3, outline.height() / 2));
auto bottom_rect = QRectF(origin + QPointF(width / 3, 0), QSizeF(width / 3, outline.height() / 2));
auto bottom_rect = QRectF(origin + QPointF(width / 3, 0), QSizeF(width / 3, outline.height() / 2));
QList<NodeKind> no_child{ NodeKind::ACTIONNODE, NodeKind::COMPARENODE };
auto pnode = this->_node_bind->parent().lock();
@ -111,7 +113,7 @@ void NodePresent::dropEvent(QGraphicsSceneDragDropEvent* e)
auto this_node = this->_node_bind;
auto appoint_index = 0;
if(parent_node)
if (parent_node)
appoint_index = parent_node->children().indexOf(this_node);
switch (_drop_target) {
@ -153,7 +155,7 @@ void NodePresent::paint(QPainter* painter, const QStyleOptionGraphicsItem* optio
painter->save();
painter->drawRect(boundingRect());
painter->fillRect(option->rect - QMargins(8, 8, 8, 8), Qt::gray);
painter->fillRect(option->rect - QMargins(padding, padding, padding, padding), Qt::gray);
auto outline = this->boundingRect();
auto width = outline.width();
@ -203,38 +205,51 @@ BehaviorsPresent::BehaviorsPresent(QWidget* parent /*= nullptr*/)
void BehaviorsPresent::setRoot(std::shared_ptr<BehaviorMapNode> root)
{
this->_bind_maproot = root;
// 清除显示节点
qDeleteAll(_present_peers);
_present_peers.clear();
this->_bind_maproot = root;
// 清空分支
qDeleteAll(this->_branch_list);
this->_branch_list.clear();
relayout();
}
void BehaviorsPresent::presentAllocate(std::shared_ptr<LogicalNode> ins)
NodePresent* BehaviorsPresent::presentAllocate(std::shared_ptr<LogicalNode> ins)
{
switch (ins->nodeKind())
{
for (auto idx = _column_aligns.size(); idx < ins->depth() + 1; ++idx)
_column_aligns.append(0);
auto& current_width = _column_aligns[ins->depth()];
QList<NodePresent*> _children_set;
switch (ins->nodeKind()) {
case NodeKind::MAPNODE:
case NodeKind::PARALLELNODE:
case NodeKind::SEQUENCENODE:
case NodeKind::SELECTORNODE:
if (ins->nodeKind() != NodeKind::MAPNODE || !ins->bindMap()) {
auto type = ins->nodeKind();
for (auto it : ins->children())
presentAllocate(it);
for (auto it : ins->children()) {
auto child_graph = presentAllocate(it);
if (child_graph) _children_set << child_graph;
}
}
default:
if (_present_peers.contains(ins))
return;
if (_present_peers.contains(ins)) {
for (auto child : _children_set) {
_branch_list << new BranchPresent(_present_peers[ins], current_width, child);
this->_bind_scene.addItem(_branch_list.last());
}
return nullptr;
}
for (auto idx = _column_aligns.size(); idx < ins->depth() + 1; ++idx)
_column_aligns.append(0);
auto& current_width = _column_aligns[ins->depth()];
_present_peers[ins] = new NodePresent(this, current_width, ins);
this->_bind_scene.addItem(_present_peers[ins]);
break;
return _present_peers[ins];
}
}
@ -258,6 +273,7 @@ void BehaviorsPresent::presentRelease(std::shared_ptr<LogicalNode> ins)
}
}
const double NodePresent::padding = 8;
void BehaviorsPresent::relayout()
{
if (!_bind_maproot)
@ -269,8 +285,26 @@ void BehaviorsPresent::relayout()
QHash<std::shared_ptr<LogicalNode>, std::pair<QSizeF, QSizeF>> results;
// ³ß´ç²âÁ¿
outlineMeasure(_bind_maproot, results);
// ÔªËØÅŲ¼
nodeRelayout(results, _bind_maproot, QPointF());
// 调整分支图形位置
for (auto ins : this->_branch_list) {
auto rect_s = ins->startNodeOutline();
auto rect_e = ins->endNodeOutline();
qDebug() << __FILE__ << __LINE__ << rect_s << rect_e;
auto start_pos = rect_s.bottomRight() - QPoint(NodePresent::padding, rect_s.height() / 2);
auto end_pos = rect_e.topLeft() + QPoint(NodePresent::padding, rect_e.height() / 2);
auto left_val = std::min(start_pos.x(), end_pos.x());
auto top_val = std::min(start_pos.y(), end_pos.y());
ins->setPos(left_val, top_val);
ins->resetArrow(start_pos, end_pos);
}
}
QSizeF BehaviorsPresent::outlineMeasure(std::shared_ptr<LogicalNode> ins, QHash<std::shared_ptr<LogicalNode>, std::pair<QSizeF, QSizeF>>& _outline_occupy)
@ -357,7 +391,6 @@ void BehaviorEditor::open_behavior_map()
if (!url.isValid())
return;
qDebug() << url;
}
BehaviorEditor::BehaviorEditor(QWidget* parent /*= nullptr*/)
@ -448,3 +481,76 @@ void NodeTypesView::startDrag(Qt::DropActions supported)
}
}
}
BranchPresent::BranchPresent(NodePresent* a, double& a_width, NodePresent* b)
:_start_node(a), _start_node_width(a_width), _end_node(b) {
}
QRectF BranchPresent::startNodeOutline() const
{
auto _start_pos = _start_node->pos();
auto _s_rect = _start_node->boundingRect();
_s_rect.moveTopLeft(_start_pos);
return _s_rect;
}
QRectF BranchPresent::endNodeOutline() const
{
auto _end_pos = _end_node->pos();
auto _e_rect = _end_node->boundingRect();
_e_rect.moveTopLeft(_end_pos);
return _e_rect;
}
void BranchPresent::resetArrow(const QPointF& start, const QPointF& end)
{
this->_arrow_start = start;
this->_arrow_end = end;
qDebug() << __FILE__ << __LINE__ << _arrow_start << _arrow_end;
this->update();
}
QRectF BranchPresent::boundingRect() const
{
auto leftv = std::min(_arrow_start.x(), _arrow_end.x());
auto topv = std::min(_arrow_start.y(), _arrow_end.y());
auto width = std::abs(_arrow_start.x() - _arrow_end.x());
auto height = std::abs(_arrow_start.y() - _arrow_end.y());
return QRectF(0, 0, width, height);
}
void BranchPresent::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing, true);
QPointF start(0, 0);
auto vtarget = _arrow_end - _arrow_start;
if (vtarget.y() < 0) {
start -= QPointF(0, vtarget.y());
vtarget -= QPointF(0, vtarget.y());
}
auto pt1 = start + QPointF(vtarget.x() / 2, 0);
auto pt2 = vtarget - QPointF(vtarget.x() / 2, 0);
QPainterPath bezier_curve;
bezier_curve.moveTo(start);
bezier_curve.cubicTo(pt1, pt2, vtarget);
QPen p(Qt::black);
p.setWidth(2);
painter->setPen(p);
painter->drawPath(bezier_curve);
//p.setColor(Qt::red);
//painter->setPen(p);
//painter->drawLine(start, pt1);
//painter->drawLine(pt1, pt2);
//painter->drawLine(pt1, vtarget);
painter->restore();
}

View File

@ -17,16 +17,17 @@ class BehaviorsPresent;
class NodePresent : public QGraphicsItem {
private:
BehaviorsPresent* const _widget_p;
std::shared_ptr<LogicalNode> _node_bind;
double& _column_width;
AcceptType _drop_target = AcceptType::NONE;
public:
std::shared_ptr<LogicalNode> _node_bind;
static const double padding;
NodePresent(BehaviorsPresent* pwidget, double& width_bind, std::shared_ptr<LogicalNode> bind);
QRectF contentMeasure() const;
AcceptType testAccept(const QPointF& local_pos, const QString &kind_str) const;
AcceptType testAccept(const QPointF& local_pos, const QString& kind_str) const;
// 通过 QGraphicsItem 继承
QRectF boundingRect() const override;
@ -39,6 +40,30 @@ protected:
virtual void dropEvent(QGraphicsSceneDragDropEvent* event);
};
/// <summary>
/// ·Ö֧ͼÐδúÀí
/// </summary>
class BranchPresent : public QGraphicsItem {
private:
NodePresent* const _start_node;
double& _start_node_width;
NodePresent* const _end_node;
QPointF _arrow_start, _arrow_end;
public:
BranchPresent(NodePresent* a, double& a_width, NodePresent* b);
QRectF startNodeOutline() const;
QRectF endNodeOutline() const;
void resetArrow(const QPointF& start, const QPointF& end);
// ͨ¹ý QGraphicsItem ¼Ì³Ð
QRectF boundingRect() const override;
void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) override;
};
/// <summary>
/// 行为树编辑展示
@ -48,9 +73,10 @@ class BehaviorsPresent : public QGraphicsView
private:
QGraphicsScene _bind_scene;
const double _space_h = 120;
const double _space_h = 30;
QVector<double> _column_aligns;
QHash<std::shared_ptr<LogicalNode>, NodePresent*> _present_peers;
QList<BranchPresent*> _branch_list;
/// <summary>
/// 绑定行为树节点
@ -72,7 +98,7 @@ public:
/// </summary>
/// <param name="_present_peers"></param>
/// <param name="ins"></param>
void presentAllocate(std::shared_ptr<LogicalNode> ins);
NodePresent* presentAllocate(std::shared_ptr<LogicalNode> ins);
/// <summary>
/// 递归释放显示节点
/// </summary>