This section details everything you need to get started using ConfigTreeView s. This includes an example of how to use the ConfigTreeView, how to create the config structure and also how to create a custom wrapper to extend its uses to fit your needs and finally how to use the DataFormatter to get your data displayed correctly in the ConfigTreeView.
To use a ConfigTreeView is simple. In your python script there are only a couple steps you need to follow:
- Initialize the ConfigTreeView with a config structure
- Apply the configuration to finish initializing the ConfigTreeView components
Example:
#Import the package from configtreeview import ConfigTreeView #Create the ConfigTreeView my_treeview = ConfigTreeView(config) #where `config` is a python dict config structure you already defined #Apply the configuration to the TreeView to finish initialization my_treeview._apply_config()
As you can see from the example, the API to use a ConfigTreeView is incredibly simple. This is possible because the bulk of the work is done in how you define and build the config structure.
The config structure itself is just a python dict instance that contains the information necessary to build all of the interface components for the ConfigTreeView. For more information on what a config structure should look like, refer to HOW TO: Config File
As an example let’s say we want a very simple treeview that contains two columns that each have a title in their header, and contain a single string as the data source for their respective GtkCellRenderers. The config structure for such a case could look like this:
{ "index_names": { 'column_1': {'markup': str}, 'column_2': {'markup': str} }, "column_order": ["column_1", "column_2"], "columns":{ "column_1":{ "header":{ "title": "Column1" }, "renderers": { "indices":{"markup": True} } }, "column_2":{ "header":{ "title": "Column2" }, "renderers": { "indices":{"markup": True} } } } }
Sometimes it is necessary to create your own implementation of a ConfigTreeView. This section describes the how? and the why?
There are many situations in your interface where you may need to subclass the ConfigTreeView so as to handle something extra that it doesn’t cover. One common situation that has come up in my own experiences has been with needing to know one of the indexes represented in the data model for some dynamic use throughout your application. For example: you would like to change the background color of a cell in the treeview based on a user clicking on it and to do this you need to know which index in a TreeModel row you’re keeping that property. Because of the way the data model is built for use in the ConfigTreeView with the actual indices hidden from the developer, this is not immediately an easy task.
But, fear not, the ConfigTreeView supplies an easy way to get around this. To achieve this, you need to do a few things:
- Pass the index that you want(in dotted-key notation) to the args`(or `kwargs) of the treeview dict within your config structure.
- Create a custom wrapper class that subclasses ConfigTreeView
- Make sure you override the _handle_args function of ConfigTreeView that will be used to assign the args you specified in the config structure to an attribute of your custom ConfigTreeView that you can use.
Example: building on from the above sample of a config structure...let’s add a variable to our config that will be used to change the background of a cellrenderer:
{ "treeview": { #Added a 'treeview' key to supply custom args to our treeview "args": ['$index.bg_color'],#Pass the 'bg_color' index to our custom treeview }, "index_names": { 'bg_color': str,#Define the 'bg_color' variable--we'll make it a variable if we plan on using the same index for multiple renderers 'column_1': {'markup': str}, 'column_2': {'markup': str} }, "column_order": ["column_1", "column_2"], "columns":{ "column_1":{ "header":{ "title": "Column1" }, "renderers": { "indices":{"markup": True} } }, "column_2":{ "header":{ "title": "Column2" }, "renderers": { "indices":{"markup": True} } } } }
And then a corresponding custom treeview implementation would look something like this:
class CustomConfigTV(ConfigTreeView): ''' An example of a custom ConfigTreeView wrapper used to get indices that were defined in the config structure ''' def __init__(self, *args): ConfigTreeView.__init__(self, *args) #Any post-initializing stuff here #This is the place to do stuff *BEFORE* the #columns, renderers, and properties are set self.background_idx = None def _handle_args(self, background_idx): ''' Override this function and set your custom args ''' self.background_idx = background_idx
And now your treeview has an attribute background_idx that will contain the index at which the ‘bg_color’ property you defined in the config will be formatted to.
Now that you’ve created a ConfigTreeView and initialized it with a config structure, you’re ready to start giving it data and using it! In order to get the data properly displayed you need to do a few things:
- Make sure you understand the ConfigTreeView data model and use it to give properly constructed data sets
- Create a DataFormatter object, initializing it with your ConfigTreeView ‘s index_map, and types structures.
- Create a GtkTreeModel to supply your TreeView with data
- Using the DataFormatter to yield formatted rows that can then be appended to your GtkTreeModel
Example(using the config that was defined above):
from configtreeview.tools import DataFormatter data = [ #The DataFormatter is expecting a list of dicts...each dict is a row following the ConfigTreeView Data Model {'column_1': {'markup': 'Some data here'}, 'column_2': {'markup': 'Column 2 data here'}}, {'column_1': {'markup': 'More data col1'}, 'column_2': {'markup': 'Column 2 data here'}}, {'column_1': {'markup': 'Even more data here'}, 'column_2': {'markup': 'Column 2 data here'}}, ] #Create the DataFormatter data_formatter = DataFormatter(my_treeview.index_map, mytreeview.types) #Get a treemodel liststore = my_treeview.get_treemodel() #Use this function to have your treeview build you a proper GtkTreeModel instance my_treeview.set_model(liststore) #Format the data rows for liststore and append them to it for row in data_formatter.get_rows(data): liststore.append(row)
And now the data should be displayed by your treeview!