SyntaxHighlighter

ラベル programming の投稿を表示しています。 すべての投稿を表示
ラベル programming の投稿を表示しています。 すべての投稿を表示

2021-12-23

[C#][Windows] MessageBox中に改行処理

仕事メモです。

Windowsプログラミングによく使用するMessageBox。大量の内容を見せやすくするには改行が必要不可欠です。

いちいちCrLfを追加するのが面倒くさいので、より分かりやすくなる名前はC#内にあるようです。

Environment.NewLine

上記の意味ある内部変数を使ったらいいです。将来LinuxやMacに変更しても同じもので対応可能。通常のCrLfはWindowsのみであり、OSによる覚え間違いは減りますが、長い英単語を覚える方が逆に難しい…なんです。

2021-10-03

LeetCode 01: Two Sum

 長い間ウワサは聞いておりますが、初めて触りました。リートコード(LeetCode)という中国発のネットジャージシステム。一応自分が登録したのはアメリカサーバですけどね。

多分アルゴリズム上ではそこまで最適化していませんが、一応コードを記録しておくことに:


public class Solution {
    public int[] TwoSum(int[] nums, int target) {
            int index1=0;
            int index2=1;

            int maxindex = nums.Length;

            while (true)
            {
                int solution = nums[index1] + nums[index2];
                if (solution == target)
                {
                    int[] result = new int[] { index1, index2 };
                    return result;
                }

                index2++;

                if(index2 >= maxindex)
                {
                    index1++;
                    index2 = index1 + 1;
                }
            }
    }
}
            

2021-09-13

在多個專案中同時設定依賴專案版本

如果你像我在做Blazor的披薩工作坊時,執行build卻發生像下面的錯誤:

warning NU1604: Project dependency 'PackageA' (<= 9.0.0) does not contain an inclusive lower bound. Include a lower bound in the dependency version to ensure consistent restore results.

很好,第一步你找對地方了。這是一個msbuild的問題,也是這個工作坊內容的一個小問題。
這個專案中牽扯到了nuget包裝版本問題。而通常我們在github等上傳資料時,並不會包含nuget引用的封包(可以自己抓的就不要浪費網路流量啦)。

基本上專案用的方法並沒有錯,他只是少傳了一個檔案。在這個檔案中,我們可以將多個proj所需的最低版本放到同一個檔案中集中管理,這樣升級的時候就不需要一個一個去打開專案檔修改參考版本。

你所需要做的動作如下:
1. 在Solution檔案夾下放一個共通的檔案。如果你像我常常使用VSCode,那就是把檔案放在sln檔的同一個目錄中。在標準設定中,他會被叫做Directory.Build.props
2. 修改檔案內容,改成像下面這樣:
<Project>
<PropertyGroup Label="Package Dependencies">
<AspNetCoreVersion>5.0</AspNetCoreVersion>
<EntityFrameworkVersion>5.0</EntityFrameworkVersion>
<BlazorVersion>5.0</BlazorVersion>
<SystemNetHttpJsonVersion>5.0</SystemNetHttpJsonVersion>
</PropertyGroup>
</Project>
3. 如果你是用dotnet cli或是Visual Studio,恭喜你,你已經可以正常build了。
如果你不是使用標準build。那你就繼續做下一步。
4. 打開你的各個專案檔(就是那些csproj檔)。在<Project>的最上層添加下面這行
<import Project="..\Directory.Build.props" />
5. 結束。這樣應該又恢復正常了。未來有升級的時候,自己進去修改所需最低nuget的版本,看是要改成6.0還是什麼的,就看大家造詣了。

ref: https://github.com/dotnet-presentations/blazor-workshop

keyword: asp.net, dependencies.props, Directory.Build.props, .net core

2021-02-12

DataGridCheckBoxColumn動作模式變更

DataGridCheckBoxColumn裡的CheckBox,在預設狀態下,必須先點一次,Row取得focurs之後才能改變狀態。使用上不是很直覺,跟一般的CheckBox不太一樣。

背後的原因是因為DataGridCell本身有分成顯示用的ElementStyle跟編輯用的EditElementStyle兩種模式,為了做出區分,犧牲了CheckBox的直覺性。

可以依靠設定Style的方法,使操作更為直覺。

修改方式如下:

在各自的Style設定中(可以放在上位DataGrid的DataGrid.Resource裡),加入以下程式碼
<Style TargetType="CheckBox" x:Key="CheckBoxCellStyle" />

或是
<Style TargetType="CheckBox" x:Key="CellCheckBoxStyle"
       BasedOn="{StaticResource {x:Type CheckBox}}" />

然後就可以在DataGridCheckBoxColumn上設定我們所需的ElementStyle
<DataGridCheckBoxColumn Binding="{Binding Selected}"
                        ElementStyle="{StaticResource CheckBoxCellStyle}" />

做完以上的設定,指定的DataGridCheckBoxColumn裡面的CheckBox就會是我們常用的單點就會有反應的CheckBox了。

以上。

2020-08-16

[IAmTimCorey]15 Visual Studio Editor Tips

這是一連串的文章,關於我所知道的C#推廣者 Tim Corey 頻道 IAmTimCorey 的內容。
這同時是我的學習筆記。以下的中文用詞,大部分是個人慣用語。一般來說會附上英文原詞,方便大家對照。

原始連結: https://www.youtube.com/watch?v=qv6ZflueASY

這次的題目,是有關那個號稱地表最強IDE的Visual Studio在設定上的一些小技巧與內容

2019-12-09

WPFでEFオブジェクトにData Bindingする場合の4t自動設定

WPFコントロールに自動的にBindingする場合、
デフォルトの4Tフレームワークで生成するファイルに少しだけの変更を入れると、あとはいつもの通りに任せきりにします。

内容はMSDNの公式文書からの抜粋で、私なりに必要な部分だけ取り出しました。

まず、適用する環境は次の通り:

  • Visual Studio Express 2017 for Windows Desktop
  • SQL Server Express 2017(大事でないけど、一応記録しておく。)
  • EF 6.0
  • WPF 3.0以上
そして、使用する手法はDatabase Firstで、ある程度データベースに保存するデータの形はDBですでに定義している前提で進みます。

ちなみに、MSDN公式は次の通り
MSDN公式を閲覧した時点では内容めちゃくちゃなので、蛇足ですが私なりに訳しておきました。
https://hackmd.io/@rokashou/rkSHqVM2H

カギになる設定の部分を抜粋:

  • ソリューションエクスプローラーを開き、edmxファイルの下にあるttファイル探します。編集としてファイルを開けます。
  • 二箇所にある「ICollection」を「ObservableCollection」へ置き換えます。それぞれは約296行目と484行目あたりにあります。
  • 最初に出た「HashSet」を見つけて「ObservableCollection」に置き換えます。 それは約50行目にあります。コードの後半にある2番目のHashSetを置き換えないでください
  • 一回だけある「System.Collections.Generic」を検索し、「System.Collections.ObjectModel」に置き換えます。 それは約424行目にあります。
  • .ttファイルを保存します。 これにより、エンティティのコードが再生成されます。 コードが自動的に再生成されない場合は、.ttファイルを右クリックして、「カスタムツールの実行」を選択します。

以上。

あとは普通にプログラムを組んでください。
ちょっと前のやつにはいろいろ不具合があるようで、見つけた次第にエラーでないように更新していく…



2016-04-15

LISP基本概念(1)

繁體中文的LISP的網路教學太少,只好自己寫筆記
起始原因只是因為AutoCAD用的很火大,想要自己寫Batch Script來做轉換
很不巧AutoCAD使用的是VisualLISP,前身是AutoLISP,最最原始的就是LISP,或者我們說是CommonLISP。新潮一點的,可以找Clozure CL

參考網站

  • 維基教科書:LISP入門 - (正體中文)說實在的他不是一個教學AutoLISP的網站,內容也有點舊,但是這是我能看到比較完整的LISP正體中文教材。
  • AfraLISP() - (English)在Google能查到的AutoLISP/Visual LISP免費教學網站,一開始由Kenny Ramage建構,有經過大改版,有很多入門文章。
  • OffshoreCad AutoLISP (SpeedDraft) - (日本語)某公司放出來的教學。也有放出原始碼供參考,算是源碼參考的好站點吧。

LISP的基礎

第一個重點,LISP是一種前制運算元的語言。換句話說,你必須改掉在其他編程語言的習慣。

舉例來說,在一般的加法上,我們也許會寫
a+b
但是在LISP裡面,你必須寫成像這樣
(+ a b)

同理可證,
A*B
必須寫成
(* A B)

ok,這是基本的二元運算,現在我們來看看函數function。
一般的編程語言中,我們會寫
f(x)
而在LISP之中,他會看起來像是
(f x)
直接將引數放在函數名後面,很容易理解吧

當有兩個以上的引數時要怎麼寫呢?在一般的語言中,他會長得像
f(x,y)
而在LISP中,他會看起來像是
(f x y)
非常直覺,很好

最後一個重點,LISP之中指令(或說函數名)是大小寫不分的。

2015-03-05

Use SQLite in Java(Netbeans)

It's my study note.
I made it by reference to Jens-André Koch's webpage, and updated it into a netbeans 8.0 with SQLite 3.8 version.

Step 1. Download the SQLite JDBC Library

To use SQLite in Netbeans, we must download the library at first.
We can get the library here:
https://bitbucket.org/xerial/sqlite-jdbc

Step 2. Add the JDBC Driver into your project

Add the downloaded JAR into our project.
It can be copied into the project's lib dir, too.

At this moment, it was sqlite-jdbc-3.8.7.jar

Step 3. use it in your code


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.sqlite.JDBC;

public class JavaSQLiteTest {

    public static void main(String[] args) throws ClassNotFoundException {
        // load the sqlite-JDBC driver using the current class loader
        //Class.forName("org.sqlite.JDBC"); // you can use this if you don't use the import.
        
        Connection connection = null;
        try{
            connection = DriverManager.getConnection("jdbc:sqlite:sample.db");
            Statement stm = connection.createStatement();
            
            stm.setQueryTimeout(30); // set timeout to 30 sec.
            stm.executeUpdate("drop table if exists person");
            stm.executeUpdate("create table person (id integer, name string)");
            stm.executeUpdate("insert into person values(1,'leo')");
            stm.executeUpdate("insert into person values(2,'yui')");
            
            ResultSet rs = stm.executeQuery("select * from person");
            while(rs.next()){
                // read the result set
                System.out.println("name = " + rs.getString("name"));
                System.out.println("id = " +rs.getInt("id"));
            }
        }catch(SQLException e){
            // if the error message is "out of memory",
            // it probably means no database file is found
            System.err.println(e.getMessage());
        }finally{
            try{
                if(connection != null)
                    connection.close();
                
            }catch(SQLException e){
                // connection close failed.
                System.err.println(e);
            }
        }
    }
}


Step 4. to manage your database in netbeans

1. Add the JDBC driver in Service->Databases->Drivers
there should be "org.sqlite.JDBC" showed in "Driver Class", and the Name field is "SQLite".
2. Add a JDBC link by SQLite JDBC Driver
right-click on the SQLite Driver, and select "Connecting Using...". Then give the JDBC URL as you like.
To connect with the file named "sample.db", the JDBC URL should be jdbc:sqlite:sample.db 3. Done.

2015-02-20

用十年自學編程

用十年自學編程
Teach Yourself Programming in Ten Years

Peter Norvig

為什麼大家要這麼急?
Why is everyone in such a rush?

走進任何書店,你可以找到像是24小時自學Java以及無數的類似書籍,在數天或是數小時內教你有關C, SQL, Ruby, 演算法, 等等類似的內容。你可以在亞馬遜書店的進階搜尋中搜尋關鍵字title: teach, yourself, hours, since: 2000並且找到512本相關的書籍。其中最前面的10到九本都是編程的書(其他是有關簿記的)。將關鍵字"自學Teach yourself"換成"學習learn"或是將"小時hour"換成"天day",你將會得到類似的結果。

結論是,要不是人們非常急於學習編程,不然就是編程本身比起其他任何東西來說都是超級無敵簡單。 Felleisen 等在他們的著書How to Design Programs中對這種趨勢下了個簡單的注解,他們說「要寫爛程式很簡單,白痴們可以在21天內學會,即是他們是傻瓜」。Abtruse Goose漫畫也對這個下了他們的注解

讓我們對來分析一下像是24小時自學C++(Teach Yourself C++ in 24 Hours之類的書籍標題可能具有的涵義:
  • 自學Teach Yourself: 在24小時之內你將不會有時間寫任何顯而易懂的程式,並且從中學到你的成功與失敗。 你將沒有機會與經驗老道的程式員一起工作並了解用C++開發環境來討生活是什麼樣的狀況。 總之,你沒有太多學習的時間。所以這本書紙會談到一些超級膚淺的內容,而不會有深度的理解。 就像Alexander Pope所說的,只學表面是件非常危險的事。
  • C++: 在24小時內,你也許可以學到C++的一些文法(如果你已經知道其他語言),但是關於如何使用這個語言,你無法學到更多。 總之,或說,如果你是個Basic的程式員,你可以學到如何用C++的文法編寫Basic風格的程式,但是你不會學到有關C++實際上是哪裡好(以及不好)。 所以重點是什麼呢?Alan Perlis說過:「一個不會影響你對編程的想法的語言,不值得去瞭解。」 一個可能的重點是,你必須學C++(或者其他常見的,像是JavaScript或是處理程序Processing)的一點皮毛,因為你需要藉由一個既存工具的介面來完成特定的工作。但是你不是在學習如何編程,你是在學習如何完成任務。
  • 24小時in 24 Hours: 不幸的是,那並不夠,就如同下一小節中所描述的一樣。

十年自學編程
Teach Yourself Programming in Ten Years

研究人員(Bloom (1985), Bryan & Harter (1899), Hayes (1989), Simmon & Chase (1973)) 指出,在任何不同的領域,包括西洋棋,編曲,電報操作,繪畫,鋼琴,游泳,網球,以及神經心理學與拓撲學等等,發展專長大約需要10年的時間。 關鍵在於審議式的(deliberative)練習:不是只有反覆的實作,而是要藉由超過你現有能力的任務來作自我挑戰,嘗試去實作,並在實作後分析你自己的能力,並且修正所有的錯誤。然後不斷的重複。似乎沒有真正的捷徑:即使是4歲時被稱作音樂神童的莫札特,在他開始作出世界頂尖的音樂之前也花了超過13年的歲月。在其他世代中,披頭四似乎在1964年Ed Sullivan的表演中突然嶄露頭角。但是他們早從1957年開始就在Livepool與Hamburg的小型俱樂部中表演,而他們真正大量出現並發行第一張超級成功的專輯Sgt. Peppers是在1967年。 Malcolm Gladwell的說法是,比起10年,他用10,000小時來堆砌他的成功。

也許10,000個小時才是魔法數字,而不是10年。或者它只是另一個不同的基準; Henri Cartier-Bresson (1908-2004) 說:「你的前10,000張相片會是你最爛的相片。」 真正的專長也許需要花上一生: Samuel Johnson (1709-1784)說:「任何部門的精英只能藉由終身勞動來達成;那無法用低廉的價錢購買。」 且Chaucer (1340-1400)抱怨說「人生太短,學習之路卻太長」。 Hippocrates (c. 400BC)有名的筆記裡寫到:「ars longa, vita brevis」, 而那是長篇短文「Ars longa, vita brevis, occasio praeceps, experimentum periculosum, iudicium difficile」的一部分,譯為「人生太短,工藝之路太長,機會稍縱即逝,體驗苦澀,判斷困難。」 當然,最終的答案不會是只是個單純的數字:似乎沒有合理的假設,編程,下西洋棋,完跳棋,演奏音樂,他們都需要相當長的時間去成為大師,而且不是每個人所需要的時間都會一樣。

那你想要成為一個程式員
So You Want to be a Programmer

要在編程中成功,以下是我的菜單:
  • 對編程感興趣,且真正因為有趣而去做。確保它有足夠的樂趣,那麼你會願意在那上面花上你的10年/10,000小時。
  • 程式Program. 最佳的學習方法是從作中學(learning by doing)。更技術性的說法,「個體在某個給定的特定領域中的最高效能不會像經驗成長的一部分自動獲得,但是在經驗豐富的個體上效能水平可藉由刻意努力的結果而獲得均衡的提升。」(p. 366)還有「最有效率的學習,需要為個體提供良好定義的任務,伴隨著適合的難度等級,訊息回饋,以及複習與錯誤改正的機會。」(p20-21) Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life這本書提供了有關這個觀點的有趣的資料。
  • 與其他程式員交流; 閱讀別人的程式碼。這比起任何書或是訓練課程來的重要。
  • 如果你願意的話,進大學(或是更上一層的研究所)去學習。這將給你參與某些需要學歷的工作的機會,並對這個領域有更深層的理解。但是如果你不喜歡學校,(透過某些方法)你可以靠自己或是在工作中獲得類似的經驗。無論如何,光靠書本的知識是不夠的。 「計算機科學教育不會讓任何人成為頂尖程式員,就像學習筆刷跟顏料不會讓任何人成為頂尖的畫家一樣。」The New Hacker's Dictionary的作者Eric Raymond說到。 我曾經雇用的最好的程式員之一,他只有高中學歷;他創造了很多偉大軟體,擁有他自己的新聞群組,並且賺取了夠多的股票去買他自己的夜店
  • 與其他程式員一同作專案。在一些專案裡當最佳程式員;並在其他某些專案中當最爛的。當你是最佳程式員的時候,你必須測試你領導專案的能力,並且用你的眼光激勵其他人。 當你是最爛的程式員的時候,你學習主人的做法,並學習他們不喜歡作的部分(因為他們會讓你幫他們做那部份)。
  • 跟隨其他程式員作專案。 理解其他人所寫的程式。看看當原始作者不在的時候如何理解並修復它。想想要如何設計你的程式讓其他人在你之後易於維護。
  • 學習至少六種程式語言。 那其中包括一種強調類抽象class abstractions的語言(像是Java或C++), 一種強調函數抽象functional abstraction的語言(像是Lisp, ML, Haskell), 一種支援語法抽象syntactic abstraction的語言(像是Lisp), 一種支援聲明規格declarative specifiaction的語言(像是Prolog或C++模板), 以及一種強調並行處理parallelism的語言(像是Clojure或是Go)。
  • 請記得在「計算機科學」之中有「計算機」這個字眼。 理解你的電腦處理指令的時間,從記憶體獲取資料的時間(伴隨以及不伴隨快取失誤),從磁碟連續讀取資料的時間,以及在磁碟上搜尋新位址所需的時間。(答案在此)
  • 涉足一項語言標準化作業。它可以是ANSI C++委員會,也可以是決定在你的團隊中的編碼風格將有2個或是4個空白來進行縮排。不管是哪一種,你學到其他人在語言中喜歡的做法,還有他們的感受有多深,甚至有可能稍微瞭解為什麼他們覺得那樣之類的。
  • 要明確果斷,盡快脫離語言標準化作業

瞭解了上述的觀點,只藉由書本學習你能夠走多遠是十分可疑的。在我第一個孩子出生前,我讀過很多要如何做 How To的書,但是還是感覺自己是個手足無措的新手。30個月後當我第二個孩子出生時,我有重新把那些書拿來讀嗎?不。相反的,我遵照我個人的經驗,那更加有用,且比起專家寫的上千頁的書更讓我放心。
Fred Brooks在他的著作No Silver Bullet中提到了一個尋找優秀軟體設計師的三部曲計畫:
  1. 有系統的尋找頂尖設計師,越早越好。
  2. 指定一個職業導師負責前景發展,並仔細地規劃職業生涯。
  3. 為設計師提供成長的機會,讓他們彼此互動與刺激。
前提是有些人已經有成為優秀設計師的素質;而工作只是引導他們正確的前進。 Alan Perlis用說得更簡潔:「任何人都可以被教導如何去雕刻:米開朗基羅也被教導過什麼是不該做的。優秀的程式員也沒有不同。」 Perlis說,優秀的人們擁有內在的素質,那超越了他們的訓練。但是那素質是從哪來的?那是與生俱來的嗎?或是他們藉由努力而開發的呢?Auguste Gusteau(Ratatouille中虛構的大廚)下了這樣的注解:「任何人都可以下廚,但只有無畏者才會偉大。」 我覺得那有一大部分是源自一個人是否願意奉獻其生命中極大部分去做審議實踐。但是無畏也許是個總結的方法。 又或者,就像Gusteau的評論家Anton Ego說的:「不是任何人都可以成為優秀的藝術家,但是優秀的藝術家可以從任何地方而來。」

所以,儘管去買那些Java/Ruby/JavaScript/PHP的書;你將也許從中知道一些用法。但是你將不會改變你的生活,或是你的作為程式員的整體專業知識在24小時或是21天內。但是如果你持續努力改善超過24個月後呢?好吧,該是你從某處開始努力的時候了...

資源 References

Bloom, Benjamin (ed.) Developing Talent in Young People, Ballantine, 1985.
Brooks, Fred, No Silver Bullets, IEEE Computer, vol. 20, no. 4, 1987, p. 10-19.
Bryan, W.L. & Harter, N. "Studies on the telegraphic language: The acquisition of a hierarchy of habits. Psychology Review, 1899, 8, 345-375
Hayes, John R., Complete Problem Solver Lawrence Erlbaum, 1989.
Chase, William G. & Simon, Herbert A. "Perception in Chess" Cognitive Psychology, 1973, 4, 55-81.
Lave, Jean, Cognition in Practice: Mind, Mathematics, and Culture in Everyday Life, Cambridge University Press, 1988.

答案Answers



典型個人電腦上各種操作的大約時間:
典型指令之執行
execute typical instruction
1/1,000,000,000 sec = 1 nanosec
從L1快取獲取資料
fetch from L1 cache memory
0.5 nanosec
分歧預測失誤
branch misprediction
5 nanosec
從L2快取獲取資料
fetch from L2 cache memory
7 nanosec
互斥鎖定/解鎖
Mutex lock/unlock
25 nanosec
從主記憶體獲取資料
fetch from main memory
100 nanosec
從1Gbps頻寬的網路傳送2K bytes資料
send 2K bytes over 1Gbps network
20,000 nanosec
從記憶體循序讀取1MB資料
read 1MB sequentially from memory
250,000 nanosec
取得新磁碟位址(搜尋)
fetch from new disk location (seek)
8,000,000 nanosec
從磁碟循序讀取1MB資料
read 1MB sequentially from disk
20,000,000 nanosec
將封包從美國送到歐洲再傳回
send packet US to Europe and back
150 milliseconds = 150,000,000 nanosec


附錄:言語選擇
Appendix: Language Choice

有些人會問,他們應該從哪個程式語言開始學習。這並沒有固定答案,但是可以考慮以下幾個標準:

  • 利用你的朋友Use your friends。 當被問到「我該用哪個作業系統呢? Windows, Unix, 還是Mac?」,我的回答通常是「用你朋友用的那個」。 向你朋友學習的好處將會在不同OS或是不同程式語言間的固有問題上被抵銷掉。 同時,考慮那些你未來會結交的朋友:程式員社群,如果你持續下去的話,你將會是他們的一部分。 你所選擇的語言是否擁有一個大型成長中的社群,還是他擁有的是一個小型且逐漸萎縮的社群?是否有書籍,網站,以及線上討論區可以得到答案? 你是否喜歡那些討論區中的人們?
  • 維持簡單Keep it simple。 像C++與Java之類的程式語言,設計給那些經驗老道的程式員所組成的大型團隊作專業開發,那些人關心他們的程式碼的執行時期效率。 結論上來說,這些語言會擁有一些為了達成這些目標而設計的複雜部分。你應該關心在學習程式上。你不需要那些複雜的部分。你需要一個語言設計便於單一新手程式員學習與記憶。
  • 玩 Play. 一樣是學彈鋼琴,你會比較喜歡哪種方法?一般,互動的方法,那這種方法之中你可以聽到每個音符,就當你壓下琴鍵之後馬上;或是"批量"模式,在那種方法中你只能在完成整首歌之後才能聽到音符。很明顯的,互動模式會讓鋼琴易於學習,而寫程式也是一樣。堅持使用一個擁有互動模式的語言。

鑑於這些標準,我建議第一個程式語言可以用Python或是Scheme。 其他的選擇是JavaScript,不是因為它是完全為初心者精心設計,而是因為它有大量的線上教學,像是可汗學院的教學 Khan Academy's tutorial。 但是你的情況可能會有所不同,而且還有其他不錯的選擇。 如果你的年紀還只有一位數,你可能會比較喜歡愛麗絲Alice 或是Squeak 或是Blockly(有點年紀的學習者也可能會喜歡他們)。重點是你已經選好了一個,並著手開始。


附錄:書籍與其他資源
Appendix: Books and Other Resources

有些人要求我建議一些學習用的書與網頁。我會重複我的論調「只看書是不夠的」,但是我可以建議以下的資源:




筆記 Notes

  1. T. Capey指出亞馬遜書店上的完全問題解決者 Complete Problem Solver一頁現在有"21天自學孟加拉Teach Yourself Bengali in 21 days"與"自學文法與風格Teach Yourself Grammar and Style"在「購買此商品的人同時也買了這些商品」的欄位中。我猜有一大部分的人是從這個網頁找到那本書的。
  2. 感謝Ross Cohen幫忙有關Hippocrates的部分。



原始內容是由Peter Norvig前輩的網站上轉譯而來
原始網址於此:(blog)http://www.yamdas.org/column/technique/21-daysj.html

原本的網站上有各國翻譯的連結。但很不巧的,中文的連結失效了。
於是我參照了日文翻譯與原文重製了我自己的翻譯版本。
希望對有需要或是想參考的各位有所幫助。
Updated: 2015/02/20

2013-10-28

[C#]Centering a Message Box on the Active Window

There are 2 way to centering the default MessageBox
or said, 1 only way, and 2 kind of Invoking.

1. Make a new WindowForm who has centerParent Location, then copy it's location to the MessageBox by "Hook" the system dialog's location.
2. Just Hook the system dialog's location and set it before call MessageBox.Show()

Way 1: CenterWinDialog by Hans Passant

There's the code(class CenterWinDialog):
using System;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class CenterWinDialog : IDisposable {
    private int mTries = 0;
    private Form mOwner;

    public CenterWinDialog(Form owner) {
        mOwner = owner;
        owner.BeginInvoke(new MethodInvoker(findDialog));
    }

    private void findDialog() {
        // Enumerate windows to find the message box
        if (mTries < 0) return;
        EnumThreadWndProc callback = new EnumThreadWndProc(checkWindow);
        if (EnumThreadWindows(GetCurrentThreadId(), callback, IntPtr.Zero)) {
            if (++mTries < 10) mOwner.BeginInvoke(new MethodInvoker(findDialog));
        }
    }
    private bool checkWindow(IntPtr hWnd, IntPtr lp) {
        // Checks if <hwnd> is a dialog
        StringBuilder sb = new StringBuilder(260);
        GetClassName(hWnd, sb, sb.Capacity);
        if (sb.ToString() != "#32770") return true;
        // Got it
        Rectangle frmRect = new Rectangle(mOwner.Location, mOwner.Size);
        RECT dlgRect;
        GetWindowRect(hWnd, out dlgRect);
        MoveWindow(hWnd,
            frmRect.Left + (frmRect.Width - dlgRect.Right + dlgRect.Left) / 2,
            frmRect.Top + (frmRect.Height - dlgRect.Bottom + dlgRect.Top) / 2,
            dlgRect.Right - dlgRect.Left,
            dlgRect.Bottom - dlgRect.Top, true);
        return false;
    }
    public void Dispose() {
        mTries = -1;
    }

    // P/Invoke declarations
    private delegate bool EnumThreadWndProc(IntPtr hWnd, IntPtr lp);
    [DllImport("user32.dll")]
    private static extern bool EnumThreadWindows(int tid, EnumThreadWndProc callback, IntPtr lp);
    [DllImport("kernel32.dll")]
    private static extern int GetCurrentThreadId();
    [DllImport("user32.dll")]
    private static extern int GetClassName(IntPtr hWnd, StringBuilder buffer, int buflen);
    [DllImport("user32.dll")]
    private static extern bool GetWindowRect(IntPtr hWnd, out RECT rc);
    [DllImport("user32.dll")]
    private static extern bool MoveWindow(IntPtr hWnd, int x, int y, int w, int h, bool repaint);
    private struct RECT { public int Left; public int Top; public int Right; public int Bottom; }
}

Usage:
    private void button1_Click(object sender, EventArgs e) {
        using (new CenterWinDialog(this)) {
            MessageBox.Show("Nobugz waz here");
        }
    }


Way 2: MessageBoxHelper by Jason Carr

There's the code(class MessageBoxHelper):
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

internal static class MessageBoxHelper
{
    internal static void PrepToCenterMessageBoxOnForm(Form form)
    {
        MessageBoxCenterHelper helper = new MessageBoxCenterHelper();
        helper.Prep(form);
    }

    private class MessageBoxCenterHelper
    {
        private int messageHook;
        private IntPtr parentFormHandle;

        public void Prep(Form form)
        {
            NativeMethods.CenterMessageCallBackDelegate callBackDelegate = new NativeMethods.CenterMessageCallBackDelegate(CenterMessageCallBack);
            GCHandle.Alloc(callBackDelegate);

            parentFormHandle = form.Handle;
            messageHook = NativeMethods.SetWindowsHookEx(5, callBackDelegate, new IntPtr(NativeMethods.GetWindowLong(parentFormHandle, -6)), NativeMethods.GetCurrentThreadId()).ToInt32();
        }

        private int CenterMessageCallBack(int message, int wParam, int lParam)
        {
            NativeMethods.RECT formRect;
            NativeMethods.RECT messageBoxRect;
            int xPos;
            int yPos;

            if (message == 5)
            {
                NativeMethods.GetWindowRect(parentFormHandle, out formRect);
                NativeMethods.GetWindowRect(new IntPtr(wParam), out messageBoxRect);

                xPos = (int)((formRect.Left + (formRect.Right - formRect.Left) / 2) - ((messageBoxRect.Right - messageBoxRect.Left) / 2));
                yPos = (int)((formRect.Top + (formRect.Bottom - formRect.Top) / 2) - ((messageBoxRect.Bottom - messageBoxRect.Top) / 2));

                NativeMethods.SetWindowPos(wParam, 0, xPos, yPos, 0, 0, 0x1 | 0x4 | 0x10);
                NativeMethods.UnhookWindowsHookEx(messageHook);
            }

            return 0;
        }
    }

    private static class NativeMethods
    {
        internal struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        internal delegate int CenterMessageCallBackDelegate(int message, int wParam, int lParam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool UnhookWindowsHookEx(int hhk);

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("kernel32.dll")]
        internal static extern int GetCurrentThreadId();

        [DllImport("user32.dll", SetLastError = true)]
        internal static extern IntPtr SetWindowsHookEx(int hook, CenterMessageCallBackDelegate callback, IntPtr hMod, int dwThreadId);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool SetWindowPos(int hWnd, int hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        internal static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    }
}


Usage:
    private void button1_Click(object sender, EventArgs e)
    {
        MessageBoxHelper.PrepToCenterMessageBoxOnForm(this);
        MessageBox.Show("Hello!", "Hello!", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1, 0);
    }

2013-10-25

[C#]Force DataGridView Save Current Row's Data to Backyard.

Usually we edit the table data with DataGridView.

I do it, too. and I get problem when I try to get the changed DataTable.

It happened if you try to save data just after editing it.


There is the situation:

I have a 3x3 DataTable dt, and I link it to a DataGridView dgv
dgv.DataSource = dt;

then I edited the content with row 3 column 3.
I can move cursor to column 1 or column 2, but before i move cursor to the other row, the changing of row 3 will not be set to DataTable.

It's not good. I want it be saved after click SAVE or Ctrl-S.

So, there is a solution: DataGridView.EndEdit().
but, the row's data didn't change with only DataGridView.EndEdit().
The CurrentRow must lose focus to save the data.
Hmm... Here is a member called CurrentCell
and Someone set CurrentCell to null, then the data is stored.

I tried it, and it works good!
so, if you want to save the current row's data.
run the below 2 statement:

dgv.EndEdit();
dgv.CurrentCell = null;

then the current row's change will be saved in to DataTable, too.


[C#]Get DataTable from Database, Update DataTable to Database

just take a note.

When we want to update database with a list, as you know, there will be 3 kinds of operation: insert(for new rows), update(for changed rows), delete(for deleted rows)

for a single record, it will be easy. But for a list of data, it will be a nightmare.

use the .NET DataAdapter, we can make it easier.
for base, we have sqlConnectString for default connection, and we try to access all columns of demoTable. There is a global DataTable named dt.

to make the example for common case, I will type it for SQL server.

1. to get DataTable from Database
string sql = @"SELECT * FROM demoTable;";
using(var conn = new SQLConnection(sqlConnectString))
{
    conn.Open();
    using(var cmd = new SQLCommand(conn))
    {
        cmd.CommandText = sql;
        var reader = cmd.ExecuteReader();
        dt.Load(reader);
    }
}
2. to update DataTable's data to Database
string sql = @"SELECT * FROM demoTable;";
using(var conn = new SQLConnection(sqlConnectString))
{
    conn.Open();
    var adp = new SQLDataAdapter(sql, conn);
    var cmb = new SQLCommandBuilder(adp);
    adp.Update(dt);
}

to speed up the database access, can add transaction commands. Begin the transaction before update, and commit the transaction after update.

2013-05-20

T-SQL中的日期函數

T-SQL,一個只能用在MS SQL中的語言...

在T-SQL中,提取目前日期時刻時可以使用getdate()函式。

getdate() 所提取的內容與current_timestamp將會相同

SELECT current_timestamp "Standard Timestamp", getdate() 'Transact-SOL datetime'


另外,使用datepart()可以提取getdate()所提供的變數中的特定欄位的內容
比如說datepart(year, getdate())可以提取年份的資料


SQL中的特殊字元(Pattern Matching in SQL)

在SQL中使用LIKE或是NOT LIKE關鍵字代替運算子(諸如=, >, <, ...)時,你可以使用SQL的Pattern Matching功能。

Pattern Matching是什麼東西哩?Pattern Matching是出自正規表現的關鍵字。有些中文網站翻譯作「樣式比對」。搜尋與特定Pattern相符合的字串,或是判斷字串是否符合Pattern的要求。

在SQL中,Pattern Matching是case-sensitive的,意思是,A與a是完全不一樣的單字。

以下是幾個在SQL的Pattern Matching裡具有特殊意義的字元


  • % (百分比符號,percent mark): 相同於windows裡的*萬用字元。0個以上的任何字元。例如:搜索"d%base",  你可以搜尋到dbase, database, 或是dkbase
  • _ (下線, underscore): 相同於windows裡的?萬用字元。任意的1個字元。搜索"A___e",你可以搜尋到Apple, Amaze, 或是任何一個A開頭e結尾的長度5的字彙
  • [] (角括號,square brackets): 包含在特定範圍內的一個特定字元。[a-f]表示a,b,c,d,e,f其中的一個字元。[abcdef]也等同於[a-f]。
  • [^] (內含脫字符號的角括號, square brackets with caret): 表示除了特定範圍內的字元以外的其他字元。"[^a-z]%"表示任何不用小寫字母開始的單字。"de[^l]%"就表示任何以de但是不是del開始的單字。(所以delete就不會出現,但是會出現demark)
在角括號裡,","(逗號)通常不帶有任何意義,只為區分字元。[^S,B,R] = [^SBR]

2013-05-14

Clone records in SQL

使用SQL文重複複製表格內容

以下手法可用於MySQL
並可以使用於任何有自動增加值(AutoIncrease)的表格

CREATE TEMPORARY TABLE temp_table ENGINE=MEMORY SELECT * FROM your_table WHERE id=1;

UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;
DROP TABLE temp_table;


在Access裡,你可以用SELECT INTO標準句來替換
SELECT * INTO temp_table FROM your_table WHERE id=1 ;

UPDATE temp_table SET id=NULL; /* Update other values at will. */

INSERT INTO your_table SELECT * FROM temp_table;

DROP TABLE temp_table;

以上

#DELETED in Access

In Access, if you have a record in form/subform is deleted after you read the data into form, the values will be showen "#DELETED".

to fix it, just force the form to requery.

with VBA, it will be like below:
Me.[SomeControlNameIfThereIsSubForm.Form].Requery


アクセス上のことです。
操作している間に、データがフォームに読み込まれた後に、実際のデータが消された場合、フォーム上で、#DELETEDという文字が出てきます。

解決方法も簡単です。フォームを再クエリしたらいいです。荒々しいが仕方ありません。

2012-11-26

如何iReport中簡單的設定List成為Datasource

大多數人使用iReport生成都會使用SQL來抓取資料庫檔案,但是iReport畢竟只是個設計表單用的程式,資料還是要靠Java餵給他。

一般的使用法,就像我以前做的
1. 在iReport中寫死SQL查詢句(SELECT xxx FROM yyy WHERE zzz),然後靠JDBC自動抓取db的內容來設定field,然後把那些Field丟進表單中

2. WHERE句所需要的最底限的資料靠HashMap丟進jasper中,讓jasper在跑的時候自動抓取資料庫內容

HashMap parameters = new HashMap();
parameters.put("FIELD1", something);
JasperFillManager.fillReportToFile(JASPER檔案路徑, parameters, 某某資料庫的Connection);

但是上面的程序對DB不是很友善。
一般來說,我們再輸出之前都會想確定一下內容寫了什麼,所以會把資料先從資料庫叫出來一次。加上關聯式資料庫方式,一般來說都會JOIN一大堆內容。可是老實說,JOIN對資料庫非常的花時間(至少在MYSQL上是這樣的)

既然已經把db的內容叫出來了,那何必再叫一次呢?


程式流程會變成下面這樣
1. Java向DB查詢資料
2. DB將資料傳給Java程式
3. Java程式將所需要的資料填進jasper生成jrprint文件

一般來說,jrprint出來之後要轉成pdf或是其他的資料型式就不成問題了


但是你會說:用Parameter也可以把資料傳進去阿
是阿,沒錯,但是那樣的話parameter會變成一長串,程式沒有美感也沒有程度可言
而且如果你是從SQL轉過來的,光是改原來的report裡面的欄位就改到手酸
$F{FIELDS}要改成$P{FIELDS}

那我們怎麼弄呢?很簡單,把Connection改成Datasource,然後把原來Java裡面的內容靠Datasource丟進去。

詳細就照著作比較快。我們用個班級的個人成績表作範例。個人成績表需要有個人姓名,學號,以及個人的各科成績。其中姓名與學號是每張單都不同的,而成績是靠學號來分辨,另外記在其他資料庫裡的。
1. 建立Datasource用的Javabean。在這個例子裡,我叫他Student
public class Student {
    private String name;
    private String serialNo;
    private List scores;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSerialNo() {
        return serialNo;
    }

    public void setSerialNo(String serialNo) {
        this.serialNo = serialNo;
    }

    public List getScores() {
        return scores;
    }

    public void setScores(List scores) {
        this.scores = scores;
    }

}



我們還需要另外一個JavaBean來紀錄各科成績,姑且叫他Score
public class Score {
    private Integer point;
    private String name;

    public Integer getPoint() {
        return point;
    }

    public void setPoint(Integer point) {
        this.point = point;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
}


讓我們做個假資料來放上面的東西
public class ContentFactory {
    static public List create(){
        List fakelist = new ArrayList<>();
        
        Student fakeStudent1 = new Student();
        fakeStudent1.setName("孫甲");
        fakeStudent1.setSerialNo("A001");
        
        List fakeScoreList1 = new ArrayList<>();
        Score fakeScore1 = new Score();
        fakeScore1.setName("國語");
        fakeScore1.setPoint(76);
        Score fakeScore2 = new Score();
        fakeScore2.setName("數學");
        fakeScore2.setPoint(100);
        
        fakeStudent1.setScores(fakeScoreList1);
        
        fakelist.add(fakeStudent1);
        
        return fakelist;
    }
}



重頭戲來了,把資料填給jasper吧
JasperFillManager.fillReportToFile("reports/epsSinglePageOutput.jasper", parameters, new JRBeanCollectionDataSource(ContentFactory.create()));



放給Jasper的資料,自然不是那麼容易拿到。接下來就告訴你怎麼設定Jasper去接這些資料。

新建一個JasperReport,資料源留白(Empty datasource)。因為資料源已經從Java程式設定好了。

你會說:Fields裡面都沒有東西,那我要從哪裡叫資料阿?
沒錯,接下來,我們就是要設定Fields。手動設定所有你需要的Field,他們的class也必須符合Java裡面的形式
在我的範例裡面,你需要三個Field:name(java.lang.String),serialNo(java.lang.String),
scores(java.util.List)。他們分別對應了Student的三個變數name, serialNo, scores。



接下來,我們要設定一個副查詢(Sub-Dataset),而這個副查詢是原本主查詢中的資料List。
我們一如往常的在頁面上添加一個表格(Table)。iReport跳出來跟你說:喔,你家沒有副查詢喔,要不要自己加一個阿。


我們不理他,繼續加個空白表格(Just create an empty table)並選擇我們需要的欄位數。在這個例子中,我們需要兩欄。完成後,你會看到表格自動被展開並準備好排版。但是我們暫時還不想理他。

在看一次Inspector,你會看到剛剛自動生成的Dataset(Table Dataset 1), 名字非常難看,但是我們可以不理他(當然,你可以自己把他改成更好看一點)。
檢查Table Dataset裡面的Fields,當然,他還是沒有任何內容。
手動增加我們需要的兩個Field以對應Score的兩個Field:
name(java.lang.String), point(java.lang.Integer)

接下來的一個非常重要:右擊table叫出功能表,點擊Edit table Datasource

一般來說,Datasource會被設定到剛剛的Table Dataset 1上,就像下圖一樣

要注意:Connection / Datasource Expression是Use datasource expression。

接下來,另一個重頭戲來了。編輯datasource的方程式,讓他變成自動擷取主查詢裡面的變數List


new net.sf.jasperreports.engine.JREmptyDataSource(1)
改成
new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{scores})

大功告成。接下來你就可以自由的編輯你的排版,看看剛剛設定的值有沒有問題囉
剛剛設定的各Field也會自動的排進你的jasper囉

2012-11-20

get the last insert id in MySQL

In fact, there is the default function names LAST_INSERT_ID().
So, Just use it!
SELECT LAST_INSERT_ID()

人気の投稿