2013年12月7日 星期六

在航技一個月的心得

基本上這篇大概又是一篇抒發心情的文章了吧 :)  原本我以為我已經習慣了這邊的生活了,和我所在的單位裡面的長官,有慢慢熟悉了,每天的時間都過得非常快,因為每天都有事情做,時間自然流逝的快,但是! 就在最近發生了一件事,讓我和我同學十分不爽。

事情是這樣的,基本上我們吃完晚餐後,由於遵守"節能省碳定律",路燈是幾乎沒再開的,很好這代表什麼事呢? 我走在路上基本上看到人都是一團黑影,我和同學就邊走邊聊天的回到宿舍,你一定在想有什麼事情發生嗎? 沒錯,我和那位同學就和往常一樣平安的走回宿舍,基本上是沒什麼事情發生的,但是在晚點名的時候,事情開始了,我們的管理幹部跟我和那位同學說,我們被投訴沒禮貌! 記你們點有沒有問題? 我們倆整個感到意外,但是嘴巴是自然反應的說沒問題,心裡盡是想的,我平常遠遠看到長官都大聲叫長官好,看到車子和機車經過也是停下來,並敬禮,連看到替代役學長都有問好,我是哪裡沒禮貌了? 哪位神人可以出來跟我們解釋一下,讓我心服口服?? 結果他說我晚上走回去沒跟長官問好,我整個冏掉,我他X的,根本連一個長官都沒看到,是要跟鬼問好? 結果他說他晚上和長官走在一起,有看到我們,結果我們沒問好,聽到這邊我更冏了,我連你在那條路上都不知道了,更何況是長官...但是那位管幹仍然說,不管~ 你們就是被投訴了,所以要記點,話說這邊,我整個就不想理他了,連這樣都可以記我點,那以後的生活要怎麼過? 改天夜黑風高,我他X的看到一堆人影,是不是該每個都問長官好,看到十個就喊十次長官好? 到底是哪個處室的神經病長官,如此無聊投訴我們? 還是說其實壓根沒長官,是該位管幹想要盯我們而已?

發生這樣的事情後,讓我更沒心情待在那種鬼地方,因為我感到更絕望了,我絕望的不是因為我還要待10個月,我絕望的是,國家花錢養這些軍人,就是讓他們無聊電電和惡整替代役?這根本是浪費公帑,想說之前做事沒效率就算了,因為做事沒效率其實不只國軍,所以我可以理解,沒公正公義就算了,因為我在軍中,是講求階級的地方,所以我可以忍氣吞聲,讓你們感受到高高居上的爽感,但是今天無聊這樣投訴我們,就讓我覺得超不爽! 軍人可以無聊到這種程度,你以為你是皇帝喔,每個人是不是都要餵你吃飯,幫你擦鞋,一聽到你的聲音,就要馬上立正站好,在以前這樣的皇帝根本是廢渣,馬上就要滅國了。

看到這樣的軍中,整個就是古代皇朝的縮影,我現在心裡想的沒有什麼,就是想要趕快離開這鬼地方,因為我不想自己被那些人同化,雖然我對自己忍耐力非常有信心,但是潛移默化這種力量是很恐怖的,即使你再怎樣不小心,或多或少都是會被感染的,我很怕自己會慢慢被他們同化...我不想成為自己討厭的那種人。

 這篇大概是我最後一篇軍中抒發心情的文章了吧,因為我決定了,我這部落格本來就不是拿來做這種事的,而且要記錄我的程式之旅,所以接下來要寫個跟programming有關的文章了,但是大概要等我下次回到家的時候了 :P

2013年11月10日 星期日

下單位過一個禮拜後

我在的單位是岡山航空技術學院某單位,這一個禮拜下來,其實感覺滿累的,我想一方面是對於新環境的不適應,另一個原因是畢竟我是替代役身分,多多少少會被長官凹去做事,不過我也早就有心理準備就是了,不過並非大部分長官會凹我就是了,只是整個單位基本上有一個長官會凹你,感覺就過得很累了,目前為止,我記得兩個會凹我,話雖如此,裡面也是有好長官,之前做事做到很累的時候,就有長官來關心我,雖然只是一個簡單的說說話,但是我心裡卻是得到很大的舒坦。

另外目前我很難適應的是,我在的單位裡面全都長官,這代表什麼,萬一我說錯話,做錯事,不小心碰觸到他們的地雷,我恐怕就吃不完兜著走了,到目前為止,我都不太敢主動開口說話.....,畢竟我是裡面最小的,不知道踩到地雷會發生什麼可怕的事= =,其他同梯的朋友至少都有兩個替代役,他們可以互相扶持,老實說我有點覺得孤單,我只有吃飯,和下班的時候,可以和大家敞開心胸來聊天,我想這或許是給我一個訓練吧,不管如何,我會想辦法找到自己生存的空間,要不然這樣的生活持續一年,根本只有可怕。

講到軍中做事,真的有很多方面都十分沒有效率! 甚至該說讓我感到無言....光是講收發公文好了,有時候只是為了一個簡單的蓋章,可以讓我等上一兩個小時....不知道該說什麼才好,個人是覺得有許多比較瑣碎的公文,可以改成電子方式,也就是用電腦的方式,這樣不僅可以節省紙張,也節省人力,可以把人力放在其他需要的地方,我相信這絕對很多人都有同樣的想法吧? 我光是進去的第一天就萌生這樣的想法了,我只能說軍中就是這樣死板板的地方,而且是講求階級,沒有公不公平,你資歷小,官階小,就是得像螞蟻一樣,默默做自己,一切就是聽長官的話,目前我也只能繼續忍耐下去,然後周末回家好好放鬆,就像現在的我一樣,在電腦前面打文章,好好的將五天累積的無奈、怒氣,發洩一下 :)。

好啦~ 放假的時光總是短暫,過沒多久我又要回到那與世隔絕的地方囉~


2013年10月20日 星期日

放假兩天,準備回去撥交了 :(

無奈無奈,明天撥交後就要去台北專訓了,雖然國防役的專訓聽說是不怎麼累,但是對我來說那不是重點,重點是以後下單位,根本就過著跟國軍一樣的生活,而且令我更怕的是會被欺負,畢竟我們跟國軍有所不同,在一個團體中如果和別人有特別不同之處,往往會被針對....,不用我多說,這大家應該都有所認同才是。

我真的滿懷疑,政府到底有沒有腦袋,竟然故意讓國防部開那麼多缺額來消耗替代役,這根本是以替代役之名行國軍之實,沒能力消耗那麼多替代役,當初就不要信口開河讓每人都有獎。老實說心情真的不是很好,當初等那麼久的入伍令(原本應該會更早進去的,被其他人搞到延後),最後選到國防役? 雙重打擊,讓我對現在的政府感覺不到任何一點信心,甚至是這社會充滿著不公,sigh,我真的覺得我該找個時間,讓自己好好冷靜一下,其實我回到家後,根本沒心情學習程式和寫程式了,一來是想要讓自己好好冷靜,二是回家頂多兩天,根本沒啥時間寫程式,頂多就是看看一些程式論壇這樣而已,不知道這樣程式會不會退步....。

話說,我在網路上查了許多資料跟國防部公共行政役有關的,大部份都是說忍著吧,忍一年就過去了....雖然也有人說他的單為挺涼的,但是依照歸納法則,看來應該是屎缺無誤,我看著那些文章,其實內心早已麻木,甚至到已不知眼見為何物的境界,因為我從以前到現在我運氣就沒很好,我早該想到,政府會做這種鬼事情,我這梯人數有2400,扣掉碩博900人,剩下1500人,國防部開缺300,恩.....知道大學畢業中這個的機率有多高了吧,我是成大資訊工程畢業的,在選役別時,讀哪間都不是重點了,"碩博"才是重點,我想後面幾梯應該都差不多的情形了吧。

不管如何,只能希望下單位可以遇到好長官了,我這樣的需求應該不過份吧? 選替代役選到最屎缺,好歹也讓我下單位可以遇到好長官,不會被欺負....,剩下幾小時就要去做火車,準備回成功嶺了,等著明天的撥交,又是一個嶄新的旅程,看看能不能遇到好事情。

2013年10月10日 星期四

雙十國慶 放假一天回來囉~

這幾天成功領新訓,其實說操也沒有很操,唯一讓我十分不習慣的就是,幾乎沒有時間可以上大號= =,而且我非常建議以後的學弟,選公差的時候,千千萬萬不要選打飯班,它會讓你整理內務,還有喝水和上廁所的時間,幾乎等於0,尤其是剛進去的前幾天會比較忙,整個就超級不爽,你可以想想,忍著屎意跑三千,是他X得什麼滋味嗎? 有些人更誇張,剛進去三天都沒有大過便...我則是第一天晚上就拉肚子,至於是什麼原因,咳咳,新訓過的都大概知道是什麼原因了,我這邊就不說明了,另外或許是我太過聽話了,不懂得偷閒,一味乖乖的聽命令行事,我是覺得真的沒辦法忍,就舉手說你要去上廁所,只是呢~ 就是全部人就會等你一人上完再去跑三千。

進去成功領,你就把你自己丟入與世隔絕的地方,這樣想你就會輕鬆多了 :) 要注意的地方其實也沒啥,只要不要天兵到神的境界,那應該一切都還好,長官大聲兇你是很正常的事 :) 另外新訓裡面最重要的事情就是,選役別!! 我這梯實在是太可恨了,碩博士整個逼近900人,這個意思就是說裡面所有的好缺,大概就是被他們包走了,你只能乖乖跟一大堆學士抽籤,如果你自認運氣一流,那你大概是不用害怕拉,我當天可是怕到手都用抖的...以前考指考也都沒這麼怕過,我就是運氣太背,抽籤都沒抽到= = 最後就選到聽說替代役裡面最屎缺國防部公共行政....名額還有剩咧!! 你就知道國防部開多少缺額!!! 我對整個選役別的流程整個感到不公平,竟然以學歷優先,X的咧,碩士有很屌嗎? 隨便私立碩沒聽過的系,都可以壓死名校名系了....我們這些被壓死的學士,也只能暗自罵在心裡,再不爽也沒用了,畢竟當國防部公共行政役,已經是天殺的事實了,而且又不能帶手機、NB,這樣跟當兵有什麼不同? 只是比當一般兵爽一點而已阿,還不是被關在那邊....真的很怕我這樣待了一年程式能力會退步很多= =,希望我到時候能夠選到好的單位,看能不能好過一點 :)

這篇打完後,又要進去那個衛生環境不怎麼好的成功嶺了 :( 大概又要過10天左右才會放假出來了~

2013年9月27日 星期五

千等萬等,終於要國軍online了

今年政府特別讓申請替代役的都人人有獎,當初我聽到消息滿開心的,因為聽說能當替代役就是爽? 一切我也是聽來的,所以我也傻傻的跟著高興 :) 但是一切從畢業後開始就不一樣了,起初我以為憑我的簽號,最晚應該也是九月就會進去,誰知道我一直等,不知不覺,九月過去了,我才開始擔心,打電話去公所問,現在籤號到哪了? 一問之下,整個人都傻了,怎麼速度如此之慢啊!! 每梯消化的人數也太少了吧,公所也無奈的口氣回應我,沒辦法,就是等吧~~~~我也很無奈 :(


結果就在最近,我終於收到徵集令了,心裡鬆了一口氣,發現上面籤號,怎麼跟我當初看到的籤號,足足多了20幾,我又傻了一次,我以為我身處夢中,一切都是虛幻的,但是螞蟻咬我的手把我痛醒了,我才知道我在現實中,於是我輕輕吹走那隻螞蟻,然後我在心中開始想,甚至是幹譙! 該不會有人偷偷用權勢讓自己籤號往前移吧....,憑什麼我要乖乖得讓你們籤號後面的先進去,浪費我的時間? 我認為我脾氣算好的,但是這是我頭一次這麼氣的,經過網路上搜尋後,我想真的是有這樣的事。

第一個我想每個公所分配的名額都不一樣,光這點就他X的不公平,很明顯北部的名額分配的比較多,消化的比較快,我想這是政府做事,小老百姓也只能無奈接受,再來就是可以用權勢、用鬧的,來讓自己早點入伍....,於是在我心中,浮現這樣的想法,這樣籤號有何意義,一切如同虛設??

在這現實的社會,權力才是一切,懂得鬧的人才有糖吃,這樣像我傻傻的人,怎麼辦? 以為政府做事公正,所以就安心等待,現在,我才在這邊抱不平,事情也都過了,能怎樣嗎? 只能說整件事下來,讓我失望透頂,眼前所見的都只能參考參考而已,就像在台灣過馬路,看紅綠燈,看到綠燈也不要傻傻的就過去,因為交通號誌在台灣什麼也不是,有權有勢的人,可以無視這一切....新聞報導已經證實了許多次,現在想想我也太天真,我應該從這種事情就該聯想到會有人耍奧步。

現在說什麼也沒用了,總之拿到徵集令了,終於可以進去,出來後就可以找工作了,同時也希望那些還沒進去的,能夠盡早進去:) 以後在社會上我也要多小心了,因為在航行在海上,何處有暗礁,你是不知道的.....,尤其是那些不是"天然"的暗礁,sigh。

打完這篇心裡也稍微舒坦了一些,不過由於要國軍online了,這blog會荒廢一年吧,目前正在碰的common lisp,也只能暫緩了,希望到時候我的程式沒忘太多,甚至是沒忘 :)

2013年9月25日 星期三

C++ regex

之前看到C++ 11發表那些新特色,就滿懷心喜的想要來嘗試一下,第一個我就嘗試了一下regular expression,因為在python中用的十分爽,簡單易用,結果呢?  讓我又喜又氣! 沒錯你沒看錯,為何我會有這種奇異的感受呢?
這就要請先看看下圖 :)


在visual studio裡面一切事都表現正常的,讓我十分開心,但是悲劇的是,當我開始用code blocks的時候,發現竟然得到的答案是不一樣的!! 竟然是沒有任何match,這讓我非常shock阿,起初我還以為是我regular expression寫錯了,畢竟又不是很常用,搞不好我忘了什麼重要的東西,心裡先這樣安慰自己一下:),但是經過多次嘗試後,仍然一樣,最後我用了python來測試一下,發現,很好,是我要的結果阿! 那到底是錯在哪?


經過我的多次搜尋,我發現因為C++ 11還太過新,目前沒有compiler是能夠完全支援的,但我在網路上看到評分,VS的compiler支援度竟然是最差?,G++反而是最多的,誰知道今天VS反而能夠滿足我= =,而且G++竟然是沒支援,讓我原本滿懷期待的心情都落空了 :( 我真心懷疑那個評分是正確的嗎? 目前,我看大概要用一些新特色的話,就是用boost這個library吧,畢竟有許多C11的特色都是借鏡這個library的,另外,也免的到時候又哪個compiler沒支援你要的特色,都不知道錯在哪了。


最後抱怨一下 :) 要是沒支援好歹也給的錯誤訊息,說你沒支援阿!! 讓我都不知道錯在哪...

2013年9月20日 星期五

lisp note 2

 最近讀lisp的心得,感覺的確是一個滿有趣的語言,要說讓我不怎麼喜歡的地方,大概就是那一堆(())這些符號,真的讓我剛開始,看到眼花,語言的可讀性跟python比起來真的差很多 :( 但是我也在想就是因為他的這種語言特性,才會讓lisp這麼多彩多姿 :),也讓lisp有個說法是lisp就像是DNA一樣。


lisp全名是(list processor),從這名字就可以略知一二了,在這程式語言裡,你會看到一堆list,事實也是如此,大致上可以這樣看,lisp裡面的元素,可以分為兩種非cons,是cons,是什麼意思呢?

cons掌控著兩個指標,第一個指標指的元素(car),第二個是(cdr),所以你會看到有語法是這樣的, (car '(1 2)), 這將會得到1,想當然爾(cdr '(1 2)),就是得到2,看到我看到這樣的語法時,心中就開始想了一件事.....
那就是,既然這語法是成功執行的,那是不是代表後面那東西就是一種cons所組成的物件?
後來,經過網路上的搜尋後,事實果然就是如此!!

其實 (1 2),它相當於(cons 1 (cons 2 nil))這樣,當然你會想,要是你想建一個很長的list,那豈不是要打一長串這樣的東西,很麻煩 :( ,lisp是有提供一個syntax sugar的,那就是list,(list 1 2),這樣的效果是一樣的。因此這也給我了一個想法,用cons是可以做出額外許多東西的,或許可以建造新型態? 只是目前我也沒試過,所以說lisp裡面的元素非cons即cons,似乎也無可厚非呢 :)

lisp這語言實在有好多東西要挖喔 :) 目前我沒辦法闡述太多心得,因為還有太多東西沒讀到,也還有太多東西沒釐清,所以沒辦法寫太多心得出來,但是,有一點是lisp有一些語法是有歷史淵源的,我覺得看那些歷史淵源,讓我了解更多的東西,千萬不要遇到語法就硬記,當你知道他的淵源,使用它就跟喝水一樣自然:)

我是這麼認為的,有太多人只把語言當作工具而利用,而沒有去深層了解他背後的語意和哲學,我覺得這是很可惜的,就像是為了考試而讀書一樣,沒有去了解書中給你的意境,想當然爾,會覺得讀書無趣,食之無味。 或許這就是現實面吧,我想lisp有效率上的問題,所以在以前才沒有熱門起來,但是不管如何,我還是覺得lisp值得一學,至少它目前讓我開了許多眼界 :)


在此提供一個可以當做文件查詢的網站 reference
另外lisp的表示法是用前序表達,這或許也是讓許多人第一次看不習慣的原因吧,這邊有個wiki 可以看

2013年9月18日 星期三

first time to play lisp

最近不知道怎麼搞的,突然想要來碰一下這十分古老的語言 :) lisp是一個充滿分支的語言,我覺得他沒有像python那樣有一個強力標準在,意思是python有一個官方版本,雖然python也有眾多分支就是了,像是Jpython, Ironpython....有的沒的。

其實在後來有一個算的上稱為標準的lisp,那就是common lisp,以後在網路上搜索的結果,發現比較多人在用的是clisp(common lisp)和SBCL,但是common lisp也是有眾多實做版本,,我是下載 gnu common lisp ,如果想要玩SBCL請自行去找載點囉 :)

lisp的在網路上的資源,說多也不多,說少也不少,但是我覺得似乎沒那麼熱門,畢竟這語言,曾經被冷落一段時間,但是經過我稍微一探lisp的世界,我發現這語言雖然古老,但是它卻有著許多現代語言的特性,甚至該說更好嗎? 垃圾回收機制他也擁有。但是令我比較驚訝的是它的例外處理,他不像目前的語言,一遇到錯誤就只是丟個訊息,然後程式結束,lisp它似乎會讓你進入debug模式的樣子,然後列出一些你可以執行的動作,目前我也才剛碰一兩天而已,所以還無法完整了解,lisp的哲學,必須過一段時間才能領域精髓。




上面是我的開發環境,因為網路上,我看到推薦的幾乎一致是 emacs + slime + your clisp,所以我就用囉,其實最近也在學vim,但是我看到的插件,竟然跟gnu screen配合,這實在是...很悲劇的他沒提供windows版的:( ,當然其實也有不是用gnu screen,純粹用vim buffer的,插件名字是slimv,但是目前還找不到無法使用的原因,目前猜想是我vim支持的python版本的不合的關係,但是我可不想為了這個,而重新去compile一個vim來用...,或許也是其他原因也說不定,只是想要無痛設定開發環境,就用emacs吧 :) 畢竟slime本來就是emacs的插件。


其實如果你不想要為了學lisp而在去安裝emacs、學emacs的話,我有找到一個IDE,方便好用,以供參考allegro common lisp ,但是介面實在是...,如果你不介意介面的話,又不想碰emacs,那就用這個吧 :)


另外這邊記錄一下目前找到的資源,滿意外的lisp,有不少免費電子書而且品質還算不錯!!
我想看完這些就差不多了吧 :)

2013年9月13日 星期五

初嘗vim

其實很久以前就常聽人說,高手都用vim,但是我一直以來就不怎麼信這套 :) 但是最近常看一些論壇,偶然看到一些愛用編輯器或IDE排名,vim遙遙領先....emacs雖然是第二名,但是票數卻落後滿多的,sublime text則是第三名,票數跟emacs滿接近的,sublime會有這樣的票數,其實我不意外拉 :) 因為自己就很愛用sublime text理由大概有這些
  • 界面十分簡潔和漂亮
  • plugin很多很強大
  • script language是用python
  • 開起速度很快,體積輕巧
還有很多,有興趣的就看看吧 sublime text

哈有點離題 :) 我會突然想用用看vim的原因是就我看看emacs和vim的差別,其實我覺得emacs遠遠強於vim,它可以做的事太多了,我只能說emacs已經不能算是editor了,而且他的腳本語言是用lisp的方言,一個很有趣的語言,只是目前我也沒涉略太深就是了,但是vim有其吸引人的地方,我覺得他強調的特色是快速編輯,他的快捷鍵設定方式比較方便,相較之下emacs則是用到大量的ctrl、alt來結合,老實說這樣對於打字速度的確會慢下來,我想或許是這樣差異讓比較多人選擇vim吧,當然還有一些決定性的原因,但是就不一一列出來了,我就是因為快捷鍵和體積輕巧而從兩者間選擇vim來玩玩,來看看他到底有什麼魅力?

首先就到這邊下載vim,這邊有事情要注意的是,我平台是windows,要是你直接用網站上提供的windows installer,那到是一切順遂,不用擔心其他問題,但是如果你像我一樣選擇官方事先幫你built好的檔案(因為我想要portable版),會有個問題那就是,這個vim並沒有python surpport,意思是你沒辦法用python來custom vim,只能乖乖用vimscript來寫,這也代表你用的plugin也不能是用python寫的,因為沒support,要是你覺得沒差那就用吧 :)

所謂的支不支持,輸入:version就可以看出來了如下圖

有+表示支持。

下載下來後,當然就要去安裝一些好用的plugin,我想第一個要安裝的應該是 pathogen
這個東西的作用就跟sublime text的package control一樣,管理你的插件,如果你不安裝這個也行,那就是你得手動慢慢安裝插件,把什麼檔放到什麼資料夾中....,到時候想要刪除該plugin嘿嘿也頗麻煩 :)

再來我安裝的是 nerdtree ,就是一個file browser,不解釋 :)

這是我目前vim的樣子


另外我還安裝一個東西,叫做 conque ,這個讓你vim buffer來做為一個terminal emulator,滿方便的東西,這功能emacs本身就有,若是你沒在在意,快捷鍵設定的方式,那就用emacs或sublime看看吧,而且兩者都有提供"一定程度"的vim快捷鍵。

目前用起來,就是還有好多快捷鍵要去記... 而且就算是我努力調整vim介面後,我還是感覺sublime text介面完勝阿,讓我動不動就關掉vim換sublime text:)  可能是我一直以來用sublime text,一個短暫時間沒用他,就開始想念它了吧。

往後發現有什麼需要記錄的東西,在來PO

2013年9月10日 星期二

vector of pointer to datatype

最近開始回去用C++,乎~真的是久沒用,除了打code時忘了用 ; 來結尾,還有忘了打 { }(因為太習慣python了...),另外對於一些C++ compiler背後運作的方式都有點生疏了,像是一些關於繼承方面會用到的語法xxx: public virtual xxx,虛擬繼承的東西,為啥會有這種東西的存在我不用多說吧? 有興趣就google: c++ diamod problem。


今天是想要記錄一些比較瑣碎的東西,以前我在用std::vector的時候,從來都沒有用資料型態是指標的,所以就沒有注意到一個問題,那就是如下code所示

class animal
{
public:
    animal()
    {
        cout<<"create default"<<endl;
    }

    virtual ~animal()
    {
        cout<<"delete default"<<endl;
    }

};

class dog: public animal
{
public:
    dog()
    {
        cout<<"create dog"<<endl;
    }

    virtual ~dog()
    {
        cout<<"delete dog"<<endl;
    }
};


class cat:public animal
{
public:
    cat()
    {
        cout<<"create cat"<<endl;
    }

    virtual ~cat()
    {
        cout<<"delete cat"<<endl;
    }
};



int main()
{
    vector<animal*> obj;
    obj.push_back(new cat());
    obj.push_back(new dog());


    //vector<animal*>::iterator
    //sintax sugar auto
    for(auto it=obj.begin(); it!=obj.end(); ++it)
    {
        delete *it;
    }
    cout<<"..."<<endl;
    return 0;
}

今天我宣告一個baseclass名為animal,然後有兩個class去繼承他分別為cat和dog,用這樣是為了來做一個upcasting的例子而已,其實這樣的做法是有其方便的地方,假如你今天在做一個遊戲,想當然爾需要常常用到Draw(...)來render物件吧,那麼這時候upcasting這種方式就可以出來耀武揚威了:) 你可以宣告一個interface裡面有draw(),然後繼承該class的class也必須分別implement它們各自的Draw的內容,那麼接下來你就可以用
vector<xxx*> obj
for(.......)
{
    obj->draw();
}

其實今天想要說的東西是,當你用vector<xxx>,xxx這是指標型態的時候,千萬要記得事後自己要delete掉,像我上面code那樣,vector只是幫你handle那些指標占掉的空間,而不會幫你清掉你new的東西,不信你就把我用來delete的那行去掉,看看程式執行會不會有跑出delete的訊息。

第二件想要記錄的是,C++11有個關鍵字叫auto,感覺真棒,一個很棒的sintax sugar,雖然沒有這東西,你也可以用typedef來達到類似功能,只是直接用auto是更爽的一件事 :)

2013年8月29日 星期四

pyqt image displayer

最近開始動手寫我之前講要實做的image displayer了,要學的東西太多,所以就晚了許多時刻才開始研究 :)
大體上動機是想要讓自己更加了解qt這個library,另外的目的就是windows預設的image displayer是無法看動態gif的,所以我打算自己做一個可以看動態gif的圖片檢視器,目前的進度是這樣,一個非常楊春的界面,還有功能 :(

介面架構:

大概就簡單如上面所示,只是toolbar的方面還要設計icon,所以目前就沒加上去,所以進度目前是50%吧 :) (或許更低),下面影片是展示目前的進度



稍後整理目前心得,一直查官方文件看的有夠累 :(
整理完再重新編輯這篇文章 :-S
目前使用的qt物件
QGraphicsScene
QGraphicsView
QgridLayout
QMainWindow
..
..
其實QT實在有太多東西了,讓我覺得其實要做同樣的東西,可以使用很多不同的元件去達成,為何最後我會選QGraphicsScene來顯示圖片,是因為他對2D圖片顯示似乎是比較快的,當然你也可以用QLabel來達成,只是我想效率可能就會比較低吧? 沒實際比較過也不清楚 ,而且QGraphicsView可以控制你觀看QGraphicsScene的視角,像是旋轉阿~有的沒的,所以在種種因素考慮下才使用這兩個。

另外QT其實有提供designer讓你可以用拖曳的方式來做GUI界面,滿方便的:) 只是我想要先嘗試一下hard coding的感覺而已

要看源碼的話,我有放在github上面點此,最近才開使用 :)


2013年8月27日 星期二

git note

git要創造repository的方式有兩種
  1. git init
  2. git clone
第一種,就是你在cmd中,先移到你要的目錄然後輸入git init,就會產生.git的directory,裡面當然就是包含著一些有的沒的,用來確認檔案狀態阿,還有一些configuration,目前不會深入講解那些。

第二種,就是比如你在網路上看到一些open source比如像這個,你有興趣想要把它整個下載下來,這時候如同上面先移到你要的目錄,然後輸入 git clone https://github.com/django/django.git 這樣就會將整個repository下載下來。



圖案來源是前一篇所堤到的電子書裡面的 :) 目前正在閱讀中

git對於檔案有分為上面這幾種狀態
對於repository裡面的檔案狀態,你隨時可以輸入git status來查看

舉例:
剛開始一個空的repository,如果你輸入git status則會告訴你nothing to commit,意指沒有檔案被修改,接著你創了一個readme.txt,再輸入一次這指令,它就會告訴你你有untracked file: readme.txt,所以當你想要讓git開始track這個檔案的時候就得輸入 git add readme.txt,如此一來這個檔案就處於staged的狀態,再來如果你修改了readme.txt,這時候檔案就處於modified狀態,必須再輸入一次git add讓它再一次處於staged狀態。

為何要讓檔案處於staged狀態呢? 因為git commit這指令只會commit那些檔案處於staged狀態。其實這些指令還有很多詳細的用法,你只要在cmd中輸入git help就會跑出一堆git可以用的指令,然後在更進一步比如你想要知道git add有什麼其他用法,那就輸入git help add,就會有更詳細的解說。

另外你可以寫一個.gitignore檔案,在裡面寫你想要避免被add到staged的檔案像是
*.[o]這樣可以避免所有副檔名為o的檔案
為何會有這種東西的存在呢?因為有時候你不想一個檔案慢慢add吧這時候你可以輸入git add -A就會把所以在目錄下的檔案都add到staged,所以不想有個萬一的話,就寫的.gitignore檔吧


大致上git其實也沒什麼好要去理解的,我想只要把git內部如何運作稍微了解,指令什麼的只要查一查用一用就好了:)




2013年8月26日 星期一

start to use git





其實以前就有用過一點git,那時候的我覺得畢竟我很少寫大型的program,實在不怎麼需要用到version control這種工具,但是隨著日子久了,我發現從以前到現在的累積的code檔案數量也不少呢,只是這些檔案我也想要有個備份,所以我就放在網路上面的空間囉 :) 那些檔案大概是不太會再動了:) 但是為什麼今天我又要用git呢? 只是要做備份又何必要用到git? 沒錯! 純粹備份是不需要用到version control的,一般的存放空間即可。

但是有時候我突然在想如果我在不同的地方,想要繼續把某個code給完成,這時候我就得先想過,我曾經在某地方是否下載過,然後做了一些修改,最後是否有上傳呢? 如果沒有的話,那我現在寫的這些又該怎麼跟之前寫過的合併?



 嘿嘿,version control這種工具就有提供merge這種功能,可以把兩種不同版本的code給merge起來,你可以先把目前寫的上傳上去,然後在回去把之前修改過的也上傳上去,最後在merge,一切輕鬆,而且另外的情形是,萬一你修改了很多很多的code,然後你突然後悔了想要復原這些修改,又剛好你在寫之前沒備份,這時候git就方便拉,它有功能是可以讓你回到上一個版本的樣子呢。

version control是不錯用的工具,所以我想說乾脆以後如果要寫什麼program的話,乾脆就用git這version control的工具,放在github這樣,順便也可以當作備份呢 :)

只是git我目前也不怎麼熟悉,所以打算做一些做記錄,免得忘記一些指令該怎麼用 :)

這是官網 上面有免費的電子書,可以下載下來,想學git就去看吧

2013年8月23日 星期五

makefile note3

關於makefile的變數assign的方式,目前看到的大概有三種,詳細資料請看 這個

第一種 simple expand variable,是使用 := 這樣的operator
舉個例子

who := mark
act :=  $(who) say
who := alice
echo $(act)

將會是 mark say,:=這種assgn的operator,如同字面上所言簡單的擴展,他一遇到該行就直接擴展並不會去查他最後是什麼樣子,如果你想要結果是 alice say的話那麼就是要使用第二種方式。

第二種 recursive expand,是使用= 這樣的operator

who = mark
act = $(who) say
who = alice
echo $(act)

這樣一來結果就會是alice say

第三種是conditional variable assginment operator,是使用?=這樣的operator
who = mark
act = $(who) say
who ?= alice
echo $(act)
嘿嘿結果是 mark say喔~ 這個operator的作用是他會檢查該變數是否有值,有值的話就不會做assign的動作

關於make,基本上似乎看官方文件就很OK了,遇到不會的符號查查官方文件大概就有解,我是看gnu make的官方文件,畢竟mingw-make我找不到相關的文件,我想大概是mingw-make就是gnu make來的吧,所以兩者差異應該不大才是。

2013年8月22日 星期四

python 分析程式效率

這是意外發現到的python standard module裡面有個較做profile.py,這東西實在是異常好用阿! 由於上次我用python寫粒子碰撞,我發現當我用到150個particle互相碰撞時,fps就開始降了,於是我開始想著要怎麼提升效率,我在論壇上面發問,結果就有人給我這個分析的方法,實在是很感謝那個人:) python又讓我驚豔了一次。  首先就來看看這張結果圖吧


非常詳細的分析,這個模組的使用方法其實很簡單,官方網站 隨便看都懂,在cmd裡面打cProfile.py -o outputfile.txt youfile.py,這麼一來就會將分析結果存在outputfile.txt中,cProfile.py是用C實現的比起profile.py純python實現,來的有效率。
然後呢要查看這個結果時再用 pstats 這模組

p = pstats.Stats('outputfile.txt')
p.sort_stats('time').print_stats(10)

經過這兩行就會,將結果過濾成以total time來排序並取前10名,如這張圖表示,拖累效率的地方在於collision這function,其實前幾名都把矛頭指向一個地方,那就是我之前寫的vector:(
果然用python來直接寫數學運算是比較沒效率的。

本來的想法是想用numpy來試試看,可是看過官方document後,我覺得numpy是對於數組的運算才有比較大的效率差別,也就是array的運算,因此決定乾脆用C++來寫一個python版的vector :) 不過這得稍微花時間來研究一下了 :)

2013年8月19日 星期一

makefile note 2

關於make的target和prerequisites是用dependency graph來做記錄的,所以像這樣的寫法

a: b.c c.c
a: d.c e.c
其實同等於
a: b.c c.c d.c e.c

他只是持續的修改dependency graph而已,但是如果是用double colon(例:a::b.c c.c)事情就會變得不一樣了,它會分別建立dependency graph,而不會append原來的。


上次說到target可以為檔名也可以不是對吧,不是檔名的target,在術語上名為phony target,其實如同字面上的意思,phony -> fake,假的target,為什麼叫做假的target? 因為這個target並非用來產生檔案的,他只是純粹執行一些shell指令,像是這樣

clean:
    rm -f *.o

如此這類的,但是呢! 當你要用來做這種事情的時候,請記得多加這一行 .phony: clean
會需要多加這行的原因是 make它是無法辨別target是要用來產生檔案或是純粹執行指令,所以要加.phony的宣告,讓make知道它是always out of date,舉個例子吧,如果今天你沒有加這行會發生什麼事呢?

當你同目錄下沒有檔案叫做clean的話那一切就會正常,always out of date,但~~~是~有的話呢!,此時你的target就會被認為是要產生檔案用的,由於clean的rule並沒有任何prerequisites所以always up to date,所以就不會被執行了。

另外make是支援自定義變數的,例如: 你宣告了 compile = g++ , 那麼當你要使用這變數時要用錢字號來取得,$(compile)這樣,make有所謂的 auto variable,詳情請見 這個
目前對這個沒太多研究,我想這個的目的大概是減少code的量,畢竟一直重複打同樣的字是一件很煩的事,像機器人的做的事就交給機器人來做吧 :)

2013年8月17日 星期六

makefile note

我一直以來其實都不怎麼想用makefile來進行編譯的工作 :( 因為實在是有太多好用的IDE了!哈哈,只是我最近常常用sublime text做為我的coding環境,但是只用它來寫python和網頁語言而已。

最近突然想到乾脆比較簡單的C++也在這環境寫好了:) 因此決定來親自碰一下這東西好了,這樣一來我只要自己寫一個subilme build的檔案,就可以按下ctrl+B進行編譯了。


如上所示!OK

 makefile的規則包括三個部份如下
  1. target
  2. prerequisite
  3. commands
target: prerequisite
[tab] commands  # [tab]表示字元\t而已

target:簡單說就是你所要建置的目標,不一定要為檔名
prerequisite:建置目標前,所需要的先決條件
commands:就是shell commands!! 記得開頭得有tab才行

ex:
cc.exe: cc.o
[tab] mingw32-g++ cc.o -o cc.exe 
cc.o: cc.cpp
[tab] mingw32-g++ cc.cpp -std=c++11 -c

然後當我在cmd中輸入mingw32-make,由於我沒給任何argument所以他會以預設得來執行,但是預設的是什麼呢? 答案就是開頭最前面的target。接下來make的分析規則大概是這樣的,先看target和prerequisite去找檔案,如果prerequisite有相關的rule存在那麼就會以他為優先去執行,另外如果prerequisite比target還要新(意思是像是進行修改),那麼就會rebuild該target。

所以,以範例為例一開始碰到cc.exe: cc.o,很好發現了cc.o有相關的rule,那就是cc.o: cc.cpp......那串,所以就會變成先優先執行這條 ,執行完後就會產生cc.o檔,然後就回去執行剛剛那條rule,最後就產生cc.exe這樣。

make是還有更多的用法的,目前這篇僅記錄最基本的法則和用法,不過印象中make不同的版本似乎會有他們獨特的用法就是了,我也不知道會不會用到那麼多 :)

2013年8月16日 星期五

初嘗pyqt

上次用python+PIL來進行將動畫GIF檔給分離出一張一張的圖片,結果不是很讓人滿意,因為PIL對於GIF檔的支援不是很好,因此有部分圖片顏色會有問題,關於當tkinter+PIL碰上gif的時候變的有多suck,看我另外一篇就知道了:(  所以我決定使用pyqt來測試看看。如下面這張animated gif





經過我寫的程式後,分離出來的結果


哈!真是完美,qt就是好用阿,只是目前我還沒有弄熟pyqt,只知道其實它不只是一個gui library,它包括的範疇可真是廣到不行阿,網路、多媒體阿,還有很多很多,目前還沒辦法寫出太多心得,對它還沒特別研究 :) 另外,它官方的文件寫得滿詳細的

