吐血的天气预报
最近闲来无事,想起天气预报那个工具很不好用,所以想自己做一个。
于是顺便体验下WPF的魅力,就用WPF开始动工了。进度很快,技术上不是很难摸,
一天吧就完成了决大部分主要功能 。其实就是一个显示界面加城市选择设置部分。
这里也大概贴一下代码
- PrivateSub MainWindow_MouseLeftButtonDown(ByVal sender AsObject, ByVal e As System.Windows.Input.MouseButtonEventArgs) HandlesMe.MouseLeftButtonDown
- Me.DragMove()
- EndSub
- PrivateSub MainWindow_Loaded(ByVal sender AsObject, ByVal e As System.Windows.RoutedEventArgs) HandlesMe.Loaded
- 'Dim desktopHwnd As IntPtr = GetDesktopPtr()
- 'Dim ownHwnd As IntPtr = New WindowInteropHelper(Me).Handle
- 'Dim result As IntPtr = SetParent(ownHwnd, desktopHwnd)
- Dim address AsString = ""
- address = GetAddress()
- 'Dim weather() As String = ws.getWeatherbyCityName(address)
- 'LoadData(weather)
- EndSub
- Function LoadData(ByVal weather() AsString) AsBoolean
- Try
- Dim Today_ImageStream, Tomorrow_ImageStream, AfterTomorrow_ImageStream As FileStream
- Dim Today_Image, Tomorrow_Image, AfterTomorrow_Image AsNew BitmapImage()
- Dim gifLen AsInteger
- Dim gifName AsString
- Dim filePath AsString
- 'today
- lblTime.Content = Now.Year & "年" & Now.Month & "月" & Now.Day & "日 星期" & ConvertToChinese(Now.DayOfWeek)
- lblAddress.Content = weather(1).ToString
- Dim len AsInteger = weather(10).ToString.IndexOf("℃") - 9
- lblNow.Content = weather(10).ToString.Substring(10, len)
- lblWind.Content = weather(6).ToString.Substring(weather(6).ToString.IndexOf(" "))
- gifLen = weather(9).ToString.Length
- If gifLen = 5 Then
- gifName = "0" & weather(9).ToString.Replace("gif", "png")
- Else
- gifName = weather(9).ToString.Replace("gif", "png")
- EndIf
- filePath = path & "images\"
- Today_ImageStream = New FileStream(filePath & gifName, FileMode.Open)
- Today_Image.BeginInit()
- Today_Image.StreamSource = Today_ImageStream
- Today_Image.EndInit()
- ImgNow.Source = Today_Image
- lblTodayTemp.Content = weather(5).ToString.Replace("/", "--")
- ImgToday.Source = Today_Image
- lblToday.Content = weather(6).ToString.Substring(0, weather(6).ToString.IndexOf(" "))
- 'tomorrow
- If weather(9).ToString = weather(16).ToString Then
- ImgTomo.Source = Today_Image
- Else
- gifLen = weather(16).ToString.Length
- If gifLen = 5 Then
- gifName = "0" & weather(16).ToString.Replace("gif", "png")
- Else
- gifName = weather(16).ToString.Replace("gif", "png")
- EndIf
- Tomorrow_Image = New BitmapImage()
- Tomorrow_ImageStream = New FileStream(filePath & gifName, FileMode.Open)
- Tomorrow_Image.BeginInit()
- Tomorrow_Image.StreamSource = Tomorrow_ImageStream
- Tomorrow_Image.EndInit()
- ImgTomo.Source = Tomorrow_Image
- EndIf
- lblTomo.Content = weather(13).ToString.Substring(0, weather(13).ToString.IndexOf(" "))
- lblTomorrowTemp.Content = weather(12).ToString.Replace("/", "--")
- 'the day after tomorrow
- If weather(21).ToString = weather(9).ToString Then
- ImgAfter.Source = Today_Image
- ElseIf weather(16).ToString = weather(21).ToString Then
- ImgAfter.Source = Tomorrow_Image
- Else
- gifLen = weather(21).ToString.Length
- If gifLen = 5 Then
- gifName = "0" & weather(21).ToString.Replace("gif", "png")
- Else
- gifName = weather(21).ToString.Replace("gif", "png")
- EndIf
- AfterTomorrow_Image = New BitmapImage()
- AfterTomorrow_ImageStream = New FileStream(filePath & gifName, FileMode.Open)
- AfterTomorrow_Image.BeginInit()
- AfterTomorrow_Image.StreamSource = AfterTomorrow_ImageStream
- AfterTomorrow_Image.EndInit()
- ImgAfter.Source = AfterTomorrow_Image
- EndIf
- lblAfterTomo.Content = weather(18).ToString.Substring(0, weather(18).ToString.IndexOf(" "))
- lblAfterTomorrowTemp.Content = weather(17).ToString.Replace("/", "--")
- ReturnTrue
- Catch ex As Exception
- MsgBox(ex.ToString, MsgBoxStyle.Critical)
- ReturnFalse
- EndTry
- EndFunction
- Function ConvertToChinese(ByVal weekday AsInteger) AsString
- SelectCase weekday
- Case 1
- Return"一"
- Case 2
- Return"二"
- Case 3
- Return"三"
- Case 4
- Return"四"
- Case 5
- Return"五"
- Case 6
- Return"六"
- Case 0
- Return"日"
- EndSelect
- Return""
- EndFunction
嗯,很好,一切很顺利。我很得意,哈哈。然而就在我沾沾自喜的时候,我想这个东西应该要贴在桌面上吧,和win7小工具一样的效果。而且应该不是难事,我没放心上。
谁知道噩梦来了。不看不知道啊,原来win7的桌面是如此的诡异,分了很多层。如果没有使用aero主题的话,还好说,可是这是个废话啊,用win7的人肯定都喜欢那家伙啊。
也许我这样写不清楚,我说代码吧。开始本想很简单,我就准备使用API SetWindowsPos ,可是事实上我太傻了,呵呵,这样只是把程序放在最后一层,但是屏蔽不了win+D这个显示桌面命令,一样不能贴住桌面(有人叫嵌入桌面)。看下代码吧,当作记录下。
- SetWindowPos(winHelp.Handle, HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.IgnoreMove Or SetWindowPosFlags.IgnoreResize)
- <DllImport("user32.dll", SetLastError:=True)> _
- PublicFunction SetWindowPos(ByVal hWnd As IntPtr, ByVal hWndInsertAfter As IntPtr, ByVal X AsInteger, ByVal Y AsInteger, ByVal cx AsInteger, ByVal cy AsInteger, ByVal uFlags As SetWindowPosFlags) AsBoolean
- EndFunction
- <Flags()> _
- PublicEnum SetWindowPosFlags As UInteger
- ''' <summary>If the calling thread and the thread that owns the window are attached to different input queues,
- ''' the system posts the request to the thread that owns the window. This prevents the calling thread from
- ''' blocking its execution while other threads process the request.</summary>
- ''' <remarks>SWP_ASYNCWINDOWPOS</remarks>
- SynchronousWindowPosition = &H4000
- ''' <summary>Prevents generation of the WM_SYNCPAINT message.</summary>
- ''' <remarks>SWP_DEFERERASE</remarks>
- DeferErase = &H2000
- ''' <summary>Draws a frame (defined in the window's class description) around the window.</summary>
- ''' <remarks>SWP_DRAWFRAME</remarks>
- DrawFrame = &H20
- ''' <summary>Applies new frame styles set using the SetWindowLong function. Sends a WM_NCCALCSIZE message to
- ''' the window, even if the window's size is not being changed. If this flag is not specified, WM_NCCALCSIZE
- ''' is sent only when the window's size is being changed.</summary>
- ''' <remarks>SWP_FRAMECHANGED</remarks>
- FrameChanged = &H20
- ''' <summary>Hides the window.</summary>
- ''' <remarks>SWP_HIDEWINDOW</remarks>
- HideWindow = &H80
- ''' <summary>Does not activate the window. If this flag is not set, the window is activated and moved to the
- ''' top of either the topmost or non-topmost group (depending on the setting of the hWndInsertAfter
- ''' parameter).</summary>
- ''' <remarks>SWP_NOACTIVATE</remarks>
- DoNotActivate = &H10
- ''' <summary>Discards the entire contents of the client area. If this flag is not specified, the valid
- ''' contents of the client area are saved and copied back into the client area after the window is sized or
- ''' repositioned.</summary>
- ''' <remarks>SWP_NOCOPYBITS</remarks>
- DoNotCopyBits = &H100
- ''' <summary>Retains the current position (ignores X and Y parameters).</summary>
- ''' <remarks>SWP_NOMOVE</remarks>
- IgnoreMove = &H2
- ''' <summary>Does not change the owner window's position in the Z order.</summary>
- ''' <remarks>SWP_NOOWNERZORDER</remarks>
- DoNotChangeOwnerZOrder = &H200
- ''' <summary>Does not redraw changes. If this flag is set, no repainting of any kind occurs. This applies to
- ''' the client area, the nonclient area (including the title bar and scroll bars), and any part of the parent
- ''' window uncovered as a result of the window being moved. When this flag is set, the application must
- ''' explicitly invalidate or redraw any parts of the window and parent window that need redrawing.</summary>
- ''' <remarks>SWP_NOREDRAW</remarks>
- DoNotRedraw = &H8
- ''' <summary>Same as the SWP_NOOWNERZORDER flag.</summary>
- ''' <remarks>SWP_NOREPOSITION</remarks>
- DoNotReposition = &H200
- ''' <summary>Prevents the window from receiving the WM_WINDOWPOSCHANGING message.</summary>
- ''' <remarks>SWP_NOSENDCHANGING</remarks>
- DoNotSendChangingEvent = &H400
- ''' <summary>Retains the current size (ignores the cx and cy parameters).</summary>
- ''' <remarks>SWP_NOSIZE</remarks>
- IgnoreResize = &H1
- ''' <summary>Retains the current Z order (ignores the hWndInsertAfter parameter).</summary>
- ''' <remarks>SWP_NOZORDER</remarks>
- IgnoreZOrder = &H4
- ''' <summary>Displays the window.</summary>
- ''' <remarks>SWP_SHOWWINDOW</remarks>
- ShowWindow = &H40
- EndEnum
看起来很吓人,呵呵,大部分都是参数,很easy。
好吧,既然这样不行,再想,开始转战用SetParent。这个API本事不小哦,而且战斗力很强,完全可以胜任,而且已经被N多大神征服了。嗯,用吧,就是他。代码:
- PublicFunction GetDesktopPtr() As IntPtr
- 'http://blog.csdn.net/mkdym/article/details/7018318
- ' 情况一
- Dim hwndWorkerW As IntPtr = IntPtr.Zero
- Dim hShellDefView As IntPtr = IntPtr.Zero
- Dim hwndDesktop As IntPtr = IntPtr.Zero
- Dim hProgMan As IntPtr = FindWindow("ProgMan", Nothing)
- If hProgMan <> IntPtr.Zero Then
- hShellDefView = FindWindowEx(hProgMan, IntPtr.Zero, "SHELLDLL_DefView", Nothing)
- If hShellDefView <> IntPtr.Zero Then
- 'hwndDesktop = FindWindowEx(hShellDefView, IntPtr.Zero, "SysListView32", "FolderView")
- hwndDesktop = FindWindowEx(hShellDefView, IntPtr.Zero, "SysListView32", Nothing)
- EndIf
- EndIf
- If hwndDesktop <> IntPtr.Zero Then
- Return hwndDesktop
- EndIf
- ' 情况二
- While hwndDesktop = IntPtr.Zero
- '必须存在桌面窗口层次
- hwndWorkerW = FindWindowEx(IntPtr.Zero, hwndWorkerW, "WorkerW", Nothing)
- '获得WorkerW类的窗口
- If hwndWorkerW = IntPtr.Zero Then
- ExitWhile
- EndIf
- '未知错误
- hShellDefView = FindWindowEx(hwndWorkerW, IntPtr.Zero, "SysListView32", Nothing)
- If hShellDefView = IntPtr.Zero Then
- Continue While
- EndIf
- hwndDesktop = FindWindowEx(hShellDefView, IntPtr.Zero, "SysListView32", Nothing)
- EndWhile
- Return hwndDesktop
- EndFunction
- DeclareFunction SetActiveWindow Lib"user32"Alias"SetActiveWindow" (ByVal hwnd As IntPtr) As IntPtr
- DeclareFunction ShowWindow Lib"user32"Alias"ShowWindow" (ByVal hwnd As IntPtr, ByVal nCmdShow As IntPtr) As IntPtr
- PublicDeclareFunction GetPrivateProfileString Lib"KERNEL32.DLL"Alias"GetPrivateProfileStringA" ( _
- ByVal lpAppName AsString, _
- ByVal lpKeyName AsString, ByVal lpDefault AsString, _
- ByVal lpReturnedString As System.Text.StringBuilder, ByVal nSize AsInteger, _
- ByVal lpFileName AsString) AsInteger
- PublicDeclareFunction WritePrivateProfileString Lib"KERNEL32.DLL"Alias"WritePrivateProfileStringA" ( _
- ByVal lpAppName AsString, _
- ByVal lpKeyName AsString, _
- ByVal lpString AsString, _
- ByVal lpFileName AsString) AsInteger
- <DllImport("User32.dll", EntryPoint:="FindWindowEx")> _
- PublicFunction FindWindowEx(ByVal hwndParent As IntPtr, ByVal hwndChildAfter As IntPtr, ByVal lpClassName AsString, ByVal lpWindowName AsString) As IntPtr
- EndFunction
- <DllImport("user32.dll", EntryPoint:="FindWindow")> _
- PublicFunction FindWindow(ByVal lpClassName AsString, ByVal lpWindowName AsString) As IntPtr
- EndFunction
- <DllImport("user32.dll", EntryPoint:="GetWindow")> _
- PublicFunction GetWindow(ByVal hwnd As IntPtr, ByVal wCmd As IntPtr) As IntPtr
- EndFunction
- <DllImport("user32.dll", EntryPoint:="SetParent")> _
- PublicFunction SetParent(ByVal hWndChild As IntPtr, ByVal hWndNewParent As IntPtr) As IntPtr
- pre class="vb" name="code"> EndFunction
- '这三句就看可以使用了
- Dim desktopHwnd As IntPtr = GetDesktopPtr()
- Dim ownHwnd As IntPtr = New WindowInteropHelper(Me).Handle
- Dim result As IntPtr = SetParent(ownHwnd, desktopHwnd)
里面有熟悉的代码和注释?别奇怪,是COPY来的,呵呵。运行代码后,觉得很牛逼吧,不错,是贴上去了。可是我想看看换个桌面图片看看什么效果。我靠,一换完蛋了,刚刚那个效果不见了。赶紧还原动作啊,折腾了半天,毛都不见了。赶紧去问娘啊,哥啊的,度娘说,很多人都是这样。遇到AERO主题下,由于有任务栏下面那个小窗体,窗体句柄不太好找了,能不能成功可能就要看人品和运气了。算了,不行咋办?听说还可以消息拦截,要不试下?好吧,我再找度娘。得到代码几行,经验+100。
- 'Dim winHelp As WindowInteropHelper = New WindowInteropHelper(Me)
- 'Protected Overrides Sub OnSourceInitialized(ByVal e As EventArgs)
- ' MyBase.OnSourceInitialized(e)
- ' Dim hwndSource As HwndSource = TryCast(PresentationSource.FromVisual(Me), HwndSource)
- ' If hwndSource IsNot Nothing Then
- ' hwndSource.AddHook(New HwndSourceHook(AddressOf Me.WndProc))
- ' End If
- 'End Sub
- 'Protected Overridable Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
- ' Return IntPtr.Zero
- 'End Function
- 'Protected Overridable Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
- ' 'If msg = WM_SIZE Then
- ' 'MsgBox("")
- ' 'If WindowState = WindowState.Minimized Then
- ' ' SetWindowPos(winHelp.Handle, HWND_BOTTOM, 0, 0, 0, 0, SetWindowPosFlags.IgnoreMove Or SetWindowPosFlags.IgnoreResize)
- ' ' handled = True
- ' 'End If
- ' WindowState = WindowState.Maximized
- ' 'End If
- ' Return IntPtr.Zero
- 'End Function
上面的代码有很多是注释了N遍,我也没恢复过来,可见我调的多认真,哈哈。哎,上面的代码主要就是取拦截消息,我的确也狠狠研究了下windows消息。结果也很失望,消息是拦截掉了,可是不知道怎么屏蔽掉这个显示桌面让他最小化的。什么办法都用了,只有那个windowstate给点脸,不过效果不太好,其他都不理我。 这个时候我想放弃了。可是难得有时间想做个东西啊,好不甘心啊,玛德,睡觉都在想着他,可怜吧。我最后想回头用GDI+来试试,实在不行用鼠标穿透看看。结果是行了,哈哈,赶紧做吧。我哼哧哼哧的又搞了一天,好了,试试效果吧。哎,那家伙怎么一直在最上面啊,怎么都盖不住啊,显示桌面是没有效果,但是其他的文件打开还是被他挡住了啊。我回头一看,原来我用了topmost,擦,难怪显示桌面萎了。这时候我好像骂人啊,为了这个功能花了几天时间没磨出一个屁来。而且用win7的人都知道,任务栏右下角还有个按钮显示桌面的,那个功能和win+D的原理还不一样。哎,彻底失望了。
GDI+的代码就不贴了,没啥意思。写这个主要想记录下我这几天的经历,也留下一点代码,我觉得蛮有用的。现在这个天气预报是做好了,就是不能完成win7小工具那样贴在桌面上的功能,就自己辛苦点,再按下显示桌面显示吧。没办法了。如果有人知道怎么做,也指点下我吧,谢谢。那个东西我传上去了,有兴趣的可以下载看看。
忘记告诉你们了,上面提到的方法在XP下完全没有问题,win7下是选择性的,哈哈。