2013年10月28日 星期一

宅女小紅

中午吃飯的時候, 我都用以前路口發的爽報來墊桌子, 吃完包一下直接投垃圾桶, 很方便. 但最近我不這麼幹了, 原因有二. 有一天我一邊吃飯, 一邊喵一下便當盒底下的爽報, 哎呀不得了, 我怎麼會拿這一張墊底呢! 這一張是正妹阿, 趕緊找張阿里不搭的換上. 其次是有一天看到底下墊的是專欄, 本來我對爽報的專欄沒啥興趣, 但看著看著, 卻看出興趣來了, 吸引我目光的是宅女小紅的專欄, 那篇叫做 "凶宅的定義", 大意是說她看中了一間房子, 但是聽說樓上曾經有一個知名藝人自殺, 導致整棟價格滑落, 很便宜又很中意, 但是凶宅 ... 雖然她要買的那間不是, 心裡總是毛毛的.  寫來詼諧有趣, 特別是她喜歡用一些台語詞彙, 懂台語的念起來更好笑. 比如說像這篇凶宅的定義裡的就有 :

某概厚=不太好
閃尿=尿失禁
粗過逮擠=出過事情
矮油=唉喲

每次揭姊姊的瘡疤時, 她都會迸出一句口頭禪 "唉喲", 所以我都叫她 "唉喲小姐", 看了小紅的文章, 我特別拿回去給姊姊看, 說改成 "矮油小姐" 會不會比較好, 她聽了之後又是一句 "矮油" .... 心情不好的時候, 去看看宅女小紅的 "垃圾文" (她自己說的), 就會覺得事情好像也沒那麼糟阿.

# 爽報宅女小紅專欄
凶宅的定義

2013年10月26日 星期六

ExtJS 4 測試 (一) : 對話框與進度條

一段時間沒注意, ExtJS4 已經升版到 4.2.1 了, 增加與修改了一些功能, 詳見 v.4.2.1 Release Note. ExtJS4 的測試環境架設之前整理過了, 參見  "ExtJS 環境部署" 一文. 為了測試對話框, 我重新下載了新版 ExtJS, 測試環境架設簡要複習如下 :
  1. 下載 ExtJS4.2.1 GPL 版本.
  2. 將下載的 ext-4.2.1-gpl.zip 解壓縮, 可以全部解開 (如果想測試一下範例), 但如果只是要用 ExtJS 來測試學習或開發雛型的話, 只需要解開根目錄下的 ext-all.js 檔與 resources 子目錄即可.
  3. 將解開的 ext-all.js 檔與 resources 子目錄複製到我們的專案目錄 project 的 extjs 目錄下, 例如下列結構 :
    project/extjs-4.2.1/ext-all.js
    project/extjs-4.2.1/resources
    project/alert_1.htm                       
接下來撰寫測試網頁 alert_1.htm, 在網頁中要匯入 ext-all.js 函式庫與所使用之 css 樣式表 :

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>ExtJS4</title>
  <link rel="stylesheet" href="extjs-4.2.1/resources/css/ext-all.css" />
  <script type="text/javascript" src="extjs-4.2.1/ext-all.js"></script>
</head>
<body>
</body>
</html>

或者使用 Sencha 的 CDN 也可以 (目前僅 V4.2.0) :

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <title>ExtJS4</title>
  <link rel="stylesheet" href="http://cdn.sencha.com/ext/gpl/4.2.1/resources/css/ext-all.css" />
  <script type="text/javascript" src="http://cdn.sencha.com/ext/gpl/4.2.1/ext-all.js"></script>
</head>
<body>
</body>
</html>

或者使用 cdnjs.cloudflare.com 提供的 CDN :

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="cache-control" content="no-cache">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <title>ExtJS4</title>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/extjs/4.2.1/resources/css/ext-all.css" />
  <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/extjs/4.2.1/ext-all.js"></script>
</head>
<body>
</body>
</html>

這樣就可以開始寫測試碼了. 首先來測試 ExtJS 的訊息框, 用來取代 Javascript 的 alert().
跟 jQuery 類似, 要先等 ExtJS 函式庫載入完成, 再進行 ExtJS 函式呼叫較妥當, 所有的 ExtJS 程式碼應該放在 Ext.onReady(function() {...}) 中的大括弧內, 這跟 jQuery 的 $(document).ready(function(){...}) 是同樣的用法.

寫 UI 最常用的就是對話框, ExtJS 處理對話框的類別是 Ext.MessageBox, 這個類別有一個捷徑別名 Ext.Msg, 可以少打一些字元, 兩者通用, 效果相同. 換言之 :

 Ext.MessageBox=Ext.Msg

其 API 與原始碼詳見 :

http://docs.sencha.com/extjs/4.2.2/#!/api/Ext.MessageBox
# Ext.MessageBox 原始碼

要跳出一個 ExtJS 訊息框非常簡單, 只要呼叫 Ext.MessageBox 類別的 alert() 方法即可, 此 alert() 方法帶兩個必要參數與兩個備選參數, 第一個參數是訊息框標題 (title),  第二個參數是要顯示之訊息, 第三個參數是使用者按對話框內的按鈕後之回呼函式 (傳入按鈕字串), 第四個參數為作用域物件 (預設是 window, 一般設為 this 表示作用域限於物件本身) :

Ext.MessageBox.alert("Title", "Message", [callback(btn)],  [scope]);

Ext.onReady(function() {
      Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
      });

測試範例 1 : https://tony1966.github.io/test/ExtJS/alert_1.htm [看原始碼]


為什麼需要一個回呼函式呢? 這跟 Ext.MessageBox 類別的實作方式有關, 而且關係到整個商業邏輯, 必須特別注意. 簡言之,  Ext.MessageBox 類別所提供的對話框功能其實只是利用 div 元素套疊與 CSS 樣式在網頁中造出的一個顯示層 (Layer) 而已, 並非針對 Javascript 的 window.alert() 進行加強或改造, 所以本質上跟 window.alert() 不同.