img = QImageReader('D:/My Pictures/2.gif')
for i in range(img.imageCount()):
    img.read().save('{}.png'.format(i))
    img.jumpToNextImage()

我僅僅是看官方文件就輕鬆寫出將animated gif分離出來的code了如上面這樣簡單幾行。
對於教學的話,我目前沒有看到哪個教學是不錯的,如果有發現的話就另外補上 :)

2013年8月13日 星期二

python 物理模擬2

上次介紹過vector後,這篇就來講講我的碰撞是怎麼寫的,目前經過測試後我的計算應該是正確的,因為我計算了動能(k),的確有守恆,除了當我用滑鼠點物體的時候,一但點下去會讓物體的速度歸0,並且可以拖曳給予速度,如下影片所示。

話說有什麼軟體是錄製的時候比較不會LAG的嗎? 我用的這個軟體錄起來好像沒說那麼順暢 :(。 回到正題,這邊我是假設兩球碰撞後是沒有旋轉的,因此不考慮進去進入我碰撞程式碼前,先給個概念。
上面要表達的是,一顆移動速度V的球,撞上靜止的球,另外當兩個球體碰撞時,在那個瞬間會有個impulse,且這個imulse方向是平行於連心線的,因此碰撞後會改變得動量也只有平行於連心線的動量,所以在此就把速度向量V拆成平行於連心線(vcos)和垂直於連心線這(vsin)兩種,之後一切就好搞啦 :) 之前說得好像很難,在這邊我要說那時候我腦筋打結阿啊!! 思考不順暢 :( 回到正題,接下來只要把vcos代入,高中教的二維碰撞公式,再將得到的結果與vsin合併,最後這就是答案 :) 這邊我就不教怎麼導出公式了,有興趣的就自己去查囉。
def collision(self, obj):
        '''
            2d collision -- split in two part
            first -- v parallel to the line connected the two circle center

            second -- v vertical to the line connected the two circle center 
            inelastic case, both will has the same velocity....

            v1' = (m1-m2)v1/(m1+m2) + 2 m2v2/(m1+m2) 

            v2' = (2m1)v1/(m1+m2) + (m2-m1)v2/(m1+m2)

        '''
        if self.boundCircle.isCollision(obj.boundCircle): #compare two circle

            o1x, o1y = self.boundCircle.pos.point
            o2x, o2y = obj.boundCircle.pos.point
            p1 = Vector(o2x-o1x, o2y-o1y)

            v1, v2 = self.velocity, obj.velocity
            v1L, v2L = v1.length(), v2.length()

            try:
                rad1 = math.acos( v1.dot(p1)/ (p1.length()*v1L) )
            except:
                rad1 = 0
            try:
                rad2 = math.acos( v2.dot(-p1)/ (p1.length()*v2L) )
            except:
                rad2 = 0
            
                
            v1 = p1.normalize()*v1L*math.cos(rad1)
            v2 = -p1.normalize()*v2L*math.cos(rad2)

            
            m1, m2 = self.mass, obj.mass

            v1f = (m1-m2)*v1/(m1+m2) + 2*m2*v2/(m1+m2) 
            v2f = 2*m1*v1/(m1+m2) + (m2-m1)*v2/(m1+m2)
            

            self.velocity = v1f + (self.velocity-v1)
            obj.velocity = v2f + (obj.velocity-v2)

目前這碰撞只是兩個圓體,我還在想,要是圓體碰撞正方體,要怎麼去計算碰撞後的情形,還要若要考慮旋轉,勢必要改寫這個碰撞公式,必須再花點時間來研究 :) 但是其實如果不想浪費時間在自己寫這些有的沒的,到是可以用別人寫好的物理模擬,目前聽過的有box2d和bullet這兩種,以供參考。

2013年8月9日 星期五

python 物理模擬

最近心血來潮,想要自己實做一些物理方面的模擬,一般來講應該都是從2D方面開始,畢竟3D的世界有很多數學概念,相較起來2D的數學概念比較不吃重,話雖如此,只是果然天算不如人算阿 :(


一開始一路過關斬將,直到我開始寫碰撞的時候,一路上荊棘滿佈,頭一次寫程式寫到有種快要發飆的感覺 :) 我只能說我的數學,大學上學的我都忘了,剩下高中程度,若是一維碰撞那到是簡單的很,公式也能輕易推算出來,但是沒想到只是從1D轉到2D,整件事情就天差地遠阿,到目前為止,我也只是寫出個勉強貼近2D碰撞的模擬。

上面這影片就是我目前寫出來的樣子,獻醜了 :) 這篇就來貼一下,我的2D運算基本工具,基本上我是自己實做了一個vector的class,讓它具有一些特性
  • normalize
  • reflect
等等。
class Vector:

    def __init__(self, x=0.0, y=0.0):
        self.x = x
        self.y = y

    def __neg__(self):
        ''' ex. -Vector(2,2) -> Vector(-2,-2)'''
        return Vector(-self.x, -self.y)

    # def __del__(self):
    #   print('vector {} is delete'.format(self.point))

    def __getitem__(self, value):
        '''return a integer due to the coordinate in pygame is integer
        '''
        return int(self.__dict__[value])

    def __setitem__(self, index, value):
        self.__dict__[index] = value

    def __add__(self, rhs):
        return Vector(self.x+rhs.x, self.y+rhs.y)

    def __truediv__(self, rhs):
        if isinstance(rhs, Vector):
            raise ValueError
        return Vector(self.x/rhs, self.y/rhs)

    def __mul__(self, rhs):
        ''' rhs is a pure num '''
        if isinstance(rhs, Vector):
            raise ValueError
        return Vector(self.x*rhs, self.y*rhs)

    def __rmul__(self, lhs):
        return Vector(self.x*lhs, self.y*lhs)

    def __sub__(self, rhs):
        return Vector(self.x-rhs.x, self.y-rhs.y)

    def __imul__(self, rhs):
        '''
            *= equals to assign and inplace calculation
            ex. a *= b --> a = operator.imul(a, b)
        '''
        if isinstance(rhs, Vector):
            raise ValueError
        self.x *= rhs
        self.y *= rhs
        return self

    def __itruediv__(self, rhs):
        if isinstance(rhs, Vector):
            raise ValueError
        self.x /= rhs
        self.y /= rhs
        return self

    def __iadd__(self, rhs):
        self.x += rhs.x
        self.y += rhs.y
        return self

    def __isub__(self, rhs):
        self.x -= rhs.x
        self.y -= rhs.y
        return self

    def __str__(self):
        return 'vector x ={} y={}'.format(self.x, self.y)

    @property
    def point(self):
        return (int(self.x), int(self.y))

    @point.setter
    def point(self, value):
        self.x = value[0]
        self.y = value[1]

    @property
    def angle(self):
        ''' return radian'''
        return math.atan(self.y/self.x)


    def reflect(self, normal):
        '''
            I <  |---->normal
               \ | /
             ___\|/____

             2*(-I.dot(normal)) -- scalar
        '''
        I = self
        self = (2*(-I.dot(normal))*normal) + I
        return self

    def normalVector(self):
        ''' return the normal vector of self'''
        l = self.length()
        angle = self.angle + math.pi/2
        return Vector(l*math.cos(angle), l*math.sin(angle))

    def normalize(self):
        try:
            length = self.length()
            return Vector(self.x/length, self.y/length)
        except:
            return self


    def rotate(self, radius):
        newx = self.x*math.cos(radius) - self.y*math.sin(radius)
        newy = self.x*math.sin(radius) + self.y*math.cos(radius)
        return Vector(newx, newy)

    def length(self):
        return math.sqrt(self.x**2 + self.y**2)

    def dot(self, v2):
        if isinstance(v2, Vector):
            return self.x*v2.x + self.y*v2.y
        else:
            raise ValueError

關於python的operator我就不說明了,有興趣的就看看這個吧

裡面有些function的意思在這邊說明一下
  1. dot: return 兩向量 內積
  2. rotate: return 旋轉 XX radus後的向量
  3. normalize: 不知道怎翻耶,應該是單位向量這樣
  4. normalVector: return 相對於自己的法向量
  5. reflect: 給予法向量後,計算出反射後的向量
雖然看起來自己另外做一個vector好像有點多餘,只是我覺得這樣對於往後的coding會帶來一些方便性,另外比起用一些 list來代替vector,可讀性也比較高。


等我二維碰撞用出一個更加貼近真實的,我在PO心得,目前到這邊為止 :)

2013年8月5日 星期一

how to write a dll

dynamic link library(dll) 這是在windows上的稱呼,至於linux的稱呼是 shared library,沒記錯的話應該是這樣沒錯。最近想嘗試用python去call自己寫的dll檔,所以就開始學習如何產生dll檔。

 經過我的嘗試後,發現dll的使用方式有兩種
  1. load-time dynamic linking (個人喜歡稱 implicity load way
  2. run-time dynamic linking ( explicit load way

為何會這樣稱呼呢? 我想在稍後或許你就會了解了。
首先寫一個dll檔,它也是有所謂的entry point的,就像是用C++和C寫一個console介面的程式,main就是entry point,win32則是WinMain。
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
{
    return TRUE;
}
我對這個entry point實際上可以做哪些還不是很清楚,依照我看到的資料是說可以在這邊做一些資料的初始化和釋放,但是這個entry point可有可無並沒有強制規定要存在,所以目前我就沒有多去了解了。

再來就是有個key word要注意了 __declspec() 這個可接受的參數有很多,但是目前我僅用到兩個
  1. dllexport
  2. dllimport
假設今天我寫了一個這樣的函式我想要讓別人用dll可以call它,就要這樣寫
extern "C" __declspec(dllexport) int multipleByTwo(int num=2)
{
    std::cout<<"num will be multipled by 2"<<std::endl;
    return num*2;
}
這樣一來被編譯成dll後,在另外一個檔案要用到這函式呢,就要如下面這樣寫,先做個宣告
extern "C" __declspec(dllimport) int multipleByTwo(int num);
宣告之後呢~嘿嘿還記得前面提到的兩種方式嗎?這個方法是implicity way,因為呢,這樣宣告後必須還要link library檔才有辦法編譯成功,要不然就會跑出錯誤提示找不到該函式的reference,另外dll也必須在執行檔的同個目錄喔! 要不然在run time的時候就會錯誤了。另外像這種宣告都會把它放在header file就是了。

至於 explicity way呢,就是用到了LoadLibrary("xxx.dll")這種函式,明顯的去load dll檔,這種方法就不需要像前面那樣link library和宣告 __declspec(dllimport),只是你相對就要去寫一些LoadLibrary和GetProcAddress之類的東西,不過這種的方式我就沒去嘗試了。

不過因為目前我只是測試如何產生dll檔,所以就沒有特別去講究結構了 :) 之後就是來繼續做深入一點的研究,有心得後再上來PO

2013年7月28日 星期日

python tkinter 匯率換算器

其實我最近正在學pyqt,然後看到有個例子是匯率換算器,所以無聊之下換成用tkinter來寫寫看code如下

def test2():
    import tkinter
    from tkinter import ttk

    rates = {}

    def getdata():
        nonlocal rates
        try:
            date = 'unknown'
            fh = request.urlopen("http://www.bankofcanada.ca/en/markets/csv/exchange_eng.csv")
            #always remember that in python3 this function returns byte object!!
            for line in fh:
                line = line.decode('utf-8')# so need to decode
                if not line or line.startswith(('#', "Closing ")):
                    continue
                fields = line.split(',')
                if line.startswith("Date "):
                    date = fields[-1]
                else:
                    try:
                        value = float(fields[-1])
                        rates[fields[0]] = value
                    except ValueError:
                        pass
            return "Exchange Rates Date: "+ date
        except Exception as e:
            return "Failed to downloads:\n%s" % e

    def show(event):
        try:
            num = float(entry.get())
        except:
            pass

        fromCur = float(rates[fromCombo.get()])
        toCur = float(rates[toCombo.get()])
        result['text'] = fromCur/toCur * num


    root = tkinter.Tk()

    dateLabel = ttk.Label(root, text=getdata())
    listVar = sorted(rates.keys())


    fromCombo = ttk.Combobox(root, values=listVar, state='readonly')
    fromCombo.current(0)
    toCombo = ttk.Combobox(root, values=listVar, state='readonly')
    toCombo.current(0)

    entry = tkinter.Entry(root)
    result = ttk.Label(root, text='...')

    calculate = ttk.Button(root, text='calculate')
    calculate.bind('<Button-1>', show)


    dateLabel.grid(column=0, row=0, columnspan=2, padx=5)
    fromCombo.grid(column= 0, row=1, padx=10, pady=5)
    toCombo.grid(column=0, row=2, padx=10, pady=5)
    entry.grid(column=1, row=1, padx=10, pady=5)
    result.grid(column=1, row=2, padx=10, pady=5)
    calculate.grid(column=0, row=3, columnspan=2)
    
    root.mainloop()


if __name__ == '__main__':
    test2()
由於只是嘗試寫寫所以就沒有特別去想結構了,用了不怎麼好看的寫法 :)

只是有個地方滿好奇的,我用這匯率去算跟台銀給的匯率計算器得出的結果不一樣(汗,不過其實我也不太懂匯率是怎麼得出來的,所以用這個程式得出來的結果看看就好,想要知道目前的匯率還是去台銀官網看吧 :) 或者就是把這篇code所抓取的csv改成台銀的 :)

2013年7月24日 星期三

python partial function

    今天到是第一次聽到這個名詞,好奇之下去孤狗了一下,沒想到其實也沒有什麼特別的,應該很多人自己在coding的時候都用過了,這種東西就像design pattern一樣,是一種大家可能都會在不知不覺中使用出來的模式,因為常被使用而且有不錯的用途,因此取個名字記錄下來罷了,首先就來看看一段code

import functools

def f(base=1, pow=1):
    return base**pow

f3 = functools.partial(f, 3)
print(f3(3)) 


    看到這裡是否看出什麼了呢? 沒錯partial function其實也就只是將原本的function多做一層包裝,因為可能在某些情況下,你需要一直打出這些函式,每次都要一直傳參數,以上面為例如果你需要一直call以3基底各種次方數的函式,比起call f(...),call f3(x)簡單多了不是嗎?所謂的partial function就大概是為此而在的。

    functools.partial 第一個參數是你原本的fucntion,接著就是放進函式參數囉,像這邊f3就是指base=3,之後呢我在CALL,f3的時候再給予pow值 ,其實我也不知道functools這模組存在的理由 :) 可能是我幾乎沒再用的關係啦,或許他有好用的一面,至少他幫你做了一些包裝,只是我還是無聊做了一個實現


def partial(f, *arg, **karg):
    def innerF(*iarg, **ikarg):
        ikarg.update(karg)
        return f(*(arg+iarg),**ikarg)
    return innerF

我不太確定是否functools.partial是否是這樣實現的,只是至少我下面這完整的code沒問題 :)

import functools

def partial(f, *arg, **karg):
    def innerF(*iarg, **ikarg):
        ikarg.update(karg)
        return f(*(arg+iarg),**ikarg)
    return innerF


def f(base=1, pow=1):
    return base**pow

f2 = partial(f, 2)
f3 = functools.partial(f, 3)

print(f2(3),f3(3))


2013年7月23日 星期二

python tkinter+PIL

有鑑於Windows內建的圖片預覽器沒辦法看animated gif,因此我突然想要自己實做一個,想當然爾是用python開發方便 :) 只是,果真是人算不如天算阿!! 由於tkinter本身並沒辦法去讀取png、jpg等格式的檔案,所以我另外去裝了PIL。

哼哼,雖然我成功讀取那些檔案,但是 "animated gif" 仍然是一個很大的問題,相信我! 千萬不要用 PIL 去讀取animated gif :(  it's the worst gif-supported library I've ever seen. 我是有成功抓到每個frame出來,但是將每個frame存成圖後簡直悲劇,失真失得好慘阿....之後找了找我發現有人的解法是類似我寫的這樣..

img = Image.open(filename)
palette = img.getpalette()
seq = []
try:
    while True:
        img.putpalette(palette)
        new_im = Image.new("RGBA", img.size)
        new_im.paste(img)
        self.frame.append(new_im)
        img.seek(img.tell()+1)
except EOFError:
    #mission complete
    pass

for i in range(len(self.frame)):
    self.frame[i].save('{}.png'.format(i))

說是這是pil的bug,說啥每當seek到下一個frame時,會失去palette,因此要幫他補上去,只是阿...我這樣做了,就只有部分gif是OK的,有些仍然會有問題!! 我想可能要用其它的library來實做了吧 :(  這次的經歷給我了一句話那就是 PIL + GIF = TORTURE

寫這篇的目地,是不希望有下個人給我一樣在這邊耗這麼久,到頭來卻毫無收穫

2013年7月22日 星期一

c++ traits

今天逛一些論壇,意外發現到我以前學C++都沒有注意過的技術" C++ traits"
我是看到這篇的解說 http://www.cantrip.org/traits.html 讓我重新知道自己似乎該是時候回到C++的懷抱了:) 之前學了一些,但是自從用了python,就一直很少回去碰C++,如今感覺,該是時候繼續精進C++了。

這個技術目前我覺得只是對於template遇到某些型態對此特別處理這樣,讓泛型的樣板,更加容易使用,更加靈活,看完這篇論述後,心裡有了一點想法,可以使用traits來進行參數的型態判斷,code如下

#include<iostream>
using namespace std;

template<typename T>
class typeof
{
    public:
        const char *type = "unknown";
};

template<>
class typeof<char>
{
    public:
        const char *type = "char";
};

template<>
class typeof<int>
{
    public:
        const char *type = "int";
};

template<typename T, typename C=typeof<T>>
class test
{
    public:
        test()
        {
            C obj;
            cout<<obj.type<<endl;
        }
};

int main()
{
    test<int> a;
    test<char> b;
    test<bool> c;
    return 0;
}

結果如圖:

結果果然如我所想一樣 :) 當然traits我現在其實也不是完全很瞭啦,畢竟剛看沒多久,另外沒想到C++ 11 竟然支援 class在宣告資料的同時也可以進行initialize,嚇到我了! 看來在我沒用C++的時期,C++改變了很多阿!!! 真的要找時間好好重新認識C++了 :)

2013年7月17日 星期三

python tkinter <簡單的滑鼠畫線>

真的好感慨啊!! 想想以前用windows api去寫相同的程式,就要多很多工夫,很多底層的東西都要自己實做,用別人幫你建構好的架構就是快速簡單阿 :)
from tkinter import *
from tkinter import ttk


def main():
    lasty, lastx = 0, 0

    def xy(event):
        nonlocal lasty, lastx
        lastx = event.x
        lasty = event.y

    def addLine(event):
        nonlocal lasty, lastx
        canvas.create_line((lastx, lasty, event.x, event.y))
        lasty = event.y
        lastx = event.x


    root = Tk()
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)

    canvas = Canvas(root)
    canvas.grid(column=0, row=0, sticky='nwes')
    canvas.bind('<Button-1>', xy)
    canvas.bind('<B1-Motion>', addLine)
    root.mainloop()


