Tuesday, June 24, 2014

35. ToggleButton

ToggleButtons are very similar to Buttons, however, their on state persists, until the next press. ToggleButtons have a property called state, which can be 'normal' or 'down' for off and on states. Here, we will not use the state property. However, we will use them in the next Tutorial.




The root is based on GridLayout, and we have to import the App class to create an app. We create an empty class which will be defined in the kv file.




A subclass of the App class is created, and we override the App class build() method to return the root. Before the build() is called, we have to start the process with the run() method of the App class.


# ex35.py

from kivy.uix.gridlayout import GridLayout
from kivy.app import App

class Ex35(GridLayout):
    pass
        
class Ex35App(App):
    def build(self):
        return Ex35()

if __name__=='__main__':
    Ex35App().run()



In the kv file, we set columns as 2. We will have 4 RelativeLayouts next. Since we do not set the size, we will have a 2 by 2 grid, with each RelativeLayout getting the same size. The background for the first RelativeLayout is red.




The first ToggleButton size and position isset. All other ToggleButtons will have the same size and relative position. For the first ToggleButton, the text is 'Toggle Button 1'.




For the second RelativeLayout with background color of green, the ToggleButton position and size are same. It's text is 'Toggle Button 2'.




For the third ToggleButton with a background RelativeLayout of blue, the text is 'Toggle Button 3'. It is part of a group. In a group, only one member may have on state at a particular time.




ToggleButton 4 is in the same group as ToggleButton 3. Thus either this ToggleButton is on or the other ToggleButton is on. It is possible for both ToggleButtons to be off.


# ex35.kv

<Ex35>:
    cols: 2
    RelativeLayout:
        canvas:
            Color:
                rgb: 1,0,0
            Rectangle:
                size: root.width/2,root.height/2
        ToggleButton:
            size_hint: None, None
            size: 0.25*root.width,0.25*root.height
            pos: 0.125*root.width,0.125*root.height
            text: 'Toggle Button 1'
            
    RelativeLayout:
        canvas:
            Color:
                rgb: 0,1,0
            Rectangle:
                size: root.width/2,root.height/2
        ToggleButton:
            size_hint: None, None
            size: 0.25*root.width,0.25*root.height
            pos: 0.125*root.width,0.125*root.height
            text: 'Toggle Button 2'

    RelativeLayout:
        canvas:
            Color:
                rgb: 0,0,1
            Rectangle:
                size: root.width/2,root.height/2
        ToggleButton:
            size_hint: None, None
            size: 0.25*root.width,0.25*root.height
            pos: 0.125*root.width,0.125*root.height
            text: 'Toggle Button 3'
            group: 'geometry'

    RelativeLayout:
        canvas:
            Color:
                rgb: 0,1,1
            Rectangle:
                size: root.width/2,root.height/2
        ToggleButton:
            size_hint: None, None
            size: 0.25*root.width,0.25*root.height
            pos: 0.125*root.width,0.125*root.height
            text: 'Toggle Button 4'
            group: 'geometry'
            



This is the result. The first two ToggleButtons in row 1 are independent, and so both can be on. However, in the second row, the two belong to the same group. Thus, if the first is selected, and we select the second, the first will be deselected. Most applications will use ToggleButtons, rather than regular Buttons, in the toolbar to give, a visual clue of the selected tool.




Monday, June 23, 2014

34. Drawing App

Unlike the previous widget applications, here widgets are added dynamically. If widgets are to be added dynamically, at run-time, depending on user interaction, they can only be added in the Python file.




Besides the App class, the Widget and RelativeLayout classes are imported. The Widget class is used for the ColorTriangle widget. The root is based on RelativeLayout.




This is the first half of the root class. Whenever a click is detected, the on_touch_down function is called by Kivy. Here we create an instance of the widget, set its position, and add the widget so it may be displayed.




When touch, or mouse, is dragged, on_touch_move is called by Kivy. We use the same code to add a ColorTriangle.




After creating a subclass of the App class, it has to be run(). We do not have to put the run code in the if __name__ is equal to '__main__': block, if we understand that we will only run the Python file directly and not import it. It does not hurt to have the condition though, as it results in more readable code.


# ex34.py

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.relativelayout import RelativeLayout

class ColorTriangle(Widget):
    pass

class Ex34(RelativeLayout):
    def on_touch_down(self, touch):
        ct = ColorTriangle()
        ct.center = touch.pos
        self.add_widget(ct)

    def on_touch_move(self, touch):
        ct = ColorTriangle()
        ct.center = touch.pos
        self.add_widget(ct)
        
class Ex34App(App):
    def build(self):
        return Ex34()

Ex34App().run()




In the kv file, we import the random module as the alias rnd. Since the widget will be added to a RelativeLayout, we have to put the size_hint to None, None so it does not use all available window space, to draw the widget, but rather use the specific size, provided here.




Finally in the canvas instructions, we set a random color, and then send it triangle coordinates. We can not fix the triangle coordinates, as that will always draw the widget at a specific place, on the window. We have to refer to self variables as they are changed at each instance.




For the root, we set a background color.


# ex34.kv
#:import rnd random

<ColorTriangle>:
    size_hint: None, None
    size: 25,50
    canvas:
        Color:
            rgb: rnd.random(),rnd.random(),rnd.random()
        Triangle:
            points:
                (self.x,self.y, self.x+self.width,self.y,
                self.x+self.width/2,self.y+self.height)
            
<Ex34>:
    canvas:
        Color:
            rgb: .9,.8,1
        Rectangle:
            size: root.size
            pos: root.pos
    
        



This is a particular result. Since this is a painting application, the total numbers of widgets, is not known initially.