Skip to content

Instantly share code, notes, and snippets.

@Dayof
Last active August 26, 2017 05:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dayof/057f7d0e7e2baf29877875d54252fc2e to your computer and use it in GitHub Desktop.
Save Dayof/057f7d0e7e2baf29877875d54252fc2e to your computer and use it in GitHub Desktop.
import toga
from collections import namedtuple
# Structure of the main data source of the tree
GRADES = namedtuple('Grades', 'cl grade')
class TreeStructure:
def __init__(self):
# Data source of the tree
self.data = (
GRADES('A', () ),
GRADES('B', ('7.5', '6.1', '8.5') ),
GRADES('C', ('1.4', '6.1', '2.5') ),
GRADES('D', ('5.5', ) ),
GRADES('E', ('2.1', '5.5') )
)
# Data visualization of the tree
self._visualization = self.tree_visualization_show_grades()
@property
def data(self):
"""
:returns: The data source of the tree
:rtype: ``tuple``
"""
return self._data
@data.setter
def data(self, data):
'''
Set the data of the tree
:param data: Data source of the tree
:type data: ``tuple``
'''
self._data = data
self.update_visualization()
def update_visualization(self, condition=False):
'''
Update the data visualization
:param condition: Condition to expand a branch on the tree.
True to show classes that contains students who
passed, False to show classes that contains
students who failed.
:type condition: ``bool``
'''
self._visualization = self.tree_visualization_show_grades(condition)
def tree_visualization_show_grades(self, condition=False):
'''
Tree visualization
:param condition: Condition to expand a branch on the tree.
True to show classes that contains students who
passed, False to show classes that contains
students who failed.
:type condition: ``bool``
:return: Return the data visualization of the Tree.
The dictionary contains items identified with the id of the
node and values that informs its icon's url and a bool that
indicates if the node is collapsed or expanded.
(default is True)
E.g. {node_id : (None, True)}
:rtype: ``dict```
'''
# Icons url and nodes that will be returned
icons, nodes = {'check': 'check.png', 'fail': 'icon.png'}, {}
for item in self.data:
passed, failed = False, False
for grade in item.grade:
# Condition to a student pass in this class
if float(grade) >= 5.0:
icon, passed = icons['check'], True
else:
icon, failed = icons['fail'], True
nodes[id(item)+id(grade)] = (icon, True)
# If the condition to expand the branch is True when there are
# students that has passed in the class (>=5.0) or the condition
# is to expand the tree when there are student that has failed
# (<5.0).
if condition and passed or not condition and failed:
nodes[id(item)] = (None, False)
return nodes
def roots(self):
'''
Top level of the tree
:return: Return the nodes of the top level of the tree.
Each node information is represent with a dictionary that
contains the text of the node, icon's url and a bool that
indicates if the node is collapsed or expanded.
:rtype: ``list`` of ``dict``
'''
final_data = []
for item in self.data:
# Joins the node data according with the current visualization of
# the tree. A root node in this application doesn't have an icon.
if id(item) in self._visualization.keys():
data = {'text': item[0],
'icon': None,
'collapsed': self._visualization[id(item)][1]}
else:
data = item[0]
final_data.append(data)
return final_data
# list of tuples
def search_node(self, text, branch=None):
for item in self.data:
if item[0] == text:
return self._make_data(id(item), item[1])
return []
def _make_data(self, node_id, children):
'''
Joins tha data of a node
:param node_id: Id of the node's parent
:type node_id: ``int``
:param children: Texts of the children of the node's parent
:type children: ``tuple``
:return: Return the information about each child of a node's parent.
Each node information is represent with a tuple that
contains the text of the node, icon's url and a bool that
indicates if the node is collapsed or expanded.
:rtype: ``list`` of ``tuple``
'''
children_data = []
for child in children:
# Adds the node id of the node's parent with the id of the current
# child node, key will be the path of the child
key = node_id+id(child)
# Joins the child node data according with the current
# visualization of the tree
if key in self._visualization.keys():
new_data = (child, self._visualization[key][0],
self._visualization[key][1])
else:
new_data = (child, None, True)
children_data.append(new_data)
return children_data
class TogaDataSource:
'''
Toga Data Source
'''
def __init__(self, data):
'''
Instantiate a new instance of the Toga data source
:param data: Data source and data visualization of the tree
:type data: :class:`TreeStructure`
'''
self._source = data
def roots(self):
'''
Top level of the tree
:return: Return the nodes of the top level of the tree.
Each node information is represent with a dictionary that
contains the text of the node, icon's url and a bool that
indicates if the node is collapsed or expanded
(default is True).
It's possible to pass just a string data instead of the
dictionary if the user don't want to bother with icons
or if a branch of the tree is expanded.
E.g. [{'text': None, 'icon': None, 'collapsed': True}] or
['text']
:rtype: ``list`` of ``dict`` or ``list`` of ``str``
'''
return self._source.roots()
def children(self, node):
'''
Children of the node
:param node: Parent node
:type node: :class:`tree.Node`
:return: Return the information about each child of the node's parent.
Each node information is represent with a dictionary that
contains the text of the node, icon's url and a bool that
indicates if the node is collapsed or expanded
(default is True).
It's possible to pass just a string data instead of the
dictionary if the user don't want to bother with icons
or if a branch of the tree is expanded.
E.g. [{'text': None, 'icon': None, 'collapsed': True}] or
['text']
:rtype: ``list`` of ``dict`` or ``list`` of ``str``
'''
# default data of a node
data = {'text': None,
'icon': None,
'collapsed': True}
# children is a list of tuples that contains text, icon and a bool that
# indicates if the child is collapsed
children = self._source.search_node(node.data['text'])
return [{k : value for (k,v), value in zip(data.items(), child)} for
child in children]
class StartApp(toga.App):
'''
Main Application
'''
def startup(self):
'''
Initial method to start a Toga application inside of a class
'''
# Main window
self.main_window = toga.MainWindow(self.name)
self.main_window.app = self
# Tree structure of this application
self.tree_data = TreeStructure()
# Tree widget from Toga
self.tree = toga.Tree(['Classes and Grades'],
data=TogaDataSource(self.tree_data))
# Button to add a node on the tree
update_tree_node_button = toga.Button('Add F grades',
on_press=self.callbackUpdateNode)
# Button to update the data visualization of the tree and show who has
# passed
update_tree_display_button_pass = toga.Button('Show who passed',
on_press=self.callbackUpdateDisplayPass)
# Button to update the data visualization of the tree and show who has
# failed
update_tree_display_button_fail = toga.Button('Show who failed',
on_press=self.callbackUpdateDisplayFail)
# Widget to control the application using buttons
self.control_box = toga.Box(children=[update_tree_node_button,
update_tree_display_button_pass,
update_tree_display_button_fail])
# Main widget of the application, show both the Ttee data and the
# buttons to control thee application
frame = toga.SplitContainer()
frame.content = [self.tree, self.control_box]
# Add the main widget inside of the main application
self.main_window.content = frame
# Show the application
self.main_window.show()
def callbackUpdateNode(self, event):
# New node to be add on the data source
self.tree_data.data += (GRADES('F', ('0.1', ) ),)
# Update the tree
self.tree.update()
def callbackUpdateDisplayPass(self, event):
# Update the data source visualization
self.tree_data.update_visualization(True)
# Update the tree
self.tree.update()
def callbackUpdateDisplayFail(self, event):
# Update the data source visualization, default is False
self.tree_data.update_visualization()
# Update the tree
self.tree.update()
def main():
# Start the application with the title and the name of the organization
app = StartApp('Test Tree using data source construction',
'org.pybee.test')
app.main_loop()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment