網頁

2020年11月17日 星期二

手機 App 程式設計 _ AppInventor2 _ 語音行事曆,Clock、TinyDB、SpeechRecognizer、TextToSpeech 元件的應用

(2022/04/09 修改)  

題目

  1. 設計一個行事曆,可選定日期,「新增」、「修改」、「刪除」該日期的工作項目。
  2. 可刪除選定日期的所有工作項目,要有「確認刪除」的對話方塊。
  3. 可刪除整個行事曆,要有「確認刪除」的對話方塊 。
  4. 可連結到中央氣象局看氣象。
  5. 輸入工作項目,除了可用文字方塊輸入,也提供語音輸入。
  6. 工作項目可語音播放。

執行畫面

選擇日期:
新增:
修改:

刪除選定日期資料:
清空行事曆:
氣象:

素材

本 app的 icon (圖示),可自己繪製或網路搜尋。
在Google 輸入關鍵字,如  calendar icon , 選擇 「圖片」,可找到相關的小圖示。
找到圖片,按下去,再按右鍵,選「另存圖片」,就可使用。但要注意著作財產權。

相關網站

App Inventor TW 中文學習網 http://www.appinventor.tw/

進入 Appinventor 

Google 輸入 appinventor 。選 「MIT App Inventor」。
選 「Create Apps」。

開新專案(project)

My projects / Start new project 。

輸入專案的 名稱,如 calendar,按 「OK」鈕。
 專案的名稱只能使用大小寫字母、數字及「 _」符號,名稱的第一個字元必須是英文字母,不能使用中文字。

Designer (畫面編排)

Screen1(頁面或稱為畫面):
AppName:calendar,可以改成 「語音行事曆」(出現在手機上面的App名稱,可用中文)

Icon : 可以上傳1個 icon(圖示) (可選背景透明的圖示),此程式在手機上面的App 圖示。
按 「 Upload File」鈕。
按「選擇檔案」,選一個圖示,按「開啟」,再按「OK」鈕。

右邊Properties(屬性視窗) 往下拉,更改 Title 的值為:   語音行事曆 (原本為 Screen1)。


Screen1 元件相關屬性表

元件

類別

屬性

功能

Screen1

 

Title: 語音行事曆
A
ppName: calendar,可以改成 語音行事曆 (出現在手機上面的App名稱)

Icon : 可以上傳1icon圖示。

1Screen元件就是1個頁面(畫面)

HorizontalArrangement1

Layout(介面配置)

AlignHorizontal:Center(水平置中)AlignVertical:Center:2(垂直置中)

Width:Fill Parent,填滿父元件,自動填滿可用空間。HorizontalArrangement1的父元件為 Screen1

水平配置元件,讓裏面的元件可以水平對齊

DatePicker1

User Interface(使用者介面)

Text: 選擇日期

日期選擇器

Label_date

User Interface(使用者介面)

Text: (清空)

標籤

Button_voiceoutput

User Interface

Text: 語音播放

按鈕

HorizontalArrangement2

Layout

Width:Fill Parent

水平配置元件,讓裏面的元件可以水平對齊

TextBox_input

User Interface

Width:Fill Parent
Hint: 輸入工作項目 (提示文字)
Text:

文字方塊,可以輸入工作項目

Button_voiceinput

User Interface

Text:語音輸入

按鈕

HorizontalArrangement3

Layout

lignHorizontal:Center(水平置中)
AlignVertical:Center(垂直置中)

Width:Fill Parent

水平配置元件,讓裏面的元件可以水平對齊

Button_add

User Interface

Text:新增

按鈕

Button_modify

User Interface

Text:修改

按鈕

Button_delete

User Interface

Text:刪除

按鈕

Button_clearinput

User Interface

Text:清除輸入

按鈕

HorizontalArrangement4

Layout

lignHorizontal:Center(水平置中)
AlignVertical:Center(垂直置中)

Width:Fill Parent

水平配置元件,讓裏面的元件可以水平對齊

Button_deletedatedata

User Interface

FontSize:13
Text:刪除選定日期資料

按鈕

Button_clearall

User Interface

FontSize:13
Text:清空行事曆

按鈕

Button_weather

User Interface

FontSize:13
Text: 氣象

按鈕

ListView1

User Interface

Height: Fill Parent
Width:Fill Parent

清單檢視器

