Python GTK (Hacking Camp)

Preview:

Citation preview

Yuren Ju <yurenju@gmail.com>

Python-GTK Tutorial

請先安裝

● sudo apt-get install python-pywapi glade

Yuren Ju● Yuren's Info Area● Hacking Thursday

本份投影片……

● 假設你學過任何一種程式語言● 特別有可能是 Java

+Python GTK+

Source: TIOBE Software index

TIOBE 程式語言社群指標

?Source: "Why?", Mike Luckovich, Pulitzer-Winning Political Cartoonist (1 of 4), cc-by-deed

別人怎麼說…

● 適合初學者,但也適合進階開發者● 高度彈性:從大型專案到小型專案都適合使用● you can get the job done

Source: What is Python and Why Python

對我來說的 Python 優點

● 短小精簡● 程式碼簡潔● 快速驗證想法● 處理工作雜事

● e.g. 產生報表、字串置換等

Python

Start!

將程式碼寫於檔案中 打開終端機直接鍵入程式

打開你的終端機!

$ python

python command-line

print "Hello World!!"

資料型態str, int, float, bool, list, dict

數值指定

● String● var = "this is String"

● Integer● var = 1

● Boolean● var = True

● Float● var = 0.1

不需要宣告形態

String var = "this is String";int var = 1;boolean var = true;float var = 0.1;

list & dict● list => 陣列● dict => hash table

list● actors = ["Neo", "Smith", "Trinity", "Oracle"]

● mixed = ["hi", "apple", 0, 0.1, False]

● print actors[1]

● actors.append ("Morpheus")

● del actors[1]

● actors.remove ("Oracle")

● actors[-1]

● actors[:2]

● [1,2,3] + [4,5,6]

If, else, for, while

4 個空白或是一個 tab

if first == True: print "Mr. Anderson."else: print "Welcome back, we missed you."

開頭原本是用括號的地方改用冒號

結尾不需要括號

list (cont.)

for a in actors:

print a

for a in actors[2:]:

print a

print sorted (actors)

del actors[2:]

dict

person = {"name": "Yuren Ju", "website": "http://yure...", "birthday": "yyyy/mm/dd"}

print person["name"]print person["website"]

dict

for k in person: print "%s: %s" % (k, person[k])

if person.has_key ("age"): print "no age attribute"

File Access● f = open('your_file')

● Open file

● readline()● readlines()

來處理些瑣事吧!

COSCUP● 前天系統爆炸了● 我發起了一個紀錄爆炸過程的小活動

無法閱讀Python 上場!

目標輸出成 HTML 方便閱讀

流程

● 下載 google docs 的 csv 檔案● 開啟檔案● 讀取內容● 切割字串● 產生 HTML 網頁

http :/ / j.mp / pygtk-c osc up

Gen.py

function

def func (arg1, arg2): #Do something... return ret

奇技淫巧

● newlist = [n for n in oldlist if n > 50]● function return tuple

Editor

將程式碼寫於檔案中

建議

● Geany● Gedit● eclipse● Of cause~ vim!

Hello-world.py

# -*- coding: utf-8 -*-print "你好世界!"

line 1

Python String

Byte String Unicode String

預設 # -*- coding: utf-8 -*-

gedit

翻譯

http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&ie=utf8&q=test&langpair=en|zh-tw

http://j.mp/dXYwLT

#!/usr/bin/env python# -*- coding: utf-8 -*-

from urllib2 import urlopenfrom urllib import urlencodeimport simplejsonimport sys

def translate(text): sl="zh-tw" tl="en" langpair='%s|%s'%(tl,sl)

base_url = 'http://ajax.googleapis.com/ajax/services/language/translate?' data = urlencode({'v':1.0,'ie': 'UTF8', 'q': text, 'langpair':langpair})

url = base_url+data urlres = urlopen(url) json = simplejson.loads(urlres.read())

result = json['responseData']['translatedText'] return result

if __name__ == "__main__": print translate (sys.argv[1])

https://gist.github.com/801339

tw-weather.py#!/usr/bin/env python# -*- coding: utf-8 -*-

import pywapi

cities = pywapi.get_cities_from_google('tw', 'zh-tw')

for c in cities: print "%s: " % (cities.index(c)+1), print c['name']

num = int (raw_input ("type: "))city = cities[num-1]weather = pywapi.get_weather_from_google(',,,%s,%s' % (city['latitude_e6'], city['longitude_e6']), 'zh-tw')

