Monday, May 21, 2012 : Article > Blackberry User : Register | Login
บทความ
Webboard
วีดีโอ
บทความจากเพื่อนๆ Guru
30
“UI มหาสนุก”ตั้งชื่อให้ดูครึกครื้นกันหน่อย แต่ก็น่าจะทำให้ทราบว่าวันนี้เราจะมาเรียนรู้เกี่ยวกับพื้นฐานการเขียน User Interface ซึ่งแน่นอนว่า Application ส่วนใหญ่มีส่วนติดต่อกับผู้ใช้งาน ดังนั้นเรื่องนี้ถือว่าสำคัญมาก

ส่วนประกอบของ BlackBerry UI
            Component เกี่ยวกับ UI ของ BlackBerry ถูกแบ่งออกเป็น 3 กลุ่มดังนี้
  1. Field : คือ control นั่นเอง เช่น TextField ,LabelFied หน้าที่ของ Fied คือแสดงผลและรอรับ Input ต่างๆจากผู้ใช้
  2. Manager :  ทำหน้าที่จัดการ layout ของ Field ในหน้าจอ    โดยที่ field แต่ละตัวสามารถอยู่ใน Manager เดียวเท่านั้น  จริงๆแล้ว Manager ก็เป็น subclass ของ field เช่นกัน นั่นหมายความว่าใน Manager สามารถบรรจุ Manager อื่นได้ด้วย ซึ่งจะถูกใช้ในการสร้าง UI ที่มีความซับซ้อน
  3. Screen : คือหน้าจอดังได้เคยอธิบายไปบ้างแล้วในเรื่อง “สวัสดี BlackBerrry”  มีหน้าที่จัดการ Layout ของ field รวมทั้ง Manager ด้วย

ลงมือสร้าง UIFun กันเลย
            บรรยายมาพอสมควรแล้ว ถ้าได้ลงมือเขียนจริงๆคงจะสนุกไม่น้อย
            ยังจำได้ไหม ถึงใครคนหนึ่ง  .. นั่นมันเพลง จำได้ไหมครับว่าเราต้องทำอะไรบ้างในการสร้าง Application ที่มี UI  ช่วยกันตอบ
  1. ต้องมีคลาส Application ขอตั้งชื่อว่า UIFunApplication
  2. ต้องมี MainScreen ให้ชื่อว่า UIFunMainScreen
เก่งมากครับสำหรับคนที่ให้ความร่วมมือ ทำเลยละนะ ใช้ความรู้เดิมเมื่อเสร็จแล้วได้โค้ดดังนี้

UIApplication

package com.mobiledevguru.uifun;
import net.rim.device.api.ui.UiApplication;
public class UIFunApplication extends UiApplication {
            public UIFunApplication() {
                        // TODO Auto-generated constructor stub
                        UIFunMainScreen screen = new UIFunMainScreen();
                        pushScreen(screen);
            }
            public static void main(String[] args) {
                        UIFunApplication app = new UIFunApplication();
                        app.enterEventDispatcher();
            }
}

MainScreen
package com.mobiledevguru.uifun;
import net.rim.device.api.ui.container.MainScreen;
public class UIFunMainScreen extends MainScreen {
            public UIFunMainScreen() {
                        // TODO Auto-generated constructor stub
            }
}

ออกแบบหน้าตาและการทำงาน

            ตัวอย่างโปรแกรมของเราจะจำลองการทำงานของ การ Login ซึ่งมี TextField สำหรับกรอก Username ,password  มี Dropdown ให้เลือก Domain   มี checkbox เพื่อกำหนดว่าต้องการให้ระบบจดจำ password หรือไม่ จากนั้นมี ปุ่ม Login และ Clear เพื่อให้เห็นภาพ ผมวาดให้ดูประมาณนี้นะครับ

รูปที่ 1

ก่อนจะลงมือเขียนผมจะบอกว่าแต่ละส่วนที่เราออกแบบไว้ต้องใช้ Field ประเภทไหนบ้าง

  • ข้อความ Please enter your credential :  LabelField
  • Username: EditField
  • Password : PasswordEditField
  • Domain : ObjectChoiceField
  • Remember Password : CheckboxField
  • ปุ่ม Clear และ Login : ButtonField

ขั้นตอนในการเพิ่ม Field เข้าไปในหน้าจอคือ สร้าง instance ของ field ขึ้นมาจากนั้น เรียกเมธอด add ของคลาส screen  เราใช้วิธีการนี้กับทุกๆ Field ซึ่งผมได้แสดงโค้ดไว้ด้านล่างให้ลองพิมพ์ตาม คิดว่าอ่านแล้วเข้าใจโดยไม่ต้องอธิบายเพิ่มเติม

package com.mobiledevguru.uifun;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.component.ButtonField;
import net.rim.device.api.ui.component.CheckboxField;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.ObjectChoiceField;
import net.rim.device.api.ui.component.PasswordEditField;
import net.rim.device.api.ui.container.MainScreen;

public class UIFunMainScreen extends MainScreen {
            BitmapField bitmapField;
            EditField usernameField;
            PasswordEditField passwordField;
            ButtonField clearButton;
            ButtonField loginButton;
            ObjectChoiceField domainField;
            CheckboxField rememberCheckbox;

            public UIFunMainScreen() {
                        // TODO Auto-generated constructor stub
                        add(new LabelField("Please enter your credentials:"));

                        usernameField = new EditField("Username:", "");
                        add(usernameField);

                        passwordField = new PasswordEditField("Password:", "");
                        add(passwordField);

                        domainField = new ObjectChoiceField("Domain:", new String[] {"Home", "Work"});
                        add(domainField);

                        rememberCheckbox = new CheckboxField("Remember password:", false);
                        add(rememberCheckbox);

                        clearButton = new ButtonField("Clear");
                        add(clearButton);

                        loginButton = new ButtonField("Login");
                        add(loginButton);
            }
}

จากนั้นลองรันดู (กด ctrl + f11) จะเห็นผลดังนี้

รูปที่ 2

ก็เกือบจะดีแล้ว แต่สิ่งที่ดูแปลกๆคือ ปุ่ม Clear และ Login เรียงกันคนละแถว ที่เป็นเช่นนี้เนื่องจาก Screen จะทำการเรียง Field ในแนวตั้งต่อกันไปเรื่อยๆ ถ้าเราจะแก้ปัญหานี้เราต้องเรียกใช้ Manager ที่มีชื่อว่า HorizontalFieldManager  จากนั้นแทนที่จะ add ปุ่ม clear และ login ไปที่ Screen ให้เปลี่ยนมา  add ไปไว้ที่ HorizontalFieldManager   ดังนี้

                        clearButton = new ButtonField("Clear",ButtonField.CONSUME_CLICK);
                        loginButton = new ButtonField("Login",ButtonField.CONSUME_CLICK);

                        HorizontalFieldManager buttonManager = new HorizontalFieldManager(Field.FIELD_RIGHT);
                        buttonManager.add(clearButton);
                        buttonManager.add(loginButton);          
        
                        add(new SeparatorField());
                        add(buttonManager);

จากโค้ดด้านบนสิ่งที่เราต้องเรียนรู้เพิ่มเติมคือ

  1. เราสามารถกดหนด Style หรือรูปแบบการแสดงผลใน constructor ของ field เช่น HorizontalFieldManager(Field.FIELD_RIGHT) เป็นการกำหนดให้จัดเรียง field ที่อยู่ภายในแบบชิดขวา เราสามารถกำหนด Style หลายๆอย่างในครั้งเดียวได้โดยการใช้ bitwise or (|)
  2. ในส่วนของ ButtonField มีการใช้ Style ButtonField.CONSUME_CLICK  ซึ่งเป็นการระบุว่า ButtonField จะรับ event Click ถ้าเราไม่ทำแบบนี้การคลิ๊กจะถูกส่งผ่านไปที่ screen ซึ่งจะตอบสนองโดยการแสดงเมนูขึ้น

ลองรันดูจะได้ผลแบบที่ควรจะเป็นดังรูปด้านล่าง

รูปที่ 3

โต้ตอบกับผู้ใช้บ้างสิ

โปรแกรมที่เราเขียนเสร็จไปนั้นนอกจากแสดง หน้าตาแล้ว ไม่ทำงานอะไรบ้างเลย เราจะลองให้มันโต้ตอบกับผู้ใช้ดูบ้าง โดยให้แสดงข้อความ “Clear button Pressed!”  เมื่อมีการกดปุ่ม Clear

ก่อนอื่นเราต้องปูพื้นฐานความรู้สักเล็กน้อย