最重要的差異是, Javascript 原生的 alert, confirm 與 prompt 與使用者溝通的方式是同步式的, 亦即它會使程式停住, 等待使用者按下對話框中的按鈕後, 才能繼續往下執行; 但 ExtJS 的 MessageBox 類別則是非同步式的, 它不會卡住程式, 當對話框跳出顯示時, 程式碼仍會繼續往下執行. 這有一些好處, 例如當使用者在對話框中輸入資料時, 程式可以繼續往下執行 Ajax 向遠端伺服器擷取資料或繼續操控 UI 介面. 但是如果你希望 ExtJS 的對話框跟 Javascript 一樣是同步式的, 那麼傳統上對話框關閉後才要執行的邏輯必須放在回呼函式中, 不可以放在對話框後面, 否則那些後續邏輯會跟對話框顯示後馬上執行, 這可能與我們所需的同步邏輯不符. 這種用 callback 函式來模擬同步式處理的方法適用以下的確認框, 輸入框等等 Ext.Msg 類別之物件.

在下列範例二中, 我們在一個 Javascript 的訊息框後面緊接著 ExtJS 訊息框, 必須關閉 Javascript 訊息框後, 才會顯示 ExtJS 的訊息框, 可見 Javascript 的訊息框是 hold 得住的 :

      alert("您好! Hello World!");
      Ext.MessageBox.alert("通知訊息", "這是 ExtJS 的訊息框");

測試範例 2 : https://tony1966.github.io/test/ExtJS/alert_2.htm [看原始碼]

在下列範例三中, 我們反過來在 ExtJS 訊息框後面緊接著一個 Javascript 的訊息框, 可見這兩個訊息框幾乎是同時出現在網頁中 (事實上是 ExtJS 的先, Javascript 的隨後), 因為 Ext.Msg.alert() 是 hold 不住的 :

      Ext.MessageBox.alert("通知訊息", "這是 ExtJS 的訊息框");
      alert("您好! Hello World!");

測試範例 3 : https://tony1966.github.io/test/ExtJS/alert_3.htm [看原始碼]

請注意, 因為執行程序已經到 Javascript 的 alert 了, 所以必須先關閉原生訊息框, 才能關得掉 ExtJS 的訊息框. 如果希望等 ExtJS 訊息框關閉後才能顯示 Javascript 訊息框, 就必須將它放在 Ext.Msg.alert() 的回呼函式中才行, 如下列範例 4 所示 (使用匿名函式) :

      Ext.MessageBox.alert("通知訊息",
                                             "這是 ExtJS 的訊息框",
                                             function(btn){
                                                alert("您按了 " + btn + " 鈕");                           
                                                });

測試範例 4 : https://tony1966.github.io/test/ExtJS/alert_4.htm [看原始碼]

請注意, 訊息框會將使用者在對話框內按下之按鈕 id 傳入回呼函式. 如果使用者按下 ok 按鈕, 傳回值就是小寫字串 "ok"; 如果按右上角的 X 鈕, 則傳回小寫的 "cancel" 字串. 其次, Javascript 原生 alert() 的訊息內容只能顯示純文字, 故範例四中的 HTML 碼沒有效果; 而 ExtJS 所有對話框的訊息內容都可以使用 HTML 碼, 如範例五所示 :

      Ext.MessageBox.alert("通知訊息",
          "這是 ExtJS 的訊息框",
          function(btn){
              Ext.MessageBox.alert("通知訊息","您按了 " + btn + " 鈕");
              });      
          });

 測試範例 5 : https://tony1966.github.io/test/ExtJS/alert_5.htm [看原始碼]

在範例五中, 我們使用了兩層 ExtJS 訊息框, 第二層因為放在回呼函式, 因此必須等第一層訊息框關閉後才會顯示, 可見按鈕字串 ok 或 cancel 已經變成粗體了.

接下來我們測試一下確認框 (取代 Javascript 的 confirm). 此 confirm() 方法的參數與 alert 一樣 :

Ext.MessageBox.confirm("title", "message", [callback(btn)],  [scope]);