print "天氣:%s" % weather['current_conditions']['condition'].encode ('utf-8')print "濕度:%s" % weather['current_conditions']['humidity'].encode ('utf-8')print "現在溫度:%s" % weather['current_conditions']['temp_c'].encode ('utf-8')

https://gist.github.com/801493

Class/Object

#!/usr/bin/env python# -*- coding: utf-8 -*-

class FirstClass: def __init__(self): self.data = ["a", "b", "c"]

def print_data(self): print self.data

if __name__ == "__main__": f = FirstClass() f.print_data()

class FirstClass { private String[] data;

public FirstClass() { String[] data = {"a", "b", "c"}; this.data = data; }

public void printData() { for (int i = 0; i < data.length; i++) { System.out.println (data[i]); } }

public static void main (String[] args) { FirstClass f = new FirstClass(); f.printData(); }}

GTK+

Windows FormwxWidgetsQt

GTK+

Swing/AWTAndroidView/Widget/Layout

MFC

Cross Platform

crossing the line, Jkönig, CC BY-NC-SA 2.0

GTK+

PythonC/C++ Perl Ruby C# ...

Linux Windows Mac

PHP

使用 GTK 的軟 / 硬體

Nokia n900

#!/usr/bin/env python

import pygtkpygtk.require ('2.0')import gtk

if __name__ == "__main__": window = gtk.Window (); window.show ()

gtk.main ()

Event Handler

widget.connect("signal-name", callback)

#!/usr/bin/env python

import pygtkpygtk.require ('2.0')import gtk

def destroy (window): gtk.main_quit ()

def hello (button): print "Hello World"

if __name__ == "__main__": window = gtk.Window () window.connect ("destroy", destroy) window.show ()

button = gtk.Button ("hello"); button.connect ("clicked", hello) button.show ()

window.add (button) gtk.main ()

gtk reference - gtk.Button

#!/usr/bin/env python

import pygtkpygtk.require ('2.0')import gtk

class HelloWorld: def __init__ (self): window = gtk.Window () window.connect ("destroy", self.destroy) window.show ()

button = gtk.Button ("hello"); button.connect ("clicked", self.hello) button.show ()

window.add (button) self.position = 0

def destroy (self, window): gtk.main_quit ()

def hello (self, button): print "Hello World, position: %d" % self.position self.position += 1

if __name__ == "__main__": hello = HelloWorld () gtk.main ()

Keep state, using class/object

https://gist.github.com/801496

Layout.layouts, Kemeny_x, CC BY-NC 2.0

GTK+ Layout – box packing

HBox

VBox

HBox VBox VBox

hbox = gtk.HBox()vbox1 = gtk.VBox()vbox2 = gtk.VBox()hbox.pack_start(vbox1)hbox.pack_start(vbox2)

pack_start / pack_end

window = gtk.Window ()hbox = gtk.HBox()vbox1 = gtk.VBox()vbox2 = gtk.VBox()hbox.pack_start(vbox1)hbox.pack_start(vbox2)

label = gtk.Label ("Text: ")vbox1.pack_start (label)

textview = gtk.TextView ()vbox1.pack_start (textview)

button_ok = gtk.Button ("OK")vbox2.pack_end (button_ok)

button_cancel = gtk.Button ("Cancel")vbox2.pack_end (button_cancel)

hbox.show_all()window.add(hbox)window.show()

layout

expand=Truefill=True

expand=Truefill=False

expand=Falsefill=False

window = gtk.Window ()hbox = gtk.HBox()vbox1 = gtk.VBox()vbox2 = gtk.VBox()hbox.pack_start(vbox1)hbox.pack_start(vbox2, expand=False)

label = gtk.Label ("Text: ")label.set_property('xalign', 0.0)textview = gtk.TextView ()vbox1.pack_start (label, expand=False)vbox1.pack_start (textview)

button_ok = gtk.Button ("OK")button_cancel = gtk.Button ("Cancel")vbox2.pack_end (button_ok, expand=False)vbox2.pack_end (button_cancel, expand=False)

hbox.show_all()window.add(hbox)window.show()

用程式刻 UI 累了嗎?

Tired Joy!, Tambako the Jaguar, by-nd

Gtk Builder

Gtk Builder