ในการจัดการ Event ของ field BlackBerry API จะใช้ Design Pattern ที่ชื่อว่า Observer โดยการระบุให้ Object ที่มีฟังก์ชั่นตอบสนอง event นั้นทำหน้าที่เป็น Listener ผมขอนำเสนอเป็นขั้นตอนดังนี้

  1. เพิ่มความสามารถให้คลาสทำหน้าที่เป็น Listener โดยการ implement Interface “FieldChangeListener” ดังนั้นเราจะเปลี่ยนแปลงส่วนประกาศของ class เป็นดังนี้
    public class UIFunMainScreen extends MainScreen implements FieldChangeListener
  2. implement ฟังก์ชั่น fieldChanged  ฟังก์ชั่นนี้จะถูกเรียกทำงานเมื่อเกิด event ขึ้น   
          public void fieldChanged(Field field, int context) {
                      // TODO Auto-generated method stub
                      if (field == clearButton) {
                                  Dialog.inform("Clear Buton Pressed!");
                      }
          }
          ฟังก์ชั่นนี้ทำงานง่ายๆ เพียงแค่ให้ Dialog แสดงข้อความว่า “Clear Buton Pressed!”  โดยคำสั่ง Dialog.inform("Clear Buton Pressed!") แต่ที่ต้องมีการตรวจสอบว่า field == clearButton หรือไม่เนื่องจากเราจะให้คลาสนี้เป็น listener ของทั้งปุ่ม Clear และ Login

  3. ทำการเซ็ต Listenner ให้กับ ButtonField โดยการเรียกฟังก์ชั่น  setChangeListener ดังนี้

                            clearButton.setChangeListener(this);
                            loginButton.setChangeListener(this);
        

    ให้คุณลองทำตามขั้นตอนที่กล่าวมาดูแล้วตรวจสอบดูว่าเหมือนกับของผมหรือไม่
    package com.mobiledevguru.uifun;
    import net.rim.device.api.ui.Field;
    import net.rim.device.api.ui.FieldChangeListener;
    import net.rim.device.api.ui.component.BitmapField;
    import net.rim.device.api.ui.component.ButtonField;
    import net.rim.device.api.ui.component.CheckboxField;
    import net.rim.device.api.ui.component.Dialog;
    import net.rim.device.api.ui.component.EditField;
    import net.rim.device.api.ui.component.LabelField;
    import net.rim.device.api.ui.component.ObjectChoiceField;
    import net.rim.device.api.ui.component.PasswordEditField;
    import net.rim.device.api.ui.component.SeparatorField;
    import net.rim.device.api.ui.container.HorizontalFieldManager;
    import net.rim.device.api.ui.container.MainScreen;
    public class UIFunMainScreen extends MainScreen implements FieldChangeListener {

                BitmapField bitmapField;
                EditField usernameField;
                PasswordEditField passwordField;
                ButtonField clearButton;
                ButtonField loginButton;
                ObjectChoiceField domainField;
                CheckboxField rememberCheckbox;

                public UIFunMainScreen() {
                            // TODO Auto-generated constructor stub
                            add(new LabelField("Please enter your credentials:"));
                            usernameField = new EditField("Username:", "");
                            add(usernameField);

                            passwordField = new PasswordEditField("Password:", "");
                            add(passwordField);

                            domainField = new ObjectChoiceField("Domain:", new String[] {"Home", "Work"});
                            add(domainField);

                            rememberCheckbox = new CheckboxField("Remember password:", false);
                            add(rememberCheckbox);

                            clearButton = new ButtonField("Clear", ButtonField.CONSUME_CLICK);
                            loginButton = new ButtonField("Login", ButtonField.CONSUME_CLICK);

                            clearButton.setChangeListener(this);
                            loginButton.setChangeListener(this);

                            HorizontalFieldManager buttonManager = new HorizontalFieldManager(Field.FIELD_RIGHT);
                            buttonManager.add(clearButton);

                            buttonManager.add(loginButton);                   
                            add(new SeparatorField());
                            add(buttonManager);

                }

                public void fieldChanged(Field field, int context) {
                            // TODO Auto-generated method stub

                            if (field == clearButton) {
                                        Dialog.inform("Clear Buton Pressed!");
                            }
                }
    }

  4. รันใน simulator และลองกดปุ่ม clear ดู

    รูปที่ 4
  5. Clear ก็ต้องเคลียร์สิ  ใช่แล้ว เราไม่ได้ต้องการให้มันแสดงข้อความแต่เราต้องการให้มันทำให้ Username และ password ว่าง แก้ไขโค้ดดังนี้และรันดูอีกครั้ง

          public void fieldChanged(Field field, int context) {
                      if (field == clearButton) {
                                  clearTextFields();
                      }
          }

          private void clearTextFields() {
                      usernameField.setText("");
                      passwordField.setText("");
    }

สร้าง Screen แสดงผลการ Login

            ที่ผ่านมาเราได้เรียนรู้การเขียน Listener เพื่อตอบสนอง event ต่อไป เราจะทำการสร้าง screen ขึ้นมาอีกหนึ่งตัวเพื่อแสดงผลการ Login หน้าจอตอบรับนี้จะแสดงข้อความว่า “Logged in!” รวมทั้ง username และ domain  ข้อความทั้งหมดจะใช้ LabelField   อีกทั้งมีการส่ง username และ domain ผ่าน constructor

