Kivy layout file

Now that we have the logic for how the GUI is supposed to function, we can actually write the code to place the widgets where we want on the diagram. You could do this within the Python file that we just created, but best practice is to separate code logic from presentation. For example, the following code from the official Kivy tutorial shows how a Python file could both accept a touch from a finger and create a small dot on the screen of a tablet:

def on_touch_down(self, touch):
with self.canvas:
Color(1, 1, 0)
d = 30.
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))

For our purposes, we will write a special .kv file to hold the layout-specific information and keep the Python logic in hmilayout.py:

# hmi.kv (part 1)
1 #:kivy 1.10.0
2
3 <HMIButton@ToggleButton>:
4 size_hint: None, None
5 size: 35, 35
6
7 <Row@BoxLayout>:
8 canvas.before:
9 Color:
10 rgba: 0.5, 0.5, 0.5, 1
11 Rectangle:
12 size: self.size
13 pos: self.pos
14 value: ''

Line 1 has the Kivy version information to ensure that the user doesn't receive errors. Lines 3-5 define the HMIButton size that will be used for the GUI; it inherits from the Kivy ToggleButton class.

size_hint (line 4) accepts proportional values from 0 to 1; the values are basically the percentage length of width and height. Because the values for size_hint are None, we provide actual values through size (line 5) to set the button to be square. If not using a set size, then only size_hint needs to be used and the GUI will automatically size the widget.

Lines 7-14 determine the layout of the rows in the parameters table. canvas.before tells Kivy to process the items beneath the line (lines 8-13) before moving onto anything else; essentially, it defines the background of the drawing canvas, where images and widgets are placed. In this case, we are defining the color of the row and the size of the cells within the table.

Color (line 9) accepts the red, green, blue, and alpha channel values as proportions, from 0 to 1. The size and pos parameters of Rectangle (lines 12 and 13) don't have values assigned, so they will accept the default values from the parent class, BoxLayout.

Line 14 provides the option for a default value to be given. As we will fill this later, we have set it to be an empty string.

The following code snippet is part 2 of hmi.kv:

# hmi.kv (part 2)
1 Label:
2 text: root.value
3
4 <HMILayout>:
5 table: table # identify this object for reference by other objects
6 swipe_threshold: .2 # Allow page turn to occur when it has been moved 20%
7 FloatLayout:
8 # First page (HMI)
9 canvas.before:
10 Rectangle:
11 pos: self.pos
12 size: self.size
13 source: "fuel_schematic.png"

Lines 1 and 2 finish up the Row from the part 1. Label is the name that would be placed on the row; in line 2, the text assignment indicates that the text value will be whatever the root class at the top of the hierarchy is; in this case, it is BoxLayout.

Starting with line 4, we define how the buttons will be placed on the GUI. Line 5 provides a reference name for this particular object, while line 6 determines how far the user must swipe before the next screen appears (whether schematic to the table or vice versa).

Line 7 declares FloatLayout, which organizes widgets with proportional coordinates using size_hint and pos_hint properties. It also allows widgets to overlay one another.

Lines 9-13 dictate what Kivy is supposed to do first when processing the file. In this case, we create a rectangle with inherited size and position; then we fill it with the schematic drawing. This way, the drawing is the first thing displayed by Kivy, allowing all other widgets to lay on top of it.

The following code snippet is part 3 of hmi.kv:

# hmi.kv (part 3)
1 HMIButton:
2 id: gate1
3 text: "G1"
4 pos: 347, 325
5 group: "gate1"
6 on_state: root.on_state(self)
7
8 HMIButton:
9 id: gate2
10 text: "G2"
11 pos: 347, 473
12 group: "gate2"
13 on_state: root.on_state(self)

After defining the canvas.before items, we move into creating widgets. In part 3, we define two buttons that will be placed on the schematic drawing. Lines 1-6 create gate valve 1 on the drawing, providing the Kivy identification value, the text to be displayed on the button, the absolute position of the button (from the bottom-left corner of the drawing), the group the button is associated with, and access to the on_state() method that we defined previously. Lines 8-13 do the same thing for gate valve 2.

