I'd like to make UI that's basically an image that a user can trace out a path on with points connected by lines. I'd like it to be cross platform so I'm considering trying out enaml. I'm not sure how to accomplish this though.
I've looked through the documentation and examples and I can't find anything like a canvas widget. Is it possible to do arbitrary drawing (points, lines, etc) on a surface with enaml?
enaml doesn't have a canvas widget, but you can use the RawWidget along with a custom QWidget and a QPainter to draw whatever you need.
from atom.api import Typed, Event
from enaml.widgets.api import Window, Container, RawWidget
from enaml.core.declarative import d_
from enaml.qt.QtCore import Qt
from enaml.qt.QtGui import QPainter, QPainterPath, QMouseEvent
from enaml.qt.QtWidgets import QWidget
class QtPaintWidget(QWidget):
""" A widget that delegates drawing to enaml """
def __init__(self, parent, widget):
super(QtPaintWidget, self).__init__(parent)
self.widget = widget
def paintEvent(self, e):
qp = QPainter()
qp.begin(self)
# Trigger the 'paint' event on th PaintWidget
self.widget.paint(qp)
qp.end()
def mouseReleaseEvent(self, e):
super(QtPaintWidget, self).mouseReleaseEvent(e)
self.widget.mouse_event(e)
class PaintWidget(RawWidget):
#: Push the paint event up to enaml
paint = d_(Event(QPainter))
#: Handle mouse event in enaml
mouse_event = d_(Event(QMouseEvent))
def create_widget(self, parent):
return QtPaintWidget(parent, self)
def update(self):
self.proxy.widget.update()
enamldef Main(Window):
Container:
padding = 0
PaintWidget: canvas:
attr points = []
minimum_size = (500, 500)
paint ::
# See https://doc.qt.io/qt-5/qpainter.html
# for how to use the QPainter
qp = change['value']
qp.setBrush(Qt.white)
qp.drawRect(0, 0, 500, 500)
qp.setBrush(Qt.NoBrush)
qp.setPen(Qt.blue)
for p in points:
qp.drawPoint(p)
qp.setPen(Qt.red)
path = QPainterPath()
if len(points) > 1:
for i, p in enumerate(points):
if i==0:
path.moveTo(p)
else:
path.lineTo(p)
qp.drawPath(path)
mouse_event ::
# Save the position
e = change['value']
print(e)
if e.button() == Qt.RightButton:
del points[:]
else:
points.append(e.pos())
canvas.update()
And wala
You don't have to push the paint event to enaml it just makes it easier to interact with other widgets. See QtPainter docs and http://zetcode.com/gui/pyqt5/painting/ for more on drawing in Qt.