package com.mobiledevguru.uifun;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.MainScreen;
public class LoginSuccessScreen extends MainScreen {

            public LoginSuccessScreen(String username, String domain) {
                        add(new LabelField("Logged in!"));
                        add(new LabelField("Username: " + username));
                        add(new LabelField("Domain: " + domain));
            }

}

ส่วนที่เราต้อง ให้ความสนใจคือหลังจากผู้ใช้คลิ๊กปุ่ม login จะเปลี่ยนไปแสดงอีกหนึ่งหน้าจอได้อย่างไร BlackBerry จัดการแสดงผล screen โดยรูปแบบของ Stack ดังนั้น เราเพียงแค่ส่ง instance ของ LoginSuccessScreen  เข้าไปให้ฟังก์ชั่น pushStack ดังนี้

            private void login() {
                        if (usernameField.getTextLength() == 0 || passwordField.getTextLength() == 0) {
                                    Dialog.alert("You must enter a username and password");
                        }

                        else {
                                    String username = usernameField.getText();
                                    String selectedDomain = (String)domainField.getChoice(domainField.getSelectedIndex());

                                    LoginSuccessScreen loginSuccessScreen = new LoginSuccessScreen(username, selectedDomain);

                                    UiApplication.getUiApplication().pushScreen(loginSuccessScreen);
                        }
            }

ทำงานโดยใช้เมนู

            สำหรับผู้ใช้ เมนูถือว่าเป็นการใช้งานที่สะดวกมากที่สุดเนื่องจากมีปุ่มให้กดอย่างง่ายๆ เราจะเพิ่มเมนู login และ clear เข้าไปใน Aplication ของเราบ้าง วิธีที่ง่ายที่สุดคือ override ฟังก์ชั่น makeMenu   ภายในเมนูจะประกอบด้วย menuItem ซึ่งเป็น abstract class  แสดงการใช้งานทั้งหมดโดยโค้ดด้านล่าง

      protected void makeMenu(Menu menu, int instance) {
            super.makeMenu(menu, instance);

            menu.add(new MenuItem("Login", 10, 20) {

                  public void run() {
                        login();
                  }
            });

            menu.add(new MenuItem("Clear",20,10) {

                  public void run() {
                        clearTextFields();
                  }
            });
      }

บรรทัดแรก super.makeMenu(menu, instance); เป็นการเรียกให้คลาสแม่ทำการสร้างเมนูที่จำเป็นอื่นๆ เช่นเมนู close

เรียก menu.add เพื่อเพิ่ม menuItem เข้าไป เราเลือกที่จะใช้ anonymous class เพื่อความสะดวก

Constructor ของ MenuItem รับ parameter 3 ตัวดังนี้

  1. Text : ข้อความที่จะแสดงบนเมนู
  2. Ordinal : ลำดับการแสดงผล ตัวเลขที่มีค่ามากกว่าจะอยู่ด้านบน
  3. Priority: menuItem ที่มีค่าน้อยที่สุดจะถูกเลือกเป็นค่า default (ถูก highlight เมื่อเปิดเมนู)

ทดลองเลือกเมนูบน simulator จะพบเมนู Login และ Clear ดังรูปด้านล่าง
รูปที่ 5

ทิ้งท้าย

            วันนี้เราได้เรียนรู้การสร้าง UI อย่างง่ายๆ เริ่มตั้งแต่ทำความรู้จัก  UI อันประกอบด้วย field,manager และ form  และสร้างหน้า Login ขึ้นมา จากนั้นยังทำการเขียน event handler เพื่อตอบสนองการใช้งานของผู้ใช้โดยการกำหนดให้มีคลาส Listener คอยดักและจัดการ  event   เราเรียนรู้การเปลี่ยน screen โดยการใช้ฟังก์ชั่น pushScreenและสุดท้ายกับการสร้างเมนู ส่วนของ UI เชื่อว่าสิ่งที่เราทดลองทำกันมาเพียงพอในการเริ่มต้นสร้าง Application โดยทั่วไป

อ้างอิง


หนังสือ : Beginning BlackBerry Development :By Anthony Rizk

Attached Files

Post Rating

Comments

BOBE's
# BOBE's
Tuesday, November 16, 2010 6:07 PM
ช่วยแนะนำการเขียนโปรแกรมที่ สามารถอ่านข้อมูลจาก Xml บน BlackBerry ให้หน่อยได้ไหมครับ หรือการเขียนโปรแกรมบน BlackBerry เพื่ออ่านข้อมูลจาก Xml ตอนนี้ ตันมากๆ ><"

Post Comment

Only registered users may post comments.
Home | Article | Webboard | Video | Blog | Showcase | News
Copyright 2010 by devguru.mobi