Dialogs and feedback (Dialog များနဲ့ user ကို အသိပေးခြင်း)

IA (Internal Assessment: IB သင်တန်းမှာ ကျောင်းသားတစ်ယောက်ချင်း ကိုယ်တိုင် တည်ဆောက်ရပြီး ကျောင်းက ဆရာက အမှတ်ပေးတဲ့ အပိုင်း) အတွက် tool တွေပါ၊ စာမေးပွဲ ခေါင်းစဉ် မဟုတ်ပါဘူး။ ဒါတွေက ကိုယ့် IA app နဲ့ ကိုက်အောင် ပြင်သုံးဖို့ JavaFX (Java နဲ့ desktop app တည်ဆောက်တဲ့ library) ပုံစံတွေပါ။ ဒီထဲက ဘာကိုမှ စာမေးပွဲမှာ မမေးပါဘူး။ IA က ကိုယ်တိုင် လုပ်ထားတဲ့ အလုပ် ဖြစ်ရလို့ message တွေနဲ့ လုပ်ဆောင်ချက်တွေကို ကိုယ့် project နဲ့ ကိုက်အောင် ပြောင်းပါ။

ဒီစာမျက်နှာက user ကို ပြန်ပြောတာ အကြောင်းပါ: user ကို တစ်ခုခု အသိပေးတာ၊ အန္တရာယ် ရှိနိုင်တဲ့ အလုပ် မလုပ်ခင် မေးတာ၊ အဓိပ္ပာယ် မရှိတဲ့ input (program ထဲ ထည့်ပေးတဲ့ ဒေတာ) ကို ကိုင်တွယ်တာ တို့ပါ။

ဒီ cookbook ကို ပထမဆုံး ဖတ်တာလား။ Start here: how every recipe fits together (ဒီမှာ စပါ: recipe တိုင်း ဘယ်လို ချိတ်ဆက်ထားလဲ) ကို အရင် ဖတ်ပါ။ အဲဒီ စာမျက်နှာက ကိုယ် ပြင်ရမယ့် နေရာ နှစ်ခုကို ရှင်းပြထားပြီး recipe (ချက်ချင်း ယူသုံးလို့ရတဲ့ code နမူနာ) တိုင်း အားကိုးရတဲ့ fx:id (screen ပေါ်က button၊ text box စတာတွေကို code ထဲက variable နဲ့ ချိတ်တဲ့ နာမည်) နဲ့ onAction (button နှိပ်ရင် run မယ့် method ကို သတ်မှတ်တဲ့ setting) ချိတ်ဆက်မှုတွေကိုလည်း ရှင်းပြထားပါတယ်။


User ကို တစ်ခုခု အသိပေးခြင်း

ဒါက ဘာလုပ်ပေးလဲ: OK button ပါတဲ့ pop-up (main window ရှေ့မှာ ပွင့်လာတဲ့ သီးခြား window) message အသေးလေး တစ်ခုကို ပြပါတယ်။ ပြီးရင် program ဆက်မသွားခင် user က အဲဒါကို ပိတ်တဲ့အထိ စောင့်ပါတယ်။

ကိုယ့် IA မှာ ဘယ်အခါ သုံးမလဲ: save လုပ်တာ အောင်မြင်ကြောင်း အတည်ပြုတဲ့အခါ၊ ရှာတာ ဘာမှ မတွေ့ကြောင်း ပြောတဲ့အခါ ဒါမှမဟုတ် အလုပ်တစ်ခု ပြီးသွားကြောင်း user ကို ပြောတဲ့အခါ သုံးပါ။ တစ်ကြောင်းတည်း message နဲ့ လုံလောက်တဲ့ ဘယ်နေရာမှာမဆို သုံးလို့ ရပါတယ်။

SceneBuilder ထဲမှာ (layout): ဒီ recipe အတွက် SceneBuilder (FXML layout ကို ပုံနဲ့ မြင်ရင်း ပြင်တဲ့ editor) ထဲက layout (control တွေကို screen ပေါ်မှာ စီစဉ်ထားပုံ) မှာ dialog (message ပြဖို့ ဒါမှမဟုတ် user ကို မေးဖို့ ပေါ်လာတဲ့ window အသေး) ကို ပေါ်စေမယ့် button တစ်ခုကလွဲပြီး ဘာမှ ထည့်စရာ မလိုပါဘူး။ Button တစ်ခု ထည့်ပြီး သူ့ onAction ကို handleSave လို့ သတ်မှတ်ပါ (ဒါမှမဟုတ် ဒီ လုပ်ဆောင်ချက်အတွက် ရှိပြီးသား button ကို ပြန်သုံးပါ)။ Dialog ကိုယ်တိုင်ကိုတော့ code ထဲမှာ ဖန်တီးပါတယ်။