TinyDB1

Storage(儲存)

 

()資料庫

Notifier1

User Interface

 

對話框元件(有的稱為通知)

Clock1

Sensors(感測器)

 

時鐘元件

SpeechRecognizer1

Media(多媒體)

 

語音辨識器元件(可將語音變成文字)

TextToSpeech1

Media

 

文字轉換語音元件

Notifier_clearall

User Interface

 

對話框元件(有的稱為通知)

如何增加Screen?

按「Add Screen」(加入新的頁面)鈕,輸入新Screen的名稱,如 Screen2,按「OK」鈕。

如何切換Screen?


Screen2(頁面或稱為畫面):


Screen2 元件相關屬性表

元件

類別

屬性

功能

Screen2

 

Title:氣象

 

 

1Screen元件就是1個頁面(畫面)

HorizontalArrangement1

Layout(介面配置)

AlignVertical:Center:2(垂直置中)

Width:Fill Parent,填滿父元件,自動填滿可用空間。HorizontalArrangement1的父元件為 Screen1。 


水平配置元件,讓裏面的元件可以水平對齊

Button_back

User Interface

Text:上一頁

按鈕

Button_forward

User Interface

Text:下一頁

按鈕

Button_home

User Interface

Text:首頁

按鈕

Button_calendar

User Interface

Text:回到行事曆

按鈕

HorizontalArrangement2

Layout

Width:Fill Parent

水平配置元件,讓裏面的元件可以水平對齊

TextBox_url

User Interface

Width:Fill Parent
Hint:請輸入網址
T
ext:http://

文字方塊,可以輸入網址

Button_clear

User Interface

Text:清除網址

按鈕

Button_Go

User Interface

Text:Go

按鈕

WebViewer1

User Interface

Height:Fill Parent
Width:Fill Parent

HomeUrl:https://www.cwb.gov.tw/

網頁檢視器

Notifier1

User Interface

 

通知元件(有的稱為對話框)

完整  Blocks(拼塊,程式設計)

Screen1
----------------------------------------------------------------
說明:
從 Variables (變數),拉出 initialize global to此程式block(拼塊)。
將 name 改名為 :item_list。
global (全域變數)可用在程式中所有程序或是事件程序內。

從 Lists (清單),拉出 create empty list 此 block(拼塊),放在 initialize global item_list to 的後面。
設定  全域變數 item_list  (工作項目清單) 為空的list (清單) 。

從 Procedures (程序),拉出 to procedure do 此程式block(拼塊)。

將  procedure 改名為 :displaynodata,程序可為其它程序重複呼叫。
displaynodata  此程序的功能 :  使用通知元件,顯示 選定的日期 "沒有工作項目"。
從 Notifier11 中,拉出  call Notifier11.ShowAlert     此 block(拼塊)。
從 Text(文字)類別中,拉出  join 此 block(拼塊),插入到 notice 的後面。
從 Label_date  中,拉出  Label_date.Text    此程式block(拼塊),插入到join 上面的缺口。
從 Text(文字)類別中,拉出  空字串 此 block(拼塊),插入到join 下面的缺口。
空子串內,輸入 ",這個日期沒有工作項目!" 此字串。
join 的意思,是將 Label_date.Text 的文字和 "沒有工作項目!" 合併在一起,即 選擇的日期那天沒有工作項目。
----------------------------------------------------------------

----------------------------------------------------------------
說明:
從 Procedures (程序),拉出 to procedure do 此程式block(拼塊)。

將  procedure 改名為 :get_data,程序可為其它程序重複呼叫。
get_data此程序的功能 : 從微資料庫取得某日期的工作項目。
從 Variables (變數),拉出 set  to此程式block(拼塊)。
選  item_list。
選 create_empty_list , 按右鍵,選「Duplicate」(複製),將複製出來的   create_empty_list,移到 set global item_list 的後面。

從 Control(控制)類別中,拉出 if then  此程式block(拼塊)。
從 Logic(邏輯)類別中,拉出 not  此程式block(拼塊)。

從 Text(文字)類別中,拉出  is empty   此程式block(拼塊),插入到 not 的後面。

從 TinyDB1 中,拉出  call GetValue    此程式block(拼塊),插入到 is empty 的後面。
從 Label_date  中,拉出  Label_date.Text    此程式block(拼塊),插入到 tag 的後面。

GetValue  :從TinyDB (微資料庫)中取得tag 標籤名稱的資料。如果 這個tag 標籤沒有資料,預設傳回空字串。
TinyDB微資料庫元件將資料儲存在行動裝置,下一次執行可再讀取出來。
TinyDB微資料庫是以一個標籤(tag)儲存一筆資料值(value), tag - value 成對儲存在資料庫。
如 tag: 2020/12/28 ,value: "國文小考","英文小考","看電影"
表示 2020/12/28 這天的工作項目為  : "國文小考","英文小考","看電影"


從 Variables (變數),拉出 set  to此程式block(拼塊)。
選  item_list。
選  call TinyDB1.GetValue , 按右鍵,選「Duplicate」(複製),將複製出來的 call TinyDB1.GetValue,移到 set global item_list 的後面。

如果 傳回值不是空字串 (表示有將選定的日期存在 TinyDB ),就取出此日期的工作項目清單,再設定給   item_list 此清單變數。

從 Control(控制)類別中,拉出 if then  此程式block(拼塊)。
從 Lists (清單),拉出 is list  empty? list 此 block(拼塊),放在 if then   的if  後面。
從 Variables (變數),拉出 get 此block(拼塊)。

get 此 block,選 global item_list 此變數,拉到  is list  empty? list 此 block 的後面。
從 Procedures (程序),拉出 call displaynodata 此程式block(拼塊),放在 then 的後面。
如果 item_list 是空的清單,就呼叫  displaynodata 此程序。
從 ListView1  中,拉出  set ListView1.Elements to 和 set  ListView1.SelectionIndex to   這2個block(拼塊),插入到 get_data 此程序內,如下:


選  get global item_list , 按右鍵,選「Duplicate」(複製),將複製出來的 get global item_list,移到  set ListView1.Elements to 的後面。
設定 ListView1 (清單檢視器)內的元素為  item_list 此清單內容。
從 Math(數值)類別中,拉出 0 此 block(拼塊),插入到 set  ListView1.SelectionIndex to 的後面 。
 ListView1.SelectionIndex, 使用者所選擇項目的索引值,由1開始。如果未選擇任何項目,傳回值為 0 。


註:程式改成下列的寫法, 如果 label_date 這個日期沒有工作項目, 會傳回空字串。因為 item_list 此清單變數不能接受 空字串,會造成執行錯誤。


可將程式改為如下,正確而且更精簡:
----------------------------------------------------------------
----------------------------------------------------------------
說明:
設定  item_list 此清單變數為空清單。
清除 輸入工作項目 此文字方塊的內容。
設定 ListView1 (清單檢視器)內的元素為  item_list 此清單變數。
設定  ListView1  未選擇任何項目。
----------------------------------------------------------------

----------------------------------------------------------------
說明:
StoreAndRefresh 此程序的功能如下:
將「 item_list 此清單變數的內容」儲存到TinyDB1 ,tag 標籤為 選定的日期。
設定 ListView1 (清單檢視器)內的元素為  item_list 此清單變數。
清除  輸入工作項目此文字方塊的內容。
設定  ListView1.SelectionIndex 為0,表示未選擇任何項目。
----------------------------------------------------------------
----------------------------------------------------------------
說明:
從 Sreen1 中,拉出  when Screen1.Initialize    此程式block(拼塊)。

When Screen1.initialize 的意思,當進入 Screen1此畫面(一開始執行此App 程式),要初始化的事件程序。

從 Label_date  中,拉出 set  Label_date.Text  to  此程式block(拼塊),插入到 When Screen1.initialize   的裏面。














從 Clock1  中,拉出 call Clock1.FormatDate    此程式block(拼塊),插入到 set  Label_date.Text   to 的後面。

pattern 的字串改為 yyyy/M/d  。
從 Clock1  中,拉出 call Clock1.Now    此程式block(拼塊),插入到 instant 的後面。


設定 Label_date.Text 選定的日期為 取出現在的日期,格式為 yyyy/M/d(年月日,如2020/11/17)。

呼叫 get_data 程序。

----------------------------------------------------------------
----------------------------------------------------------------
說明:
從 DatePicker1 中,拉出 when DatePicker1.AfterDateSet 此程式block(拼塊)。


DatePicker1.AfterDateSet,使用者從 日期選擇器 選好日期後。
選 set  Label_date.Text   to , 按右鍵,選「Duplicate」(複製),將複製出來的 set  Label_date.Text   to,移到 when DatePicker1.AfterDateSet 此程式block(拼塊)的裏面。



















選  call Clock1.FormatDate  ,按右鍵,選 Delete 3 Blocks ,刪除 call Clock1.FormatDate 。











從 Text(文字)類別中,拉出  join 此 block(拼塊),插入到 set  Label_date.Text   to 的後面。













從 DatePicker1 中,拉出 DatePicker1.Year 此程式block(拼塊),插入到 join 的上面缺口。
從 Text(文字)類別中,拉出  空字串 此 block(拼塊),插入到join 下面的缺口,並改成 /。














join 預設祇有2個參數,按 * 圖示,出現 string ,將 string  插入到 join 裏面,變成3個 string。即合併3個字串。
從 DatePicker1 中,拉出 DatePicker1.Month 此程式block(拼塊),插入到 join 下面的缺口。

按 * 圖示,出現 string ,將 string  插入到 join 裏面,變成4個 string。即合併4個字串。
選 /   此  block,按右鍵,選「Duplicate」(複製),將複製出來的 /    block,移到 join 下面的缺口。


按 * 圖示,出現 string ,將 string  插入到 join 裏面,變成5個 string。即合併5個字串。
從 DatePicker1 中,拉出 DatePicker1.Day 此程式block(拼塊),插入到 join 下面的缺口。








上面的程式的功能: 設定 Label_date.Text  (選定的日期) 為 從日期選擇器 選出的日期  年/月/日。
呼叫 get_data 程序。
----------------------------------------------------------------
----------------------------------------------------------------
說明:
 ListView1.AfterPicking 從 清單檢視器 挑選項目後。
設定  TextBox_input.Text 為 清單檢視器 選到的項目名稱。

 Button_add.Click,按了 Button_add (新增)此按鈕。
如果 TextBox_input.Text 為空字串,表示沒有輸入工作項目,出現 "請輸入工作內容!"的通知訊息,
否則把  TextBox_input.Text 加入(add) 到 item_list 此清單內。
呼叫 StoreAndRefresh 程序。
----------------------------------------------------------------
----------------------------------------------------------------
說明:
 Button_modify.Click,按了  Button_modify(修改)此按鈕。
如果沒有從  ListView1  挑選項目,出現 "請選取工作項目!"的通知訊息,
否則使用 TextBox_input.Text 取代(replace)  item_list 此清單中被選取到的位置內容。
呼叫 StoreAndRefresh 程序。
----------------------------------------------------------------

----------------------------------------------------------------
說明:
 Button_delete.Click,按了  Button_delete(刪除)此按鈕。
如果  item_list 此變數為空的清單 , 出現 "沒有資料可刪除!"的通知訊息,
否則
 如果 ListView1.SelectionIndex=0 ( 表示  未選擇任何項目),則出現 "請選取資料!"的通知訊息,
 否則從   item_list 清單中 移除(remove)  從 清單檢視器選取的索引值對應的內容。
 ListView1.SelectionIndex  ,從清單檢視器選到的元素的索引值。

呼叫 StoreAndRefresh 程序。
----------------------------------------------------------------



----------------------------------------------------------------
說明:
 Button_deletedatedata.Click,按了  Button_deletedatedata(刪除選定日期資料)此按鈕。
如果 item_list 此清單變數的內容是空的(即該日期沒有工作項目),就呼叫 displaynodata 程序,
否則
顯示 可以選擇按鈕的對話框(或稱為 通知 )視窗。
訊息為: "確定要刪除" join  "選定日期" join  "的所有工作項目嗎?" 。 join : 字串連接。
標題:刪除工作項目。
按鈕1(buttonText1)的文字為 :確定。按鈕2(buttonText2)的文字為 :取消。
cancelable 設為 false 表示不會有cancel 按鈕 ,因為已有 按鈕2 。
----------------------------------------------------------------
----------------------------------------------------------------
說明:
當使用者選擇某個按鈕,將會觸發 AfterChooseing() 的事件。
如果 choice (選擇)的值為 "確定" (使用者按了「確定」鈕),然後 清除TinyDB1內  Label_date.Text 此標籤,就是把 Label_date.Text此日期的標籤和其工作項目清除。
ClearTag :清除標籤
----------------------------------------------------------------
--------------------------------------------------------
說明:
 Button_clearall.Click,按了  Button_clearall(清空行事曆)此按鈕。
出現 選擇對話框的視窗。
訊息為: "確定要刪除整個行事曆的內容嗎?" 。
標題:刪除行事曆。
按鈕1(buttonText1)的文字為 :確定。按鈕2(buttonText1)的文字為 :取消。

如果按了「確定」鈕 然後    清除 TinyDB1 內儲存的所有資料。
TinyDB1.ClearAll : 清除所有TinyDB內儲存的資料。
----------------------------------------------------------------
------------------------------------
說明:
當 Button_voiceinput (語音輸入)按鈕被按後,呼叫 SpeechRecognizer (語音辨識元件) 以GetText 方法啟動語音辨識功能。
SpeechRecognizer 語音辨識元件。將語音傳給伺服器進行辨識,再將結果傳回。行動裝置收到結果會觸發 AfterGettingText 事件,將辨識結果存於 result 此區域變數中。
TextBox_input.Text 為原來的  TextBox_input.Text join  result(辨識結果)
 ----------------------------------------------------------------

------------------------------------
說明:
當 Button_voiceoutput (語音播放)按鈕被按後,
如果 item_list 此清單變數的內容是空的(即該日期沒有工作項目),就呼叫 displaynodata 程序,
否則
如果  ListView1(清單檢視器) 有被選取 (即索引值 > 0 ) ,然後 
     呼叫  TextToSpeech(文字變語音)元件 Speak 方法,將ListView1 選到的項目以語音輸出。
否則
  呼叫  TextToSpeech(文字變語音)元件 Speak 方法,將 item_list 清單中的每一個項目以語音輸出。

TextToSpeech(文字變語音)元件,把文字轉換為語音,由行動裝置發出聲音。
list to csv row :將清單轉換為CSV表格中的列row,並以CSV(comma-separated value)格式回傳。
 ----------------------------------------------------------------
------------------------------------
說明:
從 Button_weather  中,拉出 when Button_weather.Click   此程式block(拼塊)。

從 Control (控制),拉出 open another screen screenName  此程式block(拼塊),插入到 when Button_weather.Click 裏面。

從 Text(文字)類別中,拉出  空字串 此 block(拼塊),screenName的後面,並改成   Screen2。
如果 Button_weather(氣象)此按鈕被按後,開啟另1 個 Screen2 頁面。
----------------------------------------------------------------

Screen2

如何切換  Screen

在左上方,選 新的Screen,如  Screen2。

Screen2 的程式拼塊 和 本部落格的另一篇文章類似,就不再說明。 



------------------------------------
說明:
close screen,關閉目前 screen頁面。 
---------------------------------------------------------



如何下載 apk 到自己的手機 

Build/App (provide QR code for .apk)
產生 此 apk  的 QR code , 使用手機能辨識  QR code 的程式,如LINE,可下載此 apk程式到手機上,再安裝。

使用 Line 「加入好友」的功能,按 「行動條碼」。

按上面的連結,就可下載 寫好的 apk。

按下面的「下載」。

再按 「開啟」,「安裝」,安裝apk。

如何下載 apk 到自己的電腦

Build/App (save .apk to my computer)

電腦會自動下載已編譯好的 apk 檔。
從  BlueStacks  此模擬器 開啟 apk,就可執行此 apk。

儲存專案

My Projects /Save project ,將專案儲存到 Mit 伺服器上。

完成作品:calendar.apk


註:如果登入Windows 的帳號不具有管理者的權限,在BlueStacks執行此App 程式會沒反應,所以選 BlueStacks時,要按右鍵,選「以系統管理員身分執行」,開啟 BlueStacks。

程式改良

如果 日期選擇器選擇日期的方式,要使用下列日曆的方式選擇,怎麼做?

 選 Screen1, 把   Theme 的屬性值由  Classic,改成 Device Default。
PrimaryColor  是藍色 可改成 Gray(灰)色。
Theme 的屬性值 如果 改成 Dark,日曆的背景顏色為黑色,結果如下:
如果在手機上執行,原有的版面設計會造成 按鈕的字變成直的,很不好看,所以在 設計版面時,要重新調整。
Screen1:
Screen2:


手機執行畫面: