”;
In this chapter, we shall learn to develop a simple Kivy app that lets the user draw filled rectangles and circles (ellipses) of different dimensions and colors by dragging the mouse button.
The user drags the mouse pointer from the top-left corner to the bottomdown corner of the intended rectangle/ellipse. The approach used in the development of the following code is to capture the mouse coordinates at the touch_down event and touch_up event. Hence we start the program with this code in the build() method of App class −
def build(self): self.w= Widget() self.w.bind(on_touch_down=self.on_touch_down) self.w.bind(on_touch_up=self.on_touch_up) return(self.w)
We want to let the user choose to draw a rectangle or a circle. Three toggle buttons for choosing to draw either, or clear the canvas have to be added. Hence, we change the layout of App window to box layout, adding the
Widget object on top, and three buttons placed below it.
lo = BoxLayout(orientation=''vertical'') self.w = Widget() self.w.bind(on_touch_down=self.on_touch_down) self.w.bind(on_touch_up=self.on_touch_up) lo.add_widget(self.w) hlo = BoxLayout(orientation=''horizontal'', size_hint=(1, .1)) self.b2 = ToggleButton(text=''Circle'', group=''mode'') self.b1 = ToggleButton(text=''Rectangle'', state=''down'', group=''mode'') self.b3 = ToggleButton(text=''Clear'', group=''mode'') hlo.add_widget(self.b1) hlo.add_widget(self.b2) hlo.add_widget(self.b3) lo.add_widget(hlo) return lo
To draw the desired shape, we need to capture the mouse positions on touch down, and touch up.
The on_touch_down() method is simple −
def on_touch_down(self, *args): self.td = args[1].pos
All the processing happens in on_touch_up() method. The captured coordinates of down event and up event are used to calculate the dimensionsof rectangle or circle.
For circle, the x-radius, y-radius and the center are computed as follows −
self.tu=args[1].pos xr = (self.tu[0]-self.td[0])/2 yr = (self.td[1]-self.tu[1])/2 c=(self.td[0]+xr, self.td[1]-yr)
We need the width and height as well as the top-left corner coordinates for drawing rectangle. The self.td tuple gives top-left point, xr*2 gives the width and yr*2 gives the height.
The shapes are drawn on the widget canvas. We choose a random color for drawing. The text property of the pressed button gives us the shape to be drawn −
color = (random(), random(), random()) with self.w.canvas: Color(*color) if self.btn==''Rectangle'': Rectangle(pos=self.td, size=(xr*2,yr*2)) if self.btn==''Circle'': Ellipse(pos=(c), size=(xr,yr))
Three toggle buttons are bound to a method. If the caption is Clear, the widget canvas is cleared.
def clear_canvas(self, instance, value): self.btn = instance.text self.press = True if value == ''down'' and self.btn == ''Clear'': self.w.canvas.clear() return True
Example
The complete code for the app is given below −
from random import random from kivy.app import App from kivy.uix.widget import Widget from kivy.graphics import Color, Ellipse, Line, Rectangle from kivy.uix.togglebutton import ToggleButton from kivy.uix.boxlayout import BoxLayout from kivy.core.window import Window Window.size = (720, 400) class MyPaintApp(App): def clear_canvas(self, instance, value): self.btn = instance.text self.press = True if value == ''down'' and self.btn == ''Clear'': self.w.canvas.clear() return True def on_touch_down(self, *args): self.td = args[1].pos def on_touch_up(self, *args): if self.press == True: self.press = False return True self.tu = args[1].pos xr = (self.tu[0] - self.td[0]) / 2 yr = (self.td[1] - self.tu[1]) / 2 c = (self.td[0] + xr, self.td[1] - yr) color = (random(), random(), random()) with self.w.canvas: Color(*color) if self.btn == ''Rectangle'': Rectangle(pos=self.td, size=(xr * 2, yr * 2)) if self.btn == ''Circle'': Ellipse(pos=(c), size=(xr, yr)) def build(self): self.press = False self.btn = ''Rectangle'' lo = BoxLayout(orientation=''vertical'') self.w = Widget() self.w.bind(on_touch_down=self.on_touch_down) self.w.bind(on_touch_up=self.on_touch_up) lo.add_widget(self.w) hlo = BoxLayout(orientation=''horizontal'', size_hint=(1, .1)) self.b2 = ToggleButton(text=''Circle'', group=''mode'') self.b1 = ToggleButton(text=''Rectangle'', state=''down'', group=''mode'') self.b3 = ToggleButton(text=''Clear'', group=''mode'') self.b1.bind(state=self.clear_canvas) self.b2.bind(state=self.clear_canvas) self.b3.bind(state=self.clear_canvas) hlo.add_widget(self.b1) hlo.add_widget(self.b2) hlo.add_widget(self.b3) lo.add_widget(hlo) return lo MyPaintApp().run()
Output
Run the above code. Choose the shape you want to draw. Drag the mouse from top-left to bottom-right. The rectangles/circles are drawn at drawn at different positions with random colors.
Click the Clear button to clear the drawings on the canvas.
”;