<Button text="Save" onAction="#handleSave" />

Controller (user လုပ်တာတွေကို ကိုင်တွယ်ပြီး Model နဲ့ screen တွေကို ချိတ်ပေးတဲ့ class) ထဲမှာ (.java file):

Import (တခြားနေရာက code ကို ယူသုံးမယ်လို့ ကြေညာခြင်း) line များ:

import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;

Controller ထဲက method (သီးခြား အလုပ်တစ်ခု လုပ်ပေးတဲ့ code အပိုင်း):

@FXML
private void handleSave() {
    // your IA logic here: do the actual work (save the data, run the task)
    saveData();

    Alert info = new Alert(AlertType.INFORMATION);
    info.setTitle("Saved");
    info.setHeaderText(null);                    // null removes the bold banner line
    info.setContentText("Your changes have been saved.");
    info.showAndWait();
}

ကိုယ်ပိုင် logic (ဘာလုပ်မလဲ ဆုံးဖြတ်တဲ့ code) ကို ဘယ်မှာ ထည့်ရမလဲ: // your IA logic here (ကိုယ့် IA ရဲ့ logic ကို ဒီမှာ ထည့်ပါ) ကို အောင်မြင်ကြောင်း ပြတဲ့ dialog မပေါ်ခင် ပြီးရမယ့် လုပ်ဆောင်ချက်နဲ့ အစားထိုးပါ။ အဲဒီ line ရဲ့ ပတ်လည်က dialog code ကိုတော့ ပြန်သုံးလို့ ရပါတယ်။

ကိုယ့် project နဲ့ ကိုက်အောင် ပြင်ပါ:

  • ဖြစ်သွားတာနဲ့ ကိုက်အောင် title (ခေါင်းစဉ်) နဲ့ setContentText ထဲက message ကို ပြောင်းပါ။
  • setHeaderText(null) က တစ်ကြောင်းတည်း ပါတဲ့ ရှင်းရှင်းလင်းလင်း dialog ကို ပေးပါတယ်။ Message အပေါ်မှာ စာလုံးထူ ခေါင်းစဉ် လိုချင်ရင် null (ဘာ object ကိုမှ မညွှန်းတဲ့ တန်ဖိုး) အစား string (စာသား) အတိုလေး တစ်ခု ပေးပါ။
  • Message က သတိပေးချက် ဒါမှမဟုတ် မအောင်မြင်မှု ဖြစ်တဲ့အခါ icon (သင်္ကေတ ပုံလေး) ကို ပြောင်းဖို့ AlertType.INFORMATION အစား AlertType.WARNING ဒါမှမဟုတ် AlertType.ERROR ကို သုံးပါ။

သတိထားရမယ့် အချက်များ:

  • onAction မှာ ပေးထားတဲ့ နာမည်နဲ့ method (handleSave) က controller ထဲမှာ ရှိရပါမယ်။ မရှိရင် screen က load မဖြစ်ပါဘူး။
  • showAndWait() က user က dialog ကို ပိတ်တဲ့အထိ program ကို ရပ်စောင့်ခိုင်းပါတယ်၊ များသောအားဖြင့် လိုချင်တာလည်း ဒါပါပဲ။ Loop (ထပ်ခါထပ်ခါ run တဲ့ code အပိုင်း) ရှည်ရှည် တစ်ခုထဲကနေ ခေါ်ရင် loop တစ်ပတ်ပတ်တိုင်း user က OK ကို နှိပ်ရပါလိမ့်မယ်။ ဒါကြောင့် ဒီ dialog တွေကို တစ်ကြိမ်တည်း အသိပေးရမယ့် အခိုက်အတန့်တွေအတွက်ပဲ သုံးပါ၊ output (program က ထုတ်ပြတဲ့ ရလဒ်) အများကြီးကို ဆက်တိုက် ပြဖို့ မသုံးပါနဲ့။

တွဲသုံးလို့ရတဲ့ recipe များ: ပြန်ပြင်လို့ မရတဲ့ အလုပ် မလုပ်ခင် user ကို မေးခြင်း၊ မှားနေတဲ့ input ကို ဖမ်းပြီး ရှင်းပြခြင်း၊ Save and load text (စာသားကို save လုပ်ခြင်းနဲ့ ပြန် load လုပ်ခြင်း)။


ပြန်ပြင်လို့ မရတဲ့ အလုပ် မလုပ်ခင် user ကို မေးခြင်း

ဒါက ဘာလုပ်ပေးလဲ: confirmation dialog (အတည်ပြုချက် တောင်းတဲ့ dialog) တစ်ခု ပြပြီး user က OK ကို နှိပ်မှသာ အန္တရာယ် ရှိတဲ့ လုပ်ဆောင်ချက်ကို run ပါတယ်။ မတော်တဆ နှိပ်မိလို့ ဒေတာ ပျက်သွားတာကို ကာကွယ်ပေးပါတယ်။

ကိုယ့် IA မှာ ဘယ်အခါ သုံးမလဲ: record (အချက်အလက် အများကြီး စုထားတဲ့ ဒေတာ တစ်ခု) တစ်ခုကို ဖျက်တဲ့၊ list ကို ရှင်းတဲ့၊ form (ဒေတာ ဖြည့်ရတဲ့ အကွက်တွေ ပါတဲ့ အပိုင်း) ကို မူလအတိုင်း ပြန်ထားတဲ့ ဒါမှမဟုတ် file ကို overwrite (ရှိပြီးသား content ကို ဖျက်ပြီး အသစ် ရေးခြင်း) လုပ်တဲ့ ဘယ် button မှာမဆို သုံးပါ။ User က အရင် အတည်ပြုရအောင် အဲဒီ လုပ်ဆောင်ချက်ကို ဒီ code နဲ့ ဝိုင်းထားပါ။

SceneBuilder ထဲမှာ (layout): လုပ်ဆောင်ချက်ကို စတင်ပေးမယ့် button တစ်ခု လိုပါတယ်။ Button တစ်ခု ထည့်ပြီး btnDelete လို fx:id တစ်ခု ပေးပါ၊ ပြီးရင် သူ့ onAction ကို handleDelete လို့ သတ်မှတ်ပါ။ အတည်ပြုချက် တောင်းတဲ့ window ကိုယ်တိုင်ကို code ထဲမှာ ဖန်တီးလို့ ဒီမှာ တခြား ဘာမှ ထည့်စရာ မလိုပါဘူး။

<Button fx:id="btnDelete" text="Delete" onAction="#handleDelete" />

Controller ထဲမှာ (.java file):

Import line များ:

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import java.util.Optional;

Controller ထဲက method:

@FXML
private void handleDelete(ActionEvent event) {
    Alert confirm = new Alert(AlertType.CONFIRMATION);
    confirm.setTitle("Please confirm");
    confirm.setHeaderText(null);
    confirm.setContentText("Are you sure you want to delete this item?");

    Optional<ButtonType> result = confirm.showAndWait();
    if (result.isPresent() && result.get() == ButtonType.OK) {
        // your IA logic here: the action that cannot be undone
        removeSelectedItem();
    }
    // If the user clicked Cancel, nothing happens.
}

ကိုယ်ပိုင် logic ကို ဘယ်မှာ ထည့်ရမလဲ: user အတည်ပြုပြီးမှသာ run အောင် လုပ်ဆောင်ချက်ကို if block ထဲက // your IA logic here နေရာမှာ လုပ်ပါ။ ကိုယ့် app ရဲ့ logic ထည့်ရမယ့် နေရာက အဲဒီမှာပါ၊ recipe ရဲ့ ကျန်တဲ့ အပိုင်းကို ပြန်သုံးလို့ ရပါတယ်။

ကိုယ့် project နဲ့ ကိုက်အောင် ပြင်ပါ:

  • setContentText ထဲက message ကို ကိုယ့်ရဲ့ လုပ်ဆောင်ချက်ကို ဖော်ပြတဲ့ message အဖြစ် ပြောင်းပါ။
  • removeSelectedItem() ကို ကိုယ့်ရဲ့ အန္တရာယ် ရှိတဲ့ လုပ်ဆောင်ချက် ဘာပဲဖြစ်ဖြစ် အဲဒါနဲ့ အစားထိုးပါ။
  • if စစ်ချက်ကို ရှိတဲ့အတိုင်း အတိအကျ ထားပါ။ ကာကွယ်မှု အလုပ်လုပ်အောင် လုပ်ပေးတာ အဲဒီ အပိုင်းပါ။

