network: Add nodes features.

mesh
Pierre-Antoine Rouby 2023-03-21 16:09:47 +01:00
parent dc7c7446ff
commit 2c0b265a2b
4 changed files with 153 additions and 38 deletions

View File

@ -19,13 +19,13 @@ class Graph(object):
return f"Graph {{nodes: {self._nodes}, edges: {self._edges}}}"
def nodes(self):
return self._nodes.copy()
return self._nodes
def nodes_names(self):
return list(map(lambda n: n.name, self._nodes))
def edges(self):
return self._edges.copy()
return self._edges
def nodes_counts(self):
return len(self._nodes)
@ -67,7 +67,7 @@ class Graph(object):
return edge
def remove_node(self, node_name:str):
self._nodes = filter(lambda n: n.name != node_name, self._nodes)
self._nodes = list(filter(lambda n: n.name != node_name, self._nodes))
def remove_edge(self, edge_name:str):
self._edges = filter(lambda e: e.name != edge_name, self._edges)
self._edges = list(filter(lambda e: e.name != edge_name, self._edges))

View File

@ -31,3 +31,7 @@ class Node(object):
self.name = value
elif name == "id":
self.id = value
def setPos(self, x, y):
self.pos.x = x
self.pos.y = y

View File

@ -63,11 +63,16 @@ class ComboBoxDelegate(QItemDelegate):
class TableModel(QAbstractTableModel):
def __init__(self, headers=[], rows=[], graph=None):
def __init__(self, headers=[], graph=None, rows_type="nodes"):
super(QAbstractTableModel, self).__init__()
self.rows = rows
self.headers = headers
self.graph = graph
self._type = rows_type
if self._type == "nodes":
self.rows = graph.nodes()
elif self._type == "edges":
self.rows = graph.edges()
def flags(self, index):
return Qt.ItemIsEditable | Qt.ItemIsEnabled | Qt.ItemIsSelectable
@ -113,9 +118,12 @@ class TableModel(QAbstractTableModel):
return False
def update(self):
print("update")
self.layoutChanged.emit()
if self._type == "nodes":
self.rows = self.graph.nodes()
elif self._type == "edges":
self.rows = self.graph.edges()
self.layoutChanged.emit()
class NetworkWindow(ASubWindow):
def __init__(self, title="Network", parent=None):
@ -123,9 +131,6 @@ class NetworkWindow(ASubWindow):
self.ui.setWindowTitle(title)
self.graph = Graph()
n1 = self.graph.add_node()
n2 = self.graph.add_node(50.0,50.0)
e1 = self.graph.add_edge(n1,n2)
# Graph Widget
@ -143,8 +148,8 @@ class NetworkWindow(ASubWindow):
self.nodes_model = TableModel(
headers = ["name", "id", "pos"],
rows = self.graph.nodes(),
graph = self.graph,
rows_type="nodes",
)
self.delegate_line = LineEditDelegate(parent=self)
table = self.find(QTableView, "tableView_nodes")
@ -156,8 +161,8 @@ class NetworkWindow(ASubWindow):
self.reachs_model = TableModel(
headers = ["name", "node1", "node2"],
rows = self.graph.edges(),
graph = self.graph,
rows_type="edges"
)
self.delegate_combobox = ComboBoxDelegate(
graph = self.graph,
@ -173,20 +178,26 @@ class NetworkWindow(ASubWindow):
self.nodes_model.dataChanged.connect(self.reachs_model.update)
self.reachs_model.dataChanged.connect(self.nodes_model.update)
self.graph_widget.changeEdge.connect(self.reachs_model.update)
self.graph_widget.changeNode.connect(self.nodes_model.update)
self.find(QPushButton, "pushButton_add").clicked.connect(
self.clicked_add
)
self.find(QPushButton, "pushButton_del").clicked.connect(
self.clicked_del
)
def clicked_add(self):
if self.get_push_button_checkable("pushButton_add"):
self.set_push_button_checkable("pushButton_del", False)
self.graph_widget.state = "add"
else:
self.graph_widget.state = "move"
def clicked_del(self):
if self.get_push_button_checkable("pushButton_del"):
self.set_push_button_checkable("pushButton_add", False)
self.graph_widget.state = "del"
else:
self.graph_widget.state = "move"

View File

@ -8,7 +8,7 @@ from model.network.Graph import Graph
from PyQt5.QtCore import (
qAbs, QLineF, QPointF, QPoint, qrand, QRectF, QSizeF, qsrand,
Qt, QTime
Qt, QTime, pyqtSlot, pyqtSignal,
)
from PyQt5.QtGui import (
QBrush, QColor, QLinearGradient, QPainter,
@ -20,6 +20,36 @@ from PyQt5.QtWidgets import (
QGraphicsView, QStyle
)
class LandMark(QGraphicsItem):
def __init__(self, width, height, parent=None):
super(LandMark, self).__init__()
self.width = width
self.height = height
self.center = QPoint(width / 2, height / 2)
self.parent = parent
def paint(self, painter, option, widget):
painter.setPen(Qt.NoPen)
painter.setPen(QPen(Qt.black, 0))
painter.drawLine(
-10 + self.center.x(), 0 + self.center.y(),
10 + self.center.x(), 0 + self.center.y()
)
painter.drawLine(
0 + self.center.x(), -10 + self.center.y(),
0 + self.center.x(), 10 + self.center.y()
)
def boundingRect(self):
return QRectF(
-10 + self.center.x(), -10 + self.center.y(),
10 + self.center.x(), 10 + self.center.y()
)
class NodeItem(QGraphicsItem):
Type = QGraphicsItem.UserType + 1
@ -58,33 +88,39 @@ class NodeItem(QGraphicsItem):
def paint(self, painter, option, widget):
painter.setPen(Qt.NoPen)
# painter.setBrush(Qt.darkGray)
# painter.drawEllipse(-7, -7, 20, 20)
gradient = QRadialGradient(-3, -3, 10)
if option.state & QStyle.State_Sunken:
gradient.setCenter(3, 3)
gradient.setFocalPoint(3, 3)
gradient.setColorAt(1, QColor(Qt.yellow).lighter(120))
gradient.setColorAt(0, QColor(Qt.darkYellow).lighter(120))
else:
gradient.setColorAt(0, Qt.yellow)
gradient.setColorAt(1, Qt.darkYellow)
color = Qt.yellow
if self.graph.selectedNode() == self:
color = Qt.red
painter.setBrush(QBrush(gradient))
# painter.setPen(QPen(Qt.black, 0))
painter.setBrush(QBrush(color))
painter.drawEllipse(-10, -10, 20, 20)
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionHasChanged:
self.graph.itemMoved()
self.graph.nodeChangePosition(value, self)
return super(NodeItem, self).itemChange(change, value)
def mousePressEvent(self, event):
# Switch selected node
previous_node = self.graph.selectedNode()
self.graph.setSelectedNode(self)
# Update previous node
if previous_node:
previous_node.update()
self.update()
super(NodeItem, self).mousePressEvent(event)
# def mouseMoveEvent(self, event):
# self.node.setPos(event.pos().x(), event.pos().y())
# self.update()
# super(NodeItem, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.update()
super(NodeItem, self).mouseReleaseEvent(event)
@ -191,17 +227,22 @@ class EdgeItem(QGraphicsItem):
painter.drawPolygon(QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2]))
painter.drawPolygon(QPolygonF([line.p2(), destArrowP1, destArrowP2]))
class GraphWidget(QGraphicsView):
changeEdge = pyqtSignal(object)
changeNode = pyqtSignal(object)
def __init__(self, graph, parent=None):
super(GraphWidget, self).__init__(parent=parent)
self.timerId = 0
self.parent = parent
self.state = "move"
self._selectedNode = None
scene = QGraphicsScene(self)
scene.setItemIndexMethod(QGraphicsScene.NoIndex)
scene.setSceneRect(0, 0, 10000, 10000)
scene.setSceneRect(0, 0, 1000, 1000)
self.setScene(scene)
self.setCacheMode(QGraphicsView.CacheBackground)
self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate)
@ -209,23 +250,49 @@ class GraphWidget(QGraphicsView):
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorViewCenter)
# scene.addItem(LandMark())
self.graph = graph
for node in self.graph.nodes():
scene.addItem(NodeItem(node, self))
# for edge in self.graph.edges():
# scene.addItem(EdgeItem(edge))
self.scale(1, 1)
self.previousScale = 1
self.setMinimumSize(400, 400)
self.create_items()
def create_items(self):
for node in self.graph.nodes():
self.scene().addItem(NodeItem(node, self))
# for edge in self.graph.edges():
# scene.addItem(EdgeItem(edge))
# self.mark = LandMark(1000, 1000, self)
# self.scene().addItem(self.mark)
def add_node(self, pos):
node = self.graph.add_node(pos.x(), pos.y())
self.scene().addItem(NodeItem(node, self))
self.changeNode.emit(self.sender())
def del_node(self, node):
self.scene().clear()
self.graph.remove_node(node.name)
self.create_items()
self.changeNode.emit(self.sender())
def itemMoved(self):
if not self.timerId:
self.timerId = self.startTimer(1000 / 25)
def nodeChangePosition(self, pos, node):
node.node.setPos(pos.x(), pos.y())
def selectedNode(self):
return self._selectedNode
def setSelectedNode(self, node):
self._selectedNode = node
def keyPressEvent(self, event):
key = event.key()
@ -270,3 +337,36 @@ class GraphWidget(QGraphicsView):
# print(f"{scaleFactor} : {factor}")
self.scale(scaleFactor, scaleFactor)
def mousePressEvent(self, event):
pos = self.mapToScene(event.pos())
if self.state == "move":
self.mouse_origin_x = pos.x
self.mouse_origin_y = pos.y
elif self.state == "add":
items = self.items(event.pos())
if not items:
self.add_node(pos)
else:
print(f"TODO add edge {items}")
elif self.state == "del":
items = self.items(event.pos())
print(f"del: {items}")
if len(items) > 0:
nodes = list(filter(lambda i: type(i) == NodeItem, items))
if len(nodes) > 0:
self.del_node(nodes[0].node)
self.update()
super(GraphWidget, self).mousePressEvent(event)
def mouseReleaseEvent(self, event):
self.update()
super(GraphWidget, self).mouseReleaseEvent(event)
def mouseMoveEvent(self, event):
if self.state == "move":
self.update()
super(GraphWidget, self).mouseMoveEvent(event)