C#、VB如何顯示斷行

文字框在輸入時,如果有按下「Enter」,會讓文字有斷行的情形。
此時如果取出文字框資料(或從資料庫中)放到「Lable」或「HTML」時,斷行就不見了。
其實並不是斷行不見了,只是斷行的特殊符號無法被識別。
所以我們可以用Replace來替換這些特殊符號為可以識別的語法。
VB的斷行符號是vbCrLf
C#的斷行符號是 \r\n

例如C#:
text.Replace("\r\n","<br />") ;

國小一到六年級數學免費題庫--子由數學小學堂

今天在瀏覽網頁時,找到了由國立中央大學數學系設計的一個國小一到六年級的數學題庫,
可以依年級及類別自訂出數學題庫的PDF檔,只要用印表機就可以印出數學題庫來讓小朋友練習,
也可以線上直接測驗,而且每次的題庫都會隨機選擇,所以每次的題庫不會都是一樣的。
網址:http://www.emathschool.math.ncu.edu.tw/~ziyou/math123/page.php



下面試著以「年級分類」的出題模式產生PDF題庫,更詳細的說明可以參考網頁內的「子由數學小學堂使用手冊」









Android 利用HTTP Post模式來傳送與接收資料的範例

MainActivity.java的內容
=====================================================================
package com.example.http_test;

import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;


import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.*;  //加入widget類別

  


public class MainActivity extends ActionBarActivity {
    
    Thread HttpThread;
    EditText ed1;
EditText ed2;
EditText ed3;
TextView tv1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
   tv1 = (TextView)findViewById(R.id.textView4);
ed1 = (EditText)findViewById(R.id.editText1);
ed2 = (EditText)findViewById(R.id.editText2);
ed3 = (EditText)findViewById(R.id.editText3);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
//必須利用Handler來改變主執行緒的UI值
private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
//msg.getData會傳回Bundle,Bundle類別可以由getString(<KEY_NAME>)取出指定KEY_NAME的值
            tv1.setText(msg.getData().getString("response"));
        }
    };
    
    //按鈕的Click事件
    public void btn_onClick(View v) {
   //產生新的HttpThread物件
    HttpThread myThread = new HttpThread();
//設定變數值
    myThread.MyName=ed1.getText().toString();
    myThread.MyMessage=ed2.getText().toString();
    myThread.Url=ed3.getText().toString();
//開始執行緒
        myThread.start();
    }
       
    
    
    //宣告一個新的類別並擴充Thread
class HttpThread extends Thread { 
//宣告變數並指定預設值
public String MyName = "NoData" ;
public String MyMessage = "Nodata" ;
public String Url = "http://192.168.1.49/test/test.php";
        @Override
        public void run() {
            // TODO Auto-generated method stub
            super.run();
            
//宣告一個新的Bundle物件,Bundle可以在多個執行緒之間傳遞訊息
            Bundle myBundle = new Bundle();
            
try {    
HttpClient client = new DefaultHttpClient();
       URI website = new URI(this.Url);
//指定POST模式
       HttpPost request = new HttpPost();
//POST傳值必須將key、值加入List<NameValuePair>
             List<NameValuePair> parmas = new ArrayList<NameValuePair>();
//逐一增加POST所需的Key、值
         parmas.add(new BasicNameValuePair("MyName",this.MyName));
         parmas.add(new BasicNameValuePair("MyMessage",this.MyMessage));
//宣告UrlEncodedFormEntity來編碼POST,指定使用UTF-8
         UrlEncodedFormEntity env = new UrlEncodedFormEntity(parmas,HTTP.UTF_8);
         request.setURI(website);
//設定POST的List
         request.setEntity(env);
         HttpResponse response = client.execute(request);
         HttpEntity resEntity = response.getEntity();
         if(resEntity != null){
          myBundle.putString("response",EntityUtils.toString(resEntity));                
       }else{
              myBundle.putString("response","Nothing");     
           }              
       
   Message msg = new Message();
                msg.setData(myBundle);  
                mHandler.sendMessage(msg);
} catch (Exception e) {
                e.printStackTrace();
            }
}
}        
}



activity_main.xml的內容
=======================================================================
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/LinearLayout1"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.http_test.MainActivity" >

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="姓名"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/editText1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="訊息"
        android:textSize="20dp" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10" />

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="網址"
        android:textSize="20dp" />

    <EditText
        android:id="@+id/editText3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:text="http://192.168.1.39/test/test.php"
        android:textSize="15dp" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="btn_onClick"
        android:text="確定" />

    <TextView
        android:id="@+id/textView4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="TextView"
        android:textSize="15dp" />

</LinearLayout>