သတိထားရမယ့် အချက်များ:

  • onAction မှာ ပေးထားတဲ့ method နာမည် (handleDelete) က controller ထဲမှာ ရှိရပါမယ်။ မရှိရင် screen က load မဖြစ်ပါဘူး။ Layout ထဲက fx:id btnDelete ကတော့ ကိုယ့် code က အဲဒီ button ကို သုံးမှပဲ ကိုက်တဲ့ @FXML field (FXML ထဲက control နဲ့ ချိတ်ထားတဲ့ controller ထဲက variable) လိုပါတယ်၊ ဒီ recipe ရဲ့ code က အဲဒီ button ကို မသုံးပါဘူး။
  • showAndWait() က Optional (တန်ဖိုး တစ်ခု ပါနိုင်သလို ဗလာလည်း ဖြစ်နိုင်တဲ့ object) တစ်ခုကို return (ရလဒ်အဖြစ် ပြန်ပေး) လုပ်ပါတယ်။ Dialog ကို ပုံမှန် မဟုတ်တဲ့ နည်းနဲ့ ပိတ်လိုက်ရင် အဲဒီ Optional က ဗလာ ဖြစ်နိုင်ပါတယ်။ isPresent() စစ်ချက်က အဲဒီ အခြေအနေကို ကိုင်တွယ်ပေးလို့ ဖယ်မပစ်ပါနဲ့။
  • တကယ့် လုပ်ဆောင်ချက်ကို if block ရဲ့ နောက်မှာ မထားဘဲ if block ထဲမှာ ထားပါ။ နောက်မှာ ထားရင် user က Cancel နှိပ်တဲ့အခါမှာတောင် run သွားပါလိမ့်မယ်။

တွဲသုံးလို့ရတဲ့ recipe များ: Find out which row the user clicked (user နှိပ်လိုက်တဲ့ row ကို သိအောင် လုပ်ခြင်း)၊ User ကို တစ်ခုခု အသိပေးခြင်း၊ Save and load text (စာသားကို save လုပ်ခြင်းနဲ့ ပြန် load လုပ်ခြင်း)။


မှားနေတဲ့ input ကို ဖမ်းပြီး ရှင်းပြခြင်း

ဒါက ဘာလုပ်ပေးလဲ: text field (စာ တစ်ကြောင်း ရိုက်ထည့်တဲ့ box) ထဲကနေ ဂဏန်း တစ်ခုကို ဖတ်ကြည့်ပါတယ်။ စာသားက ဂဏန်း မဟုတ်ရင် crash (program ရုတ်တရက် ပျက်ပြီး ရပ်သွားခြင်း) မဖြစ်စေဘဲ ရှင်းလင်းတဲ့ message တစ်ခု ပြပြီး cursor (စာရိုက်မယ့် နေရာကို ပြတဲ့ အမှတ်အသား) ကို field ဆီ ပြန်ပို့ပါတယ်။

ကိုယ့် IA မှာ ဘယ်အခါ သုံးမလဲ: user က ပမာဏ၊ အသက်၊ ဈေးနှုန်း ဒါမှမဟုတ် အမှတ်ကို ရိုက်ထည့်ပြီး ကိုယ့် code က Integer.parseInt ဒါမှမဟုတ် Double.parseDouble နဲ့ ဂဏန်းအဖြစ် ပြောင်းတဲ့ ဘယ် field မှာမဆို သုံးပါ။ ဒီလို မစစ်ရင် စာလုံး တစ်လုံး ရိုက်ထည့်ထားတာ ဒါမှမဟုတ် field အလွတ် ဖြစ်နေတာက exception (program run နေစဉ် ဖြစ်တဲ့ အမှား) ကို throw (exception ဖြစ်ကြောင်း အချက်ပြ) လုပ်ပါလိမ့်မယ်။

SceneBuilder ထဲမှာ (layout): user စာရိုက်ထည့်မယ့် text field (fx:id txtQuantity)၊ error တွေ ပြမယ့် label (စာသား ပြတဲ့ control၊ fx:id lblError) နဲ့ လုပ်ဆောင်ချက်ကို run မယ့် button (onAction handleAdd) ကို ထည့်ပါ။

<TextField fx:id="txtQuantity" />
<Label fx:id="lblError" textFill="red" />
<Button text="Add" onAction="#handleAdd" />

