自從接觸python,就被他優雅而簡潔的代碼所吸引。
舉個例子:
arr
= [
1 ,
2 ,
3 ,
4 ,
5 ,
6 ,
7 ,
8 ,
9 ,
10 ,
11 ,
12 ,
13 ,
14 ]
#如果想要將arr中大於10的項取出來,然后每項乘以2,組成一個新的列表arr2,在python里只需要這么一樣就行了:
arr2 = [x * 2 for x in arr if x > 10 ]
#如果想要將arr中大於10的項取出來,然后每項乘以2,組成一個新的列表arr2,在python里只需要這么一樣就行了:
arr2 = [x * 2 for x in arr if x > 10 ]
如果用其他語言來寫的嗎,不會這么簡潔,美觀。
python還有更強大的特性,它有非常豐富的類庫,以至於它幾乎能完成大多數語言都能完成的工作。比如寫網站、寫軟件、寫游戲、寫服務器、嵌入式開發等。
最近出門總是天公不作美,仔細想想是忘了看天氣預報了。於是就想找個桌面天氣軟件,這樣一打開電腦就能看到天氣了,關電腦前也可以看一眼明天的天氣。
在百度里面找到了好幾款桌面天氣軟件,大都不完美,不是自己想要的效果(有的是界面不美觀,有的是里面夾雜着其他程序過於累贅,有的是快捷鍵沖突了,有的是只能看當前天氣不能看明天天氣等等)。
當然也有一款個人感覺挺滿意的。后來想了下,既然python這么強大,那么用python寫一個這樣的軟件豈不是更好,想要什么功能,就寫什么功能。
於是就開始了我的python桌面天氣預報的龐大工程。(為什么說龐大呢,后面就知道了。)
由於我是做界面開發的,之前學python的時候就順便學了wxPython這個強大的類庫。於是就用wxPython來寫。
寫之前肯定先要解決幾個問題:1、天氣數據的獲取與分析。2、能夠貼在桌面上,鼠標穿透,像桌面背景一樣。3、要背景透明。
1、很容易解決網上的api一大堆,可以百度一下。
2、我也找到了辦法就是用User32.dll里面的SetWindowLongA方法。具體的python代碼是這么寫的
selfWnd
= ctypes.windll.user32.FindWindowA(
"wxWindowClassNR",
None)
Ret = ctypes.windll.user32.GetWindowLongA(selfWnd, - 20)
Ret = Ret | 0x00080000 | 0x00000020
ctypes.windll.user32.SetWindowLongA(selfWnd, -20, Ret)
Ret = ctypes.windll.user32.GetWindowLongA(selfWnd, - 20)
Ret = Ret | 0x00080000 | 0x00000020
ctypes.windll.user32.SetWindowLongA(selfWnd, -20, Ret)
3、這個是最麻煩的了,也是浪費我時間最多的一個。
最開始在wxPython里面找到一個叫SetTransparent()的方法,試了下發現是設置整個窗口的透明度的,不是設置背景的透明度的。又想到把一張png圖片作為背景圖片不就行了嗎。
用盡了各種方法后發現即使用png作為窗口的背景,窗口原來的背景也會同時存在的。相當於就是用一張圖片浮在窗口背景上了,沒達到我要的背景透明的效果。
后來發現wxPython有個ShapedWindow的例子,可以實現用圖片作為背景的效果。
代碼就不貼了,效果是這樣子的

跟我要的效果很接近。如果再把這張圖片做成半透明的,那么就是我要的效果了。
於是百度、谷歌狂搜,也沒找到個方法來,最后從各種搜索結果中發現了兩個問題:
1、這張作為背景的圖片是不支持alpha通道的,即使圖片有透明度也不行,雖然wxPython有將png圖片顯示在程序里的例子,但是作為背景的話,是不可能的。
2、這張圖片顯示區域之外的部分是顯示不出來的。如圖:

文字其實是有紅框那么長,但是由於在這張圖片的區域之外,所以就沒有顯示出來。
后來在網上發現有個用tkinter實現的背景透明為文字不透明的方法,如圖:

基本上是我想要的效果。
於是又重燃了我學習tkinter的決心,放棄用wxPython了,之前一直沒有研究這個python內置的Gui工具。
放棄用wxPython來寫這個程序還有其他方面的原因:
1、不能實現我想要的用透明背景圖片作為窗口的背景。
2、wxStaticText這個文本顯示控件,是有背景的,默認的背景是從父級繼承過來的。網上有辦法可以擦除背景,但是對於右對齊的文字來說,在重繪的時候,會出現文字重疊如圖:
正常情況下:
,重疊的情況:
,這個文字被重繪了好幾遍。