test.php
=======================================================================
<?php
   //設定網頁的type及編碼,因為Android中使用了utf-8,所以這裡一定要設定,
   //否則回傳的中文資料會變成亂碼
   header("Content-Type:text/html; charset=utf-8");
   $MyName = $_POST["MyName"];
   $MyMessage = $_POST["MyMessage"];    
   echo "我的姓名是:" . $MyName  . "  傳送的訊息是:"  . $MyMessage ;
?>  



Android 4.X 的 Http ,利用Thread 和 Handle來更改textView的值

package com.example.http_test;

import java.net.URI;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.*;  //加入widget類別
import android.view.*;    //加入view類別
 


public class MainActivity extends ActionBarActivity {
   
//宣告一個執行緒
    Thread myThread;

TextView t1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
       
   t1 = (TextView)findViewById(R.id.textView1);

//產生新的執行緒並且啟動執行緒
myThread = new myThread();
        myThread.start();

    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

//因為Android 4.X已無法由其他的執行緒來更改主執行緒的UI設定,
//所以必須以Handler來更改主執行緒的UI設定
private Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

//只能以Handle來更改textView的值
            t1.setText(msg.getData().toString());
        }
    };
     
   
//新的執行緒
class myThread extends Thread {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            super.run();
           
//Bundle可以在多個執行緒中互相傳遞訊息
            Bundle myBundle = new Bundle();
           
try {
HttpClient client = new DefaultHttpClient();
       URI website = new URI("http://192.168.1.10/test.php");
       HttpGet request = new HttpGet();
       request.setURI(website);

//PHP網頁回傳的資料
       HttpResponse response = client.execute(request);
         HttpEntity resEntity = response.getEntity();
         if(resEntity != null){
   //將Response資料的前100個字以字串的類型代入Bundle
           myBundle.putString("aaa",EntityUtils.toString(resEntity).substring(1,100));
       }
           else{
               myBundle.putString("bbb","Nothing");  
           }            
   
                //以Message資料類型(不能單純以String來傳遞)傳遞資料並呼叫Handler(就是上面自訂的mHandler函數來執行更改ui的值)  
   Message msg = new Message();
                msg.setData(myBundle);
                mHandler.sendMessage(msg);

} catch (Exception e) {
                e.printStackTrace();
            }
}
}
}

Excle 群組自動累加值(假設一戶有三個Key)

最近剛好有一個需求,一個社區中每一戶分配到3個key值,但是每一戶的戶號是奇數值,不是連續的值。
因為key值很多,社區總戶數也不少,如果每3個key手動輸入戶號,肯定需要花費一段時間。

因為奇數有一個方法,例如:
1+0=  1
2+1=  3
3+2=  7
答案剛好是:被加數+(被加數-1)

所以用函數設計了一個自動編號的方法來解決這樣的問題,畫面如下:


QUOTIENT函數是取兩數相除的商,例如:10/3=3

所以QUOTIENT(A2-1,3)的結果是每三個編號的值都是一樣,例如:
1  -->  1
2  -->  1
3  -->  1
4 -->   2
5 -->   2
6 -->   2

套上奇數的方法,其公式就變成:QUOTIENT(A2-1,3)+1+(QUOTIENT(A2-1,3))

Corona SDK 換頁的範例

---------------------------------------------------------
--main.lua
---------------------------------------------------------
-- Hide the status bar.
display.setStatusBar(display.HiddenStatusBar)

-- 必須引入 controller module
local composer = require("composer")

-- 載入指定的頁面s1
composer.gotoScene( "s1", "fade", 400 )



---------------------------------------
--s1.lua
---------------------------------------
-- Hide the status bar.
display.setStatusBar(display.HiddenStatusBar)

local composer = require( "composer" )

--這裡也是重點之一,物件名稱要注意,像下列宣告scene,則最後一行的return 必須回傳scene
local scene_s1 = composer.newScene()

local function local function ButtonNext_Handle()
    composer.gotoScene("s2","slideLeft", 800 )        
end

local function ButtonApple_Handle()
     a = display.newImage("apple1.png")
     a.x=50
     a.y=50
--將image的物件a放到sceneGroup,如果沒有這一行,換頁後image還會留在畫面上,不會清除
     sceneGroup:insert(a)
end

function scene_s1:create()
    --這裡必須宣告一個view,我個人覺得比較像是容器,往後所有的物件都要insert到sceneGroup,
--這樣換頁時,執行removeSence才會把所有包在容器的物件一併刪除
--另外self.view只能在Create Event中建立,所以不要加上local,讓它變成全域變數,
--ButtonApple_Handle中產生的物件才能加到sceneGroup容器中
    sceneGroup = self.view

local ButtonNext = widget.newButton
    {
        label = "TEST",
        labelColor = { default={ 0, 0, 0 } },
        fontSize = 20,
        onEvent = ButtonNext_Handle,
        emboss = false,
        --properties for a rounded rectangle button...
        shape="roundedRect",
        width = 100,
        height = 50,
        cornerRadius = 10,
        fillColor = { default={ 0.8, 0.1, 0.4, 1 }, over={ 1, 0.1, 0.7, 0.4 } }
    }

    ButtonNext.x = 150
    ButtonNext.y = 50

    local ButtonApple = widget.newButton
    {
        label = "apple",
        labelColor = { default={ 0, 0, 0 } },
        fontSize = 20,
        onEvent = ButtonApple_Handle,
        emboss = false,
        --properties for a rounded rectangle button...
        shape="roundedRect",
        width = 100,
        height = 50,
        cornerRadius = 10,
        fillColor = { default={ 0.8, 0.1, 0.4, 1 }, over={ 1, 0.1, 0.7, 0.4 } }
    }

    ButtonApple.x = 250
    ButtonApple.y = 50
    
--把物件都加到sceneGroup,如果沒有加入的物件在換頁時不會被清除
    sceneGroup:insert(ButtonApple)
    sceneGroup:insert(ButtonNext)

end


--宣告S1 Create Event
scene_s1:addEventListener( "create", scene_s1)


--最後一行是重點,必須回傳名稱scene_s1(因為上面宣告scene_s1),這樣才能正確識別Screne Name
return scene_s1



---------------------------------------
--s2.lua
---------------------------------------
-- Hide the status bar.
display.setStatusBar(display.HiddenStatusBar)

local composer = require( "composer" )

local scene_s2 = composer.newScene()

function scene_s2:show()
    --移除s1的頁面
    composer.removeScene("s1")
end


--宣告S1 Create Event
scene_s2:addEventListener( "show", scene_s2)

--最後一行是重點,必須回傳名稱scene_s2(因為上面宣告scene_s2),這樣才能正確識別Screne Name
return scene_s2


Corona SDK 無法刪除多筆newImage的物件

程式碼如下:

NumCount = 1

function MeTouch(e)
    if e.phase == "ended" then  
        if NumCount > 5 then  
            NumCount = 1    
        end 

        if PngGroup then 
            PngGroup:removeSelf()
            PngGroup = nil
        end 

        for i = 1,NumCount do
            PngGroup = display.newImage("apple.png")          
            if i > 3 then  
            PngGroup.x = centerX + (50 * i/3) 
                PngGroup.y = 70 + (50 * (i/3)) 
            else
            PngGroup.x = centerX + (50 * i) 
            PngGroup.y = 70;
            end
        end 
        NumCount = NumCount +1
    end
end

Runtime:addEventListener( "touch", MeTouch )


每Touch一次就會刪除原來的圖片,再載入新的圖片,但是一次Touch的事件中可能會載入多張的圖片,
例如變數NumCount=2,片段程式如下:
for i = 1,NumCount do
    PngGroup = display.newImage("apple.png") 
測試的結果載入2張的圖片是沒有問題的,但是在刪除圖片時卻只會刪除最後一張,片段程式如下:
PngGroup:removeSelf()
PngGroup = nil
換句話說,雖然圖片的物件名稱都是PngGroup,但是實際上還是不一樣的2個物件,所以無法以PngGroup這個名稱來刪除多個物件

解決的方法是將PngGroup寫到Table內,例如:
local tmpTable = {}  --產生一個Table
for i = 1,NumCount do
    PngGroup = display.newImage("apple.png") 
table.insert(tmpTable,PngGroup)  --將物件新增到Table 
end 

要刪除全部的PngGroup物件時,只要將Table內的物件,一個一個刪除就可以了。
for i = #tmpTable, 1, -1 do
    local child = table.remove(tmpTable, i)    -- Remove from table
    if child ~= nil then
        child:removeSelf()
        child = nil
    end
end 

Phonegap 3.5 build release(使用Keystore) Android APK

Phonegap預設是以debug來編譯apk,所以在phonegap build android之後,
在platforms/android/ant-build內看到的都是[APP_NAME]-debug*.apk。

我先產生一個的keystore如下:
c:\ keytool -genkey -v -keystore c:/key/my-key.keystore -alias mykey01 -keyalg RSA -validity 2000

另外要注意的是alias的名稱不能超過8個字,官方說明如下:
-alias <alias_name>     An alias for the key. Only the first 8 characters of the alias are used.

kyetool的使用方法及說明,可以參考:
http://developer.android.com/tools/publishing/app-signing.html#cert

接著在platforms/android/底下新增一個名為ant.properties的文字檔(編碼格式必須是ANSI),並且增加下列的字串:
key.store=c:/key/my-release-key.keystore
key.alias=key01

最後重新編輯phonegap的專案,結果沒有效果,一樣是debug的apk。
查了好久,有一篇文章提到本機的phonegap是無法編譯release的apk,但是phonegap build的網站上是可以編譯release的apk
文章提到可以改以cordova來編譯原始檔,因為我不想在網站上編譯我的程式,於是我重新以cordova編譯就成功了。
c:\ cordova build android --release

檢查platforms/android/ant-build/底下,產生了[APP_NAME]-release-*.apk

Phonegap 3.5 plugin LocalNotification安裝與使用

測試了好幾天,搜尋了好多文章與範例,都無法讓Phonegap plugin LocalNotification正常運作,
最後總算成功發送通知,但是原因卻不是程式寫錯,也不是Phonegap 3.5無法支援(曾經懷疑)。

我的作法如下:
1、安裝LocalNotification的plugin
c:\phonegap_project\>  phonegap local plugin  add de.appplant.cordova.plugin.local-notification

2、查詢安裝的plugin
c:\phonegap_project\>  phonegap plugin list

[phonegap] the following plugins are installed
de.appplant.cordova.plugin.local-notification 0.7.6 "LocalNotification"
org.apache.cordova.device 0.2.13-dev "Device"

3、在專案www底下的config.xml加入plugin(我就是卡在這裡錯誤)
<gap:plugin name="de.appplant.cordova.plugin.local-notification" />
或指定版本(最好指定第2步驟查詢出來的版次)
<gap:plugin name="de.appplant.cordova.plugin.local-notification" version="0.7.6" />

因為我第一次下載的plugin是「de.appplant.cordova.plugin.local-notification 0.8.0dev」,
以上述的語法加在config.xml是沒有效果的,必須改為下列的語法才能正確使用
<gap:plugin name="de.appplant.cordova.plugin.local-notification 0.8.0dev" />
所以最好每次加掛plugin時查詢一下版本才不會像我一直找不到錯誤原因

4、撰寫程式測試
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="format-detection" content="telephone=no" />
        <!-- WARNING: for iOS 7, remove the width=device-width and height=device-height attributes. See https://issues.apache.org/jira/browse/CB-4323 -->
        <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, height=device-height, target-densitydpi=device-dpi" />
        <meta name="msapplication-tap-highlight" content="no" />
        <title>Hello World</title>
    </head>
    <body>
        <script type="text/javascript" src="cordova.js"></script>
       
        <script type="text/javascript">
       
              function test() {
                   //發送最簡單的方法
                   window.plugin.notification.local.add({ message: '中文測試' });
                    alert('發送成功');
               }        
        </script>
        <div class="app">
            <h1>Apache Cordova</h1>
            <section>
                <p><a href="#" onclick="test(); return false;">Notification Test</a></p>
               </section>
        </div>
    </body>
</html>

5、執行的結果


產生ADB server didn't ACK 的問題

原本ADB使用上都很正常,連接各模擬器與手機都沒有什麼問題,
但是今天執行adb kill-server後再重新執行adb server卻出現了ADB server didn't ACK,
重覆幾次的動作都是一樣的訊息,而且模擬器與手機在adb devices都抓不到裝置。

開啟工作管理員查看後發現adb.exe的處理程序有兩個,雖然有執行kill-server,但是不知道為什麼程序沒有結束,
所以手動把兩個處理程序全部關閉,再重新執行adb server就可以正常連接模擬器與手機裝置了。
若沒有adb.exe這個處理程序的話,也可以直接重新開機,這樣也能關閉ADB server程序。

Excel 2010 x64 VBA出現Microsoft.Jet.OLEDB.4.0 提供者並未登錄於本機電腦上

我有一個Excel會以資料庫的方式抓取其他Excel的資料,一開始我是在Excel 2010 32位元的版本下開發,使用下列的連接語法:

objConnection.Open "Provider=Microsoft.Jet.OLEDB.4.0;" & _
                               "Data Source=" & Str_Source_DataFile & ";" & _
                               "Extended Properties=""Excel 8.0;HDR=Yes;"";"

測試的結果是正常運作的,但是我把Excel放到另一台Excel 2010 64位元的版本下執行,卻出現了下列的錯誤:

Microsoft.Jet.OLEDB.4.0 提供者並未登錄於本機電腦上

搜尋了一些網站,試著用Command的語法重新登錄DLL,也下載了Jet的引擎,但是都沒有效果。
最後原來是Excel 2010 64位元的版本已不再支援Jet,而是改以Ace引擎。

由於Office 2007已經更改了Access與Excel的檔案格式,並且新命名為.accdb與.xlsx,因此未被Microsoft Jet引擎所支援。
只是目前office 2010 32位元的版本依舊支援Jet引擎,而Ace引擎不僅支援新版本的格式,也相容97-2003的版本,
所以我就把語法改為下列就可以正常執行了。

objConnection.Open "Provider=Microsoft.ACE.OLEDB.12.0;" & _
                               "Data Source=" & Str_Source_DataFile & ";" & _
                               "Extended Properties=""Excel 12.0;HDR=Yes;"";"