Tutorial - Python Scripting For XBMC
Tutorial - Python Scripting For XBMC
Youll notice a second level of indentation following the if statement. In Python, indentation describes
all blocks and sub-blocks.
Everything is an object. This aspect of the language is very nice sometimes, but it can be tricky for
beginners! Just remember that, in Python, everything is an object. As you get further into scripting,
youll learn the full implications of this fact.
When assigned, a variable is considered local unless you declare it global. This rule comes up often,
although its not covered within the scope of this tutorial. Still, its a helpful fact to know, especially
when you start reading through other peoples scripts.
The goal of this document is not to teach Python, though, but to teach you how to write Python for the
XBox. So instead of going into further detail here, we recommend that you read the fine documentation
available on www.python.org.
After that, we need to create a class (defined by the keyword "class") that will include some of its own
functions (defined by the keyword def)
class MyClass(xbmcgui.Window):
print "hello world"
MyClass is now set up to act like a Window (as described in the xbmcgui library). Once weve defined
the class, we need to initialize the class object (that is, create an instance of it) and then run the librarys
function doModal, which causes the graphical window to continue displaying on the screen until we
close it.
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
Note: The final command del is here for garbage collection; it keeps our code clean by deleting the
class instance that we created.
Now, put all of this code, in order, into a script, and call it display.py. It should look like this:
import xbmc, xbmcgui
class MyClass(xbmcgui.Window):
print "hello world"
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
(All we did was combine the lines above, to make it easier to read.)
Now, to test your script, you need to copy it to your XBox. We recommend you go to your XBMC
installation folder, then find the scripts subfolder, and create a folder called Tutorial within scripts.
Now copy your new display.py script to that folder, as well as the background.gif image that should
have come attached to this document. (If you dont have it, dont worry. Its a very simple 720 x 480
image and you can easily make your own. Well use it later in this text.)
Once youve got the script in place, you can run it through XBMC, using the script launcher (as
described above). When you run it, all you'll see is an empty window, which is the same window you
3
The first line is a commentcomments in Python are preceded by "#"which means it acts as a note to
the programmer, but doesn't actually do anything when the script is run. This one is telling you where
we found out that the number 10 is what you get when someone pushes the "Back" button on the XBox
controller.
Now you have to write a function that will use this information. Inside the MyClass block (where the
print statement used to be), add this function:
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
Once you've added that, you've got a script that can respond to controller actions. You've also now
written an "Exit" option into your script, so users can exit it.
Heres what the full code should look like:
import xbmc, xbmcgui
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
class MyClass(xbmcgui.Window):
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
You can see we've only really added four lines to the script, but now it's interactive! Oh, sure, it doesn't
do much, but it's a beginning. Now, each time we push the "Back" button, we will exit the class and
(therefore) the script.
There is a reason we have to write three lines just to create a single line of text on the screen, but that
will become more obvious as we get further into the tutorial. For now, think of it like this: First we tell
the program what the Control is going to look like (with the xbmcgui.ControlLabel function, and all of
its parameters), then we tell the program to make that control (with the addControl function), and then
we tell the Control what to do (in this case, display the line "BACK to quit").
So, when we start by describing the control, we pass it a bunch of numbers, and a couple of strings.
These define the Control object's position, size, and unique characteristics. In this example, we have:
300 is the control's X position on the screen
520 is the control's Y position on the screen
200, 200 is supposed to be size of the element (but it seems to not work with text)
"" is an empty string that can be used to set an initial label text, but we are setting the label later.
"font14" is the font used for this control's text, (the fonts available vary by skin)
The final element is "0xFFFFFF00" this value may look familiar to you. It represents the colour value
and transparency of the label's font, coded in hexadecimal (from 00 to FF). So read this as
0xTTRRGGBB where T is the transparency value, R is red, G is green and as you guessed B is blue.
When we add text to the label, it will show up on the screen in the color defined by this value.
Now we have a working script that could include a label telling us how to use its controls (well...just one
control, really, but who's counting?). Instead, let's build a slightly different label and associate it with the
A button of the keypad, for more practice. First, add this line near the top of your script:
ACTION_SELECT_ITEM = 7
We used a similar line earlier to identify when the user pushed the "Back" buttonthat was 10and now
we're using this one to get the "A" button, which is a value of 7.
Now, as you remember from the last segment, the way we use these values is in the special function
onAction, by telling the script how to respond when XBMC tells us the "A" button was pushed. So we
add this "if" statement to the onAction function we already have:
Once you add these lines to the script, it will show your new label whenever the "A" button is pressed.
The whole script should look like this:
import xbmc, xbmcgui
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
ACTION_SELECT_ITEM = 7
class MyClass(xbmcgui.Window):
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
if action == ACTION_SELECT_ITEM:
self.strAction = xbmcgui.ControlLabel(300, 200, 200, 200, "", "font14", "0xFF00FF00")
self.addControl(self.strAction)
self.strAction.setLabel("Hello world")
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
Copy this script to your XBox and run it. Try pressing the "A" button and see what happens. Don't
forget you have to push "Back" to stop the script!
Control Objects - Removing a Text Label
In xbmcgui.py you get a handful of widgets that are called Control objectsthese are the Button,
Image, Label, FadeLabel, List, and TextBox). All Control objects share certain characteristics. Control
object are GUI devices that are drawn over the window, and theyre the main tools youll use to interact
with the script. As mentioned in the previous segment, you initialize Control objects with a function call
(for instance: self.strAction = xbmcgui.ControlLabel(300, 200, 200, 200, "", "font14", "0xFF00FF00")), and then tell
xbmc to draw them with the addControl function.
Well, we can also tell xbmc to stop drawing any Control, which will remove it from the display. To do
this, use the function removeControl.
Lets stick with the same script, but add another option: pressing the "B" button will remove the Label
that was created when you pressed "A". To do that, you have to recognize the "B" button:
ACTION_PARENT_DIR = 9
When youve add these three lines, you should have a working script. The whole script should look
like this:
Now you can press "A" while the script is running to see how a FadeLabels reset() function works. You
should also have a pretty good idea by now how the special onAction function works. Also, youll
notice we no longer have an "if action ==" statement looking for the "B" button, so you can remove that
line from the declaration of globals up above.
When you do all that, the whole script should look like this:
import xbmc, xbmcgui
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
ACTION_SELECT_ITEM = 7
class MyClass(xbmcgui.Window):
def __init__(self):
self.strActionInfo = xbmcgui.ControlLabel(100, 120, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit - A to reset text")
self.strActionFade = xbmcgui.ControlFadeLabel(200, 300, 200, 200, "font13", "0xFFFFFF00")
self.addControl(self.strActionFade)
self.strActionFade.addLabel("This is a fade label")
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
if action == ACTION_SELECT_ITEM:
self.strActionFade.reset()
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
Try it on the XBox and see what happens. Press the "A" button while youre at it. Now try changing the
text of the FadeLabel to something longer, such as "Behold, here you see before you the first and only
almighty FadeLabel of Doom which I, in my Pythonic coolness, have created by my very will."
8
Now, as the very first line of your __init__ function, add this line:
if Emulating: xbmcgui.Window.__init__(self)
Thats all it takes. What this does, is tell the script to call the Emulators __init__ function, too
(the one replaced by your classs __init__ function), before going on with running. Of course, if
youre running the script on the XBox, it will just skip right past and do nothing.
For the sake of those of you using the Emulator in future development, Im going to include these
necessary lines in all of the rest of the tutorial scripts. Note that the Emulator has been developed
in the time since Alex first wrote this tutorial, and so these extra lines arent part of the original
tutorial. However, they wont in any way interfere with the scripts function on the XBox, so I
see no harm in including them.
Alexpoet.
Setting up Default Parameters in the Init Function
We already talked some in the last segment about the __init__ function. As we said before, the __init__
function is one that Python automatically runs whenever the class "MyClass" is launched. This is an
extremely useful tool for adding elements that we need when the script is first initialized, particularly for
adding basic GUI items, such as a background image or text instructions that need to be on screen all the
time.
To add these automatic elements, we use the __init__ function, as youve already seen. Lets change the
__init__ function from our last script slightly. Well remove the FadeLabel (now that you know all
about them), and have the instructional Label say something different:
self.strActionInfo = xbmcgui.ControlLabel(100, 120, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit, A to display text and B to erase it")
(Were also adding two more linesone up above with the globals, and one in the __init__ functions
that will make the PC Emulator scripts work. For details, read the Sidenote above.)
That might look strange to you, because were doing a lot here in one line. You see we start off with the
function self.addControl, and inside the parentheses, instead of giving it the name of a Control object,
we create the Control object right there. When you add a Control in one line like this, it has no name,
and so theres no way to modify it later. Thats why we use three lines to add (and name) a Label, and
then modify the Labels text. With a background picture, though, you only show it once, and then leave
it unchanged until the script closes.
You could just as well have written this script as two lines:
pic = xbmcgui.ControlImage(0,0,720,480, "background.gif")
self.addControl(pic)
Either way, it does the same thing, but for Controls youre only drawing and then leaving alone, its
often cleaner to just add them in one line.
But that brings up another issue: where in the __init__ function do we place that line? Its a very
important question, and you need to remember to draw the background image before the text, that way
the image will be drawn, and then the text placed over the image. If we changed that order, the text
would appear behind the image, so the user would never see it.
Now, for this to work youll have to have an image file by the name of "background.gif" (or, of course,
you could replace the filename in the script with the name of a file you have). This tutorial might have
come zipped up with a background.gif image, but if not you can create a very simple background just by
making a picture 800 pixels by 600 pixels, and saving it with that filename.
Youll have to play with the background colour some to find one that clearly shows the font colour, and
still looks good on screen. [Alexpoet's note: Of course, you might end up spending a lot of time doing
that once you start developing scripts anyway. I sometimes find myself spending twice as long in
Photoshop trying to get good support pics as I spend actually writing these scripts.]
NOTE:
When you enter the filename in the xbmcgui.ControlImage function, you can enter just a filename
(and Python will look for the file in the same folder as the script youre running), or you can enter
a path. Remember that when youre entering directory paths in Python, you always have to replace
"\" with "\\", because Python uses "\" to describe special characters.
So now we know how to build our __init__ function, lets put it into use. Everything else should be
simple stuff that you know how to do by now. Put back in the line for recognizing the "B" button, and
then change the onAction to draw a friendly message whenever you press "A", then delete it on "B".
Try to write this yourself. If youre having trouble, feel free to look ahead, but this is all stuff weve
covered before. When youre done, the whole script should look like this:
10
You can see first we create the dialog instance, and then we make the type in a separate line. You would
do the same thing if you were creating a "select" box or a "yesno". They all begin with the line: dialog =
xbmcgui.Dialog().
Now we need to build a function that will make the dialog box appear. To do this, change your onAction
function to include these lines:
if action == ACTION_SELECT_ITEM:
self.message()
You can also strip out the onAction command for ACTION_PARENT_DIR, since we're not using the
"B" button in this script.
Be sure to change the instructions in strActionInfo in your __init__ function, and that's all there is to it.
The whole script should look like this:
11
That's the code from our last segment. You can see the first line tells xbmcgui to create an instance of a
Dialog class. The second line creates the actual "ok" dialog, and passes it two strings: one for the title,
and one for the box's message.
Once you know how the Dialog Boxes work, they're a very simple way of providing information to the
user. Let's rewrite our script to use the same message function in a more general way:
First, change the dialog creation code to look like this:
def message(self, messageText):
dialog = xbmcgui.Dialog()
dialog.ok(" My message title", messageText)
Notice the difference. In the third line, we're not passing two strings, but a string and a variable. Of
course, that variable (messageText) must contain a string, or it will break the script when run. But
messageText is passed in as one of the parameters of the message function.
Which means we have to change the place where the message function is called, up in onAction:
12
Compare this onAction with the onAction code from our last segment. We're no longer just calling the
function, but passing it a string (which is, basically, the message). So now you know how to call a
function inside another function :)
This time we can leave the action globals alone, as well as the strActionInfo instructions. Nothing
changes except the way the script runs, and what it outputs. So the whole script should look like this:
import xbmc, xbmcgui
try: Emulating = xbmcgui.Emulating
except: Emulating = False
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
ACTION_SELECT_ITEM = 7
class MyClass(xbmcgui.Window):
def __init__(self):
if Emulating: xbmcgui.Window.__init__(self)
self.addControl(xbmcgui.ControlImage(0,0,720,480, "Q:\\scripts\\Tutorial\\background.gif"))
self.strActionInfo = xbmcgui.ControlLabel(100, 200, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit or A to display dialog box")
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.message("Goodbye")
self.close()
if action == ACTION_SELECT_ITEM:
self.message("You pushed A")
def message(self, messageText):
dialog = xbmcgui.Dialog()
dialog.ok("My message title", messageText)
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
This would be a helpful script to change around some on your own, to make sure you know how everything
works. Maybe try to write a script that will pop-up a dialog box telling you which button you pressed.
Be careful with the message function, though. Make sure the only values you pass to it are strings. Ints and
floats can be converted to strings explicitly (ie: number = str(num)), but you can't feed the script a non-string
value when it expects a string. It'll throw an error (and on the XBox, that almost certainly means a lock-up).
The only exception to this is Python's built-in print function. print num or print str(num) will work equally
well, but that's designed for debugging output. For any other function that expects a string, passing it
ints or floats won't work without an explicit conversion!
13
We type:
def goodbye(self):
dialog = xbmcgui.Dialog()
if dialog.yesno("message", "do you want to leave?"):
self.close()
You can see the line creating the yesno dialog begins with "if" and ends with a ":". This is the same as
saying "if dialog.yesno("message", "do you want to leave?") == True:". The line that follows (which, you can
see, is indented another level) will only run if the user selects "Yes" from the dialog box.
Now set up onAction to call this function instead of self.close() when the "Back" button is pressed.
That's really all that needs changing. To keep things clear, let's remove the onAction for the "A" button,
and rewrite our strActionInfo instructions. Three cheers for minimalism.
The whole script should look like this:
import xbmc, xbmcgui
try: Emulating = xbmcgui.Emulating
except: Emulating = False
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
class MyClass(xbmcgui.Window):
def __init__(self):
if Emulating: xbmcgui.Window.__init__(self)
self.addControl(xbmcgui.ControlImage(0,0,720,480, "Q:\\scripts\\Tutorial\\background.gif"))
self.strActionInfo = xbmcgui.ControlLabel(100, 200, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit.")
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.goodbye()
def goodbye(self):
dialog = xbmcgui.Dialog()
if dialog.yesno("Message", "Do you want to leave?"):
self.close()
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
There we have a list of strings, the creation of a Dialog instance, and then the dialog.select() call which
will return the user-selected value (and save it in the variable choice). We can replace the goodbye
function with this one.
Here's where the "select" box gets a little tricky, though. The value that it returns is not the selected
item; it's the list index of the selected item. That means, if we ran the code above, and the user selected
"Yes," then choice would be equal to 0, not the word "Yes". (In Python, as in most programming
languages, counting begins at 0, so the first item in the list is 0, and the fifth item in a list is 4 you'll get
used to it in time).
If you're familiar with lists and list indexes and not too worried about getting confused by this one, then
skip to the whole script at the end of this segment, read through it, and try it on the XBox. But I'm going
to take a moment here and explain in greater detail.
Okay...to make things more clear, let's add another Label to our script, so we can see the value of our
variable choice. We'll put it up in the __init__ function, then set its value right in the chooseOne
function. To begin with, it will be empty, but when a user selects one of the items from the dialog, it will
show the value returned.
So up in the script's __init__, add:
self.choiceLabel = xbmcgui.ControlLabel(300, 300, 100, 100, "", "font13", "0xFFFF00FF")
self.addControl(self.choiceLabel)
And then add the label's output line at the end of the chooseOne function:
self.choiceLabel.setLabel("Choice: " + str(choice))
That's all we need to use a "select" box and see the returned value, but we've got to change the onAction
to make it work. Add ACTION_SELECT_ITEM back into the globals, and change onAction to look
like this:
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
if action == ACTION_SELECT_ITEM:
self.chooseOne()
We're not finished yet, this is just for demonstration, but if you put the whole script together, it would
look like this:
15
Try this out on your XBox. When you select "Yes" in the dialog, the output says "0" (just like I said it
would :-). That's how a select dialog works.
It's not a hard problem to fix, though. Whenever you make a "select" dialog, you already have the list
available, and the list index tells you where to find the item in the list (that's the whole point).
So let's change the third line in chooseOne to say:
ndex = dialog.select("Do you think this will work?", possibleChoices)
Now run the script again, and see what the label says. It should print out exactly what you selected from
the list. You can also remove the "str(choice)" from the line after that (so its just choice), because the
variable choice is now already set to a string (when it was a list index, it was an integer).
The whole script should look like this:
16
As you can see, setFocus is the function that does it. When you add more than one button to a script,
youll only need to setFocus on one of them (whichever you want to start out selected), but get in the
habit of setting the focus at least once per script, if youre using any buttons at all.
Now that youve got a button built, you have to tell the script what to do when the button is activated. A
GUI Button is activated by pressing A on the controller when a Button (or other usable Control
Object, like a List) is selected.
17
And thats a working Button, with working events already triggered! The whole script should look like this:
import xbmc, xbmcgui
try: Emulating = xbmcgui.Emulating
except: Emulating = False
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
class MyClass(xbmcgui.Window):
def __init__(self):
if Emulating: xbmcgui.Window.__init__(self)
self.addControl(xbmcgui.ControlImage(0,0,720,480, "Q:\\scripts\\Tutorial\\background.gif"))
self.strActionInfo = xbmcgui.ControlLabel(100, 200, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit. Push the button if you absolutely must.")
self.button0 = xbmcgui.ControlButton(350, 400, 80, 30, "Push Me!")
self.addControl(self.button0)
self.setFocus(self.button0)
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
def onControl(self, control):
if control == self.button0:
self.message("You pushed the button.")
def message(self, messageText):
dialog = xbmcgui.Dialog()
dialog.ok(" My message title", messageText)
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
Note that you can also remove the button from the screen using removeControl:
self.removeControl(self.button0)
18
This tells the script that the button to the right of ButtonLeft is ButtonRight. Makes sense. You could
even make it circular, so if you go right to select ButtonRight, and then move off-screen to the right, itll
come back around to ButtonLeft. Thatd look like this:
ButtonLeft.controlRight(ButtonRight)
ButtonLeft.controlLeft(ButtonRight)
ButtonRight.controlRight(ButtonLeft)
ButtonRight.controlLeft(ButtonLeft)
You probably wouldnt bother with that, though. Mostly youre only going to set up the least you have
to that will still allow users to move around your script. But it helps to think through everything you
could do. Also, try to always make associations that make sense graphically on the page. Dont use
controlUp to get to a Control directly to your right, unless it somehow makes sense in your script.
Okay, so far these are general examples, but weve explained what really goes into making it work. And
nothing else in this segment is particularly new, so well skip straight to the end. The whole script
should look like this:
19
You can see we added all three Buttons in the __init__ function, and then used setFocus just once to start
out with button0 selected. Then we added the associations to allow users to switch which Button was
selected. And finally we adjusted onControl to make sure it had something to do for any Button pushed.
20
I dont think youll have any trouble guessing what this does. The text strings passed to self.list.addItem
will appear in the List in the same order theyre added in the script. Of course, you could add these items
to a Python list, and then use a Python for loop to add them all, like this:
self.list = xbmcgui.ControlList(200, 150, 300, 300)
self.addControl(self.list)
items = ["Item 1", "Item 2", "Item 3"]
for item in items:
self.list.addItem(item)
self.setFocus(self.list)
If youre familiar with Python, that will be familiar to you. Of course, if youre familiar with Python,
youd probably already figured that out. If that last set of code doesnt make sense to you, dont worry
about it. Well go ahead and introduce the items one at a time in our official script. But when you get
into more advanced scripting, youll find that most ListItems are added out of a Python list.
So, now weve got a List containing three different items. A List, like a Button, is a usable Control. Any
time a List has focus and the user presses A, XBMC calls the scripts onControl function, and passes it
the List. Its important to realize that onControl is given the List instance that contains the selected
ListItemit isnt handed the actual item selected from the List. We have to get that ourselves.
To do that, we use a pair of functions: getSelectedItem and getLabel. First, lets get the script ready. Pull
all of the buttons out of the __init__ and add in our new List (as described above). You can use either of
the methods I typed out, they both do the same thing.
And now that we dont have any Buttons, get rid of your old onControl. Heres where we use
getSelectedItem and getLabel. Use this for your new onControl:
def onControl(self, control):
if control == self.list:
item = self.list.getSelectedItem()
self.message("You selected : " + item.getLabel())
You can see that we first use getSelectedItem to find out which ListItem within the list is selected (a
ListItem is a separate class, its not just a text string), and then we use the ListItems getLable function to
find out what the string is. Thats most all you need to know, at least for now. Lets see this thing in action.
The whole script should look like this:
21
Thats really all you need to know about the Dialog Boxes and Control Objects, the basic widgets of the
xbmcgui library. Theres still a lot to teach, though. The next segment will teach you how to get more direct
user feedback, using a built-in virtual keyboard. The segments following that will walk you through the
process of getting information about the XBox from XBMC. Finally, well show you some more advanced
tools such as child windows and non-XBMC uses for scripts, like a simple internet file downloader.
Using the Virtual Keyboard
Before we get into the complicated stuff, though, lets do the easy one. XBMC provides a very basic but
surprisingly versatile virtual keyboard. You can call it from any script that imports the xbmc library, and
your script can get not only what text the user entered, but whether or not the keyboard was canceled.
Your script can also provide default text to the keyboard, to save the user time.
The basic keyboard call is very simple, and requires a doModal command to make it appear (just like an
xbmcgui.Window). In your display.py script, remove all the List stuff, including the onControl function.
22
Now add in the keyboard itself. These two lines make the keyboard (and provide it with a default text).
keyboard = xbmc.Keyboard("Entered Text")
keyboard.doModal()
After calling doModal, your script will sit and wait for the user to finish with the keyboard. They can
finish by typing in new text (or accepting the default) and pressing Y to confirm, or by pressing B to
cancel. Either way, the script will continue, so the first thing we do is add an if statement to make sure
the keyboards text is legitimate user input.
if (keyboard.isConfirmed()):
self.outputLabel.setLabel(keyboard.getText())
You can see we used the keyboards function getText to find out what the entered value was, once we
knew it was legitimate. And now lets add an else just so well know what counts as an accept, and
whats a cancel:
else:
self.outputLabel.setLabel("User Canceled")
Now, the way this script works, it will print to the outputLabel any text entered at the keyboard, unless
the user cancels the keyboard, in which case it will say so. This script is very simple, but a keyboards
really not hard to use. Once you know how to do it at all, you pretty much know how to do it all, see?
The whole script should look like this:
import xbmc, xbmcgui
try: Emulating = xbmcgui.Emulating
except: Emulating = False
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
class MyClass(xbmcgui.Window):
def __init__(self):
if Emulating: xbmcgui.Window.__init__(self)
self.addControl(xbmcgui.ControlImage(0,0,720,480, "Q:\\scripts\\Tutorial\\background.gif"))
self.strActionInfo = xbmcgui.ControlLabel(100, 200, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit.")
self.outputLabel = xbmcgui.ControlLabel(100, 300, 200, 200, "", "font13", "0xFFFFFFFF")
self.addControl(self.outputLabel)
keyboard = xbmc.Keyboard("Entered Text")
keyboard.doModal()
if (keyboard.isConfirmed()):
self.outputLabel.setLabel(keyboard.getText())
else:
self.outputLabel.setLabel("User Canceled")
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
23
24
You can see in the last two lines we converted the integer values to strings, so we can display them in
Labels. Now just add a couple of Labels showing the information weve gotten.
The whole script might look like this:
import xbmc, xbmcgui
try: Emulating = xbmcgui.Emulating
except: Emulating = False
#get actioncodes from keymap.xml
ACTION_PREVIOUS_MENU = 10
class MyClass(xbmcgui.Window):
def __init__(self):
if Emulating: xbmcgui.Window.__init__(self)
self.addControl(xbmcgui.ControlImage(0,0,720,480, "Q:\\scripts\\Tutorial\\background.gif"))
self.strActionInfo = xbmcgui.ControlLabel(100, 200, 200, 200, "", "font13", "0xFFFF00FF")
self.addControl(self.strActionInfo)
self.strActionInfo.setLabel("Push BACK to quit")
screenX = self.getWidth()
screenY = self.getHeight()
strscreenX = str(screenX)
strscreenY = str(screenY)
self.widthInfo = xbmcgui.ControlLabel(100, 300, 200, 200, "", "font13", "0xFFFFFFFF")
self.addControl(self. widthInfo)
self. widthInfo.setLabel("screen width is " + strscreenX)
self.heightInfo = xbmcgui.ControlLabel(100, 400, 200, 150, "", "font13", "0xFFFFFFFF")
self.addControl(self. heightInfo)
self. heightInfo.setLabel("screen height is " + strscreenY)
def onAction(self, action):
if action == ACTION_PREVIOUS_MENU:
self.close()
mydisplay = MyClass()
mydisplay.doModal()
del mydisplay
Of course, telling a user how wide his screen is isnt going to help him out much. These functions are
most useful when determining how youre going to layout the GUI. You might use them at the very
beginning of your script, as something like:
screenX = self.getWidth()
if screenX <= 720:
background = Q:\\scripts\\Tutorial\\small_background.gif
standardFont = font12
elif screenX <= 1280:
background = Q:\\scripts\\Tutorial\\medium_background.gif
standardFont = font14
else:
background = Q:\\scripts\\Tutorial\\large_background.gif
standardFont = font16
25
You can also get certain specific information, like the XBMC skin currently in use:
myskin = xbmc.getSkinDir()
This information can be important, because different skins have different font sizes, different graphics
available, and different screen placement of buttons and other GUI items.
Just like the screen size above, this information is really only useful when you build scripts that will
react to their environment, displaying properly no matter whose XBox theyre running on. It would take
too long to explain all the ways these items can be put to use, though, so were just going to show you
how to get the information, and for now (just as an example), well also display it on the screen.
26
Well add that line to the bottom of our script, after creating the class (mydisplay = MyClass()), but before
we ever tell it to show up on the screen (mydisplay.doModal()). That way the class will be created, the
__init__ will run (and will only make one Label to appear on the screen), and then after that the
localInfo() function will run, drawing two additional Labels. Then the doModal call will make the screen
appear, showing us all thee Labels.
Does that make sense? It doesnt have towere here to learn how to get information language
information using xbmc.getLocalizedString. We just added this functionality so you can get a glimpse at
another way to make Python do what you want it to do. You could always write this the same way
youve been doing, though, putting the information checks as well as the Label constructors directly in
the __init__ function.
So theres no reason to panic if all that talk before didnt make any sense. But you might go ahead and
read through it one more time, just to see if you can gain anything from it. The more you learn about
Pythonand all the ways you can make it workthe better your final scripts will be.
Now, weve already discussed our basic plan for the script, so lets put it into code. First, write a
localInfo function within MyClass that gets two different text strings out of your XML language file and
displays them in a single Label. Then add another label that tells us the name of your XBMC skin.
Heres a copy of the function:
def localInfo(self):
localtxt1 = xbmc.getLocalizedString(10000)
localtxt2 = xbmc.getLocalizedString(10004)
self.strLanguageInfo = xbmcgui.ControlLabel(100, 300, 200, 200, "", "font13", "0xFFFFFFFF")
self.addControl(self.strLanguageInfo)
self.strLanguageInfo.setLabel("Text using your xml language file: " + localtxt1 + " , " + localtxt2)
myskin = xbmc.getSkinDir()
self.strSkinInfo = xbmcgui.ControlLabel(100, 400, 200, 150, "", "font13", "0xFFFFFFFF")
self.addControl(self.strSkinInfo)
self.strSkinInfo.setLabel("Your skin dir is : /skin/" + myskin)
You can see we added /skin/ to our output on the SkinInfo Label. We did that because getSkinDir only
returns the name of the skins folder, not the path from the XBMC root installation. We know that
XBMC skins are supposed to be stored in the /skin/ subfolder, though, so we add that to the output
Label to make the information clearer to our users.
Now all thats left is to add the function call at the bottom of our script, like we described above. The
whole script should look like this:
27
When you test this on your XBox, you should see the Text using your XML language file: Label and
then two words shown in your language of choice. And the Label at the bottom should accurately
display the script youre currently using.
Its easy to test the second one; just change your skin and then run the script again (at the time Im writing
this, apparently only Symbol and Project Mayhem will run scripts). Youd have to be brave (or bilingual)
to test the other, but I managed it. Go into your XBMC settings, change the language, and then reboot if
necessary. Now go into your scripts folder (I had to do it by memory, but Ive spent a lot of time launching
scripts so it wasnt hard), run display.py, and youll see the same words in the new language!
To get the most out of this function, youll need to learn the Language file, and which words and
phrases are available across languages. Because XBMC is set up like this, its possible to write one
script that will work smoothly in multiple languagebut its a lot of work. Youll have to decide just
how much you want to support international versions of your scripts. At least now you know how to use
the tools, in case you do decide to put in the effort.
Getting Language, IP Address, DVD State, Available Memory, and CPU Temperature
These functions were my first attempt to extend the XBMC Python library and Im pretty proud of the
result. You can use getLanguage, getIPAddress, getDVDState, getFreeMem, and getCpuTemp to access
these data (all of which provide popular information to display on skins).
28
29
30
Then go on with your __init__ as normal. Change the strActionInfo Label to tell the user the new rules:
Push Back to quit, or A to open another window. Lets also throw in another Label just to let the
user know that the window hes looking at is the parent (or main) window.
Now well modify onAction to handle the A button. Add these three lines:
if action == ACTION_SELECT_ITEM:
popup = ChildClass()
popup.doModal()
del popup
And that should look very familiar. Its the same three lines you have had at the bottom of almost every
script, although weve changed the variable name, and here were calling a different class (but one that
does almost exactly the same thing).
Can you guess what that class is going to look like? All we want it to do is tell the user to push Back
to get rid of this window, and show another label making sure you know that this is the child window.
Oh, and have it go away when you push Back. Thats all stuff youve known how to do ever since
page four. Try writing out the child class yourself. Ill give you the declaration line (which should be all
the way over to the left of the page):
class ChildClass(xbmcgui.Window):
31
Thats it. Run it on your XBox and see what it does. At this point, you know everything it takes to make
an interactive Python script for your XBox. You can control it, you can access information on the XBox
and you know all about how to provide that information to the user. Of course, so far everything weve
talked about is how to use the XBMC libraries. But those libraries only exist to allow us to do other
thingscooler things. In the final segment well just touch on how youll go about putting this
information to use.
32
33
http://www.xboxmediaplayer.de/cgi-bin/forums/ikonboard.pl
http://forums.xbox-scene.com/index.php?showforum=62
http://dwl.xboxmediacenter.de/
http://www.gueux.net/xbmc-scripts/index.html
http://members.cox.net/alexpoet/downloads/
alx5962@yahoo.com
script_request@cox.net
34