if __name__ == '__main__':
    main()

這樣短短的code就實做出來了。 成果如圖案所示(掩面,用滑鼠寫字好難 :( )



其實這次會PO這篇,是想要做個記錄:) 頭一次用到nonlocal = =,這是用來取的最近的上層scope的變數,因此我在 xy函式裡面寫了 nonlocal lastx, lasty 是為了取得 main函式的 lastx, lasty的reference,讓我可以隨意改變他們的值

2013年7月13日 星期六

use ctypes to call windows api

繼續之前使用ctypes實做Windows data type,這次要做的是使用windows api,來做一個console interface的聊天室,此篇僅先做出介面的樣子



import ctypes
from ctypes import wintypes
from ctypes.wintypes import *
import msvcrt
import sys

#-----------------debug use----------------------
import inspect

def myDebugMsg(msg=''):
    print('{}   at:{}'.format(msg, inspect.stack()[1][1:3]))

def pause():
    while True:
      if msvcrt.kbhit():
         break
#------------------------------------------------


#--------------------------------------------------
# use ctypes to create a windows data type
class Char(ctypes.Union):
    _fields_ = [("UnicodeChar",WCHAR),
                ("AsciiChar", CHAR)]

class CHAR_INFO(ctypes.Structure):
    _anonymous_ = ("Char",)
    _fields_ = [("Char", Char),
                ("Attributes", WORD)]


class CONSOLE_CURSOR_INFO(ctypes.Structure):
    _fields_ = [('dwSize', DWORD),
                ('bVisible', BOOL)]


PCHAR_INFO = ctypes.POINTER(CHAR_INFO)
COORD = wintypes._COORD
#---------------------------------------------------


class dllLoader:
    '''
        load the dll written by c and call them for use 
    '''
    def __init__(self):
        self.mKernel32 = ctypes.WinDLL('Kernel32.dll')
        self.mUser32 = ctypes.WinDLL('User32.dll')

    def getKernel32(self):
        return self.mKernel32

    def getUser32(self):
        return self.mUser32

    Kernel32 = property(getKernel32)
    User32 = property(getUser32)


dll = dllLoader()

#-------------------------------------------------------

上面這些code是先將我會用到的dll檔先load好和windows api data type實做出來,另外還有方便我用來debug的函式,接下來就是用來實做介面的code

class consoleBackBuffer:
    def __init__(self, w, h):
        self.mstdout = dll.Kernel32.CreateConsoleScreenBuffer(
                        0x80000000|0x40000000, #generic read and write
                        0x00000001|0x00000002,
                        None,
                        1, #CONSOLE_TEXTMODE_BUFFER defined in winbase.h
                        None)
        if self.mstdout == HANDLE(-1):
            myDebugMsg('CreateConsoleScreenBuffer failed')


        self.cursorInfo = CONSOLE_CURSOR_INFO()
        self.cursorInfo.dwSize = 25


        self.coordBufSize = COORD()
        self.coordBufSize.X = w
        self.coordBufSize.Y = h

        self.coordBufCoord = COORD()
        self.coordBufCoord.X = 0
        self.coordBufCoord.y = 0


        self.readRgn = SMALL_RECT()
        self.readRgn.Top = 0
        self.readRgn.Left = 0
        self.readRgn.Right = w-1
        self.readRgn.Bottom = h-1


        self.writeRgn = SMALL_RECT()
        self.writeRgn.Top = 0
        self.writeRgn.Left = 0
        self.writeRgn.Right = 79
        self.writeRgn.Bottom = 24

        self.actuallyWritten = DWORD() # used when writeconsole called

        self.setCursorVisibility() # by default, set cursor invisible

    def setCursorVisibility(self, flag = False):
        self.cursorInfo.bVisible = flag
        dll.Kernel32.SetConsoleCursorInfo(self.mstdout, ctypes.byref(self.cursorInfo))

    def toggleActiveConsole(self, stdout=None):
        if stdout != None:
            dll.Kernel32.SetConsoleActiveScreenBuffer(stdout)
        else:
            dll.Kernel32.SetConsoleActiveScreenBuffer(self.mstdout)

    def getHandle(self):
        return self.mstdout

    def set_color(self, color):
        dll.Kernel32.SetConsoleTextAttribute( self.mstdout, color )


    def gotoxy(self, x, y, stdout=None):
        coord = COORD(x, y)
        if stdout == None:
            dll.Kernel32.SetConsoleCursorPosition( self.mstdout, coord)
        else:
            dll.Kernel32.SetConsoleCursorPosition( stdout, coord)

    def setWriteSrc(self, x, y):
        self.writeRgn.Top = y
        self.writeRgn.Left = x
        self.writeRgn.Right = x+self.coordBufSize.X-1
        self.writeRgn.Bottom = y+self.coordBufSize.Y-1

    def write(self, msg):
        while len(msg)>self.coordBufSize.X:
            
            tempMsg = msg[:self.coordBufSize.X-1]+'\n'
            msg = msg[self.coordBufSize.X-1:]
        
            success = dll.Kernel32.WriteConsoleW(
                self.mstdout,
                tempMsg,
                DWORD(len(tempMsg)),
                ctypes.byref(self.actuallyWritten),
                None)

            if success == 0:
                myDebugMsg('WriteConsoleW failed')

        if '\n' not in msg:
            msg = msg+'\n'

        if len(msg) != 0:
            success = dll.Kernel32.WriteConsoleW(
                    self.mstdout,
                    msg,
                    DWORD(len(msg)),
                    ctypes.byref(self.actuallyWritten),
                    None)

            if success == 0:
                myDebugMsg('WriteConsoleW failed')

    def present(self, mainBuffer):
        chiBuffer = (CHAR_INFO*(self.coordBufSize.X*self.coordBufSize.Y))()

        success = dll.Kernel32.ReadConsoleOutputW(
                self.mstdout,
                ctypes.byref(chiBuffer),
                self.coordBufSize,
                self.coordBufCoord,
                ctypes.byref(self.readRgn)
                )

        if success == 0:
            myDebugMsg('ReadConsoleOutputW failed')

        success = dll.Kernel32.WriteConsoleOutputW(
                mainBuffer,
                ctypes.byref(chiBuffer),
                self.coordBufSize,
                self.coordBufCoord,
                ctypes.byref(self.writeRgn))

        if success == 0:
            myDebugMsg('WriteConsoleOutput failed')

