Welcome to Part 3 of the basics of DesktopX
by CerebroJD
Time for part three, assuming you read through and understood part one and part two of the series.
In this tutorial, we're going to get a little complex. First, we're going to use the XmlHttp object to retrieve the contents of an xml file from the internet, then we're going to take that data, and break it down into parts that we can work with individually to make an RSS feed reader. Everyone assumes this is hard simply because of the immense load of data that can be obtained. However, in most RSS feeds, there are only 5 tags to be concerned about. They are as follows: item, title, link, description and pubDate. However, the first thing we're going to do is create a script to grab the entire contents of the xml file, and display them. To do this, simply create a new text object and call it RSSCode and then enter this script:
'Called when the script is executed
Sub Object_OnScriptEnter
GetCode
Object.SetTimer 31, 10000
End Sub
Sub Object_OnTimer31
GetCode
End Sub
Function GetCode
'Creates an instance of Microsoft.XmlHttp
Set http = CreateObject("Microsoft.XmlHttp")
'Sets the URL to download
url = "http://digg.com/rss/CerebroJD/index2.xml"
'Retrieves data
http.Open "GET", url, False
http.send ""
'Assigns the text to this object
Object.Text = http.responseText
End Function
'Called when the script is terminated
Sub Object_OnScriptExit
Object.KillTimer 31
End Sub
Once you apply the changes to that object, you'll see that you've got a freakin huge text object listing the entire contents of the xml code. Scary thing, but dont worry about it, since mostly we're just going to be using it for reference for the other code. We're going to be using alot of string parsing functions that can be found here.
Now, its time to snag the first 'item' from the feed. Its actually way easier than you'd think, since we've got these insanely handy string functions. We're going to be using the InStr and Mid commands for this first bit. The InStr command works by returning the location of the first instance of a search string from within a string, starting at a specified location. Example: InStr(1,"This is a test", "a") will return 9. We can use this to our advantage, since Mid returns the contents of a string from the designated start point for a certain length, like this: Mid("This is a test", 4, 7) will return " is a t". Hopefully, you will understand this in the code example to follow. Essentially, I am getting the location (using the InStr function) of the first 'item' tag, and the location of the first '/item' tag, subtracting them to get the length of the string, then using Mid to return the contents of the tag. I've done some small tweakage to turn the returned XML to a variable so I can process it internally then have the text of the object be our output.
...
'Assigns the text to this object
FullCode = http.responseText
ItemL = InStr(1, FullCode,"- ")
ItemR = InStr(ItemL, FullCode,"
") + 7
ItemLength = ItemR - ItemL
Item1 = Mid(FullCode, ItemL, ItemLength)
Object.Text = Item1
End Function
What this script does is return everything between the item tags, so you can see the power of this simple little bit of code. The end result of this widget is going to be to store the contents of the title, link, description and pubdate tags in public variables. This will let us access them from outside the script and really make the actual work VERY simple for the creation of the widget. Example code for the title tag (remember, we're grabbing this info out of the 'Item1' variable now! Also, I'm changing a bit so that the actual 'title' tags are removed):
Public Title1 '<-- This line goes at the VERY TOP of your script
TitleL = InStr(1, Item1,"")
TitleLength = TitleR - TitleL
Title1 = Mid(Item1, TitleL, TitleLength)
Of course, I tossed that bit of code inside the GetCode function, so it ran every time the timer triggered. This keeps everything up to date. I do exactly the same thing for all the other sections too, changing that '+ 7' as required by the width of the tag. All these are added to the Public variables shown at the top of the script:
Public Title1
Public Link1
Public Description1
Public Date1
So now, its time to make the actual widget itself, in terms of images. I've thrown together some graphics for our little project in order to show you how simple it all is. I'm gonna make it as simple as I can, but there will be some more code needed than what we have so far.
First, we need a background "container" object to hold all this stuff together. I made one and called it TutorialParent and assigned it an image that I could stretch as need be. Then I made a text object called Title1, made it a child of TutorialParent and placed it properly, then gave it a script like this:
'Called when the script is executed
Sub Object_OnScriptEnter
Object.Text = DesktopX.ScriptObject("RSSCode").Title1
End Sub
'Called when the script is terminated
Sub Object_OnScriptExit
End Sub
We do similar code for the description segment. Now heres where things get a little wierd. First off, you need to restrict the width of the description object somehow. Now, you can either do this in the object itself, in the width segment, or you can do it dynamically, relative to the width of the TutorialParent. With this next bit of code, I'm going to address this width assignment, as well as a couple other potential problems. See if you can follow along and understand what I'm doing. (I'm adding all this into the RSSCode object's script)
This bit replaces the old stuff for retrieving the title:
TitleL = InStr(1, Item1,"")
TitleLength = TitleR - TitleL
If TitleLength > 25 Then
Title1 = Mid(Item1, TitleL, 22) & "..."
Else
Title1 = Mid(Item1, TitleL, TitleLength)
End If
This stuff goes at the end of, but still inside, the GetCode function:
DesktopX.Object("Description1").Width = DesktopX.Object("TutorialParent").Width - 20
DesktopX.Object("Description1").Left = DesktopX.Object("TutorialParent").Width/2 - DesktopX.Object("Description1").Width/2
DesktopX.Object("Title1").Left = DesktopX.Object("TutorialParent").Width/2 - DesktopX.Object("Title1").Width/2
DesktopX.Object("TutorialParent").Height = DesktopX.Object("Description1").Top + DesktopX.Object("Description1").Height + 20
Well, I suppose we should do something with the Link1 and Date1 data... I'm gonna just be sneaky with that and NOT make new objects for them. Instead, I'm going to build them into the object's we've got. First, I need to change the Object Type of the Title1 object to URL. I'm going to set it up so you can just click on the title to go to the link given in the Link1 variable. Time to change some code in the Title1 object!
'Called when the script is executed
Sub Object_OnScriptEnter
Object.Text = DesktopX.ScriptObject("RSSCode").Title1
Object.Command = DesktopX.ScriptObject("RSSCode").Link1
End Sub
Sub Object_OnLButtonUp(x,y)
Object.ExecuteCommand
End Sub
'Called when the script is terminated
Sub Object_OnScriptExit
End Sub
At this point, I should remind you to make sure ALL your objects movements are locked (in Object Properties) except for the TutorialParent object. This keeps stuff from getting moved around by mouse clicks etc, but still lets you do stuff via script. Also, while you're in there, change the cursor for the Title1 object to Hand. That way people know its a link! Now, for the date, we could do all sortsa fancy stuff with all the formatting and stuff thats in there, but to be honest, with the InStr and Mid commands, you can figure that out on your own. I'm just going to slap the full timestamp on the end of the Description1 object in its script just like this:
'Called when the script is executed
Sub Object_OnScriptEnter
Object.Text = DesktopX.ScriptObject("RSSCode").Description1 & " -- " & DesktopX.ScriptObject("RSSCode").Date1
End Sub
'Called when the script is terminated
Sub Object_OnScriptExit
End Sub
Now, just for the heck of it, I added a tooltip to the title if its too wide to fit in the TutorialParent object. I did this by creating a new Public variable called TitleFull1. Inside that If statement in the title section within the RSSCode object's script, I changed it a bit:
If TitleLength > 25 Then
Title1 = Mid(Item1, TitleL, 22) & "..."
TitleFull1 = Mid(Item1, TitleL, TitleLength)
Else
Title1 = Mid(Item1, TitleL, TitleLength)
TitleFull1 = ""
End If
After I did that, I added just a bit of code into the Title1 object's script inside the OnScriptEnter section:
Object.ToolTipText = DesktopX.ScriptObject("RSSCode").TitleFull1
So there you have it! A functional little rss object with its address changeable within the script. I've been building this as I've been explaining it, and I think I've gotten everything in. Its difficult to keep things organized once you're moving between the scripts of multiple objects, but I've tried to keep things clear. The full and complete script from the RSSCode object can be found here. The complete object can be downloaded here. Questions or comments can be addressed either here, or via email (jdcerebro@gmail.com). Please, feel free to post suggestions for future tutorials, and I'll try to accomodate you as best I can!