Controller ထဲမှာ (.java file):

Import line များ:

import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;

Controller ထဲမှာ:

@FXML private TextField txtQuantity;
@FXML private Label lblError;

@FXML
private void handleAdd() {
    try {
        int quantity = Integer.parseInt(txtQuantity.getText().trim());
        lblError.setText("");                    // clear any old error
        // your IA logic here: use the validated number
        addItems(quantity);
    } catch (NumberFormatException e) {
        lblError.setText("Please enter a whole number.");
        txtQuantity.requestFocus();              // put the cursor back so they can fix it
    }
}

ကိုယ်ပိုင် logic ကို ဘယ်မှာ ထည့်ရမလဲ: // your IA logic here လို့ မှတ်ထားတဲ့ line ပါ။ အဲဒီ line က input က မှန်ကန်တဲ့ ဂဏန်း ဖြစ်မှသာ run ပါတယ်။ စာသားကို ဂဏန်း ပြောင်းတာ၊ error message နဲ့ cursor ကို field ဆီ ပြန်ပို့တာတွေက ပြန်သုံးလို့ရတဲ့ wiring (control တွေနဲ့ code ကို ချိတ်ဆက်ပေးတဲ့ အသင့် code) ပါ။

ကိုယ့် project နဲ့ ကိုက်အောင် ပြင်ပါ:

  • Error message ကို ကိုယ် မျှော်လင့်ထားတဲ့ တန်ဖိုး အမျိုးအစားကို ဖော်ပြတဲ့ message အဖြစ် ပြောင်းပါ။
  • ဈေးနှုန်း ဒါမှမဟုတ် တိုင်းတာထားတဲ့ တန်ဖိုးတွေအတွက် Double.parseDouble ကို အစားထိုး သုံးပါ။
  • lblError က field အနားမှာ ရှိတဲ့ screen ပေါ်က Label တစ်ခုပါ။ Pop-up ကို ပိုကြိုက်ရင် အဲဒီအစား AlertType.ERROR dialog တစ်ခုကို ပြလို့ ရပါတယ်။

သတိထားရမယ့် အချက်များ:

  • fx:id တန်ဖိုးတွေ (txtQuantity၊ lblError) က @FXML field နာမည်တွေနဲ့ ကိုက်ရပါမယ်။ မကိုက်ရင် screen က load ဖြစ်ပေမဲ့ အဲဒီ field တွေက null ဖြစ်နေပြီး Add ကို နှိပ်တဲ့အခါ error ဖြစ်ပါလိမ့်မယ်။ handleAdd ကတော့ controller ထဲမှာ ရှိရပါမယ်၊ မရှိရင် screen က load မဖြစ်ပါဘူး။
  • ယေဘုယျ Exception ကို မဖမ်းဘဲ NumberFormatException (ဂဏန်း မဟုတ်တဲ့ စာသားကို ဂဏန်း ပြောင်းလို့ ဖြစ်တဲ့ exception) ကို သီးသန့် ဖမ်းပါ။ Exception အားလုံးကို ဖမ်းရင် တကယ့် bug (code ထဲက အမှား) တွေကို ဖုံးကွယ်ထားမိပါတယ်။
  • Field အလွတ်က စာလုံး ရိုက်ထည့်ထားတာနဲ့ exception တစ်မျိုးတည်းကို throw လုပ်လို့ ဒီ catch တစ်ခုတည်းက အခြေအနေ နှစ်ခုလုံးကို ကိုင်တွယ်ပေးပါတယ်။
  • ဒါက input validation (ထည့်ပေးတဲ့ ဒေတာ မှန်မမှန် စစ်ခြင်း) ပါ၊ form တွေမှာ သုံးတဲ့ အယူအဆ အတိုင်းပါပဲ။ မှားတဲ့ input ကို ရိုက်ထည့်လို့တောင် မရအောင် Allow only numbers in a field (field ထဲမှာ ဂဏန်းပဲ ရိုက်ခွင့်ပေးခြင်း) နဲ့ တွဲသုံးပါ။

တွဲသုံးလို့ရတဲ့ recipe များ: Allow only numbers in a field (field ထဲမှာ ဂဏန်းပဲ ရိုက်ခွင့်ပေးခြင်း)၊ Turn a control on or off (control ကို ဖွင့်ခြင်း ဒါမှမဟုတ် ပိတ်ခြင်း)၊ User ကို တစ်ခုခု အသိပေးခြင်း။