Since the rest of the buttons follow a similar pattern, we will not cover them in detail here. However, the full code is available in this book's code repository.

The following code snippet is part 4 of hmi.kv:

# hmi.kv (part 4)
1 HMIButton:
2 id: pump1
3 text: "P1"
4 pos: 545, 294
5 group: "pump1"
6 on_state: root.on_state(self)
7 color: 1, .5, .5, 1

The preceding code listing for a pump button is slightly different from the valve buttons. Line 7 shows a color listing, in the normal RGBA setting we saw in part 1. This color defines the text color used by the button; this was done in order to help to differentiate the buttons on the drawing. Valve buttons have default text colors, while pump buttons have pinkish text.

The following code snippet is part 5 of hmi.kv:

# hmi.kv (part 5)
1 BoxLayout:
2 # Second page (table layout)
3 canvas:
4 Color:
5 rgba: 0.3, 0.3, 0.3, 1
6 Rectangle:
7 size: self.size
8 pos: self.pos
9 table: table # identify this object for reference by other objects
10 orientation: 'horizontal' # place the following layouts side-by-side
11 BoxLayout:
12 orientation: "vertical" # stack buttons
13 size_hint_x: .15 # buttons should be 15% window width

After we provide the code for all of the buttons on the GUI, we move onto the parameters table page. This is the page that is swiped in from the side.

Line 1 tells Kivy that we will use BoxLayout this time, which organizes widgets into a row or a column, depending on the orientation provided.

We define the canvas colors, rectangle size, and position in lines 3-8. Note that we didn't use canvas.before in line 3; with just canvas, items are allowed to overlap. There is also canvas.after, which places widgets after everything else that has been placed. You can think of the different canvas options as the tools that the drawing applications have for "move to back", "move to front", and so on.

In line 9, we again identify the object for future reference and line 10 tells BoxLayout that we will be using the horizontal orientation, to create a row of widgets.

Lines 11-13 create a new BoxLayout within the parent box container. This new layout will stack two buttons vertically (the Populate List and Clear List buttons).

The following code snippet is part 6 of hmi.kv:

# hmi.kv (part 6)
1 Button:
2 text: 'Populate list'
3 on_press: root.populate()
4 Button:
5 text: 'Clear list'
6 on_press: root.clear()
7 RecycleView:
8 # reference to data table
9 id: table
10 scroll_type: ['bars', 'content'] # table is scrolled by using scroll bars or touching content directly
11 bar_width: dp(20) # sets scroll bar width to 20 px
12 viewclass: 'Row' # Refer back to Row@BoxLayout for grid appearance
13 RecycleGridLayout:
14 size_hint: 1, None # Force scrolling
15 cols: 6

Lines 1-6 create the buttons we talked about in part 5 and associate them to their respective hmilayout.py methods.

Line 7 starts a way to view datasets. RecycleView is the current way to create tables within Kivy; it was added in version 1.10 and replaced the old ListView class.

Line 9 provides the ID reference for the view; the name "table" here is the same table listed in part 2 and part 5.

Line 10 indicates that scroll bars are available for mouse users, but mobile device users can touch the table directly to scroll. Line 11 provides the width of the scroll bars.

Line 12 calls back to the Row layout to determine how to display the table.

Lines 13-15 actually create the layout that will be used to display information. Line 14 forces the scroll bars to appear, rather than only showing up when scrolling starts. This allows the user to easily "grab" the scroll bars for quick scrolling. Line 15 states that six columns will be used for the table.

The following code snippet is part 7 of hmi.kv:

# hmi.kv (part 7)
1 default_size: None, dp(56) # fit table to window
2 default_size_hint: 1, None # fill width
3 height: self.minimum_height # fill height
4 spacing: dp(2) # spacing between cells

We finish up RecycleGridLayout by providing for the default sizes of the table and the cells.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset