<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-456964502679783250</id><updated>2025-11-28T03:53:49.857+08:00</updated><category term="Note"/><category term="PyQt"/><category term="Python"/><category term="Linux"/><title type='text'>OGC Gains Comfort</title><subtitle type='html'>珍愛生命　遠離編程</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-4035561088040005588</id><published>2012-02-24T15:56:00.000+08:00</published><updated>2012-07-11T18:34:58.081+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>LotR: LCG for PC</title><content type='html'>&lt;p&gt;A program for playing Fantasy Flight Games&#39; &lt;a href=&quot;http://www.fantasyflightgames.com/edge_minisite_sec.asp?eidm=129&amp;esem=4&quot;&gt;The Lord of the Rings: The Card Game&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Screenshot:&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjmbdaFLKVgBbquWQL-bR2Kb2OadT6N4eSz2ySWazRldemzQRYrZFxboHWS-vpdkFKOpSFNR53r-FrTvQokHGnDsf9pfdGA-aPycs3BCD_k1ewHPWLkUuxNvYeV-Q2vmRmdZzK8byD3lc/s1600/scenario1.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;213&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjmbdaFLKVgBbquWQL-bR2Kb2OadT6N4eSz2ySWazRldemzQRYrZFxboHWS-vpdkFKOpSFNR53r-FrTvQokHGnDsf9pfdGA-aPycs3BCD_k1ewHPWLkUuxNvYeV-Q2vmRmdZzK8byD3lc/s400/scenario1.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Setup dialog:&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe2QGYTVsNkc_ZtuwH0P1dMDWwhil5lwJYLGU8om8EM_xgVc3Znxlz__m33BjjfM6dLcFhr_j0kC-hHnuOvHVI8InzylE2V9wjk6zEBDLYjm1YsbC-Y6_yoKyO7xYfzSMehcAaqfCPmzU/s1600/SetupDialog.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;235&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe2QGYTVsNkc_ZtuwH0P1dMDWwhil5lwJYLGU8om8EM_xgVc3Znxlz__m33BjjfM6dLcFhr_j0kC-hHnuOvHVI8InzylE2V9wjk6zEBDLYjm1YsbC-Y6_yoKyO7xYfzSMehcAaqfCPmzU/s400/SetupDialog.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Deck manipulation:&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaeerT08BIHnoo9cSmeq4TicRCGc9nJ8xTG4lBDpeAmk55W716Y3CYG7qjKE7Je8kOORmQXUCs7WSMm7y2u2EMmVCrF4BWxb_7zf8qQG_ivM7sAoBVBvosUYYTM7xxx3kEZvpqrNwYNX4/s1600/screenshot2.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;213&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaeerT08BIHnoo9cSmeq4TicRCGc9nJ8xTG4lBDpeAmk55W716Y3CYG7qjKE7Je8kOORmQXUCs7WSMm7y2u2EMmVCrF4BWxb_7zf8qQG_ivM7sAoBVBvosUYYTM7xxx3kEZvpqrNwYNX4/s400/screenshot2.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
Deck Builder:&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEuRKdCrvsp8c2kgs_QhtothqD-1Ydqu8Zc0emOO_eNGtqjsecC_rTxDuktAh6tcpIIh_oBheOqoUQbakRd3UVtZhQuwfq27vLLpNjAWIwrXly_9pv1XUvxKrWZp16yKob6-qiJyL9iY8/s1600/deckbuilder.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;213&quot; width=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEuRKdCrvsp8c2kgs_QhtothqD-1Ydqu8Zc0emOO_eNGtqjsecC_rTxDuktAh6tcpIIh_oBheOqoUQbakRd3UVtZhQuwfq27vLLpNjAWIwrXly_9pv1XUvxKrWZp16yKob6-qiJyL9iY8/s400/deckbuilder.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;
&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;br /&gt;
&lt;p&gt;Solo and Multiplayer game available.&lt;/p&gt;&lt;p&gt;The program provides auto Scenario setting and Card/Token dragging.&lt;br /&gt;
Players must resolve Phases/Damage/Card-effects etc by themselves.&lt;/p&gt;&lt;p&gt;Note that you can join your own game and play multiplayer game by yourself. (Dual screen recommended!)&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Download: &lt;a href=&quot;http://db.tt/wtOLbOPl&quot;&gt;LotR LCG 2012.07.07&lt;/a&gt; (44.8 MB)&lt;br /&gt;
(&lt;a href=&quot;https://github.com/amulet-tw/LotR-LCG/blob/master/CHANGELOG.txt&quot;&gt;changelog&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
If you&#39;ve built decks by this program before, copy over your refined &amp;quot;decks.json&amp;quot; file.&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Supported expansion sets:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Core set&lt;/li&gt;
&lt;li&gt;&amp;quot;Shadows of Mirkwood&amp;quot; cycle&lt;/li&gt;
&lt;li&gt;The Massing at Osgiliath&lt;/li&gt;
&lt;li&gt;Khazad-dum&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
Their physical release dates are listed &lt;a href=&quot;https://github.com/amulet-tw/LotR-LCG/blob/master/resource/doc.txt&quot;&gt;here&lt;/a&gt;. New expansions will be supported six months after it.&lt;br /&gt;
&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Some docs from BGG may help to play this game:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;http://boardgamegeek.com/filepage/67464/universal-head-the-lord-of-the-rings-the-card-game&quot;&gt;Universal Head THE LORD OF THE RINGS: THE CARD GAME Rules Summary &amp; Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://boardgamegeek.com/filepage/66624/clarified-turn-sequence-and-quick-reference-w-faqs&quot;&gt;Clarified Turn Sequence and Quick Reference w/ FAQs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://boardgamegeek.com/filepage/66894/comprehensive-card-reference-unofficial-faq&quot;&gt;Comprehensive Card Reference &amp; Unofficial FAQ&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/p&gt;&lt;hr /&gt;Troubleshooting: If card images are missing, install &lt;a href=&quot;http://www.microsoft.com/download/en/details.aspx?id=5582&quot;&gt;vcredist_x86.exe&lt;/a&gt;.&lt;br /&gt;
&lt;hr /&gt;&lt;p&gt;Have fun and enjoy it!&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/4035561088040005588/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2012/02/lotr-lcg-for-pc.html#comment-form' title='12 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4035561088040005588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4035561088040005588'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2012/02/lotr-lcg-for-pc.html' title='LotR: LCG for PC'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjmbdaFLKVgBbquWQL-bR2Kb2OadT6N4eSz2ySWazRldemzQRYrZFxboHWS-vpdkFKOpSFNR53r-FrTvQokHGnDsf9pfdGA-aPycs3BCD_k1ewHPWLkUuxNvYeV-Q2vmRmdZzK8byD3lc/s72-c/scenario1.jpg" height="72" width="72"/><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-547861464496238829</id><published>2011-01-30T15:49:00.004+08:00</published><updated>2012-02-12T15:15:13.886+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>X11 Selection Translator</title><content type='html'>Windows 下的字典軟體都異常強大，有著螢幕取詞、即時發音等大量功能 ( 像是我現在用的&lt;a href=&quot;http://cidian.youdao.com/&quot;&gt;有道词典&lt;/a&gt; )。希望在 Linux 下也有類似螢幕取詞這樣的方便功能，於是寫了&lt;a href=&quot;https://github.com/amulet-tw/X11-Selection-Translator&quot;&gt;這玩意兒&lt;/a&gt;。&lt;br /&gt;
&lt;br /&gt;
......不過螢幕取詞貌似相當地有難度啊 (||。３。)　翻了一下 &lt;a href=&quot;http://en.wikipedia.org/wiki/Xlib&quot;&gt;Xlib&lt;/a&gt;，好像沒有相關 API 可以摳...... 所以改成實現&lt;strong&gt;自動翻譯滑鼠選取的文字，並在游標下顯示翻譯結果&lt;/strong&gt;：&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-Fiacn-cHAgBIk0S8NIFeVuPfkPV83Lpsk21-OsRvTr-kD9DTLdhlQadd5nLGW0C7G3nT9qg42Q-jhHWH0gEbSbFaqPiEQAAa7ppN5pkERp7kcuWHF2GGt44yYSqiSREroQbMynkIQg/s1600/sample.png&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;150&quot; width=&quot;215&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-Fiacn-cHAgBIk0S8NIFeVuPfkPV83Lpsk21-OsRvTr-kD9DTLdhlQadd5nLGW0C7G3nT9qg42Q-jhHWH0gEbSbFaqPiEQAAa7ppN5pkERp7kcuWHF2GGt44yYSqiSREroQbMynkIQg/s400/sample.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt; &lt;br /&gt;
在 X11 下，Copy &amp;amp; Paste 功能叫做 &lt;a href=&quot;http://www.jwz.org/doc/x-cut-and-paste.html&quot;&gt;Selections&lt;/a&gt;。有分為兩種： &lt;ul&gt;&lt;li&gt;Clipboard：一般通用的。你知道的。不解釋。&lt;/li&gt;
&lt;li&gt;Primary：用滑鼠選取字串時，自動將文字內容放入 buffer 內；之後可以用滑鼠中鍵貼上 buffer 內容。就是它了！&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
本來以為要搞低階 X Window programming 的說...... 還好想起了強大的 Qt，文檔裡還真的有 &lt;tt&gt;QClipboard.selectionChanged()&lt;/tt&gt; 這個 signal 可以用 ( 包山包海，不愧是 KDE SC 的基石 )，那就可以即時地對滑鼠選取有反應啦 (＞ω＜)♪♪&lt;br /&gt;
&lt;br /&gt;
至於翻譯部份，交給股溝提供的服務來處理。見下例： &lt;a href=&quot;http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&amp;q=python%20rocks!&amp;langpair=en|zh-TW&quot;&gt;http://ajax.googleapis.com/ajax/services/language/translate?v=1.0&amp;amp;q=python%20rocks!&amp;amp;langpair=en|zh-TW&lt;/a&gt;&lt;br /&gt;
可以觀察到，就是朝這網址塞進翻譯參數 ( 大段文章也可以塞 )，結果是 JSON 格式。Python 有 &lt;tt&gt;urllib&lt;/tt&gt; / &lt;tt&gt;urllib2&lt;/tt&gt; 可以處理網路連線，也有 &lt;tt&gt;json&lt;/tt&gt; 可以 parse。&lt;br /&gt;
&lt;br /&gt;
一個關鍵小技巧是去除翻譯小視窗的 window decorator 和邊框。&lt;tt&gt;QWidget.setWindowFlags(Qt::SplashScreen)&lt;/tt&gt; 可以完成這件事，讓 widget 具有類似 SplashScreen 的怪異性質。用這個技巧還可以寫成背單字工具、定時自動遮掩全屏的 Anti-&lt;a href=&quot;http://zh.wikipedia.org/zh-tw/%E9%87%8D%E8%A4%87%E4%BD%BF%E5%8A%9B%E5%82%B7%E5%AE%B3&quot;&gt;RSI&lt;/a&gt; 小程式等等，端視想像力。&lt;br /&gt;
&lt;br /&gt;
( 要注意的是，翻譯小視窗還是得受到 window manager 控制...... 所以如果 WM 會自動移動新視窗的話，這程式就直接挫賽瞭～～)&lt;br /&gt;
&lt;br /&gt;
最後一點，這程式是透過 SystemTray 常駐存活的，用到了兩個 icon。因為我希望把需要的資源通通搞進單一檔案內 ( 而不是又東一個西一個圖檔散了滿地 )，所以把圖檔內容轉換成 binary text 摳進程式碼，再用 &lt;tt&gt;QPixmap.loadFromData(data)&lt;/tt&gt; 讀入。轉換函式大概長得像這樣：&lt;br /&gt;
&lt;pre class=&quot;prettyprint lang-py linenums:1&quot;&gt;def dump_binary(filepath):
    with open(filepath, &#39;rb&#39;) as f:
        content = f.read()
        output = &#39;&#39;
        for byte in content:
            h = hex(ord(byte))[2:]
            if len(h) == 1:
                h = &#39;0&#39; + h
            output += &#39;\\x&#39; + h
    return &quot;&#39;&quot; + output + &quot;&#39;&quot;
&lt;/pre&gt;這就是程式碼開頭那兩行長串亂碼的由來......&lt;br /&gt;
&lt;hr /&gt;就這樣，翻譯程式完成啦！缺點是需要網路連線，而且這個 Google API 只提供單一翻譯結果 QQ &lt;hr /&gt;話說，嘗試寫這玩意兒的途中還曾經用 &lt;tt&gt;threading&lt;/tt&gt; 來設計...... 那蛋真是一陣一陣疼個沒完沒了啊！有空的話真該惡補一下多緒程式了 =.=</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/547861464496238829/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/x11-selection-translator.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/547861464496238829'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/547861464496238829'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/x11-selection-translator.html' title='X11 Selection Translator'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjo-Fiacn-cHAgBIk0S8NIFeVuPfkPV83Lpsk21-OsRvTr-kD9DTLdhlQadd5nLGW0C7G3nT9qg42Q-jhHWH0gEbSbFaqPiEQAAa7ppN5pkERp7kcuWHF2GGt44yYSqiSREroQbMynkIQg/s72-c/sample.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-7014571197499464975</id><published>2011-01-05T11:50:00.002+08:00</published><updated>2011-01-06T18:38:49.436+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>OpenCV face detection with Alcapas</title><content type='html'>&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2OM2PFQmr-nyYFVWkLe9wGmsMzgQbNDKkcsaapMTw28ZfC-oWCgeX7riXjfpZjhHxIaXXblF6DrZ0TBoaadHirZZLCWoyqfy8bmoyu8Sw2VEx5yYcmM6sc6Ay5LEPft5uLDQoupuXWc/s1600/alpaca_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; width=&quot;244&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2OM2PFQmr-nyYFVWkLe9wGmsMzgQbNDKkcsaapMTw28ZfC-oWCgeX7riXjfpZjhHxIaXXblF6DrZ0TBoaadHirZZLCWoyqfy8bmoyu8Sw2VEx5yYcmM6sc6Ay5LEPft5uLDQoupuXWc/s320/alpaca_op.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote&gt;&lt;a href=&quot;http://opencv.willowgarage.com/wiki/&quot;&gt;OpenCV&lt;/a&gt; (Open Source Computer Vision) is a library of programming functions for real time computer vision.&lt;/blockquote&gt;
我沒背景知識，只會摳摳 API =.=&lt;br /&gt;
&lt;tt&gt;&lt;a href=&quot;http://opencv.willowgarage.com/documentation/python/objdetect_cascade_classification.html&quot;&gt;HaarDetectObjects&lt;/a&gt;&lt;/tt&gt; 可以偵測物體，丟 &lt;tt&gt;haarcascade_frontalface_default.xml&lt;/tt&gt; 進去就是偵測臉部。&lt;br /&gt;
&lt;br /&gt;
藍框標出程式有反應的區域。&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPhjPemD5zkpj0x7QoGovbRcKJ925U605WFWeLjazCEtMLLuPX7b8cIcXMlRhH_68YDRjDMVf2tIWL9t7tZITkrGD2aRhWeR3RMr-zUHDJ_qihn6ut0JZXRFsvZpdNMoqJekX37u7hBcU/s1600/huggable_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;320&quot; width=&quot;191&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPhjPemD5zkpj0x7QoGovbRcKJ925U605WFWeLjazCEtMLLuPX7b8cIcXMlRhH_68YDRjDMVf2tIWL9t7tZITkrGD2aRhWeR3RMr-zUHDJ_qihn6ut0JZXRFsvZpdNMoqJekX37u7hBcU/s320/huggable_op.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;
( &lt;a href=&quot;http://codepad.org/wGsToYNU&quot;&gt;code&lt;/a&gt; )&lt;br /&gt;
&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;
# Tested under Python 2.7.1 + OpenCV 2.2&lt;br /&gt;
import cv&lt;br /&gt;
&lt;br /&gt;
image = cv.LoadImage(&#39;input.jpg&#39;)&lt;br /&gt;
cascade = cv.Load(&#39;/usr/share/opencv/haarcascades/haarcascade_frontalface_default.xml&#39;)&lt;br /&gt;
faces = cv.HaarDetectObjects(image, cascade, cv.CreateMemStorage())&lt;br /&gt;
for (x, y, w, h), n in faces:&lt;br /&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cv.Rectangle(image, (x, y), (x + w, y + h), 255)&lt;br /&gt;
&lt;br /&gt;
cv.SaveImage(&#39;output.jpg&#39;, image)
&lt;/code&gt;&lt;br /&gt;
cascade 沒丟完整路徑進去的話可能會 Segmentation fault......&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRsYWmTQCw8evrKDdviblljB3lJt8C2w1db7w6hwVYjnC2-cTyBfBExomxNp-FvZJ9x71td4sD2kYx3LrstQ-vVZBztKHHi-Lp1tvU1XtxOY_Wh86w0sGNoa7MNmGFNexbkROcqsW9RU/s1600/0922alpacas540_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;213&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgHRsYWmTQCw8evrKDdviblljB3lJt8C2w1db7w6hwVYjnC2-cTyBfBExomxNp-FvZJ9x71td4sD2kYx3LrstQ-vVZBztKHHi-Lp1tvU1XtxOY_Wh86w0sGNoa7MNmGFNexbkROcqsW9RU/s320/0922alpacas540_op.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtUCNjGQF_SpbuIDjU-s4lhUMDBD9ypgAuTdCx-sOn425mtAu7KX6AzUNaEn8BtnwN-e07ZmMR04pKyTY_F2_3OF2aVzk50bghUn7InVXQHCg8NEnb5raJapbeiHtmjCl9OKyafC-6Wfk/s1600/alpacas2bnps_450x300_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;214&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtUCNjGQF_SpbuIDjU-s4lhUMDBD9ypgAuTdCx-sOn425mtAu7KX6AzUNaEn8BtnwN-e07ZmMR04pKyTY_F2_3OF2aVzk50bghUn7InVXQHCg8NEnb5raJapbeiHtmjCl9OKyafC-6Wfk/s320/alpacas2bnps_450x300_op.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;

&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzANFY2cIGft4hXcCemVhOYWTvaAq4jmyybW01LgfAJRnYQPL9ihMCwekyalV2xNoHl3PbKp9isEXk0HBTpE-FCkSJdfXmLxlBp6iKJAQEVZdiul-aO-atVSooFHb5NJHv5rLpn56-2JM/s1600/bovian_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;224&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzANFY2cIGft4hXcCemVhOYWTvaAq4jmyybW01LgfAJRnYQPL9ihMCwekyalV2xNoHl3PbKp9isEXk0HBTpE-FCkSJdfXmLxlBp6iKJAQEVZdiul-aO-atVSooFHb5NJHv5rLpn56-2JM/s320/bovian_op.jpg&quot; /&gt;&lt;/a&gt;&lt;br /&gt;牧草泥馬人表示：......&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Z1DCmziNqLBLnzEkJ0sHFM3KSscuEQeIDsH5S5FruqHtfD44sf95HbDhkYNlHxZfZxPzQGZMuIjF-UqLkh2_evLek5y-R6NOgAkiyorlkPj-VeLl_5adbc2z3ny8mLcwRgMddOW4EB4/s1600/nicole-kidman-alpaca_op.jpg&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;300&quot; width=&quot;300&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1Z1DCmziNqLBLnzEkJ0sHFM3KSscuEQeIDsH5S5FruqHtfD44sf95HbDhkYNlHxZfZxPzQGZMuIjF-UqLkh2_evLek5y-R6NOgAkiyorlkPj-VeLl_5adbc2z3ny8mLcwRgMddOW4EB4/s320/nicole-kidman-alpaca_op.jpg&quot; /&gt;&lt;/a&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/7014571197499464975/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/opencv.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/7014571197499464975'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/7014571197499464975'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/opencv.html' title='OpenCV face detection with Alcapas'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp2OM2PFQmr-nyYFVWkLe9wGmsMzgQbNDKkcsaapMTw28ZfC-oWCgeX7riXjfpZjhHxIaXXblF6DrZ0TBoaadHirZZLCWoyqfy8bmoyu8Sw2VEx5yYcmM6sc6Ay5LEPft5uLDQoupuXWc/s72-c/alpaca_op.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-4899460400476241443</id><published>2011-01-04T20:31:00.009+08:00</published><updated>2011-01-11T14:39:57.198+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>PyQt + PyBox2D is easy!</title><content type='html'>Qt Labs 的文章 &lt;a href=&quot;http://labs.qt.nokia.com/2010/02/26/qt-box2d-is-easy/&quot;&gt;Qt + Box2D is easy!&lt;/a&gt; 給了一個物體碰撞的小範例。&lt;br /&gt;
&lt;br /&gt;
Box2D 是一個開源的 C++ 2D 剛體物理引擎，包括了連續碰撞偵測、支點限制、摩擦力、齒輪等&lt;a href=&quot;http://www.box2d.org/features.html&quot;&gt;功能&lt;/a&gt;，可以模擬物體互動...... 的數值。它的核心本身不管畫面渲染，所以只會更新物體們的狀態；欲呈現出來，請自行調用任意繪圖函式庫，抓物件狀態數值出來畫......&lt;br /&gt;
&lt;br /&gt;
所以那篇文章就用 Qt 繪圖框架結合 Box2D，弄了個漂亮的彩色小三角形下落模擬。由於我個人一看到 C++ 語法就開始覺得陣陣髮指兼蛋疼，所以把原文給的程式碼用 Python 改寫了。結果在&lt;a href=&quot;http://codepad.org/WHYdJL3z&quot;&gt;這裡&lt;/a&gt; ( &lt;a href=&quot;http://pastebin.com/2gpcdMPT&quot;&gt;備份&lt;/a&gt; )。&lt;br /&gt;&lt;br /&gt;
測試通過的環境：&lt;br /&gt;
&lt;table&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt&gt;ArchLinux&lt;/tt&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt&gt;Python&lt;/tt&gt;&lt;/td&gt;&lt;td&gt;2.7.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt&gt;Box2D&lt;/tt&gt;&lt;/td&gt;&lt;td&gt;2.1.2&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt&gt;PyBox2D&lt;/tt&gt;&lt;/td&gt;&lt;td&gt;svn&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;tt&gt;PyQt&lt;/tt&gt;&lt;/td&gt;&lt;td&gt;4.8.2&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCJRJOzdLfoLNCxKCvnx1ha_-YVQGVztlQU-qglrw1ESmCyy2effYPvZVQy92qdt0FRQ0b9reMFj8jd9stVYtXg0GEdWPfSvnGQ2SuiiA51qyezIFv-_cnt7_VcjSHo5P5EMakrUqMjgs/s1600/pybox2d.png&quot; imageanchor=&quot;1&quot; style=&quot;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;273&quot; width=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCJRJOzdLfoLNCxKCvnx1ha_-YVQGVztlQU-qglrw1ESmCyy2effYPvZVQy92qdt0FRQ0b9reMFj8jd9stVYtXg0GEdWPfSvnGQ2SuiiA51qyezIFv-_cnt7_VcjSHo5P5EMakrUqMjgs/s320/pybox2d.png&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
描述一下寫簡單 Box2D 2.0 程式的觀念，希望沒有錯誤：&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;物體由 &lt;tt&gt;b2Body&lt;/tt&gt; 儲存其位置、線性速度、角度、角速度、阻尼等數值。&lt;/li&gt;
&lt;li&gt;另由 &lt;tt&gt;b2PolygonShape&lt;/tt&gt; / &lt;tt&gt;b2CircleShape&lt;/tt&gt; 儲存實際碰撞面積、密度、摩擦力等數值。&lt;/li&gt;
&lt;li&gt;Body 可和 ( 多個 ) Shape 綁在一起，例如搞成個啞鈴，這樣它就又有物理狀態又能碰撞了，可以和其它物體們互動啦～&lt;/li&gt;
&lt;li&gt;一組一組地綁好之後用 &lt;tt&gt;b2World.CreateBody(b2BodyDef)&lt;/tt&gt; 塞進世界中。這個函式用來簡化記憶體管理：讓 b2World 接手物體，在它該升仙的時候能自動拖子孫十八代下水。Python 自己有垃圾車到處開，不過對於沒有 Garbage Collector 的 C++ 框架來說，記憶體管理需要額外關注......&lt;/li&gt;
&lt;li&gt;每次呼叫 &lt;tt&gt;b2World.Step(timeStep, velocityIterations, positionIterations)&lt;/tt&gt; 時讓整個世界往前模擬一小步。後兩個玩意兒影響模擬精度，官方建議一般場合直接塞 10 和 8。&lt;/li&gt;
&lt;li&gt;要具體呈現的話，就是在每次呼叫 &lt;tt&gt;Step(timeStep, 10, 8)&lt;/tt&gt; 後讓繪圖函式重抓物件數值，更新畫面位置囉......。&lt;tt&gt;QGraphicsItem&lt;/tt&gt; 之類東東的 API 還請自行查閱 Qt 文檔 =3=a&lt;/li&gt;
&lt;li&gt;Box2D 2.1 引進了 fixture 這玩意兒。Python binding 目前還沒更新，所以我不太瞭解是啥回事...... 貌似讓 Shape 單獨管理碰撞範圍了吧。&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
就這樣，更多的範例程式可以看 &lt;a href=&quot;http://code.google.com/p/pybox2d/&quot;&gt;PyBox2D&lt;/a&gt; 的 testbed。&lt;br /&gt;
&lt;br /&gt;
Makefile 什麼的最討厭了 (＞ω＜)♪♪</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/4899460400476241443/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/pyqt-pybox2d-is-easy.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4899460400476241443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4899460400476241443'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2011/01/pyqt-pybox2d-is-easy.html' title='PyQt + PyBox2D is easy!'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCJRJOzdLfoLNCxKCvnx1ha_-YVQGVztlQU-qglrw1ESmCyy2effYPvZVQy92qdt0FRQ0b9reMFj8jd9stVYtXg0GEdWPfSvnGQ2SuiiA51qyezIFv-_cnt7_VcjSHo5P5EMakrUqMjgs/s72-c/pybox2d.png" height="72" width="72"/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-5590327011914424634</id><published>2009-10-27T12:35:00.013+08:00</published><updated>2011-08-25T22:57:53.980+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>ArchLinux + LXDE 安裝筆記 ( 2009.08 )</title><content type='html'>&lt;p&gt;去年有寫過一篇&lt;a href=&quot;http://ogc-daily.blogspot.com/2008/10/archlinux.html&quot;&gt;相同主題的&lt;/a&gt;。過時瞭，所以再生篇新的。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;什麼樣的人適合用 Linux 呢？我覺得這個問題還挺重要的。畢竟意志不夠堅強、人品又剛好低落的話，很容易會被 Linux 折騰個火冒三丈。&lt;/p&gt;&lt;p&gt;參考答案：有工作 or 學習上的需求，或者信念使然。&lt;/p&gt;&lt;p&gt;以上皆非卻又想摸摸 Linux 世界的話，等後天出的 &lt;a href=&quot;http://www.ubuntu.com/&quot;&gt;Ubuntu&lt;/a&gt; 9.10 吧！那發行版的社群龐大無比，遇到問題隨便股溝隨便有解，穩穩坐定最適合入門者的第一把交椅。&lt;/p&gt;&lt;p&gt;至於 &lt;a href=&quot;http://www.archlinux.org/&quot;&gt;ArchLinux&lt;/a&gt;，比較適合已經對 Linux 有些基本瞭解的人用。&lt;a href=&quot;http://wiki.archlinux.org/index.php/ArchLinux_簡介&quot;&gt;特色&lt;/a&gt;是可以從基礎系統打造，量身訂做整個使用環境，並且有 AUR 這樣的龐大套件源可供使用。Rolling update 的升級方式可保持套件嶄新程度，適合網路環境不錯的用戶。&lt;a href=&quot;http://wiki.archlinux.org/index.php/Main_Page&quot;&gt;ArchWiki&lt;/a&gt; 是個強大的寶箱，實用性高，遇到問題都可以去查查。若對這些沒有特色都沒有興趣的話，其它發行版可能會比較適合。&lt;/p&gt;&lt;p&gt;確定要灌 ArchLinux 了，那麼我們繼續下去吧......&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;hr /&gt;&lt;p&gt;ArchLinux &lt;a href=&quot;http://www.archlinux.org/download/&quot;&gt;下載頁&lt;/a&gt;。如果之前不曾裝過的話，先看看這篇 &lt;a href=&quot;http://sillydong.is-programmer.com/posts/11833.html&quot;&gt;Arch Linux安U+88C5指南&lt;/a&gt;，有圖文解說。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;安裝基本系統的部份，照安裝指南寫的做就是。網路環境不錯的話，用 net install 可以直接灌最新的套件。&lt;/p&gt;&lt;p&gt;硬碟該怎樣分區，戰火已經&lt;a href=&quot;http://linuxtoy.org/archives/a-view-of-partition-in-linux-for-desktop.html&quot;&gt;綿延到天邊&lt;/a&gt;瞭。不折騰，反正能用就好。我的分法：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;root：10 GB&lt;/li&gt;&lt;li&gt;swap：主記憶體兩倍大小&lt;/li&gt;&lt;li&gt;/home：吃完剩下的空間&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;File system type 嘛，就 &lt;tt&gt;ext4&lt;/tt&gt; 吧。&lt;/p&gt;&lt;p&gt;想和 Windows 共享檔案的話，NTFS 磁區頗不錯。FAT32 和 NTFS 磁區都不必急著設掛載點，灌完再慢慢搞它們就好。&lt;/p&gt;&lt;p&gt;選擇套件包的時候記得把 &lt;tt&gt;base-devel&lt;/tt&gt; 也選上。安裝套件的時候會有一次 server sync，可以按 Alt + F7 切過去看一下連線速度，覺得慢就換；畢竟熟練安裝步驟之後，下載套件的時間會佔據安裝時間 90% 以上，不幸踩到慢源的話鐵定等到吐血。我推薦的源是這個：&lt;br /&gt;
&lt;code&gt;http://schlunix.org/archlinux/$repo/os/i686&lt;/code&gt;&lt;br /&gt;
(Update: 源已經失效了...)&lt;/p&gt;&lt;p&gt;編輯 &lt;tt&gt;/etc/pacman.conf&lt;/tt&gt; 時加入：&lt;br /&gt;
&lt;code&gt;[archlinuxfr]Server = http://repo.archlinux.fr/i686&lt;/code&gt;&lt;/p&gt;&lt;p&gt;灌完後重開機，開始量身打造屬於自己的 ArchLinux......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;以 &lt;tt&gt;root&lt;/tt&gt; 登入後，新增一般用戶 ( 以 &lt;tt&gt;amulet&lt;/tt&gt; 為例 ) 並設定群組權限和密碼：&lt;/p&gt;&lt;code class=&quot;cmd&quot;&gt;# useradd -s /bin/bash -G audio,disk,storage,power,optical,video,dbus,hal -m amulet&lt;br /&gt;# passwd amulet&lt;/code&gt;&lt;p&gt;更新套件源並優化資料庫：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;# pacman -Syu&lt;br /&gt;# pacman-optimize &amp;&amp; sync&lt;/code&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;安裝基本的東西：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;# pacman -S dbus hal acpid vim libstdc++5 ntfs-3g yaourt&lt;/code&gt;&lt;/p&gt;&lt;p&gt;安裝 Xorg 和顯卡、音效卡驅動。我的骨灰卡 GF4 Ti4200 是用 nvidia-96xx：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;# pacman -S xorg nvidia-96xx alsa-utils alsa-oss&lt;/code&gt;&lt;br /&gt;設定 xorg.conf 和 alsa：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;# nvidia-xconfig --composite --add-argb-glx-visuals# alsaconf&lt;/code&gt;&lt;/p&gt;&lt;p&gt;編輯 &lt;tt&gt;/etc/rc.conf&lt;/tt&gt;，並在 &lt;tt&gt;DAEMONS&lt;/tt&gt; 尾部加入 &lt;tt&gt;hal&lt;/tt&gt; 和 &lt;tt&gt;alsa&lt;/tt&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;安裝 sudo：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;# pacman -S sudo gksu&lt;/code&gt;&lt;br /&gt;並編輯 &lt;tt&gt;/etc/sudoers&lt;/tt&gt;，依樣畫葫蘆讓自己的帳戶能使用 sudo。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;要灌 &lt;a href=&quot;http://www.lxde.org/zh-tw/lxde&quot;&gt;LXDE&lt;/a&gt; 啦～&lt;/p&gt;&lt;p&gt;&lt;code class=&quot;cmd&quot;&gt;# pacman -S numlockx gamin openbox lxde gcin&lt;/code&gt;&lt;/p&gt;&lt;p&gt;讓 pcmanfm 能自動掛載 USB 裝置，需修改 &lt;tt&gt;/etc/pam.d/login&lt;/tt&gt;，加入一行：&lt;br /&gt;&lt;code&gt;session&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;optional&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pam_ck_connector.so&lt;/code&gt;&lt;/p&gt;&lt;p&gt;然後編輯 &lt;tt&gt;~/.xinitrc&lt;/tt&gt;，調校桌面系統：&lt;br /&gt;&lt;code&gt;xset -b/usr/bin/numlockx on&lt;br /&gt;export LC_LANG=zh_TW.UTF-8&lt;br /&gt;export LC_CTYPE=zh_TW.UTF-8&lt;br /&gt;export XMODIFIERS=&quot;@im=gcin&quot;&lt;br /&gt;export QT_IM_MODULES=gcin&lt;br /&gt;export OOO_FORCE_DESKTOP=gnomegcin &amp;&lt;br /&gt;exec ck-launch-session startlxde&lt;/code&gt;&lt;/p&gt;&lt;p&gt;之後只要登入後跑 &lt;tt&gt;startx&lt;/tt&gt; 就能進入 LXDE 啦！另有 &lt;a href=&quot;http://wiki.archlinux.org/index.php/Start_X_at_boot#Starting_X_as_preferred_user_without_logging_in&quot;&gt;Starting X as preferred user without logging in&lt;/a&gt; 可以參考。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;掛載 vfat 和 NTFS：&lt;/p&gt;&lt;p&gt;先到 &lt;tt&gt;/dev&lt;/tt&gt; 下看看分區長怎樣。例如是 &lt;tt&gt;/dev/sdb1&lt;/tt&gt; 的 NTFS 分區，就建立 &lt;tt&gt;/media/sdb1&lt;/tt&gt; 資料夾，然後修改 &lt;tt&gt;/etc/fstab&lt;/tt&gt;，加入&lt;br /&gt;&lt;code&gt;/dev/sdb1 /media/sdb1 ntfs-3g defaults 0 0&lt;/code&gt;&lt;br /&gt;FAT32 的話則是&lt;br /&gt;&lt;code&gt;/dev/sdb1 /media/sdb1 vfat user,noauto,iocharset=utf8 0 0&lt;/code&gt;&lt;br /&gt;這樣就能自動掛載了。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;一堆雜七雜八的東西，自己挑需要的灌：&lt;code class=&quot;cmd&quot;&gt;$ sudo pacman -S wqy-zenhei ttf-inconsolata gvim xarchiver p7zip unrar zip unzip jre flashplugin libflashsupport filezilla wine gimp go-openoffice abiword multiget comix brasero xchm djview4&lt;/code&gt;&lt;/p&gt;&lt;p&gt;MSN 的部份，emesene / amsn /pidgin / kmess 挑一個吧！個人習慣用 emesene。1.5 版開發代號「awesome」真是挺有自信的...... 雖然傳檔速度巨髮指還係最大痛處 = =&lt;/p&gt;&lt;p&gt;smplayer 和一堆不曉得會不會用到的編碼包：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;$ sudo pacman -S mplayer smplayer codecs-all gstreamer0.10-bad gstreamer0.10-bad-plugins gstreamer0.10-base gstreamer0.10-base-plugins gstreamer0.10-ffmpeg gstreamer0.10-good gstreamer0.10-good-plugins gstreamer0.10-ugly gstreamer0.10-ugly-plugins&lt;/code&gt;&lt;/p&gt;&lt;p&gt;AUR 上的好用東東：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;$ sudo yaourt -S tupac madedit lxinput google-chrome-dev pcmanx-gtk2 acroread acroread9-fonts q7z&lt;/code&gt;&lt;/p&gt;&lt;p&gt;Google Chrome 真係速度驚人的瀏覽器...... 而且也算是相當完善了。習慣 Firefox 的話有 Linux 優化版可用：yaourt -Ss swiftweasel，挑套件字尾帶 -pgo 的來裝。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;喜歡桌面特效的話可以用 Compiz Fusion：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;$ sudo pacman -S compiz compiz-decorator-gtk fusion-icon&lt;/code&gt;&lt;br /&gt;從 System Tools -&gt; Compiz Fusion Icon 開啟特效。如果覺得窗口怪怪的話，到 Settings Manager 把 Window Decoration、Move Window、Resize Window 打開。&lt;/p&gt;&lt;p&gt;一些修飾 LCD 字體顯示的套件，雖然我覺得沒啥差別......&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;$ yaourt -S cairo-ubuntu fontconfig-ubuntu freetype2-ubuntu libxft-ubuntu&lt;/code&gt;&lt;/p&gt;&lt;p&gt;嫌 LXDE 佈景醜的話可以設個 Clearlooks 還是啥的，然後字體換成文泉驛正黑。&lt;/p&gt;&lt;p&gt;關閉系統嗶聲，見 &lt;a href=&quot;http://wiki.archlinux.org/index.php/Disable_the_PC_speaker_beep&quot;&gt;Disable the PC speaker beep&lt;/a&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;反正現在硬碟空間不值錢，源的套件數量又頗龐大，可以隨便灌一堆軟體來玩玩看。高興的話也可以試試其它桌面環境如 KDE(mod)、Gnome、Xfce 等。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;這樣桌面環境就搞定啦！還有問題的話，就去 Google + ArchWiki 找解答吧～&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;當與 Windows 併存的時候，系統時間會一直被影響而不正確，需要動一下設定：&lt;/p&gt;&lt;p&gt;修改 &lt;tt&gt;/etc/rc.conf&lt;/tt&gt;，把 &lt;tt&gt;HARDWARECLOCK&lt;/tt&gt; 從 &lt;tt&gt;UTC&lt;/tt&gt; 改成 &lt;tt&gt;localtime&lt;/tt&gt;。&lt;/p&gt;&lt;p&gt;然後校正系統時間並設定 hardwareclock：&lt;br /&gt;&lt;code class=&quot;cmd&quot;&gt;$ yaourt -S ntpdate&lt;br /&gt;$ sudo ntpdate stdtime.sinica.edu.tw&lt;br /&gt;$ su&lt;br /&gt;# echo &quot;0.0 0 0.0&quot; &gt; /var/lib/hwclock/adjtime&lt;br /&gt;# hwclock -w --localtime&lt;/code&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;關於 DAC：&lt;/p&gt;&lt;p&gt;對我來說有個頗頭痛的問題是，fubar II 這樣的 DAC 沒辦法用 Alsa 調整輸出音量。而且我也沒有耳擴，所以只好請出 &lt;a href=&quot;http://wiki.archlinux.org/index.php/PulseAudio&quot;&gt;PulseAudio&lt;/a&gt;...&lt;/p&gt;&lt;p&gt;&lt;code class=&quot;cmd&quot;&gt;$ sudo pacman -S pulseaudio pavucontrol alsa-plugins&lt;br /&gt;$ sudo gpasswd -a amulet pulse-access&lt;br /&gt;$ sudo gpasswd -a amulet pulse-rt&lt;/code&gt;&lt;br /&gt;在 &lt;tt&gt;/etc/rc.conf&lt;/tt&gt; 的 DAEMONS 加入 &lt;tt&gt;avahi-daemon&lt;/tt&gt; 和 &lt;tt&gt;pulseaudio&lt;/tt&gt;。&lt;/p&gt;&lt;p&gt;編輯 &lt;tt&gt;~/.asoundrc&lt;/tt&gt;：&lt;br /&gt;&lt;code&gt;pcm.pulse {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type pulse&lt;br /&gt;}&lt;br /&gt;ctl.pulse {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;type pulse&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;&lt;p&gt;總算可以別把耳機當喇叭用了 =.=&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Linux 世界頗多采多姿的，而且五顏六色的輪子滾個滿地，可以方便地裝上一整票跑跑看。日常使用和程設資源也很足夠了，有啥動不了的東西再加個 WinXP 雙系統就是。ArchLinux 是個人目前最喜歡的發行版，祝大家都能使用愉快～&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/5590327011914424634/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/10/archlinux-lxde-200908.html#comment-form' title='6 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/5590327011914424634'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/5590327011914424634'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/10/archlinux-lxde-200908.html' title='ArchLinux + LXDE 安裝筆記 ( 2009.08 )'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-3401196558288042763</id><published>2009-10-27T11:43:00.003+08:00</published><updated>2011-08-25T22:57:53.980+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Linux"/><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>ArchLinux 下編寫 LaTeX 文檔</title><content type='html'>&lt;p&gt;關於 TeX，&lt;a href=&quot;http://www.ctan.org/what_is_tex.html&quot;&gt;CTAN&lt;/a&gt; 和 &lt;a href=&quot;http://edt1023.sayya.org/tex/latex123/node2.html&quot;&gt;大家來學 LaTeX&lt;/a&gt; 有很詳細的介紹。簡單講，強大的排版工具 ( 語言？)，尤其是在數學式子的排版上，因此廣泛用於數學、資訊科學、物理書籍的編排。&lt;/p&gt;&lt;p&gt;古老 TeX 的主要變種有較現代化、易用的 &lt;a href=&quot;http://en.wikipedia.org/wiki/LaTeX&quot;&gt;LaTeX&lt;/a&gt; 和 Unicode 支援較完善的 &lt;a href=&quot;http://en.wikipedia.org/wiki/XeTeX&quot;&gt;XeTeX&lt;/a&gt;。使用 LaTeX 排版的知名書籍滿地都是，包括《The Pragmatic Programmer》、《C++ Primer 4/e》、《Introduction to Algorithms》等，族激繁，不及備載。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;想搞個 TeX 編寫環境的話，Windows 下可以用 &lt;strong&gt;MikTex&lt;/strong&gt;，Linux 下可以用 &lt;strong&gt;TeX Live&lt;/strong&gt;：&lt;br /&gt;
&lt;code class=&quot;cmd&quot;&gt;# pacman -S poppler texlive-bin texlive-most texlive-langcjk&lt;/code&gt;&lt;br /&gt;
包頗大 ( 700 MB!! )，灌起來久到有點髮指，忍著點。&lt;/p&gt;&lt;p&gt;另有 &lt;a href=&quot;http://www.tug.org/texworks/&quot;&gt;TeXworks&lt;/a&gt; 這個 Qt4 寫成的圖形介面，幫助編寫和輸出：&lt;br /&gt;
&lt;code class=&quot;cmd&quot;&gt;# yaourt -S texworks-svn&lt;/code&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;目前為止個人感覺寫起來有點像 HTML + CSS。雖然要另外花費時間學習，但是排起版來效果也是相當好的。有機會的話可以嘗試看看～&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/3401196558288042763/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/10/archlinux-latex.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3401196558288042763'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3401196558288042763'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/10/archlinux-latex.html' title='ArchLinux 下編寫 LaTeX 文檔'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-7049921722540622562</id><published>2009-04-23T22:58:00.027+08:00</published><updated>2011-08-24T17:34:32.717+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 7: 聚砂成塔</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-6.html&quot;&gt;[PyQt 教學] Part 6: 物件導向的寫法&lt;/a&gt; ←&lt;/p&gt;
&lt;p&gt;一路走來，盡係寫些拉雞程式。沒關係，打好基礎後就可以準備擺脫這坨窩囊鳥氣啦 =3=&lt;/p&gt;
&lt;p&gt;這次寫個線上字典查閱程式。是的，它會跑去讀取 &lt;a href=&quot;http://tw.dictionary.yahoo.com/&quot;&gt;Yahoo! 奇摩字典&lt;/a&gt; 並顯示查詢的單字結果...... 用一種異常偷吃步的方法 =.=&lt;br /&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyCaK3Y-lS77AnW9O3p31C3wUPhXPEg9kAOj9PG7QYmdk1V2SzbDIxQ4GKalg_l9O2Ceij0Iew9ioNQHN3QRfJQcFF4fmwr-Gi0CHMXTQKLqKAu6QiXKN6muO73QSRubEYFFp2Oxv-6DM/s1600-h/dictionary.png&quot; onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot;&gt;&lt;img alt=&quot;&quot; border=&quot;0&quot; id=&quot;BLOGGER_PHOTO_ID_5327894269988547618&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyCaK3Y-lS77AnW9O3p31C3wUPhXPEg9kAOj9PG7QYmdk1V2SzbDIxQ4GKalg_l9O2Ceij0Iew9ioNQHN3QRfJQcFF4fmwr-Gi0CHMXTQKLqKAu6QiXKN6muO73QSRubEYFFp2Oxv-6DM/s400/dictionary.png&quot; style=&quot;cursor: hand; cursor: pointer; height: 303px; width: 400px;&quot; /&gt;&lt;/a&gt;&lt;br /&gt;( &lt;a href=&quot;http://codepad.org/wOHOblex&quot;&gt;code&lt;/a&gt; )&lt;/p&gt;
&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtCore import *&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;from PyQt4.QtWebKit import *&lt;br /&gt;&lt;br /&gt;class Dictionary(QWidget):&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def __init__(self, parent = None):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;super(Dictionary, self).__init__(parent)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.createLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.createConnection()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def search(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;baseUrl = &quot;http://tw.dictionary.yahoo.com/search?ei=UTF-8&amp;amp;p=&quot;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;word = self.lineEdit.text()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;url = QUrl(baseUrl + word)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.webView.load(url)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def createLayout(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lineEdit = QLineEdit()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.goButton = QPushButton(&quot;&amp;amp;GO&quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h1 = QHBoxLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h1.addWidget(self.lineEdit)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h1.addWidget(self.goButton)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.webView = QWebView()&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.quitButton = QPushButton(&quot;&amp;amp;Quit&quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h2 = QHBoxLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h2.addStretch(1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;h2.addWidget(self.quitButton)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout = QVBoxLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout.addLayout(h1)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout.addWidget(self.webView)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout.addLayout(h2)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.setLayout(layout)&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def createConnection(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lineEdit.returnPressed.connect(self.search)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.lineEdit.returnPressed.connect(self.lineEdit.selectAll)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.goButton.clicked.connect(self.search)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.goButton.clicked.connect(self.lineEdit.selectAll)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.quitButton.clicked.connect(self.close)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;dictionary = Dictionary()&lt;br /&gt;dictionary.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;沒錯，60 行不到的程式就可以完成這份單字查找的艱鉅任務了。讓我們稍微瞭解一下：&lt;br /&gt;
經觀察可知 Yahoo! 字典的查詢網址都是很規律的字串組合；這個程式就利用這一點，直接載入目標網址。memfunc &lt;tt&gt;search()&lt;/tt&gt; 和 connect 的部份是核心，其它都沒啥特別的。&lt;/p&gt;
&lt;p&gt;第 4 行：導入 &lt;tt&gt;PyQt4.QtCore&lt;/tt&gt; 以使用 &lt;tt&gt;QUrl&lt;/tt&gt; class。&lt;br /&gt;
第 6 行：導入 &lt;tt&gt;PyQt4.QtWebKit&lt;/tt&gt; 以使用 &lt;tt&gt;QWebView&lt;/tt&gt; class。這個 widget 能用來檢視網頁。&lt;br /&gt;
第 16～18 行：調用 &lt;tt&gt;search()&lt;/tt&gt; 後，將 &lt;tt&gt;lineEdit&lt;/tt&gt; 中輸入的文字與 Yahoo! 字典的查詢網址結合成新的 URL。&lt;br /&gt;
第 19 行：讓 &lt;tt&gt;webView&lt;/tt&gt; 載入 URL 並顯示。&lt;br /&gt;
第 43 + 45 行：在 &lt;tt&gt;lineEdit&lt;/tt&gt; 中輸入 &lt;tt&gt;Enter&lt;/tt&gt; 或點擊 &lt;tt&gt;goButton&lt;/tt&gt; 時調用 &lt;tt&gt;search()&lt;/tt&gt;。&lt;br /&gt;
第 44 + 46 行：調用 &lt;tt&gt;search()&lt;/tt&gt; 後保持 &lt;tt&gt;lineEdit&lt;/tt&gt; 中的文字在被選取狀態，以便下次輸入查詢。&lt;br /&gt;&lt;br /&gt;
其中最 imba 的莫過於第 19 行...... N 個願望一次滿足，高抽象度讓人們得以站在超高的巨人肩膀上吹風 =3=&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;熟悉整個 framework 之後，寫這樣的程式需要多久呢？其實只要 10 分鐘就可以完成了...... 就和一個 &lt;a href=&quot;javascript:(function(){var%20word=prompt(%22%E5%96%AE%E5%AD%97:%22);window.open(%22http://tw.dictionary.yahoo.com/search?ei=UTF-8&amp;amp;p=%22+word);})();&quot;&gt;JavaScript booklet&lt;/a&gt; 同樣簡單。&lt;br /&gt;
基本功練完後，接下來就是自行深入啦！下一篇講查閱 API 的方法 =3=/&lt;/p&gt;
&lt;p&gt;→ [PyQt 教學] Part 8: ？？？&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/7049921722540622562/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-7.html#comment-form' title='10 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/7049921722540622562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/7049921722540622562'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-7.html' title='[PyQt 教學] Part 7: 聚砂成塔'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhyCaK3Y-lS77AnW9O3p31C3wUPhXPEg9kAOj9PG7QYmdk1V2SzbDIxQ4GKalg_l9O2Ceij0Iew9ioNQHN3QRfJQcFF4fmwr-Gi0CHMXTQKLqKAu6QiXKN6muO73QSRubEYFFp2Oxv-6DM/s72-c/dictionary.png" height="72" width="72"/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-1743416797931424714</id><published>2009-04-23T21:10:00.019+08:00</published><updated>2011-08-24T17:34:32.718+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 6: 物件導向的寫法</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-5-signals-slots-mechanism.html&quot;&gt;[PyQt 教學] Part 5: Signals &amp; Slots mechanism&lt;/a&gt; ←&lt;/p&gt;&lt;p&gt;到目前為止，我們都是用 procedure-oriented 的方式寫 PyQt code。對於本就是 object-oriented 的 GUI framework 來說，物件導向寫法貌似更加自然，是必需要學會的。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;將先前那個 &lt;tt&gt;connect&lt;/tt&gt; 的例子改成 &lt;tt&gt;class&lt;/tt&gt; 型式：( &lt;a href=&quot;http://codepad.org/UbTQvx7n&quot;&gt;code&lt;/a&gt; )&lt;br /&gt;&lt;br /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtCore import *&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;class MyWidget(QWidget):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def __init__(self, parent = None):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;super(MyWidget, self).__init__(parent)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.createLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.spinBox.valueChanged.connect(self.slider.setValue)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.slider.valueChanged.connect(self.spinBox.setValue)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;def createLayout(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.spinBox = QSpinBox()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.spinBox.setPrefix(&quot;$&quot;)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.spinBox.setRange(0, 100)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.slider = QSlider(Qt.Horizontal)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.slider.setRange(0, 100)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout = QHBoxLayout()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout.addWidget(self.spinBox)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;layout.addWidget(self.slider)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;self.setLayout(layout)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;widget = MyWidget()&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;&lt;p&gt;第 7 行：我們定義出 &lt;tt&gt;MyWidget&lt;/tt&gt; 這個新的 class，繼承自外觀空白一片的 &lt;tt&gt;QWidget&lt;/tt&gt;，好讓我們自行塞入東西。內含兩個 memfunc：建構式 &lt;strong&gt;&lt;tt&gt;__init__()&lt;/tt&gt;&lt;/strong&gt; 和自行設計的函式 &lt;strong&gt;&lt;tt&gt;createLayout()&lt;/tt&gt;&lt;/strong&gt;。&lt;/p&gt;&lt;p&gt;第 14 行：開始定義 &lt;tt&gt;createLayout()&lt;/tt&gt;。Python 的 instance method 必帶一個 &lt;tt&gt;self&lt;/tt&gt; 參數。&lt;/p&gt;&lt;p&gt;第 15～20 行：搞出 &lt;tt&gt;self.spinBox&lt;/tt&gt; 和 &lt;tt&gt;self.slider&lt;/tt&gt; 兩個 property，並設定之。&lt;/p&gt;&lt;p&gt;第 22～25 行：設定版面。&lt;tt&gt;setLayout()&lt;/tt&gt; 這個 method 繼承自 &lt;tt&gt;QWidget&lt;/tt&gt;；&lt;tt&gt;self.setLayout(layout)&lt;/tt&gt; 把 &lt;tt&gt;layout&lt;/tt&gt; 設給 &lt;tt&gt;MyWidget&lt;/tt&gt; 自身的版面。( 原本的版面是繼承自 &lt;tt&gt;QWidget&lt;/tt&gt;，空白一片...... )&lt;/p&gt;&lt;p&gt;第 8 行：開始定義建構式。因為我們的 class 不需要寄生在其它 widget 中，所以設定參數 &lt;tt&gt;parent = None&lt;/tt&gt;，以成為 top-level window。&lt;/p&gt;&lt;p&gt;第 9 行：讓 &lt;tt&gt;MyWidget&lt;/tt&gt; 的建構式調用 parent class 的建構式。這個過程是必備的，因為繼承得來的 &lt;tt&gt;__init__()&lt;/tt&gt; 已被覆寫，Python 不會再自動調用 parent class 的建構式；&lt;tt&gt;QWidget&lt;/tt&gt; 未被初始化的話，&lt;tt&gt;MyWidget&lt;/tt&gt; 一開就會瞬間爆炸。&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;super()&lt;/tt&gt; 這樣的語法，讓 Python 能自動判別 &lt;tt&gt;MyWidget&lt;/tt&gt; 的 parent class，避免直接寫死在程式碼內。&lt;/p&gt;&lt;p&gt;第 10 行：呼叫 instance method &lt;tt&gt;createLayout()&lt;/tt&gt;&lt;/p&gt;&lt;p&gt;第 11～12 行：建立 connection，讓兩個 widget 能互相影響。&lt;/p&gt;&lt;p&gt;第 30～31 行：建構出 &lt;tt&gt;MyWidget&lt;/tt&gt; 的 instance 並顯示出來。&lt;/p&gt;&lt;p&gt;需要特別注意的地方，就是內部物件&lt;strong&gt;到底該不該加前綴 self.&lt;/strong&gt; 以變成 property 吧！我個人的心得是：取決關鍵在於&lt;strong&gt;該物件會不會被跨函式存取&lt;/strong&gt;。例如 &lt;tt&gt;spinBox&lt;/tt&gt; 和 &lt;tt&gt;slider&lt;/tt&gt; 是在 &lt;tt&gt;createLayout()&lt;/tt&gt; 中建構，但也會在 &lt;tt&gt;__init__()&lt;/tt&gt; 中被存取到，所以必需成為 property。而 &lt;tt&gt;layout&lt;/tt&gt; 用完沒事就可以滾了，所以只活在 &lt;tt&gt;createLayout()&lt;/tt&gt; 中無所謂。&lt;/p&gt;&lt;p&gt;當然啦，程式架構與流程解法並不是唯一的，所以寫成&lt;a href=&quot;http://codepad.org/DYb6uW78&quot;&gt;這樣&lt;/a&gt;也是可以的，省下一卡車的 &lt;tt&gt;self.&lt;/tt&gt;。怎樣的寫法在各種情境中比較合情合理，就有賴自行判斷了。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;平常寫 PyQt 程式，建議都用物件導向的方式，自創 widget class 後再利用之。困難嗎？老樣子，pattern 記起來，轉換就很快了。&lt;/p&gt;&lt;p&gt;下次來寫個稍微有用的玩意兒吧......&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-7.html&quot;&gt;[PyQt 教學] Part 7: 聚砂成塔&lt;/a&gt;&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/1743416797931424714/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-6.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/1743416797931424714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/1743416797931424714'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-6.html' title='[PyQt 教學] Part 6: 物件導向的寫法'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-4390669307959355176</id><published>2009-04-23T20:16:00.036+08:00</published><updated>2011-08-24T17:34:32.718+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 5: Signals &amp;amp; Slots mechanism</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-4-layout-management.html&quot;&gt;[PyQt 教學] Part 4: Layout Management&lt;/a&gt; ←&lt;/p&gt;&lt;p&gt;回到先前的範例，一個簡單的 &lt;tt&gt;PushButton&lt;/tt&gt;：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;button = QPushButton(&quot;&amp;Quit&quot;)&lt;br /&gt;button.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTZ-fipj5RhabeMOQdpQkUh86Tvi8U40auW_jzP61eWeXGIBZH8cwekCUmUcdT8ayJl4QvXEZb5GNm-oQXu2yV55sBJTmfxFJbpJcwhUoWMGfRiivMO43KtSJq6pYOoF7-5QZ8aQ7d4oA/s1600-h/quit.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 59px; height: 53px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTZ-fipj5RhabeMOQdpQkUh86Tvi8U40auW_jzP61eWeXGIBZH8cwekCUmUcdT8ayJl4QvXEZb5GNm-oQXu2yV55sBJTmfxFJbpJcwhUoWMGfRiivMO43KtSJq6pYOoF7-5QZ8aQ7d4oA/s400/quit.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327847021496200498&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;事與願違。儘管按鈕上寫著斗大的「&lt;tt&gt;Quit&lt;/tt&gt;」，猛擊幾百遍也是無動於衷。&lt;br /&gt;&lt;br /&gt;然而其實當它被按下時，就會發出「我被按了」的訊號；只是因為沒人接收到，所以這訊號便隨風而逝瞭 QQ&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;為了讓 widget 間能彼此溝通，Qt 有一套 &lt;a href=&quot;http://doc.trolltech.com/latest/signalsandslots.html&quot;&gt;&lt;strong&gt;Signals &amp;amp; Slots&lt;/strong&gt;&lt;/a&gt; 機制。看看官方的廣告：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;strong&gt;Signals and slots are used for communication between objects.&lt;/strong&gt; The signals and slots mechanism is a central feature of Qt and probably the part that differs most from the features provided by other frameworks.&lt;/p&gt;&lt;/blockquote&gt;&lt;hr /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;在原本的程式碼加個一行：( &lt;a href=&quot;http://codepad.org/rz3MvfWL&quot;&gt;code&lt;/a&gt; )&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;button = QPushButton(&quot;&amp;Quit&quot;)&lt;br /&gt;&lt;strong&gt;button.clicked.connect(button.close)&lt;/strong&gt;&lt;br /&gt;button.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;外在並沒有變，但是心已經變了。&lt;/p&gt;&lt;p&gt;新增的第 9 行：&lt;strong&gt;把 &lt;tt&gt;button&lt;/tt&gt; 的 &lt;tt&gt;clicked()&lt;/tt&gt; 這個 signal，與 &lt;tt&gt;button&lt;/tt&gt; 的 &lt;tt&gt;close()&lt;/tt&gt; 這個 slot 聯繫 ( &lt;tt&gt;connect&lt;/tt&gt; ) 起來。&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;之後當 &lt;tt&gt;button&lt;/tt&gt; 被按下 ( 觸發 &lt;tt&gt;clicked()&lt;/tt&gt; ) 時，送出的訊號就會把自己關掉瞭 (＞ω＜)♪♪&lt;/p&gt;&lt;p&gt;( 各個 class 所擁有的 signal 與 slot，在文檔裡都有列出。本例中 &lt;tt&gt;QPushButton&lt;/tt&gt; 的 &lt;tt&gt;clicked()&lt;/tt&gt; signal 是繼承自 &lt;tt&gt;QAbstractButton&lt;/tt&gt;，而 &lt;tt&gt;close()&lt;/tt&gt; slot 是繼承自 &lt;tt&gt;QWidget&lt;/tt&gt;。)&lt;/p&gt;&lt;p&gt;這是 PyQt 4.5 起新的 pythonic 寫法，相信不難理解。要是看過之前版本的語法，就知道那不僅是一根髮指可以帶過的了......&lt;/p&gt;&lt;p&gt;總結 &lt;tt&gt;connect&lt;/tt&gt; 的語法：&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;開槍的物件.signalName.connect(中槍的物件.slotName)&lt;/tt&gt;&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Qt 的 Signals &amp;amp; Slots 機制是用 &lt;tt&gt;QObject&lt;/tt&gt; 這個 class 來實現的 ( 它是一切 Qt objects 的 base class )。signal 和 slot 都長得像一般函式一樣，而且可透過 &lt;tt&gt;QObject.connect()&lt;/tt&gt; 連接在一起 ( 舊版語法 )。Class 本身的 signal 知道自己何時會被觸發，並且自動被 emit 出去 ( 也可以手動 &lt;tt&gt;emit&lt;/tt&gt; )。slot 則會完成某些事，其實就是個普普通通的函式，也許會與聯繫的 signal 夾帶的參數有關。&lt;/p&gt;&lt;p&gt;signal 可以和許多 slot 或普通函式連接在一起 ( 多對多關係 )；也可以讓 signal 與 signal 連接，產生連鎖反應。當然啦，如果 signal emit 出去卻沒人鳥的話，最後就會蒸發彷如無物瞭 (〒3〒)&lt;/p&gt;&lt;p&gt;signal emitter 並不需要知道是誰中槍，對於目標型別完全不必在乎；同樣地，slot 也不需要知道是誰開槍，只要知道自己中槍了就好。這個特色提供相當大的彈性；decoupling 的優勢隨著軟體愈來愈大，會愈發明顯。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Qt 主要就是靠這套機制讓 widget 間能夠相互溝通：我的 signal 摳你的 slot，你的 signal 摳他的 slot...... 摳來摳去組織出錯綜複雜的關係，讓程式能牽一髮而動全身。理解這套機制，對於上手 Qt programming 是相當關鍵的。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;最後，給出另一個常見的 signals &amp;amp; slots 範例：( &lt;a href=&quot;http://codepad.org/K4qEly1H&quot;&gt;code&lt;/a&gt; )&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8SCnZ3MZ6bjsFKQSzx2h3kZi8tIn-FXlp4WmrHIt41h-oxFUTdGIK7U3QG_dpsrwbrqxybaw93pohm9Vn6B9rJ-gpPVF4n4qWdSbmJ6cHnsau7SFb_1NtnP-m1jcStTX3uabxqMMdE-I/s1600-h/signal2.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 204px; height: 76px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8SCnZ3MZ6bjsFKQSzx2h3kZi8tIn-FXlp4WmrHIt41h-oxFUTdGIK7U3QG_dpsrwbrqxybaw93pohm9Vn6B9rJ-gpPVF4n4qWdSbmJ6cHnsau7SFb_1NtnP-m1jcStTX3uabxqMMdE-I/s400/signal2.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327883086546133602&quot; /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;&lt;br /&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtCore import *&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;spinBox = QSpinBox()&lt;br /&gt;spinBox.setPrefix(&quot;$&quot;)&lt;br /&gt;spinBox.setRange(0, 100)&lt;br /&gt;&lt;br /&gt;slider = QSlider(Qt.Horizontal)&lt;br /&gt;slider.setRange(0, 100)&lt;br /&gt;&lt;br /&gt;spinBox.valueChanged.connect(slider.setValue)&lt;br /&gt;slider.valueChanged.connect(spinBox.setValue)&lt;br /&gt;&lt;br /&gt;layout = QHBoxLayout()&lt;br /&gt;layout.addWidget(spinBox)&lt;br /&gt;layout.addWidget(slider)&lt;br /&gt;&lt;br /&gt;widget = QWidget()&lt;br /&gt;widget.setLayout(layout)&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;其中 &lt;tt&gt;PyQt4.QtCore&lt;/tt&gt; 的導入是為了使用 &lt;tt&gt;Qt.Horizontal&lt;/tt&gt; 這個 enum。&lt;br /&gt;&lt;br /&gt;剩下的就請自行解讀吧！&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-6.html&quot;&gt;[PyQt 教學] Part 6: 物件導向的寫法&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/4390669307959355176/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-5-signals-slots-mechanism.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4390669307959355176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4390669307959355176'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-5-signals-slots-mechanism.html' title='[PyQt 教學] Part 5: Signals &amp;amp; Slots mechanism'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTZ-fipj5RhabeMOQdpQkUh86Tvi8U40auW_jzP61eWeXGIBZH8cwekCUmUcdT8ayJl4QvXEZb5GNm-oQXu2yV55sBJTmfxFJbpJcwhUoWMGfRiivMO43KtSJq6pYOoF7-5QZ8aQ7d4oA/s72-c/quit.png" height="72" width="72"/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-4721561577235611898</id><published>2009-04-23T19:06:00.019+08:00</published><updated>2011-08-24T17:34:32.719+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 4: Layout Management</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-3.html&quot;&gt;[PyQt 教學] Part 3: 起步走&lt;/a&gt; ←&lt;/p&gt;&lt;p&gt;看看 Qt 中精美的 widget 們：&lt;a href=&quot;http://doc.trolltech.com/latest/gallery-windowsvista.html&quot;&gt;Qt Widget Gallery&lt;/a&gt;&lt;/p&gt;&lt;p&gt;平常使用作業系統圖形介面時，就已經摸過不少了；而在 Qt 中也可以看到這些老朋友們。從 &lt;tt&gt;PushButton&lt;/tt&gt;、&lt;tt&gt;CheckBox&lt;/tt&gt; 到 &lt;tt&gt;ProgressBar&lt;/tt&gt;、&lt;tt&gt;SpinBox&lt;/tt&gt; 乃至精美的 &lt;tt&gt;CalendarWidget&lt;/tt&gt;，應有盡有。認識老朋友的名字，對於日後呼叫會有幫助。&lt;/p&gt;&lt;p&gt;先召喚個 &lt;tt&gt;QPushButton&lt;/tt&gt; 出來：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;button = QPushButton(&quot;H&amp;ello!&quot;)&lt;br /&gt;button.resize(200, 75)&lt;br /&gt;button.move(500, 400)&lt;br /&gt;button.setWindowTitle(&quot;Hello World&quot;)&lt;br /&gt;button.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtE9x1aFN8mN9o6GhWbaq-85P9a2LXqxmJyZmEu65DGs2LD_igkkzpbbzsyD67egPODzijRm60bwUGqvfW7cXrUa-Hy7VrLJJaEc4B1L1yANKyBkywO64qi84TWH1HmQmPYdjpqcQt32Y/s1600-h/button.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 204px; height: 100px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtE9x1aFN8mN9o6GhWbaq-85P9a2LXqxmJyZmEu65DGs2LD_igkkzpbbzsyD67egPODzijRm60bwUGqvfW7cXrUa-Hy7VrLJJaEc4B1L1yANKyBkywO64qi84TWH1HmQmPYdjpqcQt32Y/s400/button.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327763662284054994&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;和之前的範例差不多，只是主角從 &lt;tt&gt;QWidget&lt;/tt&gt; 變成 &lt;tt&gt;QPushButton&lt;/tt&gt;。它帶一個字串參數初始化顯示的文字，並調用一些從 &lt;tt&gt;QWidget&lt;/tt&gt; 繼承來的 memfunc。&lt;/p&gt;&lt;p&gt;注意字串參數的樣子，以及 &lt;tt&gt;e&lt;/tt&gt; 下面那條底線；試著按按看 &lt;tt&gt;Alt + E&lt;/tt&gt;。這是 Qt 設定 action focus 的簡便方法。&lt;/p&gt;&lt;p&gt;( 現在這按鈕啥 p 也做不了，我們下一篇再回頭調教它。)&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Qt 的排版系統：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;ok = QPushButton(&quot;&amp;OK&quot;)&lt;br /&gt;cancel = QPushButton(&quot;&amp;Cancel&quot;)&lt;br /&gt;&lt;br /&gt;layout = QHBoxLayout()&lt;br /&gt;layout.addWidget(ok)&lt;br /&gt;layout.addWidget(cancel)&lt;br /&gt;&lt;br /&gt;widget = QWidget()&lt;br /&gt;widget.setLayout(layout)&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_XOgDqtdtEAParaKYwLVVvUM4WIoUKhCiTPsd0wmalkpRpgvq0KqQLDQtoHdWhNHLv4fWaYCSqnRPPJdIsUah_Emg1ekCbcxcEqVCVoW3WFg3O_4DgG6STdczwwXWr-y0CWymKY8ruVE/s1600-h/layout.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 149px; height: 75px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi_XOgDqtdtEAParaKYwLVVvUM4WIoUKhCiTPsd0wmalkpRpgvq0KqQLDQtoHdWhNHLv4fWaYCSqnRPPJdIsUah_Emg1ekCbcxcEqVCVoW3WFg3O_4DgG6STdczwwXWr-y0CWymKY8ruVE/s400/layout.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327769927263559282&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;......我想這其中的邏輯應該一看就懂，夠直覺了 =.=&lt;br /&gt;&lt;br /&gt;&lt;tt&gt;Q&lt;abbr title=&quot;horizontal&quot;&gt;H&lt;/abbr&gt;BoxLayout&lt;/tt&gt; 和 &lt;tt&gt;Q&lt;abbr title=&quot;vertical&quot;&gt;V&lt;/abbr&gt;BoxLayout&lt;/tt&gt; 掌管基本排版：就像裝箱一樣，用 &lt;tt&gt;addWidget()&lt;/tt&gt; 依序塞入 widget。最後再將它設為空容器 &lt;tt&gt;QWidget&lt;/tt&gt; 的 layout。被裝箱的 widget 不必再額外調用 &lt;tt&gt;show()&lt;/tt&gt;。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;每個 widget 都有其所屬的 parent ( constructor 預設參數 &lt;tt&gt;parent = None&lt;/tt&gt; )。指定了 parent 之後，就由 parent 掌管、限制該 child 的顯示。當 parent 解構時，child 們也會一同升天。&lt;/p&gt;&lt;p&gt;Layout 系統也是類似的：Layout class 調用 &lt;tt&gt;addWidget(w)&lt;/tt&gt; 之後，就會成為 &lt;tt&gt;w&lt;/tt&gt; 的 parent。另一個 widget 調用 &lt;tt&gt;setLayout(layout)&lt;/tt&gt; 時，成為 layout 的 parent，並把 layout 的 child 們全部接管過去。&lt;/p&gt;&lt;p&gt;parent 的意義，除了接管 child 的資源以外，還決定了 widget 是否為 top-level window。像 &lt;tt&gt;w = QWidget()&lt;/tt&gt; 這樣建構時不帶參數的語法，由於並沒指定 &lt;tt&gt;w&lt;/tt&gt; 的 parent，所以 &lt;tt&gt;w&lt;/tt&gt; 本身成為 top-level window，擁有標題列和邊框。通常我們只需要一個 top-level window，並會把一堆小 widget 塞進裡面顯示。&lt;/p&gt;&lt;p&gt;上例中 &lt;tt&gt;widget&lt;/tt&gt; instance 最終成為所有子元件的 parent，並由它成為 top-level window。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;再看看稍微進階一些的排版：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;lineEdit = QLineEdit()&lt;br /&gt;go = QPushButton(&quot;&amp;GO&quot;)&lt;br /&gt;h1 = QHBoxLayout()&lt;br /&gt;h1.addWidget(lineEdit)&lt;br /&gt;h1.addWidget(go)&lt;br /&gt;&lt;br /&gt;ok = QPushButton(&quot;&amp;OK&quot;)&lt;br /&gt;cancel = QPushButton(&quot;&amp;Cancel&quot;)&lt;br /&gt;&lt;br /&gt;h2 = QHBoxLayout()&lt;br /&gt;h2.addStretch(1)&lt;br /&gt;h2.addWidget(ok)&lt;br /&gt;h2.addWidget(cancel)&lt;br /&gt;&lt;br /&gt;layout = QVBoxLayout()&lt;br /&gt;layout.addLayout(h1)&lt;br /&gt;layout.addLayout(h2)&lt;br /&gt;&lt;br /&gt;widget = QWidget()&lt;br /&gt;widget.setLayout(layout)&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdrRn2Uru2nfTSOF3KEwT-z2CLjozcOPY7Bn9dPtFT14jQNULHEztkrGS-F7kfTl0733mhqcacMAIPBa-93hEtlgLYlkbdH6uqQaSegplRjgIE53aYUmQjWG_2CL_Z6MNnQ9JC5O-97IY/s1600-h/layout2.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 204px; height: 108px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdrRn2Uru2nfTSOF3KEwT-z2CLjozcOPY7Bn9dPtFT14jQNULHEztkrGS-F7kfTl0733mhqcacMAIPBa-93hEtlgLYlkbdH6uqQaSegplRjgIE53aYUmQjWG_2CL_Z6MNnQ9JC5O-97IY/s400/layout2.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327837599960242546&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;比起前一個例子，多了些 widget 以及 &lt;tt&gt;addLayout()&lt;/tt&gt;。像這樣把 layout 塞入 layout，就可以實現層層堆砌的複雜排版。另外還有 &lt;tt&gt;addStretch()&lt;/tt&gt;，塞入空白的可伸縮空間。&lt;/p&gt;&lt;p&gt;拖拉邊框，可以看到 Qt 怎樣自動調整 widget 們的大小並管理定位。一般來說，交給 &lt;a href=&quot;http://doc.trolltech.com/latest/layout.html&quot;&gt;Qt 內部 Layout 系統&lt;/a&gt;來排列 widget 就夠了，很是省心 (＞ω＜)♪♪&lt;/p&gt;&lt;p&gt;其它排版用的 layout class 還有 &lt;tt&gt;QGridLayout&lt;/tt&gt;、&lt;tt&gt;QFormLayout&lt;/tt&gt; 等，和一堆 container class。有興趣的話再去查文檔吧！&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-5-signals-slots-mechanism.html&quot;&gt;[PyQt 教學] Part 5: Signals &amp; Slots mechanism&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/4721561577235611898/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-4-layout-management.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4721561577235611898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/4721561577235611898'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-4-layout-management.html' title='[PyQt 教學] Part 4: Layout Management'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtE9x1aFN8mN9o6GhWbaq-85P9a2LXqxmJyZmEu65DGs2LD_igkkzpbbzsyD67egPODzijRm60bwUGqvfW7cXrUa-Hy7VrLJJaEc4B1L1yANKyBkywO64qi84TWH1HmQmPYdjpqcQt32Y/s72-c/button.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-8203060284448363967</id><published>2009-04-23T00:22:00.022+08:00</published><updated>2011-08-24T17:34:32.720+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 3: 起步走</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-2.html&quot;&gt;[PyQt 教學] Part 2: 建構開發環境&lt;/a&gt; ←&lt;/p&gt;&lt;p&gt;第一個 GUI 程式：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;widget = QWidget()&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;/p&gt;&lt;p&gt;摳起來存成 &lt;tt&gt;first.py&lt;/tt&gt; 後，雙點 or 進 terminal 輸入 &lt;strong&gt;&lt;tt&gt;python first.py&lt;/tt&gt;&lt;/strong&gt; 就可以執行了！( Windows&amp;reg; 下可能得用完整路徑 &lt;tt&gt;C:\Python26\python.exe&lt;/tt&gt; )&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijGQ8gBJw-Ld1pz1vZAFGgisdn3RCSQvFMhbtTfNN_UEdDqHkte0_4F3HC_6cRVhvOzh6TnT_5y6gpM5cM_Ptz9VqHMoH87aD8G1DljbrjthLkWgAQQ2CIHbsS3eqGZDyZGCmi6xgb2sc/s1600-h/first.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 290px; height: 211px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijGQ8gBJw-Ld1pz1vZAFGgisdn3RCSQvFMhbtTfNN_UEdDqHkte0_4F3HC_6cRVhvOzh6TnT_5y6gpM5cM_Ptz9VqHMoH87aD8G1DljbrjthLkWgAQQ2CIHbsS3eqGZDyZGCmi6xgb2sc/s400/first.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327433062718253410&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;一行一行來看 code：&lt;/p&gt;&lt;p&gt;&lt;tt&gt;#!/usr/bin/env python&lt;/tt&gt;：Windows&amp;reg; 下沒作用。在 Unix 下執行時可幫助尋找 Python 直譯器。&lt;/p&gt;&lt;p&gt;&lt;tt&gt;import sys&lt;/tt&gt;：Qt 程式初始化時需要用到一些參數 ( &lt;tt&gt;sys.argv&lt;/tt&gt; )。&lt;/p&gt;&lt;p&gt;&lt;tt&gt;from PyQt4.QtGui import *&lt;/tt&gt;：導入 PyQt4 裡面的圖形介面庫，包含許多圖形元件 ( &lt;strong&gt;widget&lt;/strong&gt; / window gadget )。之後用到的 QWidget 就是屬於這個庫的。&lt;br /&gt;&lt;br /&gt;這裡用了完整導入的語法 ( 而非 &lt;tt&gt;from PyQt4 import QtGui&lt;/tt&gt; )，以免之後得打 &lt;tt&gt;QtGui.QApplication&lt;/tt&gt; 和 &lt;tt&gt;QtGui.QWidget&lt;/tt&gt; 之類又臭又長的 scope name。&lt;br /&gt;&lt;br /&gt;( 基本上，Qt 對自身組件的命名都有&lt;strong&gt;前綴 Q&lt;/strong&gt;，想撞到也難...... 所以應該不用太怕 namespace pollution。)&lt;/p&gt;&lt;p&gt;&lt;tt&gt;app = QApplication(sys.argv)&lt;/tt&gt;：每個 Qt GUI 程式都需要一個 ( 唯一一個 ) &lt;tt&gt;QApplication&lt;/tt&gt;，負責管理 Qt 資源、控制執行流程和有的沒的例行事務。雖然很少會用 command line 來開 GUI 程式，還是得帶 &lt;tt&gt;sys.argv&lt;/tt&gt; 參數來初始化它......&lt;/p&gt;&lt;p&gt;接下來兩行，搞出 &lt;tt&gt;QWidget&lt;/tt&gt; instance 並調用 member function &lt;tt&gt;show()&lt;/tt&gt; 讓它顯示出來。所有圖形元件被創造時都是 hidden 狀態，可以先設定好它的外觀再顯示出來，免得一直重繪造成畫面閃爍。&lt;/p&gt;&lt;p&gt;&lt;tt&gt;app.exec_()&lt;/tt&gt;：讓 &lt;tt&gt;QApplication&lt;/tt&gt; 進入 event loop，直到程式接收結束訊號。原本 C++ Qt 是用 &lt;abbr title=&quot;member function&quot;&gt;memfunc&lt;/abbr&gt; &lt;tt&gt;exec()&lt;/tt&gt;，但在 Python 中名稱已被佔用，所以不幸得改成這鳥名......&lt;/p&gt;&lt;p&gt;不懂某些語法的必要性的話也沒關係，總之這些是基本的 code pattern，依樣畫葫蘆就是，以後長大就會慢慢懂了......。我當初看&lt;a href=&quot;http://www.amazon.com/Programming-Prentice-Source-Software-Development/dp/0132354160&quot;&gt;《C++ GUI Programming with Qt 4》&lt;/a&gt;時也是滿腦子 &amp;quot;WTF&amp;quot; = =&lt;/p&gt;&lt;p&gt;總結：導入相關庫 → 初始化 &lt;tt&gt;QApplication&lt;/tt&gt; → 把想要的 widgets 搞定 → 開始執行 &lt;tt&gt;QApplication&lt;/tt&gt; event loop。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;很明顯，這是個一點 p 用也沒的拉雞程式。除了拉來拉去改變大小以外啥 p 也做不了。但是其中卻蘊含了不少東西......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;Qt GUI 採用 &lt;a href=&quot;http://doc.trolltech.com/qq/qq11-events.html&quot;&gt;Event&lt;/a&gt;-driven architecture：有事件發生時就處理之；沒事件發生 or 這事件不干我屁事時，就卡在那邊乾等新的事件。&lt;br /&gt;&lt;br /&gt;「&lt;strong&gt;Event&lt;/strong&gt;」指啥？包括了滑鼠點擊、游標飄過、鍵盤輸入等；event 發生後，會被轉交到 event handler 以決定該怎麼應對處理。&lt;/p&gt;&lt;p&gt;以我們的第一個程式來說，因為並沒指定該怎麼特別處理上述那些事件，所以就讓它們隨風而逝不了了之了。但是像視窗大小改變、最大化等事件，event handler 就知道該調用重繪函式改變外觀 ( class 自己會搞定，程式設計師去泡咖啡準備加班便可 )。&lt;/p&gt;&lt;p&gt;Event-driven 是很重要的概念 ( 據說現行圖形系統都是用這種方式運作的...... )；請謹記，就算是游標掃過去，也會產生 event 的。「繼承並改寫 event handler」，可讓程式依自己想要的方式處理事件。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;接下來看第二個程式：&lt;br /&gt;&lt;br /&gt;&lt;code class=&quot;prettyprint lang-py linenums:1&quot;&gt;#!/usr/bin/env python&lt;br /&gt;&lt;br /&gt;import sys&lt;br /&gt;from PyQt4.QtGui import *&lt;br /&gt;&lt;br /&gt;app = QApplication(sys.argv)&lt;br /&gt;&lt;br /&gt;widget = QWidget()&lt;br /&gt;widget.resize(200, 150)&lt;br /&gt;widget.move(500, 400)&lt;br /&gt;widget.setWindowTitle(&quot;Hello World&quot;)&lt;br /&gt;widget.show()&lt;br /&gt;&lt;br /&gt;app.exec_()&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU48JG69SItqFdtWXKl1RWaXv-0Eo7YWLuQesBkU_lGkgypPkX-f-Klez5OMuADg8ed2vyAVY0Ty2zP0A5yFUhkC4VPuG_q6FZ5LYXrNUc_opy5KfUVth5dxVIPIBVuLcI3WuzaoCvppk/s1600-h/second.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 204px; height: 175px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiU48JG69SItqFdtWXKl1RWaXv-0Eo7YWLuQesBkU_lGkgypPkX-f-Klez5OMuADg8ed2vyAVY0Ty2zP0A5yFUhkC4VPuG_q6FZ5LYXrNUc_opy5KfUVth5dxVIPIBVuLcI3WuzaoCvppk/s400/second.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5327543737784297522&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;只多了 3 行，調用 &lt;tt&gt;QWidget&lt;/tt&gt; instance 的一些 memfunc 改變視窗狀態。包括了改變視窗大小、把視窗移動到螢幕特定位置 ( 而不像初體驗一樣，任由作業系統分派 )，以及改變視窗的 title。&lt;/p&gt;&lt;p&gt;( 初學程式的人可能會問：怎麼知道有啥函式可以呼叫呢？&lt;br /&gt;&lt;br /&gt;沒事就多熟悉這個 framework 和 API，看看有啥函式可以摳吧...... 別無它法了。Qt API 和命名方式都頗為清楚有規律，算是賞心悅目，可以多翻翻 =3= )&lt;/p&gt;&lt;p&gt;從 &lt;a href=&quot;http://doc.trolltech.com/latest/qwidget.html&quot;&gt;QWidget 的文檔&lt;/a&gt;可以看出來，雖然這玩意兒長得空空如也毫不起眼，卻有兩百多個函式可供呼叫。由&lt;a href=&quot;http://doc.trolltech.com/latest/hierarchy.html&quot;&gt;繼承架構&lt;/a&gt;更可知道，Qt 中所有的圖形元件都繼承自 &lt;strong&gt;&lt;tt&gt;QWidget&lt;/tt&gt;&lt;/strong&gt; (||°３°)&lt;/p&gt;&lt;p&gt;因此，&lt;tt&gt;QWidget&lt;/tt&gt; class 有兩大功用：一是提供海量函式讓 child class 繼承使用；二是做為空空的容器，拿來裝 child widgets。以後會慢慢提到......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;下次再見 (||°３°)&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-4-layout-management.html&quot;&gt;[PyQt 教學] Part 4: Layout Management&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/8203060284448363967/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-3.html#comment-form' title='7 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8203060284448363967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8203060284448363967'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-3.html' title='[PyQt 教學] Part 3: 起步走'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEijGQ8gBJw-Ld1pz1vZAFGgisdn3RCSQvFMhbtTfNN_UEdDqHkte0_4F3HC_6cRVhvOzh6TnT_5y6gpM5cM_Ptz9VqHMoH87aD8G1DljbrjthLkWgAQQ2CIHbsS3eqGZDyZGCmi6xgb2sc/s72-c/first.png" height="72" width="72"/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-3246184689410701589</id><published>2009-04-22T16:06:00.018+08:00</published><updated>2011-08-24T17:34:32.720+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 2: 建構開發環境</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-1-introduction.html&quot;&gt;[PyQt 教學] Part 1: Introduction&lt;/a&gt; ←&lt;/p&gt;&lt;p&gt;如何建構 PyQt 開發環境呢？先把 runtime library 裝好吧：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Windows 用戶：到巨慢速又常掛點的&lt;a href=&quot;http://www.riverbankcomputing.co.uk/software/pyqt/download&quot;&gt;官網下載頁&lt;/a&gt;把 Windows installer bundle 載下來灌 ( 記得還要先灌對應版本的 &lt;a href=&quot;http://python.org/download/&quot;&gt;Python&lt;/a&gt; )。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Linux 用戶：包管理系統搜一下 &lt;strong&gt;pyqt&lt;/strong&gt; 應該就有了。找出來安裝之。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;裝了 runtime lib 之後，執行 *.py 程式碼就可以跑 PyQt 程式啦！&lt;del&gt;當前 PyQt 最新版本是 4.4.4，之後的程式碼範例也會以這個版本為主。&lt;/del&gt; 更新後的這系列文章以 Python 2.6 + PyQt 4.5 語法為主。&lt;/p&gt;&lt;p&gt;( 這系列教學的所有程式碼：&lt;a href=&quot;http://sapporo.cool.ne.jp/randalaaaa01/Tutorial44.zip&quot;&gt;4.4&lt;/a&gt; / &lt;a href=&quot;http://sapporo.cool.ne.jp/randalaaaa01/Tutorial45.zip&quot;&gt;4.5&lt;/a&gt; )&lt;/p&gt;&lt;hr /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;再來是文檔。之前說過，開發過程就是猛力翻找 API 文檔；基本上，除非已經對那幾百頁文檔瞭然於心，否則不查閱的話係啥事也幹不瞭的。可以考慮看&lt;a href=&quot;http://doc.trolltech.com/latest/index.html&quot;&gt;線上版&lt;/a&gt;，或是使用 Qt 官方的離線文檔查閱工具 &lt;strong&gt;Qt Assistant&lt;/strong&gt; ( 推薦 )：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Windows 用戶：到 Qt Software &lt;a href=&quot;http://www.qtsoftware.com/downloads&quot;&gt;官網下載區&lt;/a&gt;的 &lt;strong&gt;LGPL / Free&lt;/strong&gt; 那頁找 &lt;strong&gt;Qt libraries&lt;/strong&gt; 來灌。是的，很遺憾，它就是有上百 MB。&lt;br /&gt;&lt;br /&gt;我們要的只是&lt;strong&gt;安裝目錄\doc\qch&lt;/strong&gt; 下，可供 PyQt Assistant 載入的壓縮文檔。摳完後若不需要龐大的 C++ 開發環境的話，就可以刪除了。&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Linux 用戶：搜 &lt;strong&gt;qt-doc&lt;/strong&gt; 或類似的玩意兒。至於 assistant，在安裝 qt 時應該就有附帶了。&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;再建議一次：雖然是寫 PyQt，還是看相對豐富、完善的 C++ Qt 文檔比較好。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;編寫 PyQt code 嘛，文字編輯器足矣。但是雙擊 *.py 執行時，若有語法錯誤 會直接噴發，一片虛無；所以得用 terminal 或下面的 batch script 來跑，才能看到 error msg 以幫助 debug。如果喜歡用 IDE 的話，&lt;a href=&quot;http://eric-ide.python-projects.org/&quot;&gt;Eric IDE&lt;/a&gt; 對於編寫 Python 程式來說是個挺不錯的選擇。&lt;/p&gt;&lt;p&gt;Windows 下可將這行指令&lt;br /&gt;&lt;br /&gt;&lt;code&gt;C:\Python26\python.exe -i test.py&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;存成 *.bat 並點它，會執行同一資料夾下的 test.py，並在跑完後叫出 interpreter 待命，讓執行結果別瞬間蒸發。&lt;/p&gt;&lt;p&gt;相反地，如果覺得跑 GUI 程式卻帶出個黑黑的 cmd 著實激醜的話，可以把程式碼副檔名改成 &lt;tt&gt;pyw&lt;/tt&gt; 再執行，就不會有這困擾了。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;另外，除了開發要用到 runtime lib 以外，執行時當然也是需要的。所以，當你開開心心寫好 PyQt 程式，想和親朋好友分享的話，可能得說服他們也安裝個 PyQt bundle...... ( 好在 Linux 社群比較沒這問題 =3=a )&lt;br /&gt;&lt;br /&gt;( 對其它發佈方式有興趣的話，可參考 &lt;a href=&quot;http://diotavelli.net/PyQtWiki/Deploying_PyQt_Applications&quot;&gt;這篇&lt;/a&gt; 或 &lt;a href=&quot;http://www.py2exe.org/index.cgi/Py2exeAndPyQt&quot;&gt;這篇&lt;/a&gt;。)&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;終於可以開始 coding 啦......&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-3.html&quot;&gt;[PyQt 教學] Part 3: 起步走&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/3246184689410701589/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-2.html#comment-form' title='4 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3246184689410701589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3246184689410701589'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-2.html' title='[PyQt 教學] Part 2: 建構開發環境'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-9086485392310233453</id><published>2009-04-19T15:38:00.036+08:00</published><updated>2011-08-24T17:34:32.721+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="PyQt"/><title type='text'>[PyQt 教學] Part 1: Introduction</title><content type='html'>&lt;p&gt;因為我對 PyQt 頗為有愛 ( 以前用它寫過 &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/01/money-expenser-20.html&quot;&gt;Money Expenser&lt;/a&gt; )，所以打算生一點 PyQt4 的入門文......&lt;/p&gt;&lt;p&gt;( 礙於個人知識與經驗的有限，難以保證所述完全正確；若有發現錯誤，請提出指正。)&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;對於初學程式設計的人來說，一項很大的挫折，就是只能在黑黑的屏幕印出九九乘法表，一點 fu 也沒有。不精研演算法之類玩意兒的話，還是得寫出可以點來點去的圖形介面 ( Graphical User Interface )，會比較有成就感。&lt;/p&gt;&lt;p&gt;以工學院常教的 C/C++ 來說，standard 內並無包含 GUI 的部份；想寫 GUI，就得借助一些現成 library / framework 的幫助。選擇很多，滿地都是，但其中個人最有愛的是 Qt ( ......也只摸過這個 )。這系列教學文簡單介紹較好寫的 Qt Python binding - &lt;strong&gt;PyQt&lt;/strong&gt;，期能對對這方面有興趣的人們有些幫助。&lt;/p&gt;&lt;p&gt;當然啦！萬丈高樓平地起；若沒先打好一些程設基本功 ( 像是物件導向概念 ) 的話，一路走下去終究還係會躺平在路邊的......&lt;/p&gt;&lt;hr /&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;關於 Qt 的簡介，可參考以前寫的 &lt;a href=&quot;http://ogc-daily.blogspot.com/2007/09/qt.html&quot;&gt;Qt 介紹與安裝&lt;/a&gt; 前幾段。這些日子以來，又有了不小的變動：Trolltech 被 Nokia 收購 + 改名為 Qt Software；Qt 版號進展到 4.5；最大的改動大概就是從 4.5 版起，&lt;a href=&quot;http://jarsing.blogspot.com/2009/02/qtnokiaqtlgplqt.html&quot;&gt;Qt 適用 LGPL&lt;/a&gt; 吧！&lt;/p&gt;&lt;p&gt;至於 &lt;a href=&quot;http://www.riverbankcomputing.co.uk/software/pyqt/intro&quot;&gt;PyQt&lt;/a&gt;，則是 Qt 的 Python binding。Qt 原本是用 C++ 寫成的 framework，呼叫 &lt;a href=&quot;http://doc.trolltech.com/latest/mainclasses.html&quot;&gt;API&lt;/a&gt; 時得用 C++ 語法；為了方便使用其它程式語言的人用，出現了像是 Java、Ruby、Perl 等 binding。PyQt 讓大家可用 Python 語法調用 C++ Qt API，誠可謂佛心。比起用 C++ 寫，Python 語法的複雜度與長度都少多了，也不用 compile，嚴重省心，開發起來很是愉快 (＞ω＜)♪♪&lt;br /&gt;&lt;br /&gt;( 相對地，執行效率就會比 native C++ 差一些...... 用電腦高速增長的處理速度來換取開發時間吧。)&lt;/p&gt;&lt;p&gt;但是畢竟係截然不同的語言，光是 C++ static typing vs. Python dynamic typing 就已有鴻溝；因此，在 PyQt 中可能看到一些因 C++ 而來的怪異語法，例如：&lt;br /&gt;&lt;br /&gt;&lt;code&gt;self.connect(tabWidget, SIGNAL(&lt;strong&gt;&#39;currentChanged(int)&#39;&lt;/strong&gt;), self.tabChanged)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;這樣提及特定型別的玩意兒。&lt;/p&gt;&lt;p&gt;既然寄 C++ 籬下，得過且過罷；好在 PyQt 的維護者頗為有心，在 &lt;a href=&quot;http://www.riverbankcomputing.co.uk/software/pyqt/roadmap&quot;&gt;roadmap&lt;/a&gt; 提及許多讓語法更加 &lt;a href=&quot;http://yukuan.blogspot.com/2006/11/be-pythonic-python.html&quot;&gt;pythonic&lt;/a&gt; 的改變。例如前述 typing 問題，自 PyQt 4.5 起將可用這樣的寫法完成：&lt;br /&gt;&lt;br /&gt;&lt;code&gt;tabWidget.currentChanged.connect(self.tabChanged)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;優美許多 (＞ω＜)♪♪&lt;/p&gt;&lt;p&gt;此外還有許多改變，像是 Python v3 support、更多的語言整合等，前景是蠻可期的。( 很好奇 Qt 4.5 轉換成 LGPL 有對 PyQt 維護公司造成怎樣的影響...... )&lt;/p&gt;&lt;p&gt;( 更新：PyQt 4.5 已於 6 月 6 號發佈。)&lt;br /&gt;( 更新：Riverbank 決定維持 PyQt 的 GPL/Commercial 雙授權型式。Nokia 交涉未果，只好又造了一個 LGPL 的輪子 &lt;a href=&quot;http://www.pyside.org/&quot;&gt;PySide&lt;/a&gt;... )&lt;/p&gt;&lt;p&gt;以 PyQt 寫成的著名軟體，包括 Python IDE &lt;a href=&quot;http://eric-ide.python-projects.org/&quot;&gt;Eric&lt;/a&gt; 和 Linux 遊戲管理器 &lt;a href=&quot;http://linuxtoy.org/archives/djl.html&quot;&gt;djl&lt;/a&gt; 等，都是優秀的例子。&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;想學 PyQt 的話，自然前提就是要先會 Python ( 尤其是物件導向部份 )。這方面，如果已有其它高階語言編程經驗的話，讀讀 &lt;a href=&quot;http://docs.python.org/tutorial/index.html&quot;&gt;Python 官方的 Tutorial&lt;/a&gt; 還不錯。&lt;a href=&quot;http://rgruet.free.fr&quot;&gt;Quick Reference&lt;/a&gt; 也是個好東西。Python 本身算是好學易用的語言，&lt;a href=&quot;http://jerrylovesrebol.blogspot.com/2009/03/blog-post_5289.html&quot;&gt;學起來不會後悔&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;另外，最好還是能有些 C++ 背景；因為開發過程就是猛力翻找 &lt;abbr title=&quot;Application Programming Interface&quot;&gt;API&lt;/abbr&gt; 文檔，而目前 PyQt 自身的文檔還不成熟，讀起來幾乎像是 C++ 官方版的重度閹割版，也沒專門的查閱工具。所以腦內內建轉換能力，直接衝 C++ API reference 會比較好。&lt;/p&gt;&lt;p&gt;至於 Qt / PyQt，其實都已經有 &lt;a href=&quot;http://thelins.se/learnqt/&quot;&gt;tuto&lt;/a&gt; &lt;a href=&quot;http://zetcode.com/tutorials/pyqt4/&quot;&gt;rial&lt;/a&gt; 了。不過基於食飽太撐，我接下來還是會自己搞個幾篇出來 =3=&lt;/p&gt;&lt;p&gt;最後需要注意一下，PyQt 目前使用的 license 是 GPL；若有顧慮的話請趁早收手......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;那麼 introduction 就到這裡。我們下次再見 ^.&amp;lt;&amp;sim;*&lt;/p&gt;&lt;p&gt;→ &lt;a href=&quot;http://ogc-daily.blogspot.com/2009/04/pyqt-part-2.html&quot;&gt;[PyQt 教學] Part 2: 建構開發環境&lt;/a&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/9086485392310233453/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-1-introduction.html#comment-form' title='2 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/9086485392310233453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/9086485392310233453'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/pyqt-part-1-introduction.html' title='[PyQt 教學] Part 1: Introduction'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-3263041487801149683</id><published>2009-04-15T17:25:00.014+08:00</published><updated>2011-08-25T22:57:53.981+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書心得] 愛麗絲夢遊仙境</title><content type='html'>&lt;p&gt;是的，就是那本《Alice&#39;s Adventures in Wonderland》&lt;a href=&quot;http://findbook.tw/book/9789861244518/basic&quot;&gt;中譯版&lt;/a&gt;，同場加映《Through the Looking-Glass》。&lt;/p&gt;&lt;p&gt;該怎麼說呢...... 讓我狂冒 WTF 的一本書。&lt;/p&gt;&lt;p&gt;&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGnuHlFqhrYIr3KcutXsT6kq0qsSgIh6Kj-LF3-Vj63Jjx2vJqAlw3ahaD3DApy1KYQfIyjlzfe3TnWoxZzD8zwdlRYj_Jj8cCW17OFQAaZz0RWorxRIM2zSyNy_8ryNZPfPx7Zw-uE_Y/s1600-h/the-only-valid-measurement-of-code-quality-wtfs-per-minute.png&quot;&gt;&lt;img style=&quot;cursor:pointer; cursor:hand;width: 400px; height: 362px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGnuHlFqhrYIr3KcutXsT6kq0qsSgIh6Kj-LF3-Vj63Jjx2vJqAlw3ahaD3DApy1KYQfIyjlzfe3TnWoxZzD8zwdlRYj_Jj8cCW17OFQAaZz0RWorxRIM2zSyNy_8ryNZPfPx7Zw-uE_Y/s400/the-only-valid-measurement-of-code-quality-wtfs-per-minute.png&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5324960907374618546&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;不愧是童話經典，劇情跳 tone 的程度很係驚人，跳很大跳不用錢；任何風馬牛不相及的事都能湊在一起，角色無釐頭、對話也無釐頭，滿坑強者齊心共創不和諧的夢中社會。&lt;/p&gt;&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;&lt;p&gt;受到幼年曾被迪士尼錄影帶洗過腦的影響，現在又看到那些老朋友，感覺巨溫馨呢。兔子 &amp;amp; 帽匠 &amp;amp; 睡鼠無限泡茶三人組、衰洨撲克士兵、激愛砍人頭的紅心皇后、咧嘴科科笑的柴郡貓...... 正直與善良都回來啦～&lt;br /&gt;&lt;br /&gt;( 相對的，鏡中奇緣對我而言就比較沒有吸引力了。面生的莫名其妙角色一堆，簡直不知所云 =.=a )&lt;/p&gt;&lt;p&gt;收穫嘛，其實沒有太多，幾乎就純娛樂性質。畢竟已經脫離愛幻想的童年太久了，看了只會冒出「WTF」。不過，我對第七章「瘋狂的下午茶」實在太有愛啦！&lt;/p&gt;&lt;p&gt;打翻牛奶瓶兼把帽匠懷表泡進茶杯的兔子 + 把熱茶倒進睡鼠鼻子的帽匠 + 邊睡覺邊唱歌講故事的睡鼠 + 傲嬌愛麗絲 + 強而有力的對嗆，說有多瘋狂就有多瘋狂，讀來簡直令人熱血沸騰！恨不得能一起進入夢中世界泡茶打屁鬼扯呢 (＞ω＜)♪♪&lt;br /&gt;&lt;br /&gt;儘管海象 &amp;amp; 木匠誘拐牡蠣雙人組也很強大，不過讀遍全書後，還是對這出類拔粹的茶會三人組最為有愛，餘韻久久不絕......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;天馬行空也好，荒謬無理也好；無論如何，終歸係神作吧。連好萊塢電影也一直影射書中橋段，對後世的文化影響頗大，不愧為世界名著之一。&lt;/p&gt;&lt;p&gt;最後，引用全書最末結尾詩的最後一行：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Life, what is it but a dream?&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/3263041487801149683/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/blog-post_15.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3263041487801149683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3263041487801149683'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/blog-post_15.html' title='[讀書心得] 愛麗絲夢遊仙境'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGnuHlFqhrYIr3KcutXsT6kq0qsSgIh6Kj-LF3-Vj63Jjx2vJqAlw3ahaD3DApy1KYQfIyjlzfe3TnWoxZzD8zwdlRYj_Jj8cCW17OFQAaZz0RWorxRIM2zSyNy_8ryNZPfPx7Zw-uE_Y/s72-c/the-only-valid-measurement-of-code-quality-wtfs-per-minute.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-8808535992401636847</id><published>2009-04-02T23:38:00.011+08:00</published><updated>2012-02-10T22:21:50.803+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>講座心得</title><content type='html'>&lt;p&gt;最近學校舉辦一系列講座，邀請了幾位名人來演講。紀錄一下其中最有印象的幾句話：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;朱學恆：&lt;br /&gt;
1. 情緒管理？不要生氣。&lt;br /&gt;
2. 莫忘初衷。&lt;/li&gt;
&lt;li&gt;蔣　勳：生命如果沒有沉澱一些苦味在底層的話，可能會顯得有點膚淺、輕浮。&lt;/li&gt;
&lt;li&gt;詹宏志：婚姻是用長久的理性來彌補當初一時的感性。&lt;/li&gt;
&lt;li&gt;嚴長壽：&lt;br /&gt;
1. 我希望這個比賽的獎金別只有一百萬，而能提高到上千萬，請來世界知名的選手；別在同一個場地中跑個幾十圈，而是在花東一帶的美麗風景沿途進行；還能請到知名頻道來拍攝，將台灣好好地宣傳出去。&lt;br /&gt;
2. 當我看到媒體採訪外國訪客「花了多少錢」之類膚淺的問題時，我是非常心痛的。&lt;/li&gt;
&lt;/ul&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;p&gt;當然，大師們所論述的東西還有很多啦...... 可惜沒有錄音做筆記，所以記住的所剩不多了。也許再過個幾年，還能記得的真的只剩這一點點。不過聽講過程中確實可以感受到諸位大師的閱歷之豐富...... 信手拈來一堆例子，口若懸河層層闡述核心觀點，很是強大。尤其又以嚴長壽的無雙排比法，最教我嘖嘖稱奇 @3@&lt;/p&gt;&lt;p&gt;另一項大師們讓人崇拜的原因，就是視野的寬廣程度了。在宿舍聽了一整天的計程車喇叭聲，再去洗禮一番，簡直目瞪口呆。或許閱歷與器度是相輔相成的吧，也是偉大人物的共通特質。五體投地 Orz&lt;/p&gt;&lt;p&gt;回顧一番，最喜歡的還是蔣勳那一句。儘管帶些無奈和自我安慰，不過人生大概真的就是這樣吧...... 只能吃苦當吃補囉。未來我還會很需要這句話的。&lt;/p&gt;&lt;p&gt;四個美好的夜晚。很高興不是又在宿舍中虛度了......&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/8808535992401636847/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8808535992401636847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8808535992401636847'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/04/blog-post.html' title='講座心得'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-499582916640396535</id><published>2009-01-27T21:02:00.009+08:00</published><updated>2012-02-10T22:32:09.416+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 8 END)</title><content type='html'>&lt;h4&gt;Chapter 8 - Pragmatic Projects&lt;/h4&gt;&lt;br /&gt;
&lt;div id=&quot;fullpost&quot;&gt;&lt;h4&gt;Section 41: Pragmatic Teams&lt;/h4&gt;&lt;p&gt;( 本節以團隊的角度重新走了一遍先前的章節們。)&lt;br /&gt;
團隊間的熱情可以互相勉勵，質量由全員貢獻。不要保留破窗、不要被呆呆地煮熟；對內交流熱絡，對外口徑一致。DRY、orthogonality 是值得花費心思分配的事。給予成員們能夠以自己的方式閃耀的空間，但也要知道何時該停下來。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 42: Ubiquitous Automation&lt;/h4&gt;&lt;p&gt;Don&#39;t use manual procedures. 人類的可重覆性並不像機器那麼好，而且手動完成機器就可以完美處理的東西 並不是一件值得誇耀的事。保留自己的時間精力來做更重要、更困難、更有趣的事吧。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 43: Ruthless Testing&lt;/h4&gt;&lt;p&gt;Test early. Test often. Test automatically. Coding ain&#39;t done &#39;til all the tests run.&lt;/p&gt;&lt;p&gt;測試的範疇：Unit testing → Integration testing → Validation and verification ( 軟體有做它應該完成的事嗎？) → Resource exhaustion / errors ( 如何應變？能否讓軟體復原？) → Performance testing → Usability testing ( 真實環境下實際使用的狀況、手感 )、Regression testing ( code 更新後是否還能通過先前的 test cases？)&lt;/p&gt;&lt;p&gt;Test your testing. Find bugs once.&lt;/p&gt;&lt;p&gt;老樣子：Test your software, or your users will.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 44: It&#39;s All Writing&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;好記性不如爛筆頭。 --中國諺語&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;文檔也是開發中重要的環節。將 code 和 documentation 當成同一 model 的兩種 view。以適當的 comment 寫在 source code 中是一種方法，可以使用自動化工具來提取它。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 45: Great Expectations&lt;/h4&gt;&lt;p&gt;滿足了客戶的期望，才算是成功。並且，如果想讓客戶高興的話，還得再多做一點點......&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 46: Pride and Prejudice&lt;/h4&gt;&lt;p&gt;防止匿名所造成的品質低落，抑或宣示值得自豪的作品，sign your work.&lt;/p&gt;&lt;br /&gt;
&lt;hr /&gt;&lt;p&gt;另有 &lt;a href=&quot;http://www.codinghorror.com/blog/files/Pragmatic%20Quick%20Reference.htm&quot;&gt;Quick Reference Guide&lt;/a&gt;，是書中觀點精華，值得收藏。&lt;/p&gt;&lt;hr /&gt;&lt;br /&gt;
&lt;p&gt;總算讀完了......&lt;/p&gt;&lt;p&gt;整體感覺，就一本 1999 年出版的書來說，所闡述的多樣內容依然歷久彌新。可以想見為何 TPP 會成為這行的經典之一。&lt;/p&gt;&lt;p&gt;書中讓我印象最深刻的一句話，是 Section 38 出現的：&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Software development is still not a science.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;很奇特的觀點，眼神為之一亮 (｡◕‿◕｡)&lt;/p&gt;&lt;p&gt;以往我一直覺得程式設計主要鍛練邏輯思考：資料結構、演算法、循序 / 選擇 / 重覆...... 讓人整個條理化起來。加之多年來興起的大批方法論，似乎都愈加將它拉入理科範疇。&lt;/p&gt;&lt;p&gt;而從該句的觀點來看，確實也有另一番道理：畫家在畫布上揮灑，程設師在鍵盤上敲打，同樣都是為了創造、轉化腦海中所想表達的而努力 ( 只是女孩子的傾心程度會不一樣 )。&lt;/p&gt;&lt;p&gt;把自己當成一個隨興不拘的藝術家，貌似也頗不錯 (＞ω＜)♪♪&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;我所讀過的書，圈出了我所知道的宇宙邊界。&lt;/p&gt;&lt;p&gt;仔細回想，其實我從中學開始就不曾再大量閱讀了......。接觸電腦之後，所有注意力都從歡樂雜書叢中抽離。到現在還延用十年前所得的知識，以及延途隨手採摘的小花朵，真是相當汗顏啊 (||。３。)&lt;/p&gt;&lt;p&gt;網路確實是很偉大，不過也有比不上實體書的地方。&lt;br /&gt;
該是時候重拾書本了......&lt;/p&gt;&lt;hr /&gt;&lt;p&gt;在這綿延伸展至無窮遠方的道路上，我又多完成了一小段。可喜可賀。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/499582916640396535/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-8-end.html#comment-form' title='1 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/499582916640396535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/499582916640396535'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-8-end.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 8 END)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-320422899639927720</id><published>2009-01-26T16:32:00.007+08:00</published><updated>2012-02-10T22:30:22.610+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 7)</title><content type='html'>&lt;h4&gt;Chapter 7 -  Before the Project&lt;/h4&gt;&lt;br /&gt;
&lt;div id=&quot;fullpost&quot;&gt;&lt;h4&gt;Section 36: The Requirements Pit&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;Perfection is achieved, not when there is nothing left to add, but when there is nothing left to take away.&lt;br /&gt;
--Antoine de St. Exupery, Wind, Sand, and Stars, 1939&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;需求不是架構 / 設計 / UI。Requirements are &lt;strong&gt;need&lt;/strong&gt;，是對某件需要完成的事的陳敘。&lt;/p&gt;&lt;p&gt;Don&#39;t gather requirements—dig for them. 瞭解需求背後的&lt;strong&gt;原因&lt;/strong&gt;而不僅僅是方式。&lt;/p&gt;&lt;p&gt;Work with a user to think like a user. 切身瞭解客戶需求，共創和諧社會。對專案建立詞彙表，確保所想的和客戶所講的是同一樣東西。&lt;/p&gt;&lt;p&gt;使用簡單準確的敘述來描述需求，避免規定過度。Abstractions live longer than details.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 37: Solving Impossible Puzzles&lt;/h4&gt;&lt;p&gt;難題給出約束，並限制自由度，局限、誤導思考方向。Don&#39;t think outside the box—find the box. 確定了真正的約束之後，才能証明某些解法確實無用。否則就只是畫地自限，親手扼殺了正確解法。&lt;/p&gt;&lt;p&gt;有些時候，對需求的重新詮釋能讓整個問題蒸發－－它並沒有真的那麼難。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 38: Not Until You&#39;re Ready&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;He who hesitates is sometimes saved.&lt;br /&gt;
--James Thurber, The Glass in the Field&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;相信自己累積的經驗與智慧。當感到疑慮時，用 prototype 來驗證它；結果或許可為團隊節省可觀的時間與精力。Start when you&#39;re ready.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 39: The Specification Trap&lt;/h4&gt;&lt;p&gt;Some things are better done than described.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 40: Circles and Arrows&lt;/h4&gt;&lt;p&gt;Don&#39;t be a slave to formal methods. 要記得誰才是主人，從中提煉出更寬廣的世界邊界。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/320422899639927720/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-7.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/320422899639927720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/320422899639927720'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-7.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 7)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-8158758391828646278</id><published>2009-01-25T23:40:00.004+08:00</published><updated>2012-02-10T22:35:12.454+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 6)</title><content type='html'>&lt;p&gt;除夕夜，讓 TPP 陪我過年...... QQ&lt;/p&gt;&lt;h4&gt;Chapter 6 - While You Are Coding&lt;/h4&gt;&lt;p&gt;Coding 不是機械性的工作；在這過程中必須對決策進行仔細的思考和判斷。&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Section 31: Programming by Coincidence&lt;/h4&gt;&lt;p&gt;深思熟慮地寫 code，別依賴巧合。瞭解自己在做什麼，照計劃行事，並只依靠可靠的事物。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 32: Algorithm Speed&lt;/h4&gt;&lt;p&gt;Big-Oh notation: worst-case time.&lt;br /&gt;
O(n&lt;sup&gt;2&lt;/sup&gt;): on the order of n&lt;sup&gt;2&lt;/sup&gt;.&lt;/p&gt;&lt;p&gt;Estimate the order of your algorithms. Test your estimates.&lt;/p&gt;&lt;p&gt;特別注意當輸入集很小的時候，某些演算法的開銷可能會比其它簡單演算法的還大。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 33: Refactoring&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;Change and decay in all around I see...&lt;br /&gt;
--H. F. Lyte, &quot;Abide With Me&quot;&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;以園藝來比擬軟體開發。重寫 + 重做 + 重新架構 = 重構。重構就是重新設計。&lt;/p&gt;&lt;p&gt;何時重構？違反 DRY / 非正交設計 / 過時知識 / 性能低落。&lt;/p&gt;&lt;p&gt;它得花費額外的時間來完成，不過早期切除腫瘤總是比較好的。Refactor early, refactor often.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 34: Code That&#39;s Easy to Test&lt;/h4&gt;&lt;p&gt;Design to test. 讓 testability 成為軟體的一環。&lt;/p&gt;&lt;p&gt;Unit testing: testing against contract. 保留單元測試並時常跑它。有些現成的框架可以協助完成。&lt;/p&gt;&lt;p&gt;Test your software, or your users will.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 35: Evil Wizards&lt;/h4&gt;&lt;p&gt;Don&#39;t use wizard code you don&#39;t understand. 否則就是在靠巧合編程。確保自己完全瞭解了才用。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/8158758391828646278/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-6.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8158758391828646278'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/8158758391828646278'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-6.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 6)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-5112342371643870015</id><published>2009-01-24T22:45:00.004+08:00</published><updated>2012-02-10T22:36:42.269+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 5)</title><content type='html'>&lt;h4&gt;Chapter 5 - Bend, or Break&lt;/h4&gt;&lt;p&gt;為了適應瞬息萬變的步伐，盡力讓 code flexible &amp;amp; adaptable 是必要的。&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Section 26: Decoupling and the Law of Demeter&lt;/h4&gt;&lt;p&gt;去除不必要的依賴關係，將模組間的耦合降至最小。&lt;/p&gt;&lt;p&gt;The Law of Demeter for functions: object 的任何 method 中都只調用這些 method：obj 自身的、parameter obj 的、持有 / 創建的 obj 的。&lt;br /&gt;
代價是可能會需要很多的包裝 來將東西承包出去，因而降低性能。箇中取捨，自行評估吧......&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 27: Metaprogramming&lt;/h4&gt;&lt;p&gt;Configure, don&#39;t integrate. 讓演算法、容器、資料庫、GUI style 等都可以自由選擇。&lt;/p&gt;&lt;p&gt;Put abstractions in code, details in metadata. ( metadata 如 Windows 中的 .ini 檔。) 這樣一來便可專注於強健的抽象設計、推遲細節處理。讓程式得以在運行中途改變配置，也是一大優點。&lt;/p&gt;&lt;p&gt;要嘛適應，要嘛 &lt;a href=&quot;http://zh.wikipedia.org/wiki/%E6%B8%A1%E6%B8%A1%E9%B8%9F&quot;&gt;as dead as a Dodo&lt;/a&gt;. 演化就是這麼一回事。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 28: Temporal Coupling&lt;/h4&gt;&lt;p&gt;Analyze workflow to improve concurrency. 降低時序依賴，能減少時間耦合。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 29: It&#39;s Just a View&lt;/h4&gt;&lt;p&gt;GUI 中的 MVC ( Model-View-Controller ) 概念：&lt;strong&gt;Model&lt;/strong&gt; 儲存資料本體 / &lt;strong&gt;View&lt;/strong&gt; 負責顯示 / &lt;strong&gt;Controller&lt;/strong&gt; 控制 view 的呈現 ( 像是放大、縮小等操作 )。如此一來可以解除耦合，像是 &lt;a href=&quot;http://doc.trolltech.com/4.4/model-view-programming.html&quot;&gt;Qt 的 Model/View programming&lt;/a&gt; 就有呈現這樣的概念。&lt;/p&gt;&lt;p&gt;將 MVC 推廣到 GUI 之外：&lt;strong&gt;Model&lt;/strong&gt; 是目標 obj 的抽象數據模型 / &lt;strong&gt;View&lt;/strong&gt; 解釋 model / &lt;strong&gt;Controller&lt;/strong&gt; 控制 view 並可向 model 提供新數據。一種有用的技術是 model-viewer network。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 30: Blackboards&lt;/h4&gt;&lt;p&gt;共用的黑板讓大家能匿名、非同步地交換訊息，並協調 workflow。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/5112342371643870015/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-5.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/5112342371643870015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/5112342371643870015'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-5.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 5)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-244882363028310196</id><published>2009-01-21T23:01:00.003+08:00</published><updated>2012-02-10T22:37:55.547+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 4)</title><content type='html'>&lt;h4&gt;Chapter 4 -  Pragmatic Paranoia&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;You Can&#39;t Write Perfect Software&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;Pragmatic Programmer 不光是不信任別人寫的 code，他們也不信任自己所寫的。所以他們針對自己的錯誤進行防衛性編程。&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Section 21: Design by Contract&lt;/h4&gt;&lt;p&gt;與人打交道很困難，所以有了合約這種東西，規範雙方的權利和責任。同樣地，與程式打交道也可以用合約 ( DBC ) 以保證其正確性 ( 做的事不多也不少 )。這包含了 &lt;strong&gt;precondition&lt;/strong&gt; ( 調用 routine 時必須滿足的條件 )、&lt;strong&gt;postcondition&lt;/strong&gt; ( routine 保證會做的事，以及完成後對外圍狀態造成的影響 )、&lt;strong&gt;class invariant&lt;/strong&gt; ( class 會確保由調用者的角度來看，某條件總是為真 )。&lt;/p&gt;&lt;p&gt;於是，routine 與 caller 間的合約就是：所有 precondition 成立時，routine 保證所有 postcondition 和 class invariant 為真。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 22: Dead Programs Tell No Lies&lt;/h4&gt;&lt;p&gt;Crash early. Crash, don&#39;t trash. 程式崩掉比起暗地裡搞爆破好的多。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 23: Assertive Programming&lt;/h4&gt;&lt;p&gt;用 assertion 確保不該發生的事情絕對不會發生。但是它不應該用來：包起必須執行的述句、取代錯誤處理、產生副作用。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 24: When to Use Exceptions&lt;/h4&gt;&lt;p&gt;Use exceptions for exceptional problems. Exception 應該保留來處理&lt;strong&gt;意外&lt;/strong&gt;事件，否則可能會影響可讀性、可維護性，破壞封裝、增加耦合。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 25: How to Balance Resources&lt;/h4&gt;&lt;p&gt;Finish what you start. 用像 XHTML 這樣的嵌套次序釋放資源。負責分配資源的東西，也該負責釋放。本節有給出 C++ 和 Java 處理 exception 時釋放資源的範例。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/244882363028310196/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-4.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/244882363028310196'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/244882363028310196'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-4.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 4)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-1571620123903421687</id><published>2009-01-17T14:33:00.006+08:00</published><updated>2012-02-10T22:41:52.415+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 3)</title><content type='html'>&lt;p&gt;馬不停蹄，第三章的讀書筆記。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Chapter 3 - The Basic Tools&lt;/h4&gt;&lt;p&gt;保持工具的鋒利與契身。工具是雙手的延伸，可以放大你的才幹。&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Section 14: The Power of Plain Text&lt;/h4&gt;&lt;p&gt;Plain text 是 self-describing 的格式。用它來保存資料。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 15: Shell Games&lt;/h4&gt;&lt;p&gt;GUI 的優點 &lt;abbr title=&quot;What You See Is What You Get&quot;&gt;WYSIWYG&lt;/abbr&gt; / 缺點 &lt;abbr title=&quot;What You See Is All You Get&quot;&gt;WYSIAYG&lt;/abbr&gt;。The shell is your friend.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 16: Power Editing&lt;/h4&gt;&lt;p&gt;Use a &lt;strong&gt;single&lt;/strong&gt; editor &lt;strong&gt;well&lt;/strong&gt;.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 17: Source Code Control&lt;/h4&gt;&lt;p&gt;&lt;strong&gt;Always&lt;/strong&gt; use source code control.&lt;/p&gt;&lt;p&gt;它也同樣適用於工作以外的東西 ( 例如作業系統的配置文件 )。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 18: Debugging&lt;/h4&gt;&lt;p&gt;開頭引用句就很震撼呢......&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;It is a painful thing&lt;br /&gt;
To look at your own trouble and know&lt;br /&gt;
That you yourself and no one else has made it&lt;br /&gt;
--Sophocles, Ajax&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;嗯。&lt;strong&gt;程式不會照自己所想的跑，只會照所寫的跑。&lt;/strong&gt;所有程設師共同、永遠的痛苦......&lt;/p&gt;&lt;p&gt;Bug 已經發生，就別訝異地說「那不可能」。面對它吧。&lt;/p&gt;&lt;p&gt;第一步：&lt;strong&gt;Don&#39;t panic.&lt;/strong&gt; 確保程式碼在 compiler 高警告級別下也能正常編譯成功，並搜集 bug 發生時的確實情境，讓它重現。&lt;/p&gt;&lt;p&gt;別歸咎於 OS、compiler。試著描述問題的來龍去脈，可能就會浮現出新觀點。根源或許是在稍遠的地方，而非眼前立即所見。確保以後的測試足夠完整，並清除其它有可能受同一個 bug 影響的地方。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 19: Text Manipulation&lt;/h4&gt;&lt;p&gt;awk、sed、Tcl、Python、Perl 等都是不錯的 text manipulation language，可以用來讓事情自動化。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 20: Code Generators&lt;/h4&gt;&lt;p&gt;Write code that writes code.&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/1571620123903421687/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-3.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/1571620123903421687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/1571620123903421687'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-3.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 3)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-2629414302070976995</id><published>2009-01-12T20:23:00.005+08:00</published><updated>2012-02-10T22:43:00.367+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 2)</title><content type='html'>&lt;p&gt;第二章的讀書筆記。&lt;/p&gt;&lt;h4&gt;Chapter 2 - A Pragmatic Approach&lt;/h4&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Section 7: The Evils of Duplication&lt;/h4&gt;&lt;p&gt;Maintenance 是件持續伴隨著開發過程的例行事務。想讓開發、維護、理解都更容易的話，秉持 DRY 原則：Don&#39;t Repeat Yourself. 並且 Make it easy to reuse.&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 8: Orthogonality&lt;/h4&gt;&lt;p&gt;( 本節開頭給的關於直昇機操控相依性的例子，實在激生動...... )&lt;/p&gt;&lt;p&gt;正交系統中，某個區域的改變不會影響其它地方。這與 DRY 習習相關。設計 self-contained 的組件，以讓事物間不會相互依賴、影響。正交系統可以增加生產力 ( local fix、reuse ) 並降低風險 ( 模組化了 )。&lt;/p&gt;&lt;p&gt;如何讓 code 保持正交性？建構 decoupled 組件 + 避免 global data + 避免寫出相似的函式 ( DRY )。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 9: Reversibility&lt;/h4&gt;&lt;p&gt;你很難在一開始就做出最正確的決策，且決策很可能一而再再而三地更改。保持 code 的 modularity + flexibility + portability，並致力讓東西在該滾蛋時能輕易地滾蛋。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 10. Tracer Bullets&lt;/h4&gt;&lt;p&gt;如何在黑暗的戰場上 以正確的方向和仰角 確實地擊中目標？可以把一堆環境因素丟進電腦求解，或是試射曳光彈並視著彈點修改下次射擊。曳光彈與實彈共享現實的狀況，比起模擬求解更加貼近現實。&lt;/p&gt;&lt;p&gt;Prototyping 是用過即丟的 code，而曳光彈最終將成為整體系統骨架中簡約而完整的一部份。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 11: Prototypes and Post-it Notes&lt;/h4&gt;&lt;p&gt;Prototype 是目標項目的概略模型，可用來測試特定的 aspect，及早找出潛在問題。製作 prototype 是為得從中得到經驗，以讓之後架構實際項目時能有更佳的基礎。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 12: Domain Languages&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;The limits of language are the limits of one&#39;s world. --Ludwig Von Wittgenstein&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;建立並使用與當前項目相關的小型語言。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 13: Estimating&lt;/h4&gt;&lt;p&gt;Estimate to avoid surprises.&lt;/p&gt;&lt;p&gt;步驟：瞭解問題 → 建立模型 → 拆分組件 → 代入參數 → 運算求解。給出的估量單位會影響別人對此的精準感。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/2629414302070976995/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-2.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/2629414302070976995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/2629414302070976995'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-2.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 2)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-3316196090443791406</id><published>2009-01-10T16:07:00.011+08:00</published><updated>2012-02-10T22:44:09.364+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>[讀書筆記] The Pragmatic Programmer (Chapter 1)</title><content type='html'>&lt;p&gt;&lt;a href=&quot;http://www.pragprog.com/the-pragmatic-programmer&quot;&gt;The Pragmatic Programmer&lt;/a&gt; 和 &lt;a href=&quot;http://cc2e.com/&quot;&gt;Code Complete 2&lt;/a&gt;，並列 programming 界呼聲最高的兩本書。&lt;br /&gt;
( 至於中譯版，前者只有簡體的「程序员修炼之道」，後者有繁體的「軟體建構之道」。)&lt;/p&gt;&lt;p&gt;評價之高當然得來有自。有幸兩本都到手了...... 努力生時間出來讀 =.=&lt;/p&gt;&lt;p&gt;本篇為 TPP 第一章的閱讀筆記。&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;br /&gt;
&lt;h4&gt;Preface&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;pragmatic 這字源於拉丁語的「skilled in business」，再溯源就是希臘語的「to do」。&lt;/li&gt;
&lt;li&gt;謹記 programming 是一項工藝；別侷限於特定的技術，而應擁有廣博的知識背景與實際經驗，以適應各種變化，漂亮地完成工作。&lt;/li&gt;
&lt;li&gt;Pragmatic Programmer 的特徵：多才多藝 + 基於經驗累積起來的自信，能快速地理解新事物 + 有著打破砂鍋問到底的精神 + 不會人云亦云，能做批判性思考 + 能設法洞悉問題的內在本質。&lt;/li&gt;
&lt;li&gt;最重要的是，關心自己的技藝，且不間斷地進行思考。&lt;/li&gt;
&lt;li&gt;每天持續提煉，最終將能得到豐碩的成果。&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;
&lt;h4&gt;Chapter 1 - A Pragmatic Philosophy&lt;/h4&gt;&lt;br /&gt;
&lt;h4&gt;Section 1: The Cat Ate My Source Code&lt;/h4&gt;&lt;p&gt;負起責任，承認不足之處。給出選項，別給愚蠢理由。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 2: Software Entropy&lt;/h4&gt;&lt;p&gt;由於&lt;a href=&quot;http://zh.wikipedia.org/wiki/%E7%A0%B4%E7%AA%97%E6%95%88%E5%BA%94&quot;&gt;破窗效應&lt;/a&gt;，在事情惡化、擴散之前，將其修補好。沒人在乎，大家都不在乎了。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 3: Stone Soup and Boiled Frogs&lt;/h4&gt;&lt;p&gt;&lt;a href=&quot;http://www.wretch.cc/blog/erichk/11905960&quot;&gt;石頭湯&lt;/a&gt;這玩意兒，我小時候就從床邊故事錄音帶聽過了...... 不過一直覺得只是個歡樂的故事，沒放在心上。現在才猛然發現是個寓言 (||。３。)&lt;/p&gt;&lt;p&gt;帶頭煮石頭湯，帶動所有人。扮演催化劑的角色。&lt;/p&gt;&lt;p&gt;為什麼別人強我這麼多？因為別人每天多進步一點點。&lt;br /&gt;
為什麼專案進度 delay 這麼多？因為每天 delay 一點點。&lt;br /&gt;
為什麼軟體可以爛成這樣？因為每次爛一點點。&lt;/p&gt;&lt;p&gt;Remember the big picture. 別被溫水煮熟了。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 4: Good-Enough Software&lt;/h4&gt;&lt;p&gt;與客戶討論軟體何時已經夠好。&lt;br /&gt;
「足夠好」的軟體，足夠了。因為在這不完美的世界中，不會有完美的軟體。&lt;br /&gt;
知道何時該停下來；不要為了過度的修飾，而失去宏觀的焦點。&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 5: Your Knowledge Portfolio&lt;/h4&gt;&lt;blockquote&gt;&lt;p&gt;An investment in knowledge always pays the best interest. --Benjamin Franklin&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;遺憾的是，IT 產業日行千里，大量知識都是 expiring asset，淘汰得很快。有幾項管理方法可以稍微改善：保持&lt;strong&gt;定期投資&lt;/strong&gt;的&lt;strong&gt;習慣&lt;/strong&gt; + 多元化 + 風險管理 + 低買高賣 + 重新評估、平衡。&lt;br /&gt;
另外也要保持 pragmatic programmer 批判性思考的習慣，確保自己的知識資產是準確的。&lt;/p&gt;&lt;p&gt;總之最重要的就是持續 update &amp;amp; 拓展思維吧......。走上了隨波逐流的這一行，這也是沒辦法的事。&lt;a href=&quot;http://www.programmingbooks.org/&quot;&gt;生也有涯，而學也無涯。&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;
&lt;h4&gt;Section 6: Communicate!&lt;/h4&gt;&lt;p&gt;與人交流，無庸置疑是相當重要的一件事。如何做呢？清楚地知道自己想表達什麼 + 瞭解並鼓舞聽眾、與之互動 + 分清輕重緩急並選擇時機 + 美化修飾 + 傾聽。有效的交流能增加自己的影響力。&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/3316196090443791406/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-1.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3316196090443791406'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3316196090443791406'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2009/01/pragmatic-programmer-chapter-1.html' title='[讀書筆記] The Pragmatic Programmer (Chapter 1)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-3338973140808851590</id><published>2008-12-20T11:19:00.013+08:00</published><updated>2012-02-10T22:45:03.547+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><title type='text'>時間管理</title><content type='html'>&lt;p&gt;筆記 &lt;a href=&quot;http://blogs.myoops.org/lucifer.php/2007/11/08/randypausch&quot;&gt;Randy Pausch&lt;/a&gt; 生前&lt;a href=&quot;http://blogs.myoops.org/lucifer.php/2008/10/28/randypauschtime&quot;&gt;關於時間管理的演講&lt;/a&gt;。&lt;/p&gt;&lt;p&gt;這場演講包含的內容頗廣泛，從各式輔助工具到如何分派作業給別人，並分享一些教授自身的經驗。將近 90 分鐘的影片，值得一看。&lt;/p&gt;&lt;p&gt;「30 天後重新檢視時間日誌，並問問自己：『我改變了什麼？』如果我沒有改變任何事物，那至少我們共同渡過愉快的一小時。如果你改變了事物，你會有更多時間陪伴心愛的人。」&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;ul&gt;&lt;li&gt;Remember that time is money. --Ben Franklin&lt;/li&gt;
&lt;li&gt;許多人都善於管理金錢，但卻忽略了如何管理時間。僅記金錢可以再賺，但時間一去便不復返。把時間當成錢來管理，並問問自己：我的一小時值多少錢？&lt;/li&gt;
&lt;li&gt;人生苦短，做自己覺得有&lt;strong&gt;樂趣&lt;/strong&gt;的事。&lt;/li&gt;
&lt;li&gt;Being successful doesn&#39;t make you manage your time well. Managing your time well makes you successful.&lt;/li&gt;
&lt;li&gt;時間規劃應該做長遠、系統的改變。&lt;/li&gt;
&lt;li&gt;Do the right thing &amp;gt; Doing things right&lt;/li&gt;
&lt;li&gt;問問自己：為啥我要做這個？目標是啥？如果我不去做呢？&lt;/li&gt;
&lt;li&gt;將事情依照重要與否、急迫與否做出四個組合，則重要的事總是優先於不重要的事，即便期限未至也是。挪出時間提早將「重要但不急迫的事」做好，可以避免它晉級成「重要且急迫」。&lt;/li&gt;
&lt;li&gt;Doing it at the last minute is very expansive.&lt;/li&gt;
&lt;li&gt;訂出 fake deadline&lt;/li&gt;
&lt;li&gt;Scheduling: You don&#39;t &lt;strong&gt;find&lt;/strong&gt; time for important things, you &lt;strong&gt;make&lt;/strong&gt; it!&lt;/li&gt;
&lt;li&gt;Make time by electing not to do something else. ( Opportunity cost )&lt;/li&gt;
&lt;li&gt;捨棄沒有價值的事。值得就是值得，不值得就是不值得。要懂得說「&lt;strong&gt;不&lt;/strong&gt;」！&lt;/li&gt;
&lt;li&gt;列出「100 things to do in my life!」。然後當我在做清單上沒列出的事時，我會覺得......&lt;/li&gt;
&lt;li&gt;Failing to plan is planning to fail.&lt;/li&gt;
&lt;li&gt;無論計劃會如何改變，總是得&lt;strong&gt;先有一個計劃&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;訂出短 / 中 / 長期目標。&lt;/li&gt;
&lt;li&gt;列出 To do list，並依優先順序排列。將事項細分成更小的事並逐項完成。總是先做最困難的事。&lt;/li&gt;
&lt;li&gt;If you can dream it, you can do it. --Walt Disney&lt;/li&gt;
&lt;li&gt;善用狀態最好、最有創造力的時段做重要的事，並用低潮做瑣事。&lt;/li&gt;
&lt;li&gt;迴避、限制干擾的頻率和長度。( 這點在 &lt;a href=&quot;http://findbook.tw/book/9789867889645/basic&quot;&gt;Peopleware&lt;/a&gt; 講了不少 )&lt;/li&gt;
&lt;li&gt;做事應注重&lt;strong&gt;效益&lt;/strong&gt;：也許不是最高效率，但有最好的結果。Work fewer hours, get more done.&lt;/li&gt;
&lt;li&gt;迴避 Parkinson&#39;s Law ( Work expands so as to fill the time available for its completion. )&lt;/li&gt;
&lt;li&gt;做好 Time Journal，並時常更新它。用它來紀錄時間到底花到哪裡去了，並且改善。&lt;/li&gt;
&lt;li&gt;經驗是無價的。錯誤的決策讓我們得到經驗，因而在未來做出正確的決策。&lt;/li&gt;
&lt;li&gt;用 fake class 填補空堂，在圖書館與書獨處。&lt;/li&gt;
&lt;li&gt;Kill your TV.&lt;/li&gt;
&lt;li&gt;會議開始前必先給出 agenda。結束後花個一分鐘紀錄所得到的結論與結果。&lt;/li&gt;
&lt;li&gt;單身會浪費時間，因為行為無需對其他人負責。如果揮霍會影響其他人的生活，就會更加注意克制自身。&lt;/li&gt;
&lt;li&gt;可能的話，把金錢換成時間，因為時間永遠不夠。&lt;/li&gt;
&lt;li&gt;最重要的事：睡、吃、運動。尤其是&lt;strong&gt;睡&lt;/strong&gt;：如果沒睡好，啥事都做不好。You always have time to sleep.&lt;/li&gt;
&lt;li&gt;如果沒時間把事情做好，也沒時間把事情做壞。&lt;/li&gt;
&lt;li&gt;尋求 Work-Life Balance&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Time is all we have.&lt;/strong&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;單身會浪費時間，嗯。&lt;/p&gt;&lt;p&gt;題外話，教授在投影片中放了一張南瓜燈的照片，圖案很是眼熟。後來終於想到這頗類似 &lt;a href=&quot;http://amarok.kde.org/&quot;&gt;amaroK&lt;/a&gt; 的 icon......&lt;br /&gt;
&lt;a onblur=&quot;try {parent.deselectBloggerImageGracefully();} catch(e) {}&quot; href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiATRoYksdjnar5BFxeo6UaWdmSSqCKJXF57OeT3XRP4_4u85bgry_14Pw3XcsjenD9qW5BQZ28__EYFketJ10WBbxZjXS9UYFFzCWgk94s7twuWmtkGaB4j67qMZJXlF76H_et0NQ8Nso/s1600-h/pumpkin.jpg&quot;&gt;&lt;img style=&quot;margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 180px; height: 168px;&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiATRoYksdjnar5BFxeo6UaWdmSSqCKJXF57OeT3XRP4_4u85bgry_14Pw3XcsjenD9qW5BQZ28__EYFketJ10WBbxZjXS9UYFFzCWgk94s7twuWmtkGaB4j67qMZJXlF76H_et0NQ8Nso/s400/pumpkin.jpg&quot; border=&quot;0&quot; alt=&quot;&quot;id=&quot;BLOGGER_PHOTO_ID_5281722573877797314&quot; /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;有空再修「人生的最後一堂課」......&lt;/p&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/3338973140808851590/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2008/12/blog-post.html#comment-form' title='0 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3338973140808851590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/3338973140808851590'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2008/12/blog-post.html' title='時間管理'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiATRoYksdjnar5BFxeo6UaWdmSSqCKJXF57OeT3XRP4_4u85bgry_14Pw3XcsjenD9qW5BQZ28__EYFketJ10WBbxZjXS9UYFFzCWgk94s7twuWmtkGaB4j67qMZJXlF76H_et0NQ8Nso/s72-c/pumpkin.jpg" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-456964502679783250.post-6182657784034402059</id><published>2008-12-03T23:17:00.002+08:00</published><updated>2012-02-10T22:46:13.348+08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Note"/><category scheme="http://www.blogger.com/atom/ns#" term="Python"/><title type='text'>[讀書筆記] Python 核心編程 (Ch13~14)</title><content type='html'>&lt;p&gt;第 13 章物件導向程式設計 / 第 14 章執行環境 ( 講如何調用 &amp;amp; 終止程序 )&lt;/p&gt;&lt;p&gt;本書的 &lt;strong&gt;Part I: Core Python&lt;/strong&gt; 就到此為止了；接下來的 Chapter 15 ~ 23 被歸為 &lt;strong&gt;Part II: Advanced Topics&lt;/strong&gt;，不一定會繼續寫筆記 =3=&lt;/p&gt;&lt;div id=&quot;fullpost&quot;&gt;&lt;h4&gt;Chapter 13: Object-Oriented Programming&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;types 和 classes 被統一了。&lt;/li&gt;
&lt;li&gt;object 是 mother of all classes。宣告時至少繼承自 object 的為 new-style class，否則為 classic class。&lt;/li&gt;
&lt;li&gt;class 的宣告與定義沒有區別。&lt;/li&gt;
&lt;li&gt;對 instance 做 assignment 會增加 reference count&lt;/li&gt;
&lt;li&gt;class method 定義時需要的 self 參數，同 C++ 的 this，是為了識別呼叫的 instance。&lt;/li&gt;
&lt;li&gt;__init__() 為 constructor，應回傳 None。__del__() 為通常無需去碰它的 destructor&lt;/li&gt;
&lt;li&gt;子類重寫 __init__() 後就不會自動調用父類的了。需顯式調用 parent.__init__(self,...) 並顯式傳遞 self 參數 ( 因為不是透過 instance 調用，interpreter 無法自動給出 method 所需的 self )。__del__() 亦同。&lt;/li&gt;
&lt;li&gt;基本上，class attribute 都是 public&lt;/li&gt;
&lt;li&gt;class 定義中出現的 variable assignment 產生 class attribute (static variable)&lt;/li&gt;
&lt;li&gt;可為個別 instance 添加 attribute，尤以 __init__() 中設定 self.attribute 最為常見。&lt;/li&gt;
&lt;li&gt;同名時會優先存取 instance attribute，然後才是 class attribute&lt;/li&gt;
&lt;li&gt;dir(obj) 傳回 list，列出 obj 的所有 attribute 及 method。help(obj) 也可列出這些資料。&lt;/li&gt;
&lt;li&gt;特殊的 class attribute：&lt;strong&gt;__name__&lt;/strong&gt; class name string、&lt;strong&gt;__doc__&lt;/strong&gt; documentation string、&lt;strong&gt;__bases__&lt;/strong&gt; 列出 tuple of direct parents、&lt;strong&gt;__dict__&lt;/strong&gt; 屬性的 {name:value}、&lt;strong&gt;__module__&lt;/strong&gt; 定義所在處。instance attribute：&lt;strong&gt;__class__&lt;/strong&gt; type，避免顯式給出名稱。&lt;/li&gt;
&lt;li&gt;documentation string 不會被繼承。&lt;/li&gt;
&lt;li&gt;繼承時以 DFS 搜尋 indirect base classes 的集合。&lt;/li&gt;
&lt;li&gt;管理 instance count 的好方法是用 static member&lt;/li&gt;
&lt;li&gt;binding：bound method 需有 class instance 才能被呼叫。想呼叫 unbound method 必需言明 class name 並手動傳入 self&lt;/li&gt;
&lt;li&gt;class 中定義的 function 若不帶 self 參數，即為 static method 或 class method。用 @staticmethod 修飾為 static method；用 @classmethod 並傳入標示 class 的變數 ( 通常為 cls )，為 class method。&lt;/li&gt;
&lt;li&gt;可由多個 parent classes 繼承 attribute 和 method&lt;/li&gt;
&lt;li&gt;若 C 繼承 P，super(C, self).foo() 等同於 P.foo(self)，可避免顯式給出 parent name&lt;/li&gt;
&lt;li&gt;繼承後，__init__() 若沒被覆寫就會自動調用 parent class 的；覆寫後則不會。&lt;/li&gt;
&lt;li&gt;想從 built-in immutable type 繼承時，constructor 用 class method __new__(cls,...)&lt;/li&gt;
&lt;li&gt;Table 13.4 列出一大票可供自訂的 special methods&lt;/li&gt;
&lt;li&gt;多重繼承時的 method resolution order：由左至右 BFS。class attribute __mro__ 給出這個次序。&lt;/li&gt;
&lt;li&gt;BIFs：issubclass(sub, sup)、isinstance(inst, cls)、has/get/set/delattr(inst, string)、dir()、super()、vars()&lt;/li&gt;
&lt;li&gt;可在定義時用 __repr__ = __str__ 這樣設定 reference alias&lt;/li&gt;
&lt;li&gt;相較於 addition operation 傳回新的物件，像 += 這樣的 in-place operation 需傳回 self。&lt;/li&gt;
&lt;li&gt;attribute 加前綴 _ 可防止 from module import * 這樣導入屬性。前綴 __ 可防止繼承階層中的名稱衝突。&lt;/li&gt;
&lt;li&gt;Delegation：增刪修改原有物件的功能。藉由覆寫 __getattr()__ 實現。&lt;/li&gt;
&lt;li&gt;Section 13.16: Advanced Features of New-Style Classes。嗯，真的很 advanced。&lt;/li&gt;
&lt;li&gt;class attribute __slots__ 限制了 instances 能存取的屬性，主要目的是節約記憶體。&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://blog.chinaunix.net/u/23216/showart_189009.html&quot;&gt;Descriptors&lt;/a&gt; 有 3 個 special method 做為 descriptor protocol：__get__()、__set__()、__delete__()。激晦澀，讀不通...... =3=&lt;/li&gt;
&lt;li&gt;還有啥 metaclass 的，一樣難懂......&lt;/li&gt;&lt;/ul&gt;&lt;h4&gt;Chapter 14: Execution Environment&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;&lt;abbr title=&quot;Built-In Function&quot;&gt;BIF&lt;/abbr&gt;、&lt;abbr title=&quot;User-Defined Function&quot;&gt;UDF&lt;/abbr&gt;、&lt;abbr title=&quot;Built-In Method&quot;&gt;BIM&lt;/abbr&gt; 都有許多內建的 attribute。&lt;/li&gt;
&lt;li&gt;定義 class 時若實作了 __call__()，就可以對 instance 做 () 呼叫。&lt;/li&gt;
&lt;li&gt;compile(str, file, type) 將 str 以 type 類型編譯。編譯後的 object 可用 exec 或 eval() 跑。先 compile 可避免重覆解讀字串。&lt;/li&gt;
&lt;li&gt;exec obj、eval(obj) 以 Python interpreter 的角度對待 obj。另有 execfile(filename)&lt;/li&gt;
&lt;li&gt;input(str) 等價於 eval(raw_input(str))&lt;/li&gt;
&lt;li&gt;Section 14.5 講述 os module 中一大票用來跑程序的函式。&lt;/li&gt;
&lt;li&gt;sys.exit(status=0) 丟出 SystemExit 這個 ( 唯一不被當成錯誤的 ) 異常，表明退出 python 的意願。&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ogc-daily.blogspot.com/feeds/6182657784034402059/comments/default' title='張貼留言'/><link rel='replies' type='text/html' href='http://ogc-daily.blogspot.com/2008/12/python-ch1314.html#comment-form' title='7 個意見'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/6182657784034402059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/456964502679783250/posts/default/6182657784034402059'/><link rel='alternate' type='text/html' href='http://ogc-daily.blogspot.com/2008/12/python-ch1314.html' title='[讀書筆記] Python 核心編程 (Ch13~14)'/><author><name>Randal Hsu</name><uri>http://www.blogger.com/profile/16850664622754641920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry></feed>