3、由於要實現鼠標穿透效果,需要獲取窗口句柄,而wxPython沒有任何一個方法可以返回自己的窗口句柄。
雖然可以通過 selfWnd
= ctypes.windll.user32.FindWindowA(
"wxWindowClassNR",
None) 來獲取句柄,
但是這個方法不可靠,因為窗口類名
wxWindowClassNR不是唯一的,用spy++可以看到有好多窗口的類名都是
這個名字。這種方法會造成,返回的不是自己窗口的句柄,而是別人窗口的句柄。
俗話說 磨刀不誤砍柴工,我把tkinter入門,各個組件的介紹,使用方法,例子都看了一遍,都一一測試過,防止學的時候沒學好,理解不透徹,導致用的時候碰到各種問題。
.........
n天后,已經學的差不多了,就開始用tkinter來寫這個程序。窗口透明效果很容易就實現了。
代碼如下:
# -*- coding: utf-8 -*-
import Tkinter
root = Tkinter.Tk()
#這一行可以隱藏掉窗口邊框和標題欄
root.overrideredirect( True)
root[ "width"] = 100
root[ "height"] = 80
#這一行可以將所有的白色透明掉
root.attributes( "-transparentcolor", "white")
root[ "background"] = "white"
x, y = 0, 0
def StartMove(event) :
global x, y
x = event.x
y = event.y
def StopMove(event) :
x = None
y = None
def OnMotion(event) :
global x, y
deltax = event.x - x
deltay = event.y - y
_x = root.winfo_x() + deltax
_y = root.winfo_y() + deltay
root.geometry( "+%s+%s" % (_x, _y))
label = Tkinter.Label(root, text = "ddddd", bg = "white")
label.place(x = 10, y = 10, anchor = Tkinter.NW)
root.bind( "<ButtonPress-1>", StartMove)
root.bind( "<ButtonRelease-1>", StopMove)
root.bind( "<B1-Motion>", OnMotion)
root.mainloop()
import Tkinter
root = Tkinter.Tk()
#這一行可以隱藏掉窗口邊框和標題欄
root.overrideredirect( True)
root[ "width"] = 100
root[ "height"] = 80
#這一行可以將所有的白色透明掉
root.attributes( "-transparentcolor", "white")
root[ "background"] = "white"
x, y = 0, 0
def StartMove(event) :
global x, y
x = event.x
y = event.y
def StopMove(event) :
x = None
y = None
def OnMotion(event) :
global x, y
deltax = event.x - x
deltay = event.y - y
_x = root.winfo_x() + deltax
_y = root.winfo_y() + deltay
root.geometry( "+%s+%s" % (_x, _y))
label = Tkinter.Label(root, text = "ddddd", bg = "white")
label.place(x = 10, y = 10, anchor = Tkinter.NW)
root.bind( "<ButtonPress-1>", StartMove)
root.bind( "<ButtonRelease-1>", StopMove)
root.bind( "<B1-Motion>", OnMotion)
root.mainloop()
這是效果圖:

但是有一個很明顯的問題,文字變得不清晰了。
這是在win7下的效果但是在xp下就顯示正常了,如圖:

現在都用win7了 不可能寫個程序只能在xp下運行吧。所以得找解決辦法。
又百度、谷歌狂搜,最后還是在python自帶的文檔里找到了這么一句話:
like anti-aliased font rendering under X11, window transparency (on X11 you will need a composition window manager) will be missing.
意思是字體抗鋸齒、窗口透明在window下將會丟失。
就說是tkinter里面是沒有抗鋸齒和窗口透明功能的。之前的透明方法只是把特定顏色透明了,並不是真正意義上的透明。tkinter里面是沒有alpha通道的。所以用半透明圖片做背景是不可能實現的。
不過tkinter相比wxPython來說有個優點就是它可以返回窗口句柄了,
print hex(root.winfo_id())
無奈之下,只好再找其他的python GUI工具了。
接下來裝了個pygtk,但是裝上之后,導入時會報錯,大概意思是缺少某個dll文件。我都是按照教程安裝的。
后來在虛擬機的xp系統里面裝了下,卻沒有報錯。
真是奇怪了,同樣的幾個文件,同樣的安裝順序,在win7下裝完后有問題,在xp下就正常運行。
我估計是某個pygtk用到的dll文件在win7和xp里面不一致導致的。
搜了下發現網上也有人遇到同樣情況的,但是基本上找不到解決方案,或者說很難找,於是就暫時放棄了。
之后又裝了個pyqt,安裝過程也很方便,有個獨立安裝包,直接安裝就行,可以正常運行。
看了里面的例子后頓時感覺:“夢里尋她千百度,驀然回首,那人卻在燈火闌珊處。”
真是太好了,由於我是做actionscript開發的,發現qt幾乎能實現flash的所有功能。
再次,磨刀不誤砍柴工。先看基礎吧。
經過一番努力和研究之后,終於實現了我想要的效果了。
先貼圖看下效果:

pyqt里面實現窗口無邊框的是:
self.setWindowFlags(QtCore.Qt.FramelessWindowHint
|QtCore.Qt.SubWindow
|QtCore.Qt.WindowStaysOnBottomHint)
實現背景透明的是:
self.setAttribute(QtCore.Qt.WA_TranslucentBackground,
True)
我寫了個函數來實現鼠標穿透的切換:
def toggleMouseThrough(
self, through
=
None)
:
if through == None :
self.mouseThrough = not self.mouseThrough
else :
self.mouseThrough = bool(through)
selfWnd = int( self.winId())
ret = ctypes.windll.user32.GetWindowLongA(selfWnd, - 20)
if self.mouseThrough :
ret = ret | 0x00000020
self.SetTopTexts( self.miniWeatherArr[ 0].data)
else :
ret = ret & ~0x00000020
ctypes.windll.user32.SetWindowLongA(selfWnd, - 20, ret)
if through == None :
self.mouseThrough = not self.mouseThrough
else :
self.mouseThrough = bool(through)
selfWnd = int( self.winId())
ret = ctypes.windll.user32.GetWindowLongA(selfWnd, - 20)
if self.mouseThrough :
ret = ret | 0x00000020
self.SetTopTexts( self.miniWeatherArr[ 0].data)
else :
ret = ret & ~0x00000020
ctypes.windll.user32.SetWindowLongA(selfWnd, - 20, ret)
源碼放在百度網盤里了,有想研究的可以看下。
http://pan.baidu.com/s/1mntsc