回呼函式 callback 用來處理使用者按了 yes, no 或 cancel 之事件. 按鈕事件物件會將使用者所按的按鈕字串 btn 傳入 callback. 確認框有三個按鈕 Yes, No 與 Cancel (即右上角的叉叉), 但其傳入值一律都是小寫字串 : "yes", "no", 與 "cancel". 如下列範例六, 當按下 yes 鍵後, 便進行資料刪除作業 (略), 然後以訊息框顯示結果.

      Ext.MessageBox.confirm(
          "確認訊息",
            "確定要刪除這筆留言?",
            function(btn) {
               if (btn=="yes") {
                   //delete data ...
                   Ext.MessageBox.alert("訊息", "留言已刪除!");
                   }
              else {
                   Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
              });

測試範例 6 : https://tony1966.github.io/test/ExtJS/confirm_1.htm [看原始碼]


 

最後來測試一下 ExtJS 的輸入訊息框, 用來取代 Javascript 的 prompt(). 這要呼叫 Ext.MessageBox 的 prompt() 方法, 此方法有兩個必要參數, 四個備選參數, 其中回呼函式 callback 有兩個來自按鈕事件的傳入參數, btn 是標示使用者按哪個按鈕之傳回值 (傳回小寫的 "ok" 或 "cancel" 字串), text 是使用者輸入的字串. 備選參數 multiline=true/false, 用來控制輸入框顯示多行或單行輸入區, 預設是 false (單行). 而參數 value 則是用來設定輸入欄位的預設值.

Ext.Msg.prompt("title", "message", [callback(btn, text)], [scope], [multiline], [value]);

下列範例三我們用華氏轉攝氏換算來說明其用法 :

Ext.MessageBox.prompt("輸入訊息",
                                       "請輸入華氏溫度",
                                       function(button, text) {
                                          if (button=="ok") {
                                              var f=parseFloat(text,10);
                                              var c=Math.round((f-32)*5/9);
                                              var msg="華氏 " + text + " 度=攝氏 " + c + " 度";
                                              Ext.MessageBox.alert("通知訊息",msg);
                                              }
                                         else {return;}
                                         });

測試範例 6 : https://tony1966.github.io/test/ExtJS/prompt_1.htm [看原始碼]

回呼函式中可以再呼叫訊息框方法, 在範例六中, 當使用者輸入華氏度數, 按下 ok 鍵後, 就呼叫 Ext.MessageBox.alert() 方法來顯示結果. 我在 IE8/Chrome/Firefox 上測試都是如下圖所示, 視覺效果相當一致, 特別是圓角 (round corner) 在 IE8 中還是維持原樣沒變方框, 這是 ExtJS 比 jQuery UI 優勝的地方.



下面範例七測試 multiline=true 的情況, 這時輸入區就變成多行, 亦即變成一個 textarea 元件. 但是如果要在訊息框中顯示輸入的多行資料的話, 必須將純文字的跳行符號 "\n" 全部改成 HTML 的跳行符號 "<br>" :

      Ext.Msg.prompt("輸入訊息","請留言",callback,this,true);
      function callback(btn, text) {
        if (btn=='ok') {
           Ext.Msg.alert("您的留言內容",text.replace(/\n/g,"<br>"));
           } //end of if
        else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");}
        } //end of function

測試範例 7 : https://tony1966.github.io/test/ExtJS/prompt_2.htm [看原始碼]

ExtJS 還提供一個比較少用的對話框 wait (等候框), 通常用在上傳檔案或提示需時較久之處理上, 讓使用者不至於認為程式沒在跑. 原生 Javascript 並無等候框, 這是 ExtJS 的設計, 它是在 Ext.MessageBox 內實做了一個進度條, 其呼叫函式 wait 有一個必選參數 message, 用來顯示訊息內容, 其下方會有一個周而復始不間斷的進行條, 備選參數 title 是等候框的標題, 第三個備選參數 configObj 可以是一個設定進度條用的 JSON 物件實體,  也可以是一個 Ext.ProgressBar 類別的物件實例, 最常用的屬性是 text, 用來設定此進行條上的文字.

Ext.Msg.wait("message", ["title"], [configObj]);

請特別注意, 等候框與上面三種對話框的前兩個參數順序顛倒, 它的第一個參數是訊息主體, 第二個參數才是對話框標題. 下面範例八我們用一個 JSON 物件實體來設定進度條 :

Ext.MessageBox.wait("請耐心等候!", "等待訊息",{text: "檔案處理中 ..."});

測試範例 8 : http://mybidrobot.allalla.com/extjstest/wait_1.htm [看原始碼]


注意, 等候框上沒有按鈕可以關閉它, 必須於程式中呼叫 hide() 方法來使其消失. 下列範例九我們用 Javascript 的 setInterval() 定時器在指定時間 (10 秒) 後關閉等候框. 同時也改用 Ext.ProgressBar 物件來設定進度條, 可以發現效果是一樣的 :

      var config=Ext.create('Ext.ProgressBar',{text:"檔案處理中 ..."});
      var wait=Ext.MessageBox.wait("請耐心等候!", "等待訊息", config); 
      var timer=window.setInterval(callback,1000);
      var i=0;
      function callback() {
        if (i>10) {  //處理完畢
            window.clearInterval(timer);  //停止定時器
            wait.hide();  //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
           wait.updateText("請耐心等候! (" + i*10 + "%)");
           ++i;
           }    
        }

在上例中, Ext.Msg.wait() 會傳回對話框物件本身, 我們先用 wait 變數紀錄此參考, 定時器 timer 每秒鐘會執行 callback 函式一次, 然後呼叫等候框物件之 updateText() 方法更新訊息內容 (可標示完成度), 當旗標增至 10 次時, 便呼叫 hide() 將 wait 等候框隱藏起來, 達到關閉對話框的效果. 這裡只是模擬測試, 實際上在專案中主要是放在 Ajax 的回呼函式中, 當檔案上傳或處理完畢, 回傳 success 時再關閉等候框. 上例中的進度條物件也可以這樣寫 :

var config=new Ext.ProgressBar({text:"檔案處理中 ..."});

測試範例 9 : http://mybidrobot.allalla.com/extjstest/wait_2.htm [看原始碼]


Ext.ProgressBar 類別用法 

上面我們利用 Ext.ProgressBar 類別來設定等候框中的進度條, 事實上, 這個類別也是可以單獨使用的. 現在暫時岔開一下, 先來看看進度條的用法. 它有兩種操作模式 : 人工模式與自動模式. 在人工模式中, 我們必須利用 updateProgress() 方法自行控制進度條的進度變化, 適合用在可以明確量測進度的作業; 而自動模式不需自行操控進度條, 只要呼叫 wait() 方法, 進度條就會週而復始不停的增量-歸零, 直到偵測到作業結束, 適合用在只能偵測到作業結束, 但無法準確得知目前進度的場合. 

下列範例 10 中, 我們把 Ext.ProgressBar 物件直接描繪在 body 容器裡, 然後用定時器每秒呼叫進度條物件的 updateProgress() 方法, 以人工模式 (manual mode) 直接更改進度條中的顯示文字 :

      var progressbar=new Ext.ProgressBar({
                                           width: 300,
                                           renderTo: Ext.getBody()
                                           });
      var timer=window.setInterval(callback,1000);  //每秒觸發一次
      var i=0;
      function callback() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
          progressbar.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");
          ++i;
          }       
        }

這 updateProgress([value], [message], [animate]) 方法有三個參數, 全都是備選參數, 但第一個參數是進度條的值 value (0~1), 若不給, 進度條就不會顯示前進了, 在上面範例中, 我們用 i/10 計算每秒的更新值. 第二個參數 message 是要顯示在進度條上的字串, 第三個參數是 animate (true/fasle), 控制進度條前進時是否要有動畫效果, 預設 false (其實設為 true 後感覺也沒差多少).


測試範例 10http://mybidrobot.allalla.com/extjstest/progressbar_1.htm [看原始碼]

下列範例 11 我們用三個進度條測試 Ext.ProgressBar 的自動模式, wait() 方法可以用一個 JSON 物件來設定. 其屬性說明如下 :

  1. duration  (單位 ms) :
    設定進度條定時器時間長度, 過了這段時間後, 進度條就會停止不再前進.
  2. interval (單位 ms) :
    設定進度條的更新週期, 也就是幾毫秒前進一格, 可以用來控制進度條的速度. 
  3. increment (單位 : 段數)
    設定進度條之分段數目, 預設值為 10 段

