learning about qtile widgets via the medium of cricket
I’m a person who has spent an unreasonable amount of time making minute changes to the appearance of my bar in qtile. Despite the very nice selection of widgets availabe by default with qtile, it was only a matter of time before I decided I wanted to experiment with making my own custom widget. Fortunately, if you can do a bit of python this is quite an approachable undertaking.
The dream widget I was lacking was a little live crikcet score ticker type thing; something which would scroll along on my bar showing me the score in live cricket matches. I’m sure this will interest very few people but I learnt some good stuff along the way.
Hello World?!
As far as I can tell from looking at the code for some of the built-in widgets and this very helpful guide, a basic hello world widget would look something like this.
from libqtile.widget import base
class HelloWorld(base._TextBox):
def __init__(self, **config):
super().__init__("", **config)
self.text = 'Hello world!'
Qtile provides a selection of base widget classes to do various useful things. This example uses the simple _TextBox
which displays the content of the self.text
property.
Hello World Version 2
Very nice, but for the cricket widget we’ll need something which lets us update the text. The answer is ThreadPoolText
. This class lets you periodically update the text by overridding its poll
method with a function that returns the updated text.
This example updates itself with hello world in a different language every five seconds.
import random
class HolaMundo(base.ThreadPoolText):
defaults = [
("update_interval", 5, "Update interval for the widget"),
]
def __init__(self, **config):
super().__init__("", **config)
self.add_defaults(HolaMundo.defaults)
def poll(self):
messages = [
'Hola mundo',
'Ciao mondo',
'مرحبا بالعالم',
'Saluton Mondo',
'Sawubona Mhlaba'
]
return random.choice(messages)
Along with the whole poll thing, this example also introduces defaults
. This is a list of tuples which define parameters that the user can configure. Here we’ve added update_interval
which defines how often the widget is updated.
Cricket Scores
For getting the cricket scores we’ll be using a handy rss feed from cricinfo so no brute force scraping will be required, just my beloved feedparser. This doesn’t involve anything directly widget related, just massaging the rss feed into something that would look useful on your bar. Anyway, this is what the finished item looked like.
from libqtile.widget import base
import feedparser
class CricketScores(base.ThreadPoolText):
defaults = [
("update_interval", 60, "Update interval for the cricket scores widget"),
("teams",[],"Teams to display scores for"),
("separator"," \U0001F3CF ","Text to place between scores"),
("no_scores_string","","Text to show when there are no scores to show"),
]
def __init__(self, **config):
super().__init__("", **config)
self.add_defaults(CricketScores.defaults)
def get_scores(self):
# parse rss feed and get
# live matches from title field
feed = feedparser.parse("http://static.cricinfo.com/rss/livescores.xml")
scores = []
for match in feed.entries:
# filter live matches
if "*" in match.title:
scores.append(match.title)
# remove scores not involving chosen teams
filtered_scores = []
for score in scores:
for team in self.teams:
if team in score:
filtered_scores.append(score)
# if no scores, show no_scores_string
if len(filtered_scores) == 0:
return self.no_scores_string
else:
# form pretty string with separators
final_scores = ""
for score in filtered_scores:
if score != filtered_scores[-1]:
final_scores += score + self.separator
else:
final_scores += score
return final_scores
def poll(self):
return get_scores()
Actaully Using It In Your Config
Assuming you have a my_widget.py
file in the same directory as your config.py
, you simply have to import it and add it your list of widgets.
from my_widget import LovelyWidget
screens = [
Screen(
top = bar.Bar(
widgets = [
LovelyWidget(),
widget.GroupBox(),
]
)
)
]
Happy widget writing.