File downloader
A slightly more complex example, loading our gui from a glade file and dynamically add and remove widgets based on an xml file.
This is the start of a simple file downloader, it reads an xml file and creates a gui dynamically with download buttons for each element in the xml data to retrieve files.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
#!/usr/bin/env python
import os
import requests
from io import StringIO, BytesIO
import subprocess
from lxml.html import parse
from gi.repository import Gtk, GLib, Gdk, GdkPixbuf
class application_gui:
"""Tutorial 13 custom treeview list boxes"""
count = 0
retrieve_job = None
def __init__(self):
#load in our glade interface
xml = Gtk.Builder()
xml.add_from_file('tut13.glade')
#grab our widget using get_object this is the name of the widget from glade, window1 is the default name
self.window = xml.get_object('winFetcher')
#load our widgets from the glade file
self.widgets = {}
self.widgets['listbox'] = xml.get_object('listbox1')
self.widgets['progress'] = xml.get_object('listProgress')
self.widgets['refresh'] = xml.get_object('btnRefresh')
self.widgets['refresh'].connect('button_press_event', self.refresh)
self.widgets['close'] = xml.get_object('btnClose')
self.widgets['close'].connect('button_press_event', self.closeFetcher)
#wrap the listbox so we can reuse the code, pass in the listbox widget to our wrapper class
self.listbox = ListBoxSelect(self.widgets['listbox'])
#connect to events, in this instance just quit our application
self.window.connect('delete_event', Gtk.main_quit)
self.window.connect('destroy', lambda quit: Gtk.main_quit())
#show the window else there is nothing to see :)
self.openFetcher()
self.refresh()
def openFetcher(self):
self.window.show_all()
def refresh(self, *args):
""" get a new xml and start the progress bar"""
self.listbox.clear()
self.widgets['progress'].show()
self.retrieve_job = subprocess.Popen(
['curl', 'file://%s/example.xml' % os.path.abspath('./')],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
GLib.timeout_add_seconds(1, self.update_active_progress_bar)
def update_active_progress_bar(self):
""" move the progress bar, when the subprocess returns handle the xml and hide the progress bar"""
self.widgets['progress'].pulse()
if self.retrieve_job.poll():
return True
self.widgets['progress'].hide()
self.update_list()
return False
def update_list(self):
""" parse the xmland grab the elements we are intrested in"""
nsmap = {'media': 'http://search.yahoo.com/mrss/'}
results = BytesIO(self.retrieve_job.communicate()[0])
doc = parse(results).getroot()
for item in doc.iterfind(".//item", namespaces=nsmap):
title = item.find('title').text
link = item.find('link').tail
description = item.find('description').text
image = item.find('thumbnail', namespaces=nsmap).get('url')
self.listbox.model_append(image, title, description, link)
def download(self):
""" retrieve the xml file in a subprocess using curl """
self.retrieve_job = subprocess.Popen(
['curl', 'file://%s/example.xml' % os.path.abspath('./')],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
def closeFetcher(self, widget):
self.window.hide()
class ListBoxSelect:
""" handle the listbox rows dynamically add and remove widgets, and handle download. """
listbox = None
gui_rows = [] # store widgets here so we can destroy them later.
def __init__(self, listbox):
""" pass in list box to manage and connect event"""
self.listbox = listbox
self.listbox.connect('row-activated', self.selection)
def selection(self, lbox, lbrow):
""" row selected we may want to react here"""
boxrow = lbrow.get_children()[0]
boxinfo = boxrow.get_children()[1]
print(boxinfo.get_children()[1].get_text())
def model_append(self, image, title, description, link):
""" create new widgets, and connect events for our new row"""
items = {}
items['row'] = Gtk.ListBoxRow()
items['vbox'] = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
items['label1'] = Gtk.Label(title, xalign=0)
items['label2'] = Gtk.Label(link, xalign=0)
items['progress'] = Gtk.ProgressBar()
items['progress'].hide()
items['progress'].set_fraction(0)
items['vbox'].pack_start(items['label1'], True, False, 0)
items['vbox'].pack_start(items['label2'], True, False, 0)
items['vbox'].pack_start(items['progress'], False, False, 0)
items['hbox'] = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
items['image'] = Gtk.Image.new_from_file(image)
items['button'] = Gtk.Button(label="Download")
items['button'].connect('button_press_event', self.download, items, link)
items['hbox'].pack_start(items['image'], False, False, 0)
items['hbox'].pack_start(items['vbox'], True, True, 0)
items['button_box'] = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
items['button_box'].pack_end(items['button'], False, False, 0)
items['hbox'].pack_start(items['button_box'], False, False, 0)
items['row'].add(items['hbox'])
self.listbox.add(items['row'])
items['row'].show_all()
self.gui_rows.append(items)
def download(self, widget, args, items, link):
""" download button click, change widgets and start the progress bar and download """
items['button'].hide()
items['job'] = subprocess.Popen(
['curl', '-O', link],
shell=False,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
GLib.timeout_add_seconds(1, self.update_active_progress_bar, items)
def update_active_progress_bar(self, widgets):
""" update progress bar until command finished """
widgets['progress'].pulse()
if widgets['job'].poll():
return True
widgets['progress'].hide()
return False
def clear(self):
""" remove all rows so we can pre-populate"""
for item in self.gui_rows:
item['row'].destroy()
self.gui_rows = []
application = application_gui()
Gtk.main()
|