Wednesday, August 13, 2014

58. TabbedPanel

TabbedPanels provide tabs to select between different screens.




The TabbedPanel widget is used for the root. The App class is needed for any application.




We have to have a subclass of the App class.


# ex58.py
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.app import App

class Ex58(TabbedPanel):
    pass

class Ex58App(App):
    def build(self):
        return Ex58()
    
if __name__ == '__main__':
    Ex58App().run()



In the kv file, the MyImage dynamic class is created and it allows for a stretchable image.




The first 2 screens are of the images p1 and p2. There will only be tabs for the Panels and their width is 199 pixels.




The next 3 screens corresponds to images p3, p4 and p5.


# ex58.kv
<MyImage@Image>:
    keep_ratio: False
    allow_stretch: True

<Ex58>:
    do_default_tab: False
    tab_width: 199
    TabbedPanelItem:
        text: 'The Basin'
        MyImage:
            source: 'p1.png'
    TabbedPanelItem:
        text: 'Boise Rock'
        MyImage:
            source: 'p2.png'
    TabbedPanelItem:
        text: 'Old Forest'
        MyImage:
            source: 'p3.png'
    TabbedPanelItem:
        text: 'Old Man of the Mountain'
        MyImage:
            source: 'p4.png'
    TabbedPanelItem:
        text: 'Flume Gorge'
        MyImage:
            source: 'p5.png'



In this result, we select the p1 image. The window was resized to show all tabs. For the mobile, you will have to make calculations about the tab size so they all fit in a fixed-size screen.




Thursday, August 7, 2014

Java jMonkeyEngine3 Series

Most Android programming is in Java.  I intend to go over the Java jMonkeyEngine3 gaming library later. It is a 3D library. However, it is important to have understand Java skills before that. 

I will post the tutorials at Java Programming Tutorials.




Tuesday, August 5, 2014

57. Accordion

The Accordion offers dividers to select between different screens.




The Accordion widget is used for the root. The App class is needed for any application.




We have to have a subclass of the App class.


# ex57.py
from kivy.uix.accordion import Accordion
from kivy.app import App

class Ex57(Accordion):
    pass

class Ex57App(App):
    def build(self):
        return Ex57()
    
if __name__ == '__main__':
    Ex57App().run()



In the kv file, the MyImage dynamic class is created and it allows for a stretchable image. The orientation of the Accordion is 'vertical'. The default is 'horizontal'.




The first 3 screens are the images p1, p2 and p3.




The next 2 screens corresponds to images p4 and p5.


# ex57.kv
<MyImage@Image>:
    keep_ratio: False
    allow_stretch: True

<Ex57>:
    orientation: 'vertical'
    AccordionItem:
        title: 'The Basin'
        MyImage:
            source: 'p1.png'
    AccordionItem:
        title: 'Boise Rock'
        MyImage:
            source: 'p2.png'
    AccordionItem:
        title: 'Old Forest'
        MyImage:
            source: 'p3.png'
    AccordionItem:
        title: 'Old Man of the Mountain'
        MyImage:
            source: 'p4.png'
    AccordionItem:
        title: 'Flume Gorge'
        MyImage:
            source: 'p5.png'



In this result, we select the p3 image. Any widgets, including layouts, could be used for the individual Accordion items. Besides the orientation, we can also change the animation transition effects between different screens.




Monday, August 4, 2014

56. Carousel


The Carousel can be used to create a slide show. Here, we will have a 1-second delay between each slide.




Since this is an application, we need the App class. The Carousel widget is the super class of the root. We use the Clock to create a 1-second timer.




The root is based on Carousel. The update() function runs the Carousel's load_next() function to load the next slide.




In the build() of the app, a title is set and a continuous 1-second timer is started.


# ex56.py
from kivy.app import App
from kivy.uix.carousel import Carousel
from kivy.clock import Clock

class Ex56(Carousel):
    def update(self, dt):
        self.load_next()

class Ex56App(App):
    def build(self):
        self.title = 'Carousel Example'
        ex56 = Ex56()
        Clock.schedule_interval(ex56.update, 1)
        return ex56

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



In the kv file, a dynamic class MyImage is created so the images are stretched.




For the root, the direction of Carousel is 'right' and looping is True. Here, we have the first 2 images.




The next 3 slides are of images p3, p4 and p5.


# ex56.kv
<MyImage@Image>:
    keep_ratio: False
    allow_stretch: True
    
<Ex56>:
    direction: 'right'
    loop: True
    MyImage:
        source: 'p1.png'
    MyImage:
        source: 'p2.png'
    MyImage:
        source: 'p3.png'
    MyImage:
        source: 'p4.png'
    MyImage:
        source: 'p5.png'


Demo of App on Youtube.

Saturday, August 2, 2014

55. FileChooser

If an application requires user data, we might display the FileChooser.




Since this is an application, we need the App class. The root is based on BoxLayout. The root has one function, select(). This will be called from the kv file, when the user selects any file. If a filename has been passed to select(), it will pass it to the label. label is defined in the kv file and is an attribute.




In the app class, we have to return the root class.


# ex55.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout

class Ex55(BoxLayout):
    def select(self, *args):
        try: self.label.text = args[1][0]
        except: pass

class Ex55App(App):
    def build(self):
        return Ex55()
    
if __name__ == '__main__':
    Ex55App().run()



In the kv file, we define the outer BoxLayout to have a 'vertical' orientation, and then we start the inner BoxLayout.




The inner BoxLayout has a default orientation of 'horizontal'. The first element is a FileChooserListView. We first set a background color. The on_selection is called, when the user selects a particular file, by clicking it. It will call the select() function.




The next element in the Boxlayout is FileChooserIconView. We set a background color, and route the selected filename, to the select() function.




Finally, we have a Label. It has an ID of label, which was used earlier in the attribute definition. It has a small size_hint in y direction as it will occupy a small portion of the screen at the bottom. We then set a background color.


# ex55.kv
<Ex55>:
    label: label
    orientation: 'vertical'
    BoxLayout:
        FileChooserListView:
            canvas.before:
                Color:
                    rgb: .4,.5,.5
                Rectangle:
                    pos: self.pos
                    size: self.size
            on_selection: root.select(*args)
        FileChooserIconView:
            canvas.before:
                Color:
                    rgb: .5,.4,.5
                Rectangle:
                    pos: self.pos
                    size: self.size
            on_selection: root.select(*args)
    Label:
        id: label
        size_hint_y: .1
        canvas.before:
            Color:
                rgb: .5,.5,.4
            Rectangle:
                pos: self.pos
                size: self.size
        



In the result, we can see the two FileChooser views, on the top-left, and top-right, which together, are about 90% of the screen area. These have different background colors, set in the kv file. The label on the bottom, indicates currently selected file.




Thursday, July 24, 2014

54. JsonStore

The JsonStore is used to store data to permanent memory so it can be read later.




The imports include the App to create an app, and the GridLayout for the root. Each of the grids will be a Label. We need a few graphics classes. The Window is used to find the size of screen. Finally, JsonStore is needed for saving and reading of data, from the json file.




In the build() of the app, we create a store variable, pointing to the json file. Here, four dictionary elements are written to it.




These are the last four elements which are saved to json file.




The variable y0, indicates the y-separation of horizontal lines. There will be 9 such lines separating the rows of the grid. The variable y, initially, points to top of the screen. It is moved down by y0 each time a new horizontal line is drawn. The root is a GridLayout with 2 columns. Str and Str1 are templates, for header and non-header labels.




The background color is set. The left header is written.




The right header is written, as well as a horizontal line, just below the header labels.




We iterate, over the 8 elements, of the store. Since store is a dictionary structure, that is, a dictionary of dictionaries, it is not sorted. That is why the sorted() function is used. The left-most label is written.




The right label is written, as well as the horizontal line just underneath acting as a divider. Besides this, we have the main code with the run() function.


# ex54.py
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.graphics import Line, Color, Rectangle
from kivy.core.window import Window
from kivy.storage.jsonstore import JsonStore

class Ex54App(App):
    def build(self):
        store = JsonStore('ex54.json')
        store['p1'] = {'name':'Mercury', 'mass':0.055}
        store['p2'] = {'name':'Venus', 'mass':0.815}
        store['p3'] = {'name':'Earth', 'mass':1}
        store['p4'] = {'name':'Mars', 'mass':0.107}

        store['p5'] = {'name':'Jupiter','mass':317.8}
        store['p6'] = {'name':'Saturn','mass':95.152}
        store['p7'] = {'name':'Uranus','mass':14.536}
        store['p8'] = {'name':'Neptune','mass':17.147}
              
        y0 = Window.height/(len(store)+1)
        y = Window.height
        gl = GridLayout(cols = 2)
        Str = '[size=32][color=FF4488]{}[/color][/size]'
        Str1 = '[size=44][color=2222FF]{}[/color][/size]'
        with gl.canvas:
            Color(1,.95,.95,1)
            Rectangle(size = Window.size)
        y = y - y0
        Strin = Str1.format('Planet')
        lbl = Label(text=Strin, markup = True)
        gl.add_widget(lbl)
        Strin = Str1.format('Relative Mass')
        lbl = Label(text=Strin, markup = True)
        gl.add_widget(lbl)
        with gl.canvas:
            Color(0,1,0,1)
            Line(points=(0,y,Window.width,y))
        for key in sorted(store):
            y = y - y0
            Strin = Str.format(store[key]['name'])
            lbl = Label(text=Strin, markup = True)
            gl.add_widget(lbl)
            Strin = Str.format(store[key]['mass'])
            lbl = Label(text=Strin, markup = True)
            gl.add_widget(lbl)
            with gl.canvas:
                Color(0,1,0,1)
                Line(points=(0,y,Window.width,y))
        return gl
        
if __name__=='__main__':
    Ex54App().run()



We can always open the json file which is saved to the hard drive on desktop. Here is the first four elements, with newlines manually added for clarity.




This result shows the header and the 8 rows with the data. The header row and data rows are different colors since they are based on different string templates, with different color and size markup. We can also see the horizontal lines dividing the rows.




Tuesday, July 22, 2014

53. Settings

We can use Kivy settings to set up our setting screens. In almost any Kivy application, pressing F1 will lead to the Kivy setting screen.




To show how to set up your setting screen you have to write a json file, or alternatively, a json variable. We use the later here. A python file ex53json.py is written. It includes one variable in json format. First, there is a heading of Shape. Next there is a Circle selector. There are three other shapes, shown after Slide 3.




Finally, we start a Size section. Its only element is a number called 'pixels'. Finally the entire json variable is turned into a String, using the dumps(), function.


#ex53json.py
import json
A=[
    { "type": "title",
      "title": "Shape"},
    
    { "type": "bool",
      "title": "Circle",
      "key": "circle",
      "section": "shape"},

    { "type": "bool",
      "title": "Square",
      "key": "square",
      "section": "shape"},

    { "type": "bool",
      "title": "Up Triangle",
      "key": "up_triangle",
      "section": "shape"},

    { "type": "bool",
      "title": "Down Triangle",
      "key": "down_triangle",
      "section": "shape"},

    { "type": "title",
      "title": "Size"},

    { "type": "numeric",
      "title": "Pixels",
      "key": "pixels",
      "section": "size",
      "desc": "Size of shapes"}
]
json_data = json.dumps(A)



In the main file, the json python file is imported, in the last line of the import section. Besides App, the graphics Color and Rectangle are imported as we use them in Python code. The root is based on RelativeLayout. The Window is imported to get size of screen. We use a DictProperty to set a Dictionary.