所以將 duration 除以 interval 就會得到定時器時間內, 進度條更新的頻率 (次數), 其值若等於 increment, 則進度條只走一個輪迴; 若為 increment 段數的 2 倍, 進度條就輪迴兩次. 例如第一個進度條 duration=10000, interval=1000, 10 秒內會更新 10 次, 而其 increment 設為 10 段, 剛好一個輪迴. 第二個進度條 interval 改成 500, 10 秒內會更新 20 次, 其 increment 設為 10 段, 因此會走兩個輪迴; 第三個進度條 duration=10000, interval=400, 它在十秒鐘內更新 25 次, 其 increment 設為 25 段, 因此也是一個輪迴. 可見, increment 越大, 進度條走起來就越平順, 愈小就越會跳, 若 interval*increment=duration, 那麼進度條終止時就剛好走一輪.

      var progressbar1=new Ext.ProgressBar({
                                            width: 300,
                                            renderTo: Ext.getBody()
                                            });
      progressbar.wait({
        duration:10000,
        interval:1000,
        increment:10,
        text:"進度條 1 號 ...",
        scope:this,
        fn:function(){
          progressbar.hide();
          }
        });


測試範例 11http://mybidrobot.allalla.com/extjstest/progressbar_2.htm [看原始碼]

當 duration 時間到時, 會呼叫 fn 屬性之回呼函式, 此處呼叫進度條的 hide() 方法可以將其隱藏, 模擬關閉的效果. 注意, 自動模式的進度條如果不給 duration 屬性, 那麼它會變成永不停止, 因為其回呼函式 fn 是靠 duration 控制的計時器來觸發, 沒有 duration 就不會呼叫回呼函式.

在上面範例九, 我們是用 updateText() 方法把 realtime 的進度 (百分比) 顯示在等候框的訊息中, 既然我們也可以傳入 Ext.ProgressBar 物件給等候框, 我們能否像上面範例十獨立的 ProgressBar 物件那樣, 用 updateProgress() 方法更改等候框中進度條的顯示文字呢 (主要是處理進度 % 資訊)? 測試的結果是否定的 (why?). 如下列範例 11 所示 :

      var config=new Ext.ProgressBar({text:"檔案處理中 ..."});
      var wait=Ext.MessageBox.wait("請耐心等候!", "等待訊息", config);
      var timer=window.setInterval(callback,1000);
      var i=0;
      function callback() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            wait.hide(); //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
          config.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");  //無效果
          ++i;
          }       
        }

測試範例 11http://mybidrobot.allalla.com/extjstest/wait_3.htm [看原始碼]

OK, 上面範例都是直接呼叫對話框, 不過專案中常見的是透過事件觸發, 下面範例 12 我們就把這三個對話框都分別利用一個按鈕的 click 事件來觸發 :

  <input id="btn_alert" type="button" style="width:100px;" value="訊息框">
  <input id="btn_confirm" type="button" style="width:100px;" value="確認框">
  <input id="btn_prompt" type="button" style="width:100px;" value="輸入框">

測試範例 12 : http://mybidrobot.allalla.com/extjstest/dialog_1.htm [看原始碼]

利用 get() 方法取得按鈕物件後, 呼叫 on() 方法綁定一個 click 事件給 callback 函式, 例如觸發訊息框寫法如下 :

      Ext.get("btn_alert").on("click",function(){
         Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
         }); //end of on

這樣就會在按下按鈕觸發 click 事件時顯示對話框. 但請注意, 我特別將 input 按鈕的 width 設為 100px, 因為套用 ExtJS 的 CSS 後, 按鈕邊界會縮到內容寬度與高度, 使得按鈕看起來很小. 其實除了 Apple 瀏覽器外, 瀏覽器所繪製的原生按鈕真的都不怎麼好看, 既然用了 ExtJS, 那麼應該使用 ExtJS 提供的按鈕物件來製作, 不要直接用 HTML 語法寫出按鈕, 這樣在 UI 視覺上比較一致.

ExtJS 製作按鈕元件的語法如下 :

var btn_alert=new Ext.Button({
                                       text : "訊息框",
                                       width : 100,
                                       renderTo : Ext.getBody(),
                                       handler : show_alert
                                       });

var btn_alert=new Ext.Button({
                                       text : "訊息框",
                                       width : 100,
                                       renderTo : Ext.getBody(),
                                       handler : function(btn) {
                                           Ext.MessageBox.alert("通知訊息", "您好! Hello World!");
                                           }
                                       });

其中屬性 text 是顯示在按鈕上的文字, width 是寬度 (px), renderTo 是要把此按鈕描繪在哪一個容器物件上, 這裡 Ext.getBody() 是取得 body 元素, 以便把按鈕放入 body 中; 而 handler (或用 listener 亦可) 則是指定事件處理函式名稱 (不要加括弧), 也可以直接用匿名函式. 我們將範例 11 改寫為範例 12 如下, 其中訊息框採用匿名函式, 其他用外部函式 :

測試範例 12 : http://mybidrobot.allalla.com/extjstest/dialog_2.htm [看原始碼]

這按鈕看起來就比較美觀了. 比較如下 :


以上便是 ExtJS 常用的對話框用法, 這在專案中常常會用到, 是應用程式與使用者溝通的重要介面. 既然使用了 ExtJS 框架, 那麼必須讓使用者有一致的 GUI 介面, 不宜再穿插使用 Javascript 原生的 alert, confirm, 與 prompt 了. 當然呼叫時要敲比較長的指令很不方便, 因此 ExtJS 給 MessageBox提供了 Msg 這個名稱捷徑, 亦即, MessageBox 可以用 Msg 這個捷徑名稱取代 :

Ext.Msg.alert()
Ext.Msg.confirm()
Ext.Msg.prompt()
Ext.Msg.wait()

在使用這四種對話框時, 首先要注意的是, 對話框中的四種按鈕 yes, no, ok, 與 cancel 其傳回值都是小寫的字串, 因此回呼函式中的第一個參數 button 在比對時務必要用小寫的 "yes", 不可以用 "Yes" 或 "YES", 否則你會發現事件根本沒被處理.

以上四種對話框使用上很簡單, 但相對地能設定的項目也較少. 例如沒辦法加上小圖檔. 如果要製作更有彈性地客製化對話框, 就要用更一般的方法 Ext.Msg.show(), 事實上面四種對話框就是用特定之設定值呼叫 Ext.Msg.show() 的.

Ext.Msg.show() 提供了很多屬性, 其中 title (標題), msg (訊息), buttons (按鈕), 與 fn (回呼函式) 是每一種對話框最基本的屬性, 所有的 show() 對話框預設都是強制模式對話框 (modal=true), 所以除非應用上需要非強制對話框, 否則 modal 屬性不需要給.

我們先用 show() 來製作帶有 icon 訊息框, 如範例 13 所示.


測試範例 13http://mybidrobot.allalla.com/extjstest/show_alert.htm [看原始碼]

      Ext.MessageBox.show({
        title: "通知訊息",
        msg: "您好! Hello World!",
        buttons: Ext.Msg.OK,
        icon: Ext.Msg.INFO,
        fn: function(btn) {
          Ext.Msg.alert("通知訊息", "您按了 " + btn + " 鈕");
          }
        });

在上例中, buttons 屬性設為 Ext.Msg.OK, 表示要在訊息框中放置一個按鈕 : Ok. 屬性 buttons 的可能值列於下表.

 buttons 按鈕
 Ext.Msg.OK Ok
 Ext.Msg.CANCEL Cancel
 Ext.Msg.OKCANCEL Ok + Cancel
 Ext.Msg.YES Yes
 Ext.Msg.NO No
 Ext.Msg.YESNO Yes + No
 Ext.Msg.YESNOCANCEL Yes + No + Cancel

而 icon 屬性是用來在訊息 msg 字串前面加上一個圖型, 可用之值如下表 :

icon 圖形
 Ext.Msg.INFO
 
 Ext.Msg.ERROR
 
 Ext.Msg.WARNING
 
 Ext.Msg.QUESTION
 

對於訊息框而言, 可以使用 Ext.Msg.INFO, ERROR, 或 WARNING, 視情況而定.

其次用 show() 來製作確認框, 它需要一個 Question 圖形, Yes 與 No 按鈕, 如範例 14 所示, 其實它跟訊息框的差別就是 icon 部分為 Yes/No, 而非 Ok 而已, 而且要依據使用者按 Yes 或 No 來反應.

測試範例 14http://mybidrobot.allalla.com/extjstest/show_cinfirm.htm [看原始碼]

      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        });

接著我們用 show() 來製作單行文字輸入框, 它需要一個 INFO 圖形, Ok 與 Cancel 按鈕, 如範例 15 所示.

測試範例 15http://mybidrobot.allalla.com/extjstest/show_prompt_1.htm [看原始碼]

      Ext.MessageBox.show({
        title: "輸入訊息",
        msg: "請輸入華氏溫度",
        prompt: true;
        value: 32,

        buttons: Ext.Msg.OKCANCEL,
        icon: Ext.Msg.INFO,
        fn: function(btn, text) {
              if (btn=='ok') {
                  var f=parseFloat(text,10);
                  var c=Math.round((f-32)*5/9);
                  var msg="華氏 " + text + " 度=攝氏 " + c + " 度";
                  Ext.Msg.alert("通知訊息",msg);
                  } //end of if
              else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");} 
              } //end of function
        });

下面範例 16 是測試多行輸入框, 這需要將 multilines 屬性設為 true (預設為 false 是單行), 而多行輸入區的高度可以利用 defaultTextHeight 屬性來調整 (預設是 75px) :

測試範例 16http://mybidrobot.allalla.com/extjstest/show_prompt_2.htm [看原始碼]

      Ext.MessageBox.show({
        title: "輸入訊息",
        msg: "請留言",
        prompt: true,
        multiline: true,
        defaultTextHeight: 100,

        buttons: Ext.Msg.OKCANCEL,
        icon: Ext.Msg.INFO,
        fn: function(btn, text) {
              if (btn=='ok') {
                  Ext.Msg.alert("您的留言內容",text.replace(/\n/g,"<br>"));
                  } //end of if
              else {Ext.Msg.alert("通知訊息","您按了 " + btn + " 鈕");} 
              } //end of function
        }); 

最後看看如何用 show() 製作等候框. 要在 show() 方法產生的對話框中出現進度條, 必須將 progress 屬性設為 true (預設 false 不顯示), 這會在對話框的訊息下方顯示一個進度條, 但是, 這個進度條不會動, 必須透過呼叫  Ext.Msg 物件的 updateProgress() 方法去更新進度條的值 (value) 才會動, 所以 progress=true 適合可以掌握精確進度的等候框 (手工控制模式), 如下面範例 16 所示 :

測試範例 16 : http://mybidrobot.allalla.com/extjstest/show_wait_1.htm [看原始碼]

      var wait=Ext.MessageBox.show({ //傳回 Ext.MessageBox 物件
                 title: "等待訊息",
                 msg: "請耐心等候!",
                 width: 300,
                 progress: true
                 });
      var timer=window.setInterval(update,1000);
      var i=0;
      function update() {
        if (i>10) {
            window.clearInterval(timer); //停止定時器
            wait.hide(); //隱藏等候框
            Ext.Msg.alert("通知訊息", "檔案處理完成!");
            }
        else {
            wait.updateProgress(i/10, "檔案處理中 ...(" + i*10 + "%)");
            ++i;
            }      
        }

在上面範例中, 我們同時設定了 width 屬性將對話框寬度改為 300px. 但是, 如果只是設定 progress=true 還不夠, 那只是顯示一個不會跑的進度條而已, 你必須 範例 16 中使用一個定時器每秒呼叫自訂的 update() 函式, 呼叫 Ext.Msg 物件的 updateProgress() 方法, 更新其 value 參數值, 這樣進度條才會跑. 這通常是在可以精確掌握進度 (例如檔案處理) 情況時使用; 如果是檔案上傳或資料庫查詢使用 Ajax 無法預知處理進度情況時, 適合使用下列範例 17 會自動跑的等候框 (自動模式), 這就要改用 wait 屬性 (設為 true).

測試範例 17 : http://mybidrobot.allalla.com/extjstest/show_wait_2.htm [看原始碼]

      var wait=Ext.MessageBox.show({
                 title: "等待訊息",
                 msg: "請耐心等候!",
                 width: 300,
                 wait: true,
                 waitConfig: {
                   duration:10000,
                   interval:1000,
                   increment:10,
                   text:"檔案處理中 ...",
                   scope:this,
                   fn:function(){
                        wait.hide();
                        Ext.Msg.alert("通知訊息", "檔案處理完成!");
                        }
                   }
                 });

自動控制模式是將 wait 屬性設定為 true (預設為 false), 這會在對話框的訊息下方顯示一個進度條, 這跟 progress=true 的進度條不同的是, 它會以預設的速度自動前進. 我們可用 waitConfig 設定進度條的文字與速度等屬性, 這跟上面 Ext.ProgressBar 的用法一樣. 在上例中我們用 duration 指定進度條計時器為 10 秒, 用 interval 與 increment 指定速度, 也指定了計時器終止時的回呼函式來隱藏等候框. 實際專案中使用 Ajax 存取資料時, 不需要設定 duration 與 fn, 而是在 Ajax 的 success 等回呼函式中呼叫 hide() 方法來隱藏等候框, 在這之前, 進度條會周而復始地不間斷自動變化. 注意, 設定 wait=true 的等候框沒有右上角的 X (Cancel 鈕), 即使你將 closable 屬性設為 true 亦然 (預設即為 true), 這跟前面 Ext.Msg.wait() 的等候框是一樣的 (別忘了 wait 就是用 show 訂製出來的).

最後, 有沒有發現所有的對話框上的按鈕文字都是英文 (Ok, Yes, No, Cancel)?  有沒有辦法把他們變成 "確定", "是", "否", "取消"? 在 ExtJS 解壓縮檔案中有一個 locale 目錄, 底下有許多語言本土化檔案, 繁中是 ext-lang-zh_TW.js, 但打開該檔案會發現它並沒有處理對話框按鈕文字中文化, 它是給日期選擇器等元件用的. 對話框中文化有兩種作法, 對於 alert(), confirm(), prompt() 這三個訂製型的對話框 (wait 沒有按鈕, 不需中文化), 必須在呼叫方法前設定 buttonText 屬性如下 (注意, key 都是小寫)  :

      Ext.MessageBox.buttonText={ok:'確定',yes:'是',no:'否',cancel:'取消'};
      Ext.MessageBox.alert(
        "通知訊息",
        "這是 ExtJS 的訊息框",
        function(btn){
          Ext.MessageBox.alert("通知訊息","您按了 " + btn + " 鈕");
          });

測試範例 18http://mybidrobot.allalla.com/extjstest/alert_locale.htm [看原始碼]


可見 Ok 按鈕已經變成 "確定" 按鈕了. 雖然在設定時四種按鈕都有設定中文化, 但實際上 alert 只有一個 Ok 按鈕, 所以只顯示確定鈕.

至於使用 show() 製作的對話框也是一樣, 如下列範例 19 所示 :

      Ext.MessageBox.buttonText={ok:'確定',yes:'是',no:'否',cancel:'取消'};
      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        });

測試範例 19http://mybidrobot.allalla.com/extjstest/show_locale_confirm_1.htm [看原始碼]


特別注意, 上例中 buttonText 屬性必須先設定後再呼叫 Ext.Msg 物件的 show() 方法, 否則中文化c無作用, 仍顯示英文. 其次, buttonText 僅改變按鈕上的顯示文字, 傳入回呼函式的按鈕 id 之值不受影響, 仍是小寫的 ok/yes/no/cancel 字串.

除了上面的方法外, 還可以在設定項中指定 buttonText 屬性, 但是這種做法是用到幾個按鈕就列出幾個, 不要像第一種做法那樣全列, 否則會顯示全部按鈕. 如範例 20 所示 :

      Ext.MessageBox.show({
        title: "確認訊息",
        msg: "確定要刪除這筆留言?",
        buttons: Ext.Msg.YESNO,
        buttonText: {ok:'確定',yes:'是',no:'否'},
        icon: Ext.Msg.QUESTION,
        fn: function(btn) {
              if (btn=="yes") {
                  //delete data ...
                  Ext.MessageBox.alert("訊息", "留言已刪除!");
                  }
              else {
                  Ext.MessageBox.alert("通知訊息", "您按了 " + btn + " 鈕");
                  }
          }
        }); 

測試範例 20http://mybidrobot.allalla.com/extjstest/show_locale_confirm_2.htm [看原始碼]


可見雖然 buttons 屬性只設定 Yes 與 No 兩個按鈕, 但是因為 buttonsText 多設定了 Ok, 所以顯示了三個中文化按鈕. 注意, 此處 buttons 與 buttonText 先後順序沒有關係.

以上便是 ExtJS 4 對話框常用方法的測試, 花了我兩周斷斷續續修改, 總算摸出 ExtJS 的一點象尾巴了. 我覺得學習 ExtJS 主要就是要學會其設定方法而已.

2013年10月25日 星期五

爽死了

近日假油案大爆發, 全民怒爆, 但是我發現有些人爽死了.

事情是這樣的, 報載政府清查才發現, 富味鄉進口棉仔油 M 公噸, 出口 N 公噸, M >> N 說全數出口騙誰呀, 結果廠商啞口無言只好承認, 政府好像立了大功終於查出來了. 但是這件稽查工作以前沒人做嗎? 結論, 整件事情的真相就是 ~~~ 真的沒人管.

其實這些問題再過兩周就會自然平息, 然後我們就靜靜等待下一次, 毒米? 毒水果? 毒自來水?
請想想看, 毒澱粉, 塑化劑事件不是今年的事嗎? 你記得啥?

報載塑化劑求償事件, 統一公司向上游廠商求償獲判 7340 萬, 民眾打官司向統一等公司求償 78 億, 法院僅准 120 萬 (這是總和吧), 所以光是統一公司一家就從這事件中淨賺 7000 萬! 也就是說統一以低成本進料塑化劑, 已經在過去賺了不少錢囉! 發生這種事竟然還能倒賺? 這不是爽死了嗎? 

是誰讓法官做出這種天理不容的判決? 答案是咱們罵政府,  Yahoo 新聞摘要 "黑心塑化劑事件輕判 最低竟只須賠償9元"   :

"塑化劑風暴席捲全台時,衛生署國民健康局為了消弭民眾的不安,在網站上公布「食品中塑化劑污染衛教手冊」,並提及DEHP、DINP等塑化劑,會在短時間內經人體代謝排出體外,對健康並未造成損害等見解。
  這項衛教訊息在訴訟過程中,反而成為被告廠商在法庭上答辯的利器,而法院也採信此觀點,同時以下游業者也是塑化劑的受害者,在不知情下使用含有黑心起雲劑的食品。並駁回消基會提出的精神賠償損害請求,僅以消費者保護法規定,各商品製造商仍應對消費者負責,判決業者賠償消費者「商品價格」的金額。其中,最低竟只須賠償一瓶鋁箔包飲料價格9元。"

塑化劑求償 統一獲賠7340萬
塑化劑求償78億 判賠120多萬

 

問題在哪裡

台灣的民主制度運作多年來, 大家都知道是有問題的, 像這次馬王鬥, 就暴露了許多憲政危機, 但問題在哪裡, 因為太多, 所以也無法理出頭緒, 一次講清楚. 這篇林濁水寫的分析非常有條理, 抽絲剝繭讓不懂政治的也能了解. 摘要如下 :

  1. 總統不該有的權過大,該有的權卻沒有。這非常要命。
  2. 半總統制國家的三權分立實質上成了圍繞總統的權力,因為無論在法律上還是實際上總統都凌駕於行政、立法、司法三權之上。
  3. 中華民國憲法還有法總統所沒有的一個非常重要權力,那就是在組織架構上,國安機關和法國情報機關隸屬於總理之下,但中華民國延續兩蔣體制直屬總統。這自然又錦上添花了。
  4. 我們總統比起法國大的權力是一種「打高空」的「純政治性」權力,但是少了法國總統擁有可以實際掌握全盤決策和執行程序的權力,而且比法國總統更少了斷然解決行政立法僵局的權力。這就是馬扁兩人雖然認真到睡眠不足卻當不好總統,而成一對悲慘的難兄難弟的根本原因。

人民的幸福端賴政治機器運轉得好不好. 就像工廠買好的機器, 雇好的操作員, 就能生產好的產品. 中國歷史上數千年封建王朝的起起落落, 就是印證一件事, 一個王朝一部機器, 其實都是抄來抄去, 運轉起來短則十數年, 長則數百年, 都逃不過崩解再造的命運. 民主讓改朝換代從百年縮短為 4 年, 但是政治機器的良莠則關係到民主的根基是否能穩固. 雖然好制度不能保證成功, 但沒制度或壞制度則保證會失敗.

我贊成內閣制, 不喜歡現在這種四不像制, 更不喜歡這個修修補補, 千瘡百孔, 補這裡漏那裏的怪獸憲法. 難道我們不能擁有為台灣量身訂做的合用憲法嗎?

馬扁成了難兄難弟

2013年10月24日 星期四

絕非笑話

國中同學自從去上海工作聽我建議買了 iPad 後, 每天都會用 Line 傳訊息給我, 但我又不是每天用手機上網, 所以有時候兩三天才回訊息. 今天他傳的訊息分享如下 :

馬英九, 吳敦義, 江宜樺三個人一起坐直升機去巡視, 馬英九說, 如果我丟一千塊錢下去, 撿到的人一定很高興. 吳敦義說, 如果我丟兩張五百元下去, 那就會有兩個人很高興了. 江宜樺聽完, 很興奮地說, 那如果我丟十張一百元下去, 不就有十個人很高興囉? 這時駕駛員嘴裡嘟噥地說, 何不把你們三個都丟下去, 讓兩千三百萬人都高興呢?

嘿嘿.

2013年10月23日 星期三

機器學習的好書

今天找到一本機器學習的好書, Manning 出版, Peter Harrington 所著 "Machine Learning in Action". 此書是實務取向的書, 沒有理論推演, 但摘要整理了一些理論方面的基本概念. 重點是作者以 Python 語言作為實作工具, 使其極具可讀性, 我只對理論派的結論有興趣, 那些推演數學式對我來說簡直味同嚼蠟. 為什麼會以 Python 作為機器學習的程式語言呢? 作者理由如下 :
  1. 文字處理方式簡潔且功能極強, 有時甚至可以不用正規表達式即可達成目的.
  2. 內建 tuple, list, dictionary, set, queue 等高階資料類型, 易於對於實作抽象概念.
  3. 提供物件導向, 程序導向與函式導向寫法, 能迎合各種需求. 
  4. 有許多功能強大的模組可擴充各式各樣的應用功能
# Machine Learning in Action

精神分裂症探索

很多人以為精神分裂症 (schizophrenia ) 是有多重人格, 雙面人, 或者多面人, 其實這種認知是錯誤的.  根據小小神經學家網站的解釋 :

"雖然 schizophrenia 這個名詞在希臘原文中所指的是 「分裂的心靈 」(split mind),但是有精神分裂症的人並非人格分裂。所謂「分裂的心靈 」指的是有精神分裂症的人與現實分隔脫節,他們無法告訴你什麼是真,什麼是假。".

根據維基百科的說明 :

"精神分裂症是一種嚴重精神疾病,症狀為思考方式及情緒反應出現崩潰。常見病徵包括幻覺、妄想及胡言亂語,嚴重者會有自毀及傷人的傾向,並出現社會或職業功能退化。".

咱們馬先生最近不斷拋出兩岸論述, 為了解釋那不切實際的 "非國際關係" 論點, 只好搬出憲法, 說依據憲法, 中國大陸是中華民國領土. 依據上述醫學論述可知, 馬先生完全符合下列症狀 :
  1. 與現實分隔脫節 (有向大陸課稅, 徵兵, 下達行政命令嗎?)
  2. 無法告訴你甚麼是真, 甚麼是假 (這 GMP 認證的油可以吃嗎?)
  3. 有幻覺, 妄想及胡言亂語 (症狀明顯毋須多言)
  4. 有自毀及傷人傾向 (自降為區長 + 拖大家下海)
  5. 出現社會與職業功能退化 (鬥王失敗 + 無能 + 捕鞋大隊)
診斷意見 : 罹患嚴重精神分裂症, 應隔離治療, 定時服藥!

# 馬:中國大陸仍是我們領土
消毒兩岸特殊航線說? 馬:陸屬我領土

2013年10月22日 星期二

罪過大矣

以前老蔣說一年準備, 兩年反攻, 許多老兵想說很快就打回大陸了, 所以不願再娶, 結果蹉跎青春, 老來卻無子嗣, 孑然一身. 感慨 "毛澤東讓我妻離子散, 蔣介石卻讓我斷子絕孫", 這罪過應該不小吧.
但大統混油案, 這個高老闆的棉仔油, 報載每日 15cc, 一年左右即可能失去生育能力, 據說國軍與各學校營養午餐已經吃了多年, 外面自助餐為了成本, 相信也是買這種便宜油吧, 您說, 問題大不大? 呵呵, 這十年內服役的, 讀中小學的, 十年後會不會發現生不出小孩? 不孕率節節高升?
現在獨子這麼多, 那高老闆您斷人子嗣的能耐, 比老蔣要厲害多了啊!
看看 YAHOO 這篇新聞, 就知道高老闆能躺著賺這麼多年, 沒有達官貴人壓陣, 這奸商能呼攏 GMP 與食品檢驗員這麼多年嗎?

