A Full Yahoo! Weather App, Yes Another One
Uses Farhad Siasar's YahooWeathertlb library with a few added functions
Introduction
This is a full weather application complete with 2-Day and 5-Day forecasts. It displays the local weather and 4 maps (Radar, IR Satellite, HeatIndex and WindChill). The application has panel animation (thanks to Fredrik Bornander) that imitates CloneDVD2's sliding frames and I also added some taskbar buttons using the WindowsAPICodePack
. I added a folder in the Debug folder called "states". In this folder are the 50 states' text files that contain all the cities, towns, villages, and townships. I also added a zipcode and woeID file. WoeID stands for "Where on Earth ID". The WoeID combobox is in sync with the zipcode combobox. I added these so you wouldn't have to go searching through Yahoo to find your WoeID. The WoeID is used to retrieve the 5-day forecast only. I used horizontal bar styles to display the temperature, wind velocity and wind direction using Steve Lows "NextUI library". A splashscreen was also added because the weather app takes a while to boot up. There is also a Daffy Duck Cursor that I use quite a bit for all my applications.
This weather app uses a re-write of Farhad Siasar's YahooWeathertlb
and is now called "pWeatherLib.dll". The library is a bit larger than the original because of the way it was designed.
Panel Animation
I had to come up with a solution to move the panels (Left-to-Right and Right-to-Left) so I asked a question in the VB forum and Fredrik Bornander came up with a solution that worked very well. I had to change some of his code to work with this app, but all-in-all, it's still his Idea. Thanks Fredrik.
To get started with the animation, I first added 5 panels to the form. I placed 4 of them off the screen so that they could not be seen. I placed them in sequential order when scrolling (forward and backwards). To do the scrolling, first we must add the panels to a List, set the panels locations, then we use a timer with a couple of button click events. In the next 4 code blocks below are the subs for the animation.
Private Sub frmWeatherDesktop_Load_
(sender As Object, e As System.EventArgs) Handles Me.Load
'Panel Animation setup
panels.Add(pnlLocalWeather)
pnlLocalWeather.Location = New Point(0, 0)
panels.Add(pnlTwoDayForecast)
pnlTwoDayForecast.Location = New Point(816, 0)
panels.Add(pnlFiveDayForecast)
pnlFiveDayForecast.Location = New Point(1632, 0)
panels.Add(pnlMaps)
pnlMaps.Location = New Point(2448, 0)
panels.Add(pnlAbout)
pnlAbout.Location = New Point(3264, 0)
For Each panel As Panel In panels
Controls.Add(panel)
Next
animationTimer.Interval = 50
animationTimer.Start()
'...more code follows.
End Sub
The panel sizes are 814x561. As you can see in the code above, I spaced the panels 2 pixels apart from each other by adding 2 to the panels width location. Next we add them to a Controls array and set and start the timer.
Private Sub animationTimer_Tick_
(sender As Object, e As System.EventArgs) Handles animationTimer.Tick
If panels(currentIndex).Location.X <> 0 Then
Dim delta As Integer = panels(currentIndex).Location.X / 5.0
For Each panel As Panel In panels
panel.Location = New Point(panel.Location.X - delta, panel.Location.Y)
Next
End If
End Sub
When scrolling using the "Previous and Next" buttons, we check the currentIndex
to see where we are at. If we are at the beginning and press the "Previous Button" we do not want a run-time error popping up on us, so we just exit the sub gracefully and the same for the "Next Button" if we are at the last panel, we do the same, exit with grace.
Private Sub btnPrevious_Click(sender As Object, e As System.EventArgs) _
Handles btnPrevious.Click
If currentIndex = 0 Then
Exit Sub
Else
currentIndex = Math.Max(0, currentIndex - 1)
End If
End Sub
Private Sub btnNext_Click(sender As Object, e As System.EventArgs) Handles btnNext.Click
If currentIndex = 4 Then
Exit Sub
Else
currentIndex = Math.Min(panels.Count - 1, currentIndex + 1)
End If
End Sub
Starting the Application
When the app is first started, there is a splashscreen as an introduction that displays a cartoon weather pic along with the Version numbers and what it does before the main form displays. While we are waiting, it is building the gauges, loading the zip codes and WoeID's in their respective combo boxes. To get the zipcode combobox and the WoeID combo box to sync with each other, we just set the WoeID combo box's selected index equal to the zipcode combo box's selected index into the zipcode' combobox's SelectedIndexChanged
event.
Private Sub cmbZip_SelectedIndexChanged(sender As Object, e As System.EventArgs) _
Handles cmbZip.SelectedIndexChanged
cmbWoeID.SelectedIndex = cmbZip.SelectedIndex
End Sub
Searching the ComboBoxes or Pull Your Hair Out
Because of the extensive amount of data that is loaded into the combo boxes, we need to add a auto-complete to the combo boxes. To do this, you must set the combo boxes DropDownStyle
property to "DropDown
". This will let you type in the combo boxes. Then set the AutoCompleteMode
to "Suggest
" and the AutoCompleteSource
to "CustomSource
" and that's all. To fill up the custom sources, we just fill them up when filling the combo boxes with their data. The code is below.
Private Sub OpentextFile(ByVal fname As String)
Dim fs As FileStream
Dim sr As StreamReader
Dim strFile As String
Try
Dim strParts() As String
fs = New FileStream(fname, FileMode.Open, FileAccess.Read)
sr = New StreamReader(fs)
strFile = sr.ReadLine()
Do Until strFile Is Nothing
strParts = Split(strFile, ",")
cmbZip.Items.Add(strParts(0))
cmbZip.AutoCompleteCustomSource.Add(strParts(0))
cmbWoeID.Items.Add(strParts(1))
strFile = sr.ReadLine()
Loop
fs.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
We do the same thing for the states combo box and the cities combo box. We don't need to fool around with the WoeID combo box as it is synced to the zipcode combo box.
The GetCondition
function takes a String
as a value and passes back that same String
. First, we have to get the enum
code from the pWeatherLib
library which is 0
through 47
and 3200
. 0
is for Tornado
, we have to use the same picture for 0
and 1
, then each number matches up with the picture number. Below is the code I used for this routine.
Private Function GetCondition(ByVal strCondition As String) As String
'Code by RSPercy 07/10/09
Dim p As New pWeatherLib.pWeatherForecast(cmbZip.Text, temperatureUnit.Fahrenheit)
Select Case t.rss.channel.item.condition.codeEnum
Case 0
strCondition = "Tornado"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/1d.png"
Case 1
strCondition = "Tropical Storm"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/1d.png"
Case 2
strCondition = "Hurricane"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/2d.png"
Case 3
strCondition = "Severe Thunderstorms"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/3d.png"
Case 4
strCondition = "Thunderstorms"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/4d.png"
Case 5
strCondition = "Mixed Rain and Snow"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/5d.png"
Case 6
strCondition = "Mixed Rain and Sleet"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/6d.png"
Case 7
...
...
...
Case 46
strCondition = "Snow Showers" 'Night
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/46d.png"
Case 47
strCondition = "Isolated Thundershowers" 'Night
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/47d.png"
Case 3200
strCondition = "Not Available"
pb1.ImageLocation = "http://l.yimg.com/a/i/us/nws/weather/gr/44d.png"
End Select
Return strCondition
End Function
Is it HOT Out or is it Me?
Updated the RetreiveHeatIndex
function. This uses the air temperature (AT) and the relative humidity (RH) that we get from the Yahoo! Weather RSS Feed. The routine for this is available at Wikipedia. There is a short and a long routine. I used the long routine as it is more precise. This routine works best if the temperature is above 80 degrees and the humidity is above 40 degrees. If these conditions are not met, it displays a heat index temperature that is lower than the air temperature. So, I added a couple of If
-Then
-End If
statements to correct this problem. Here is the code for this:
Private Function RetrieveHeatIndex(ByVal h As Long) As String
'Code by RSPercy 03/25/2011
'This is the more advanced version
Dim p As New pWeatherLib.pWeatherForecast(cmbZip.Text, temperatureUnit.Fahrenheit)
Dim HEATINDEX As Long
'Heat Index Should be calculated only when air temperatures
'are greater than 80°F (27°C), dew point temperatures are
'greater than 60°F (16°C), and relative humidities are higher than 40%.
HEATINDEX = Math.Round(C1 + (C2 * AT) + (C3 * RH) - _
(C4 * AT * RH) + (C5 * (AT ^ 2)) + (C6 * (RH ^ 2)) + _
(C7 * (AT ^ 2) * RH) - (C8 * AT * (RH ^ 2)) + _
(C9 * (AT ^ 2) * (RH ^ 2)) - (C10 * (AT ^ 3)) + _
(C11 * (RH ^ 3)) + (C12 * (AT ^ 3) * RH) + _
(C13 * AT * (RH ^ 3)) - (C14 * (AT ^ 3) * (RH ^ 2)) + _
(C15 * (AT ^ 2) * (RH ^ 3)) - (C16 * (AT ^ 3) * (RH ^ 3)))
If (AT > 80) And (GetDewPoint(RH) > 60) And (RH > 40) Then
h = HEATINDEX
Else
h = AT
End If
'Wind Chill Should only be calculated when temperatures
'are at or below 50°F and wind speeds are above 3 MPH. Bright
'sunshine may increase the wind chill temperature by 10°F to 18°F.
If AT <= 50 And p.rss.channel.wind.speed > 3 Then
h = p.rss.channel.wind.chill
Else
h = AT
End If
Return h
End Function
Updated the btnGo_Click
event. I had to rework the dew point to work correctly with the program. Now it gives the correct results. The GetDewPoint()
function is called here, and is displayed below the btnGo_Click()
event.
Using the Code
Private Sub btnGo_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnGo.Click
'Code by RSPercy 03/25/2011
Try
Dim p As New pWeatherLib.pWeatherForecast_
(cmbZip.Text, temperatureUnit.Fahrenheit) 'p = all the goodies
'Fill the main form with weather data.
lblLatitude.Text = p.rss.channel.item.lat.ToString
lblLongitude.Text = p.rss.channel.item.long.ToString
lblLocation.Text = p.rss.channel.item.title 'Display the Title
lblHigh.Text = p.rss.channel.item.forecast.high & "°" 'High temperature
lblLow.Text = p.rss.channel.item.forecast.low & "°" 'Low temperature
newWindD = p.rss.channel.wind.direction
newWindS = p.rss.channel.wind.speed
If newWindS = 0 Then
lblWindVelocity.Text = "Wind Velocity is Calm."
End If
newTemp = p.rss.channel.item.condition.temp 'Current temperature
AT = newTemp 'A variable used in RetrieveHeatIndex
lblCondition.Text = GetCondition(strMyString) 'Current Weather Condition
lblHumidity.Text = p.rss.channel.atmosphere.humidity 'Humidity percentage
RH = CInt(lblHumidity.Text) 'A variable used in RetrieveHeatIndex
lblHeatIndexWindChill.Text = RetrieveHeatIndex(HI) & "°" 'Heat Index
lblSunrise.Text = p.rss.channel.astronomy.sunrise 'Sunrise
lblSunset.Text = p.rss.channel.astronomy.sunset 'Sunset
lblVisibility.Text = p.rss.channel.atmosphere.visibility & " mi." 'Visibility
If p.rss.channel.atmosphere.rising = 0 Then
lblPressure.Text = p.rss.channel.atmosphere.pressure & " " & _
"in'' and steady"
ElseIf p.rss.channel.atmosphere.rising = 1 Then
lblPressure.Text = p.rss.channel.atmosphere.pressure & " " & _
"in'' and rising"
ElseIf p.rss.channel.atmosphere.rising = 2 Then
lblPressure.Text = p.rss.channel.atmosphere.pressure & " " & _
"in'' and falling"
End If
lblDewPoint.Text = GetDewPoint(RH).ToString() & "°"
RetrieveZipCode() 'Gets the zip-code and displays the correct doppler maps
lblHumidity.Text += "%"
lblTemperature.Text = newTemp.ToString & "°"
lblTodaysDate.Text = FormatDateTime(Now.Date, DateFormat.ShortDate)
WDTimer.Enabled = True
WVTimer.Enabled = True
TMPTimer.Enabled = True
Me.Text = "Your Local Weather - " & p.rss.channel.title.ToString()
'MessageBox.Show(t.rss.channel.item.guid)
'Fill the 2-day forecast with data
Get2DayForecast()
'Do the same for the 5-day forecast.
GetFiveDayInfo()
'Display the About information.
GetAboutInfo()
Catch ex As System.NullReferenceException
MessageBox.Show("Please Enter a Valid Zip-Code.", "Info to the Rescue")
cmbZip.Focus()
Catch 'exs As IOException
MessageBox.Show("Please Try Again Later. Weather is Not Available.", _
"Info to the Rescue")
cmbZip.Focus()
End Try
End Sub
Private Function GetDewPoint(ByVal intRH As Integer) As Integer
'Code by RSPercy 03/25/2011
Dim dewpoint As Integer
Select Case intRH
Case 40 To 43
dewpoint = AT - 18
Case 44 To 46
dewpoint = AT - 17
Case 47 To 49
dewpoint = AT - 16
Case 50 To 52
dewpoint = AT - 15
Case 53 To 55
dewpoint = AT - 14
Case 56 To 59
dewpoint = AT - 13
Case 60 To 63
dewpoint = AT - 12
Case 64 To 66
dewpoint = AT - 11
Case 67 To 69
dewpoint = AT - 10
Case 70 To 72
dewpoint = AT - 9
Case 73 To 76
dewpoint = AT - 8
Case 77 To 79
dewpoint = AT - 7
Case 80 To 82
dewpoint = AT - 6
Case 83 To 85
dewpoint = AT - 5
Case 86 To 89
dewpoint = AT - 4
Case 90 To 93
dewpoint = AT - 3
Case 94 To 96
dewpoint = AT - 2
Case 97 To 99
dewpoint = AT - 1
Case 100
dewpoint = AT
Case Else
dewpoint = Math.Round(AT - ((100 - RH) / 5))
End Select
Return dewpoint
End Function
The GetWind
function was removed and replaced with three CreateGauge
subs. CreateTempGuage
(code below), CreateWindDirectionGuage
, and CreateWindSpeedGuage
were added. The gauges have timer animation along with LED display. See the picture above. Here is my code for the compasses:
Compass Code
Private Sub CreateTempGauge()
'Code by RSPercy 02/25/2010
Dim hfTemp As HorizontalFrame = New HorizontalFrame(New Rectangle(1, 1, 912, 50))
Me.BaseUI1.Frame.Add(hfTemp)
hfTemp.BackRenderer.CenterColor = Color.DarkRed
hfTemp.BackRenderer.EndColor = Color.Black
Dim bar1 As New HorizontalScaleBar(hfTemp)
bar1.StartValue = -60
bar1.EndValue = 120
bar1.MajorTickNumber = 19
bar1.MinorTicknumber = 1
bar1.CustomLabel = New String() {"-60", "-50", "-40", "-30", "-20", _
"-10", "0", "10", "20", "30", _
"40", "50", "60", "70", "80", _
"90", "100", "110", "120"}
bar1.TickMajor.Width = 3
bar1.TickMajor.Height = 12
bar1.TickMajor.FillColor = Color.Lime
bar1.TickMajor.Type = TickBase.TickType.RoundedRect
bar1.TickMinor.Width = 3
bar1.TickMinor.Height = 8
bar1.TickMinor.FillColor = Color.Lime
bar1.TickMinor.TickPosition = TickBase.Position.Cross
bar1.TickMinor.Type = TickBase.TickType.RoundedRect
bar1.FillColor = Color.DarkBlue
bar1.TickLabel.FontColor = Color.White
bar1.TickLabel.LabelFont = New Font("Elephant", 8, FontStyle.Regular)
hfTemp.ScaleCollection.Add(bar1)
Dim pointer As HorizontalPointer = New HorizontalPointer(hfTemp)
bar1.Pointer.Add(pointer)
bar1.Pointer(0).BasePointer.PointerShapeType = Pointerbase.PointerType.Type1
bar1.Pointer(0).BasePointer.FillColor = Color.Blue
bar1.Pointer(0).BasePointer.Length = 15
End Sub
Timer Events
Private Sub TMPTimer_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles TMPTimer.Tick
If oldTemp < newTemp Then
oldTemp += 1
DirectCast((Me.BaseUI1.Frame(0)), _
HorizontalFrame).ScaleCollection(0).Pointer(0).Value = oldTemp
lblTemperature.Text = "Temperature " & oldTemp.ToString() & "°"
If oldTemp = newTemp Then
oldTemp = newTemp
TMPTimer.Enabled = False
End If
End If
If oldTemp > newTemp Then
oldTemp -= 1
DirectCast((Me.BaseUI1.Frame(0)), _
HorizontalFrame).ScaleCollection(0).Pointer(0).Value = oldTemp
lblTemperature.Text = "Temperature " & oldTemp.ToString() & "°"
If oldTemp = newTemp Then
oldTemp = newTemp
TMPTimer.Enabled = False
End If
End If
End Sub
The TMPTimer_Tick
event above is for the temperature gauge animation. When the app is first started, oldTemp
is equal to zero and newTemp
is equal to the temperature we get from the Yahoo! RSS Feed. When the timer gets activated, the code above is pretty much self-explanatory. If oldTemp
is less than newTemp
, then we add 1
to the digital display and the pointer value and display it to the user; if greater than, then we subtract one and do the displaying. The other two timer tick events are the same except for the variables.
When designing the compass, I had problems getting the "N" to line-up with the center top. I played around with the StartAngle
and the SweepAngle
till I got it right. I also had to do the same for bar2
(wind speed). You will need the NextUI
library which can be found here, and the FunkyLibrary
can be found here. All the compasses are pretty much the same.
Two Day Forecast
At first, I had no idea on how to extract a few items that I needed from an HTML document, so I decided to use Regex strings. The next thing was learning how to do this. I copied the 30 minute Regex tutorial and printed it out. It is included in the zip file. Next, you will need expresso. This is a very handy tool for learning regex strings.
I used a Regex string for this sub. I used the pipe operator to retrieve the six different condition types. There is probably a more complex string
, but as I am a noob in this area, I used what worked for me.
Private Sub Get2DayForecast()
'Code by RSPercy 03/25/2011
Try
lblDate1.Text = FormatDateTime(Now.Date, DateFormat.ShortDate).ToString()
lblDate2.Text = FormatDateTime(DateAdd(DateInterval.Day, 1, Now.Date))
Dim parts() As String
Dim m As Match
Dim strMatch As String = String.Empty
Dim p As New pWeatherLib.pWeatherForecast_
(cmbZip.Text, temperatureUnit.Fahrenheit)
'''''''''''''''''''''''''''Day, Condition, High, Low
Dim pattern As String = _
"\w*\s-\s(\w*|\w*\s\w*|\w*\s\w*\s\w*|\w*\s\w*\s\w*\s\w*|\w*\/\w*" &
"|\w*\/\w*\/\w*|\w*\s\w*\/\w*\s\w*|\w*\s\w*\/\w*|\w*\s\w*\/\w*\-\w*)_
\.\s\w*:\s(\d{1,3}" &
"|\-\d{1,3})\s\w*:\s(\d{1,3}|\-\d{1,3})"
Dim input As String = p.rss.channel.item.description
For Each m In Regex.Matches(input, pattern, RegexOptions.Multiline)
strMatch = m.Value
If strMatch = Nothing Then
Exit For
Else
strMatch = strMatch.Replace(" - ", ",")
strMatch = strMatch.Replace(". High: ", ",")
strMatch = strMatch.Replace(" Low: ", ",")
'MessageBox.Show(strMatch) 'For testing ONLY
parts = Split(strMatch, ",")
If parts(0) <> p.rss.channel.item.forecast.day Then
lblTomorrow.Text = parts(0)
lblcc2.Text = parts(1)
RetrieveForecastCode()
lblHi2.Text = "High: " & parts(2)
lblLo2.Text = "Low : " & parts(3)
ElseIf parts(0) = p.rss.channel.item.forecast.day Then
lblcc1.Text = parts(1)
RetrieveForecast1()
lblHi1.Text = "High: " & parts(2)
lblLo1.Text = "Low : " & parts(3)
End If
End If
Next
Catch ex As Exception
MessageBox.Show("Sorry...Try again later!", "Info to the Rescue!")
End Try
End Sub
The only thing that differs is the conditions in the pattern string. In the subs in the paragraph below is where you will find the six different patterns:
- Tornado
- Severe Thunderstorms
- Light Snow Showers
- Mixed Rain and Snow
- Rain/Thunder
- AM Clouds/PM Sun
The list contains the 14 different patterns that I have came across so far. I have asked all over how to get one regex string to do the work of six different strings. After a lot of trial and error, I finally got it. I used the pipe operator to do this. I got rid of 189 lines of code.
The RetrieveForecastCode()
and RetrieveForecast1()
subs get the correct JPG files from the YahooWeatherPics folder and they are displayed in the correct PictureBox
es.
5-Day Forecast?...Weather Changes Everyday
This is by far the hardest thing I have had to do to this app. I had to learn how to request information from the Yahoo! server, switch data from one control to another for editing, and pass it back to the original control for use again; then I had to add a few regex strings for the 5-days, 5-conditions, 5-highs, 5-lows, 5-images, and 5-dates. Because there are six different types of strings that Yahoo! uses, I had to come up with a way to get and display these strings. I used a regex string to get all the strings that I needed. The results from this can be seen in the last picture above. This was all done in one sub (GetFiveDayInfo()
). There is way too much code to display, so I will only display how to access the Yahoo! server for the page source code. Once we have the requested HTML page source code, we can start to take it apart and display the info that we need. This code in the previous app was removed as I stated earlier.
Private Sub GetFiveDayInfo()
'Code by RSPercy 03/25/2011
Try
Dim parts() As String
Dim parts1() As String
Dim parts2() As String
Dim m As Match
Dim strMatch As String = String.Empty
'Finds the 5-day forecast conditions...EX: Partly Cloudy, Rain/Thunder....etc.
'There are 14 different patterns that we need.
Dim patternAA As String = "<[\w]*/>{1}_
([\w\s/-]*|[\w\s/]*-{1}[der]{1,2})</div>"
'Finds the days oy the week....EX: Mon, Tue, Wed, Thur, Fri, Sat, Sun.
Dim pattern5Day As String = "\<\w*\>\w*\<\/\w*\>\<_
\w*\>\w*\<\/\w*\>\<\w*\>\w*\<\/\w*\>\<_
\w*\>\w*\<\/\w*\>\<\w*\>\w*\<\/\w*\>"
'Finds the 5-day forecast Hi's and Low's
Dim patternHiLow As String = "\<\w*\>\w*\:\s(\d{1,3}|\-\d{1,3})_
\&\#\d{1,3}\;\s\<\w*\>\w*\:\s(\d{1,3}|\-\d{1,3})"
'Create a request using a URL that can receive a post.
Dim request As WebRequest = WebRequest.Create_
("http://weather.yahoo.com/united-states/" & cmbStates.Text _
& "/" & cmbCity.Text & "-" & cmbWoeID.Text & "/")
'Create POST data and convert it to a byte array.
request.Method = "POST"
Dim postData As String = "This is a test."
' Set the ContentType property of the WebRequest.
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(postData)
' Set the ContentType property of the WebRequest.
request.ContentType = "application/x-www-form-urlencoded"
' Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length
'Create datastream and a response stream.
Dim dataStream As Stream = request.GetRequestStream()
' Write the data to the request stream, then close it
dataStream.Write(byteArray, 0, byteArray.Length)
dataStream.Close()
' Get the response.
Dim response As WebResponse = request.GetResponse()
' Get the status.
Dim myString As String = CType(response, HttpWebResponse).StatusDescription
' Get the stream containing content returned by the server.
dataStream = response.GetResponseStream()
' Open the stream using a StreamReader for easy access.
Dim sr As StreamReader = New StreamReader(dataStream)
' Put the content in a textbox.
Dim myTB As TextBox = New TextBox
myTB.Multiline = True
myTB.WordWrap = False
myTB.Text = sr.ReadToEnd
' Clean up the streams.
sr.Close()
dataStream.Close()
response.Close()
'Move the content to a string variable.
strMatch = myTB.Text
'Remove the carriage returns and line feeds
'so our regex patterns work correctly.
strMatch = strMatch.Replace(ControlChars.CrLf, "")
strMatch = strMatch.Replace(ControlChars.Cr, "")
strMatch = strMatch.Replace(ControlChars.Lf, "")
'Reset the textbox to nothing.
myTB.Text = ""
'populate the textbox with the new data
myTB.Text = strMatch
'Reset strMatch to nothing.
strMatch = String.Empty
'Get the Dates for the forecasts
GetFiveDates()
'Get the days of the week.
For Each m In Regex.Matches(myTB.Text, pattern5Day, RegexOptions.Multiline)
strMatch = m.Value
If strMatch = Nothing Then
Exit For
Else
strMatch = strMatch.Replace("<th>", "")
strMatch = strMatch.Replace("</th>", ",")
'MessageBox.Show(strMatch) 'For testing ONLY
parts = Split(strMatch, ",")
If parts(0) = "Today" Then
lblDay1.Text = parts(0)
lblDay2.Text = parts(1)
lblDay3.Text = parts(2)
lblDay4.Text = parts(3)
lblDay5.Text = parts(4)
ElseIf parts(0) = "Tonight" Then
lblDay1.Text = parts(0)
lblDay2.Text = parts(1)
lblDay3.Text = parts(2)
lblDay4.Text = parts(3)
lblDay5.Text = parts(4)
End If
End If
Next
strMatch = String.Empty
'Get the Highs and Lows.
For Each m In Regex.Matches(myTB.Text, patternHiLow, RegexOptions.Multiline)
strMatch += m.Value
Next
strMatch = strMatch.Replace("<td>High: ", ",")
strMatch = strMatch.Replace("° <div>Low: ", ",")
'MessageBox.Show(strMatch) 'For testing ONLY
parts1 = Split(strMatch, ",")
lblHigh1.Text = "High : " & parts1(1)
lblLow1.Text = "Low : " & parts1(2)
lblHigh2.Text = "High : " & parts1(3)
lblLow2.Text = "Low : " & parts1(4)
lblHigh3.Text = "High : " & parts1(5)
lblLow3.Text = "Low : " & parts1(6)
lblHigh4.Text = "High : " & parts1(7)
lblLow4.Text = "Low : " & parts1(8)
lblHigh5.Text = "High : " & parts1(9)
lblLow5.Text = "Low : " & parts1(10)
strMatch = String.Empty
'Get the five conditions and the Images that we need.
For Each m In Regex.Matches(myTB.Text, patternAA, RegexOptions.Multiline)
strMatch += m.Value
Next
strMatch = strMatch.Replace("<br/>", "")
strMatch = strMatch.Replace("</div>", ",")
'MessageBox.Show(strMatch) 'For testing ONLY
parts2 = Split(strMatch, ",")
lblCon1.Text = parts2(0)
RetrieveForecastA()
lblCon2.Text = parts2(1)
RetrieveForecastB()
lblCon3.Text = parts2(2)
RetrieveForecastC()
lblCon4.Text = parts2(3)
RetrieveForecastD()
lblCon5.Text = parts2(4)
RetrieveForecastE()
strMatch = String.Empty
Catch ex As Exception
MessageBox.Show("Unexplained Error has occurred," & vbCrLf _
& "The 5-Day Weather Forecast" & vbCrLf _
& "will be unavailable. Please" & vbCrLf _
& "try again later.", "Info to the Rescue", _
MessageBoxButtons.OK, MessageBoxIcon.Information)
End Try
End Sub
Download NextUI.dll and pWeatherLib.dll
The NextUI.dll and the pWeatherLib.dll can be downloaded HERE. This is in case CodeProject decides to strip out the DLL files. Download, Unzip, Re-Add libs to project. You can download the complete project HERE.
Download WindowsAPICodePack
You can download the WindowsAPICodePack
project HERE.
I hope you can use and enjoy this app.
Conclusion
I watch the Weather Channel all the time. Why? you are probably asking yourself. It's because the Weather Channel is the only channel that doesn't have re-runs. Since I have always had a fascination with weather, that's how this application came about.
History
- This version was created with VB.NET Pro 2010.