The root is empty in python file. For the app, we first set use_kivy_settings as False so the Kivy setting screen is disabled. You can comment this out, or remove it, if you do want the main Kivy setting screen. Next, a dictionary with 5 elements is set up.




After run() is called, Kivy will execute build_config(). This will set the defaults for the setup screen. Here, it sets the 4 shapes as 1 (ON), and 'pixels' as 50. A text file, .ini file will be created, if it does not already exist.




Shortly afterwards, build() is called. Using the values in the .ini file, we set up the Dictionary.




When we click on the Button, which we will later create in the kv file, or press F1, this function will be executed, unless it is already cached, and in memory. We create a 'Settings' screen, and populate with data from the json file. Then using the canvas.before, we set the color for the setup screen.




Whenever a setting is changed, the on config change is called by Kivy. This will update the dictionary as well as the .ini file.


#ex53.py
from kivy.app import App
from kivy.graphics import Color, Rectangle
from kivy.uix.relativelayout import RelativeLayout
from kivy.core.window import Window
from kivy.properties import DictProperty
from ex53json import json_data
# Uncomment, next 2 lines to remove warning
#from kivy.clock import Clock
#Clock.max_iteration = 15

class Ex53(RelativeLayout):
    pass

class Ex53App(App):
    use_kivy_settings = False
    Val = DictProperty({'circle':0,'square':0,'up_triangle':0,
                        'down_triangle':0,'pixels':0})

    def build_config(self, config):
        config.adddefaultsection('shape')
        for val in ['circle','square','up_triangle','down_triangle']:
            config.setdefault('shape', val, '1')
        config.add_section('size')
        config.setdefault('size', 'pixels', '50')

    def build(self):
        for val in ['circle','square','up_triangle','down_triangle']:
            self.Val[val]=self.config.getint('shape',val)
        self.Val['pixels']=self.config.getint('size','pixels')
        return Ex53()
    
    def build_settings(self, settings):
        settings.add_json_panel('Settings',
                                self.config, data=json_data)
        with settings.canvas.before:
            Color(.2,.25,.25,1)
            Rectangle(pos=(0,0),size=Window.size)
            
    def on_config_change(self, config, section, key, value):
        self.Val[key] = value
        config.set(section,key,value)
        config.write()

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



In the kv file, we first set the background color.




The Circle Label is created, which will output the 'circle' dictionary value.




Then, we do the same for Square. Labels are also created for the Up Triangle and the Down Triangle Shapes, shown after Slide 14.




After the 4 shapes, we output a label with 'pixels' value.




We create a button with text of 'Settings (F1)'. If the button is clicked, it manually opens the settings. Note, you will get a warning, as well as the solution, which is included in the source file at blogspot, as comments.


# ex53.kv
<Ex53>:
    canvas:
        Color:
            rgb: .5,0,.5
        Rectangle:
            pos: self.pos
            size: self.size
    Label:
        text: 'Circle: ' + str(app.Val['circle'])
        pos: 0,400
        size_hint: None,None
        size: 100,100
    Label:
        text: 'Square: ' + str(app.Val['square'])
        pos: 150,400
        size_hint: None,None
        size: 100,100
    Label:
        text: 'Up Triangle: ' + str(app.Val['up_triangle'])
        pos: 300,400
        size_hint: None,None
        size: 100,100
    Label:
        text: 'Down Triangle: ' + str(app.Val['down_triangle'])
        pos: 450,400
        size_hint: None,None
        size: 100,100
    Label:
        text: 'Size: ' + str(app.Val['pixels'])
        pos: 200,200
        size_hint: None,None
        size: 100,100
    Button:
        text: 'Settings\n(F1)'
        pos: 200,50
        size_hint: None,None
        size: 100,100
        on_press: app.open_settings()



After opening the Settings, two shapes are selected and pixel is set to 100.




As we can see, the program indicates it has read the values.