高振利「關係」好 馬以南、蔡令怡站台剪綵

門當戶對

現在是自由戀愛時代, 誰還會再談 "門當戶對" 與 "媒妁之言" 呢? 今天 YAHOO 新聞這則 "婚姻人生大事 魏應充親挑女婿媳婦", 頂新大老闆自有其復古看法, 證諸現時學校裡因父母離婚而單親的小朋友越來越多 (學校會要求填寫家庭狀況), 自由戀愛是否變成自由亂愛? 但現代父母幾乎都採美式 "我完全尊重孩子的決定", 然後就坐等隔代教養的機會, 這不是社會底層才有的事, 連達官貴人的子女也是如此. 魏董的看法我完全認同, 節錄如下 :

"兒女娶嫁「家風」很重要,大約從孩子國中時期,平常就要灌輸孩子正確的擇偶觀念,並透露了挑媳婦和女婿的小撇步以及觀察細節。他說,挑媳婦要去對方家裡,看看廚房、衛浴等家庭空間乾不乾淨,女方在家懂不懂得幫忙父母做家事,幫長輩倒茶;挑女婿同樣要先觀察家風,至對方家觀察父母相處模式,男方學歷和女方不能差太多。"

為人父母現在若是一派輕鬆, 老來可能還要顧孫子, 那就不輕鬆了.


2013年10月21日 星期一

關於 SPA (Single Page Web Applications)

今天看到 Manning 今年的新書 "Single Page Web Applications", 突然眼睛一亮, 這不就是我現在做的事嗎? 就是使用 HTML5+jQuery UI 打造只有一個 HTML 檔的網頁應用程式? 稍微翻了一下, 卡好, 代寄毋係憨人想的哈尼甘丹啦! 這本書是舊金山大學教授 Mikowski 多年打造的一個專案, 企圖以 MVC 架構建構一個從頭 (SERVER) 到尾 (CLIENT) 都使用 Javascript 的單頁應用程式解方案, 將傳統應用程式使用經驗複製到網頁應用中來, 真的沒有想像中簡單. 伺服端用的是 NodeJS, 一個出色的 Javascript 伺服主機, 資料庫用的是 MongoDB.  原作者的 SPA 簡報可在 Youtube 看到 :

# Single Page Web Applications: JavaScript End-to-End
# Adventures in Single Page Applications

但是, 並非每一種應用都適合採用 SPA, 因為 :

  1. 架構複雜, 維護與學習不易
  2. 搜尋引擎無法擷取頁面內容, 影響 SEO

詳見阿舍的 SPA 評論, 他的觀點我完全認同.

阿舍的隨手記記、隨手寫寫...

CSS 中的 overflow:hidden 與 clear:both 怎麼用

用 CSS 來排版面一直是我的弱點, 我還是喜歡用表格來排版, 雖然很土, 但是直觀又有效. 對於急於看到成果的專案而言, 搞了半天 CSS 還是歪七扭八, 不如用表格一招打死.
然而 HTML5 時代若還是堅持表格, 不精通 CSS 是無法 "上少林寺" 的. 特別是排版常用的 float, overflow, clear 這三個屬性, 常常搞到發瘋, 怎麼試就是歪七扭八. 下面這篇文章點出了三者令人混淆之處, 只是說法有點 "黃".

全面闡述overflow:hidden屬性

2013年10月20日 星期日

Win 8.1 操作摘要

家中客廳的聯想電腦終於由 Win 8 順利升級為 8.1, 開始鍵回來了, 確實方便不少. 但對於熟悉 XP 多年的我而言, 要習慣用 Win 8 介面實在需要一些時間. 以下摘要一些常用小秘訣 :
  1. 怎麼關機 ?
    聽說關機名列 Win 8 最罵第一名. 就算你使出 Windows 萬年不變的 Ctrl+Alt+Del, 很抱歉, 沒有關機了, 最多只有登出. 正常是把滑鼠移到螢幕右下角, 螢幕右邊框就會滑出透明選單, 點最下面那個齒輪狀的 "設定", 就會看到 "開啟/關閉" 的電源按鈕, 按下去就可以關機了.
    快捷法 : 同時按鍵盤上的微軟國旗鍵 [Win] + i, 就會出現 "開啟/關閉" 的電源按鈕了. 或者用 [Win] + X 也可以, 見第三項.
  2. 如何切換磚塊/傳統介面 ?
    以前 8.0 要將滑鼠移到左下角才能切換, 現在 8.1 版在傳桌面模式下, 左下角就是微軟國旗, 點一下就回到磚塊模式, 在磚塊模式點一下桌面方塊, 就切回傳統桌面模式.
    快捷法 : 直接按鍵盤上的微軟國旗鍵 [Win], 就可以在兩種模式切來切去.
  3. 檔案總管與控制台在哪裡 ?
    跟叫出關機按鈕過程一樣, 在齒輪 "設定" 選單最上面就可以看到 "控制台".
    快捷法 : 同時按鍵盤上的微軟國旗鍵 [Win] + X, 左下角就會出現一張選單, 裡面就有 "控制台" 跟 "檔案總管" (還有關機!).
只要會這三招, 就可以像回到 XP 時代一樣, 馬上就可以上工了.

其他 :
  1. 如何設定螢幕保護?
    Win 8 的螢幕保護已經不能在畫面內容中設定, 而是要把滑鼠移到螢幕右下角, 在右邊框滑出的選單中點選 "搜尋", 然後輸入搜尋字串 "螢幕保護裝置", 點選 "開啟或關閉螢幕保護裝置", 就會出現像以前 XP 時代的畫面內容設定了. 參見 : 微軟網站.
  2. 怎樣打開好幾個檔案總管 ?
    整理電腦資料時, 通常要開啟數個檔案總管視窗, 方便檔案移動, 不用頻繁切換目錄. 但是點按釘選在工作列上的檔案總管時, 總是會叫出目前那唯一的檔案總管視窗, 而非產生第二個視窗, 這該怎麼辦?  只要按 [Win] + X, 點選 "檔案總管", 這樣就會另外開啟一個新視窗了.


(未完待續...)