我會實做一個console buffer的原因是,我想要用double buffer,畢竟畫面需要常常更新,為了不讓畫面有閃爍,因此使用這個技術。題外話,其實感覺滿新鮮的 :) 因為我以前用過double buffer是在使用 windows api的gdi才用過,果然在CLI裡也有 :) 親自實做的感覺,其實滿有成就感的,接下來就是做一些 widget出來,只是我對於GUI的元件該有怎樣的包裝,我也不清楚,因此只是隨意的做做而已 :(

class widget:
    def __init__(self, sx, sy, w, h):
        self.console = consoleBackBuffer(w, h)
        self.console.setWriteSrc(sx, sy)
        self.gx = sx
        self.gy = sy
        #global position
        self.w = w
        self.h = h
        self.mTitle = 'no name'
        self.content = []

    def getConsole(self):
        return self.console

    def getContent(self):
        return self.content[:]

    def setContent(self, content):
        self.content = content[:]


    def setTitle(self, title):
        self.mTitle = title

    def getTitle(self):
        return self.mTitle

    title = property(getTitle, setTitle)

    def addContent(self, s):
        if len(s) >= self.w-3:
            self.content.append(s[:self.w-3])
            self.content.append(s[self.w-3:])
        else:
            self.content.append(s)

    def delContent(self, s):
        self.content.remove(s)

    def display(self, stdout):
        self.console.present(stdout)


class usermenu(widget):
    '''
        show user list
    '''
    def __init__(self, sx, sy, w, h):
        super().__init__(sx, sy, w, h)

    def update(self):
        #draw outline
        border = '|'+'-'*(self.w-2)+'|'
        emptyLine = '|'+' '*(self.w-2)+'|'
        for y in range(self.h):
            if y in (0, 2, self.h-1):
                self.console.write(border)
            else:
                self.console.write(emptyLine)

        #draw title and user list
        tx = int( (self.w - len(self.title))/2 )
        self.console.gotoxy(tx, 1)
        self.console.write(self.title)


        for i in range(len(self.content)):
            self.console.gotoxy(2, 3+i)
            self.console.write(self.content[i])
        self.console.gotoxy(0, 0)


class msgroom(widget):
    def __init__(self, sx, sy, w, h):
        super().__init__(sx, sy, w, h)
        self.scroll = 0
        self.start = 0

    def scrollContent(self, offset):
        self.scroll += offset
        if self.scroll > 0:
            self.scroll = 0

    def detectPageUpAndDown(self):
        pageUP = dll.User32.GetAsyncKeyState(0x21)
        pageDown = dll.User32.GetAsyncKeyState(0x22)

        if pageUP != 0:
            self.scrollContent(-2)
        if pageDown != 0:
            self.scrollContent(2)

    def update(self):
        self.detectPageUpAndDown()
        border = '|'+'-'*(self.w-2)+'|'
        emptyLine = '|'+' '*(self.w-2)+'|'

        for y in range(self.h):
            if y in (0, 2, self.h-1):
                self.console.write(border)
            else:
                self.console.write(emptyLine)
        #draw title and content
        tx = int( (self.w - len(self.title))/2 )
        self.console.gotoxy(tx, 1)
        self.console.write(self.title)

        index = len(self.content)-(self.h-4)+self.scroll
        self.start = 0 if index < 0 else index

        obj = self.content if len(self.content) < self.h-4 else self.content[self.start : self.start+self.h-4]
        # wow, slice in python seems to automatically check the index if it is out of range
        # ex. lst = [1,2,3,4,5]
        # lst[-6:] no error produce

        for i in range(len(obj)):
            self.console.gotoxy(1, 3+i)
            self.console.write(obj[i])
        self.console.gotoxy(0, 0)



class inputLabel(widget):
    def __init__(self, sx, sy, w, h):
        super().__init__(sx, sy, w, h)

    def update(self):
        border = '|'+'-'*(self.w-2)+'|'
        emptyLine = '|'+' '*(self.w-2)+'|'

        for y in range(self.h):
            if y in (0, 2, self.h-1):
                self.console.write(border)
            else:
                self.console.write(emptyLine)

        tx = int( (self.w - 8))
        self.console.gotoxy(tx, 0)
        self.console.write('|')
        self.console.gotoxy(tx, 2)
        self.console.write('|')
        self.console.gotoxy(tx, 1)
        self.console.write('|submit')
        self.console.gotoxy(0, 0)
好了到這邊為止任務就完成了,想當然爾,要寫個code來測試,自己寫出來的code是不是跟自己想的效果一樣
def test():
    ''' 
        like this?
        in windows, the size of console is 80X25 by default 

        setting: 
            2 space for left and rigth edge
            one space or \n for each panel

            chatroom: 15 height, 55 width
            user list: 16 height, 15 width
            submit: 71 width, height 3
        |-------------------------------------------------------------| |-----------|
        |                        chatroom                             | | user list |
        |-------------------------------------------------------------| |-----------|
        |name2: hello, you                                            | |df         |
        |name1: yo                                                    | |yeah       |
        |                                                             | |one        |
        |                                                             | |           |
        |                                                             | |           |
        |-------------------------------------------------------------| |-----------|

        |-------------------------------------------------------------------|-------|
        |  yo, hahaha                                                       |submit |
        |-------------------------------------------------------------------|-------|

    '''
    from threading import Timer, Thread


    hstdout = dll.Kernel32.GetStdHandle(DWORD(-11))

    if(hstdout == HANDLE(-1)):
        print('create buffer failed')

    backBuffer = consoleBackBuffer(80, 25)

    userpanel = usermenu(56, 0, 15, 17)
    userpanel.title = 'user list'
    userpanel.addContent('heyhey')
    userpanel.addContent('haha')
    userpanel.update()
    userpanel.display(backBuffer.getHandle())

    chatroom = msgroom(0, 0, 55, 17)
    chatroom.title = 'chat room'
    chatroom.addContent("eric: I'm so happy")
    chatroom.update()
    chatroom.display(backBuffer.getHandle())

    inLabel = inputLabel(0, 18, 71, 3)
    inLabel.update()
    inLabel.display(backBuffer.getHandle())

    backBuffer.present(hstdout)
    input()



if __name__ == '__main__':
    test()

結果跑出來的,如同我想像 happy :)
其實後來我有使用socket,thread模組,加上這篇寫的code實做出一個多人聊天室,只是感覺鳥鳥的,有點不想PO出來 :( ,最近是打算寫出一個聊天軟體是GUI介面的,所以要先來研究tkinter,希望能夠成功做出來。

2013年7月12日 星期五

tkinter 雜記

最近想要用python寫個GUI的聊天軟體,於是在網路上查了一些資料,似乎pyQT滿受歡迎的,只是本人我一直以來有個毛病,就是不喜歡在電腦裝東裝西的 :) 因此決定使用python標準庫裡面的tkinter,只是剛開始不知從何下手的我,搜尋了很久,發現似乎沒有個很全面的文件,都是零零碎碎的,於是記錄一下目前發現的幾個reference

http://thinkingtkinter.sourceforge.net/
http://infohost.nmt.edu/tcc/help/pubs/tkinter.pdf
http://www.tkdocs.com/
http://docs.python.org/3.2/library/tkinter.html

大概要花一些時間來研究一下,才能有心得。
總之就先來個無聊的hello world吧 :-S
剛剛發現其實python官網文件好像就很不錯了,已補上,發現什麼的話,此篇隨時會更新 :)

from tkinter import *
from tkinter import ttk
from tkinter.ttk import *

def main():
    root = Tk()
    style = ttk.Style().configure('TLabel', foreground='black', background='green')
    ttk.Label(root, text='Hello World').grid()
    root.mainloop()

if __name__ == '__main__':
    main()

已發現 http://www.tcl.tk/man/tcl8.5/TkCmd/grid.htm 這是tcl/tk的官方文件,從這裡就可以查到你所有想要的關於tkinter的reference。

#追加目前為止的心得,從網路上學了一些關於tkinter使用到的原理,也照著教學,寫了一個嘗試的code,如下
from tkinter import *
from tkinter import ttk



def main():
    root = Tk()
    
    content = ttk.Frame(root, padding=(3, 3, 12, 12))
    frame = ttk.Frame(content, borderwidth=7, relief='solid', width=200, height=100)
    namelbl = ttk.Label(content, text='Name')
    name = ttk.Entry(content)

    onevar = BooleanVar()
    twovar = BooleanVar()
    threevar = BooleanVar()

    onevar.set(True)
    twovar.set(False)
    threevar.set(True)

    one = ttk.Checkbutton(content, text='one', variable=onevar, onvalue=True)
    two = ttk.Checkbutton(content, text='two', variable=twovar, onvalue=True)
    three = ttk.Checkbutton(content, text='three', variable=threevar, onvalue=True)

    ok = ttk.Button(content, text='OK')
    cancel = ttk.Button(content, text='Cancel')

    content.grid(column=0, row=0, sticky=(N,S,E,W))
    frame.grid(column=0, row=0, columnspan=3, rowspan=2, sticky=(N,S,E,W))
    namelbl.grid(column=3, row=0, columnspan=2, sticky=(N,W), padx=5)
    name.grid(column=3, row=1, columnspan=2, sticky=(N,E,W), pady=5, padx=5)
    one.grid(column=0, row=3) # row=2 seems the same
    two.grid(column=1, row=3)
    three.grid(column=2, row=3)
    ok.grid(column=3, row=3)
    cancel.grid(column=4, row=3)

    # when the window resized, all widget will be resized, too
    root.columnconfigure(0, weight=1)
    root.rowconfigure(0, weight=1)
    content.columnconfigure(0, weight=3)
    content.columnconfigure(1, weight=3)
    content.columnconfigure(2, weight=3)
    content.columnconfigure(3, weight=1)
    content.columnconfigure(4, weight=1)
    content.rowconfigure(1, weight=1)

    root.mainloop()



if __name__ == '__main__':
    main()

其實有稍微學過視窗程式設計的應該都知道,這類的都跑不掉有一個主迴圈,是用來處理event queue的,因此python tkinter也不例外 root.mainloop(),到目前為止,跟我以前用windows api寫的概念有所不同的是,tkinter他有所謂的 geometry management,是用來計算每個widget該放置的位置以及大小,geometry management 有三種
  1. place
  2. pack
  3. grid
從我看過的教學,pack是最早有的,它說功能強大(掩面 但是我不知道強在哪,place目前還沒用所以不清楚,最後grid是後來tkinter才出現的,但是它一出現後來很多人都用它,由此可見grid應該是比pack好用,因此我看的教學也是用grid居多,說穿grid頂多只是把視窗分成row和column這樣,方方格格,之後規定每個widget所在的row, column,以及它所跨越的row, column區間(ex. columnspan),這樣程式執行後,它就會自動計算每個widget的位置了~
至於columnconfigure and rowconfigure則是用來window resize的時候,它會讓裡面的元件,依照你規定的weight去放大( ex. weight=1 => 1 pixel to 1 pixel,  weight=3 => 1 pixel to 3 pixel)

2013年7月5日 星期五

python ctypes

最近做了小小的測試,使用python的ctypes來實做windows api的data type

ex.1
typedef struct _CHAR_INFO {
    union{
        WCHAR UnicodeChar;
        CHAR  AsciiChar;
    } Char;
    WORD  Attributes;
} CHAR_INFO, *PCHAR_INFO;


用ctypes實做如下先將名為Char的union實做出來

class Char(ctypes.Union):
    _fields_ = [("UnicodeChar",WCHAR),
                ("AsciiChar", CHAR)]
再來將CHAR_INFO整個structure實做出來

class CHAR_INFO(ctypes.Structure):
    _anonymous_ = ("Char",)
    _fields_ = [("Char", Char),
                ("Attributes", WORD)]
PCHAR_INFO = ctypes.POINTER(CHAR_INFO)

噹噹噹~mission complete
ex.2
typedef struct _CONSOLE_CURSOR_INFO {
    DWORD dwSize;
    BOOL  bVisible;
}CONSOLE_CURSOR_INFO, *PCONSOLE_CURSOR_INFO;
class CONSOLE_CURSOR_INFO(ctypes.Structure):
    _fields_ = [('dwSize', DWORD),
                ('bVisible', BOOL)] 
        其實ctypes這模組挺方便的,可以隨意的call用C寫出來的dll檔,如果只是想要用到一點點dll檔,我想自己寫就好了,不需要去用到其它模組,像是如果你要大量的用到windows api那就果斷用pywin32吧:),裡面可幫你寫好一堆的東西呢,畢竟這動作實在是很機械式,有別人幫你種樹,就去乘涼吧。
    
        當然用python去CALL用C寫的dll也有其他目的,通常是效率問題,把效率吃緊的地方給較低階的語言去實做,目前知道有個叫SWIG,可以將很多語言黏在一起,因為小弟也沒用過所以不敢多言