bj0
bj0

Reputation: 8213

Is there a drawing/canvas widget in enaml?

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?

Upvotes: 4

Views: 334

Answers (1)

frmdstryr
frmdstryr

Reputation: 21362

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

Drawing

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.

Upvotes: 3

Related Questions