builder = gtk.Builder () builder.add_from_file ("layout.glade") window = builder.get_object ("window1") window.show ()

builder.connect_signals (self)

翻譯軟體 – GTK 版本

● 拉 UI (glade)● 事件分配 (glade)● 事件分配 (python)

gtk.TextView

gtk.TextView

gtk.TextBuffer

顯示文字內容

操作文字:- insert- delete

UI Freeze

Frozen Moment, drinksmachine, by-nc-nd

English 中文

UI Freeze

費時的操作

UI Freeze

Thread

嘿 Neo, 又是我

費時的操作

Thread

UI update

def translate(text): ... ...

class TransThread (Thread): def __init__(self, text, obj): self.text = text Thread.__init__(self)

def run(self): try: self.result = translate(self.text) except: self.result = "error"

Thread

Communication?

UI part Thread part?

概念

● 繼承gobject 或 gtk.Object● 註冊一個信號 (signal)● 連接此 signal● 當 Thread 結束後射出 (emit)此 signal

步驟

● gobject.type_register (Translation)

● gobject.signal_new("thread-complete", Translation, gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, ())

● self.connect ("thread-complete", self.thread_complete)

● self.obj.emit("thread-complete")

gtk-gtr2.py

範例

TreeViewTreeViewColumnCellRendererText

ListStoreTreeStore

View Model

Glade

ListStore

Weather

load-cities-completed load-weather-completed__init__

CitiesThread

Create

selected_city

WeatherThread

Create

產生城市列表 取得城市天氣

def __init__(self): self.__gobject_init__() self.builder = gtk.Builder() self.builder.add_from_file ("weather.glade") self.builder.connect_signals(self)

win = self.builder.get_object("window1") win.show_all() self.register_signals()

self.cities_thread = CitiesThread(self) self.cities_thread.start()

self.tree = self.builder.get_object("treeview_cities") col_name = gtk.TreeViewColumn("city name") self.tree.append_column(col_name) cell = gtk.CellRendererText() col_name.pack_start(cell, True) col_name.add_attribute(cell, 'text', 0)

self.tree.connect("cursor-changed", self.selected_city)

__init__

class CitiesThread(Thread): def __init__(self, obj): self.obj = obj Thread.__init__(self)

def run(self): self.cities = pywapi.get_cities_from_google('tw', 'zh-tw') gtk.gdk.threads_enter() self.obj.emit("load-cities-completed") gtk.gdk.threads_leave()

CitiesThread

WeatherThread

class WeatherThread(Thread): def __init__(self, obj, latitude, longitude): self.obj = obj self.latitude = latitude self.longitude = longitude Thread.__init__(self)

def run(self): weather = pywapi.get_weather_from_google(',,,%s,%s' % (self.latitude, self.longitude), 'zh-tw') self.weather = {"condition": weather['current_conditions']['condition'], "humidity": weather['current_conditions']['humidity'], "temp_c": weather['current_conditions']['temp_c']} gtk.gdk.threads_enter() self.obj.emit("load-weather-completed") gtk.gdk.threads_leave()

load-cities-completed

def load_cities_completed(self, obj): self.cities = self.cities_thread.cities self.liststore = self.builder.get_object("cities") for city in self.cities: self.liststore.append \ ([city['name'], long(city['latitude_e6']), long(city['longitude_e6'])])

load-weather-completed

def load_weather_completed(self, obj): weather = self.weather_thread.weather self.builder.get_object("label_temperature") \ .set_markup ("<span size='xx-large'>溫度:%s</span>" % weather['temp_c'])

self.builder.get_object("label_current") \ .set_label ("現在天氣:%s" % weather['condition'])

self.builder.get_object("label_humidity") \ .set_label ("濕度:%s" % weather['humidity'])

selected_city

def selected_city(self, tree): selection = self.tree.get_selection() (model, iter) = selection.get_selected() name = model.get_value(iter, 0) latitude = model.get_value(iter, 1) longitude = model.get_value(iter, 2) print "%s (%s, %s)" % (name, latitude, longitude) self.weather_thread = WeatherThread(self, latitude, longitude) self.weather_thread.start()

gtk-weather.py

https://gist.github.com/800513

釣竿

● Dive Into Python 中文版● PyGTK 2.0 Tutorial● PyGTK 2.0 Reference Manual● google "python gtk <問題關鍵字 >"● 在 stackoverflow.com 上面找答案

Recommended