• Thứ Sáu, 15/10/2010 07:40 (GMT+7)

    Trả lời thư bạn đọc

    BBT
    Mục giải đáp thắc mắc của các bạn đọc do TS. Nguyễn Văn Hiệp phụ trách.

    Q: Xin hướng dẫn lập trình Java giả lập máy tính bỏ túi trên điện thoại di động, có các button thực hiện các phép toán cơ bản như +, -, *, /.

    A: Platform J2ME (Java 2 Mobile Edition) chỉ cung cấp các đối tượng nhỏ và đơn giản đủ dùng để viết các ứng dụng nhỏ và đơn giản chạy trên các thiết bị di động (như điện thoại di động,...), nó chỉ hỗ trợ một số đối tượng giao diện như TextBox, DateField... Do đó để viết ứng dụng cần các đối tượng mà J2ME không hỗ trợ như Button, Checkbox... bạn phải tự viết code để xử lý các đối tượng này. Việc xử lý 1 đối tượng giao diện gồm 2 công việc chính: hiển thị hình ảnh đồ họa của đối tượng và xử lý các sự kiện mà người dùng tác động lên đối tượng trong khi ứng dụng chạy. Để giúp bạn thấy rõ ràng, chi tiết về cách viết code quản lý các đối tượng giao diện, chúng tôi xin giới thiệu qui trình điển hình để xây dựng phần mềm giả lập máy tính bỏ túi thực hiện các phép toán cơ bản như +, -, *, / dùng môi trường NetBean 6.9 với giao diện như sau:

    1. Chạy môi trường lập trình NetBean 6.9, đóng các Project đang được NetBean quản lý lại.

    2. Chọn menu File.New Project để hiển thị cửa sổ New Project. Chọn mục Java ME trong danh sách Categories, chọn mục Mobile Application trong danh sách Projects, chọn button Next để hiển thị cửa sổ New Mobile Application. Nhập tên Project là Calculator, chọn thư mục chứa Project, bỏ chọn checkbox Create Hello Midlet, chọn button Next để hiển thị cửa sổ kế tiếp. Chọn tên driver quản lý thiết bị di động (thí dụ DefaultCldcPhone1), chọn button Finish để hoàn thành việc đặc tả Project cần tạo mới.

    3. Ấn phải chuột vào Project Calculator trong cửa sổ Project, chọn New.MIDlet, nhập tên MIDlet là Calculator, chọn button Finish để hiển thị cửa sổ soạn code cho MIDlet rồi viết code như sau:

    //Mã nguồn Java của ứng dụng di động Calculator
    import javax.microedition.midlet.*;
    import javax.microedition.lcdui.*;
    //đặc tả class phần mềm Calculator
    public class Calculator extends MIDlet implements CommandListener {
    //định nghĩa các biến cần dùng
    private boolean midletPaused = false;
    private SampleCanvas mycanvas;
    private Command exitCommand;
    private Command backCommand;
    //định nghĩa các hàm chức năng
    private void initialize() {}

    public void startMIDlet() {
    Display display = Display.getDisplay(this);
    exitCommand = new Command("D\u1eebng", Command.EXIT, 1);
    backCommand = new Command("Reset", Command.BACK, 2);
    mycanvas=new SampleCanvas();
    mycanvas.addCommand(exitCommand);
    mycanvas.addCommand(backCommand);
    mycanvas.setCommandListener(this);
    display.setCurrent(mycanvas);
    }
    public void resumeMIDlet() {}
    public void switchDisplayable(Alert alert, Displayable nextDisplayable) {
    Display display = Display.getDisplay(this);
    if (alert == null) display.setCurrent(nextDisplayable);
    else display.setCurrent(alert, nextDisplayable);
    }

    public void commandAction(Command command, Displayable displayable) {
    if (command == backCommand) mycanvas.MyInit ();
    else if (command == exitCommand) {
    destroyApp(false);
    this.notifyDestroyed();
    }
    }

    public void exitMIDlet() {
    switchDisplayable (null, null);
    destroyApp(true);
    notifyDestroyed();
    }

    //điểm nhập của ứng dụng
    public void startApp() {
    if (midletPaused) resumeMIDlet ();
    else {
    initialize ();
    startMIDlet ();
    }
    midletPaused = false;
    }

    public void pauseApp() {
    midletPaused = true;
    }
    public void destroyApp(boolean unconditional) {}
    }

    //class đặc tả form làm việc của ứng dụng
    class SampleCanvas extends Canvas {
    //định nghĩa các hằng gợi nhớ cần dùng
    final int ADDID = 1;
    final int SUBID = 2;
    final int MULID = 3;
    final int DIVID = 4;
    final int EQUALID = 5;
    //định nghĩa các biến cần dùng
    Font font;
    Graphics gh;
    int ww, wh;
    int baseX, baseY;
    int bw,bh;
    String valdisp,strOldValue;
    int row, col;
    boolean fDot, fStartData;
    int OldOpID;
    //hàm khởi tạo đối tượng
    SampleCanvas() {
    //thiết lập font chữ cần dùng
    font = Font.getFont(Font.FACE_PROPORTIONAL,
    Font.STYLE_BOLD, Font.SIZE_LARGE);
    MyInit();
    }
    //hàm thiết lập trạng thái đầu cho Calculator
    public void MyInit() {
    //xác định độ rộng, độ cao của form
    ww=this.getWidth();
    wh = this.getHeight();
    //xác định độ rộng, độ cao của từng button
    bw= (ww-15)/4;
    bh = 25;
    //xác định vị trí trên trái của vùng làm việc
    baseX = 3; baseY= 4;
    valdisp = "0.";
    fStartData = true;
    fDot = false;
    strOldValue = "0";
    OldOpID = EQUALID;
    repaint();
    }
    //hàm xử lý phím ấn, hiện chỉ có khung sườn
    protected void keyPressed(int key) {
    int action = getGameAction(key);
    switch (action) {
    case LEFT:
    break;
    case RIGHT:
    break;
    case UP:
    break;
    case DOWN:
    break;
    case FIRE:
    break;
    }
    repaint();
    }

    //hàm cập nhật màn hình tinh thể lỏng
    protected void UpdateDisplay(int d) {
    if(fStartData) {
    valdisp = Integer.toString(d);
    fStartData = fDot = false;
    } else
    valdisp = valdisp + Integer.toString(d);
    repaint();
    }

    //hàm xử lý phím phép toán
    private void Op_Process(int op) {
    double dblOldValue;
    double dblValue;
    //xác định 2 toán hạng
    dblValue = Double.parseDouble(valdisp);
    dblOldValue = Double.parseDouble(strOldValue);
    //kiểm tra phép toán cần thực hiện
    switch (OldOpID) {
    case ADDID :
    dblValue = dblOldValue + dblValue; break;
    case SUBID:
    dblValue = dblOldValue - dblValue; break;
    case MULID:
    dblValue = dblOldValue * dblValue; break;
    case DIVID :
    dblValue = dblOldValue / dblValue; break;
    }
    valdisp = Double.toString(dblValue);
    strOldValue = valdisp;
    OldOpID = op;
    fStartData = true;
    }

    //hàm xử lý sự kiện ấn chuột (chạm màn hình cảm ứng)
    protected void pointerPressed(int x, int y) {
    //kiểm tra vị trí chuột có nằm trên các button?
    if (baseY+bh+3 > y || y > baseY + (bh+3)*6) return;
    //xác định vị trí button được chọn
    col = (x - baseX) / (bw+3);
    row = (y - baseY-bh-3) / (bh+3);
    switch (row) {
    case 0: //các button hàng đầu
    switch (col) {
    case 0: //nút C
    MyInit(); break;
    case 1: //nút sqrt
    valdisp = Double.toString(Math.sqrt(Double.parseDouble(valdisp)));
    break;
    case 2: //nút 1/x
    valdisp = Double.toString(1/Double.parseDouble(valdisp)); break;
    case 3: //nút /
    Op_Process(DIVID);
    }
    break;
    case 1: //các button hàng thứ 2
    switch (col) {
    case 0: //nút 7
    UpdateDisplay(7); break;
    case 1: //nút 8
    UpdateDisplay(8); break;
    case 2: //nút 9
    UpdateDisplay(9); break;
    case 3: //nút *
    Op_Process(MULID);
    }
    break;
    case 2: //các button hàng thứ 2
    switch (col) {
    case 0: //nút 4
    UpdateDisplay(4); break;
    case 1: //nút 5
    UpdateDisplay(5);break;
    case 2: //nút 6
    UpdateDisplay(6);break;
    case 3: //nút -
    Op_Process(SUBID);
    }
    break;
    case 3: //các button hàng thứ 3
    switch (col) {
    case 0: //nút 1
    UpdateDisplay(1);break;
    case 1: //nút 2
    UpdateDisplay(2); break;
    case 2: //nút 3
    UpdateDisplay(3);break;
    case 3: //nút +
    Op_Process(ADDID);
    }
    break;
    case 4: //các button hàng thứ 4
    switch (col) {
    case 0: //nút 0
    UpdateDisplay(0);break;
    case 1: //nút .
    if (fStartData) {
    valdisp = "0.";
    fStartData = false;
    } else if (fDot==false) {
    valdisp = valdisp + ".";
    fDot = true;
    }
    break;
    case 2: //nút +/-
    //nếu là số âm thì đổi thành dương và ngược lại
    if (valdisp.charAt(0)!= '-') {
    //chỉ đảo dấu khi giá trị khác 0
    if (Double.parseDouble(valdisp) != 0)
    valdisp = "-" + valdisp;
    } else valdisp = valdisp.substring(1);
    break;
    case 3: //nút =
    Op_Process(EQUALID);
    }
    break;
    }
    repaint();
    }

    //hàm hiển thị các đối tượng trong form
    protected void paint(Graphics g) {
    int x, y;
    gh = g;
    g.setFont(font);
    x = baseX;
    y = baseY;
    //vẽ textbox miêu tả màn hình display
    gh.setColor(128,128,128);
    gh.fillRect(x, y, ww-6,bh);
    gh.setColor(0,255,255);
    gh.drawRect(x, y, ww-6,bh);
    gh.setColor(255,255,255);
    gh.drawString(valdisp, ww-8, y, Graphics.RIGHT|Graphics.TOP);
    //vẽ hàng button thứ nhất
    y = y + bh+3;
    DispButton(x, y,"C",0);
    DispButton(x+bw+3, y,"sqrt",0);
    DispButton(x+(bw+3)*2, y,"1/x",0);
    DispButton(x+(bw+3)*3, y,"/",0);
    //vẽ hàng button thứ nhất
    y = y + bh+3;
    DispButton(x, y,"7",0);
    DispButton(x+bw+3, y,"8",0);
    DispButton(x+(bw+3)*2, y,"9",0);
    DispButton(x+(bw+3)*3, y,"*",0);
    //vẽ hàng button thứ nhất
    y = y + bh+3;
    DispButton(x, y,"4",0);
    DispButton(x+bw+3, y,"5",0);
    DispButton(x+(bw+3)*2, y,"6",0);
    DispButton(x+(bw+3)*3, y,"-",0);
    //vẽ hàng button thứ nhất
    y = y + bh+3;
    DispButton(x, y,"1",0);
    DispButton(x+bw+3, y,"2",0);
    DispButton(x+(bw+3)*2, y,"3",0);
    DispButton(x+(bw+3)*3, y,"+",0);
    //vẽ hàng button thứ 5
    y = y + bh+3;
    DispButton(x, y,"0",0);
    DispButton(x+bw+3, y,".",0);
    DispButton(x+(bw+3)*2, y,"+/-",0);
    DispButton(x+(bw+3)*3, y,"=",0);
    }
    //hàm vẽ 1 button
    private void DispButton(int x, int y, String str, int flag) {
    if (flag==0) { //ở trạng thái chưa chọn
    gh.setColor(128,128,128);
    gh.fillRect(x, y, bw,bh);
    gh.setColor(0,255,255);
    gh.drawRect(x, y, bw,bh);
    gh.setColor(0,0,255);
    gh.drawString(str, x+15, y, Graphics.LEFT|Graphics.TOP);
    } else { //ở trạng thái đang chọn
    gh.setColor(0,0,255);
    gh.fillRect(x, y, bw,bh);
    gh.setColor(0,255,255);
    gh.drawRect(x, y, bw,bh);
    gh.setColor(255,255,255);
    gh.drawString(str, x+15, y, Graphics.LEFT|Graphics.TOP);
    }
    }
    }

    4. Chọn menu Run.Run Project để dịch và chạy thử ứng dụng. Nếu bạn nhập đúng mọi hàng lệnh như được liệt kê ở trên thì chương trình sẽ chạy tốt.

    5. Vào thư mục Calculator\dist, copy file Calculator.jar sang điện thoại di động và chạy nó thử trên điện thoại di động. Nếu điện thoại của bạn là điện thoại cảm ứng, hỗ trợ các version CLDC và MIDP như lúc cấu hình cho ứng dụng thì ứng dụng sẽ chạy tốt.

    Q: Xin hướng dẫn cách lấy/thiết lập màu background và màu font của 1 ô trong Excel.

    A: Trong Excel, để thực hiện 1 chức năng nào đó trên file *.xls, bạn có thể viết macro hay hàm hay thủ tục. Macro (hay hàm, thủ tục) là 1 thủ tục phần mềm được viết bằng ngôn ngữ VBA, nó gồm nhiều lệnh thực thi miêu tả thuật giải cần thực hiện. Đoạn code VBA dễ dàng truy xuất các file *.xls, các sheets trong từng file, các cell trong từng sheet theo mô hình hướng đối tượng. Thí dụ macro Proc() sau đây sẽ kiểm tra nội dung cell A1 trong sheet1 của workbook hiện hành, nếu nội dung của cell A1>2 thì tô background của cell A3 là màu đỏ, ngược lại thì tô background của cell A3 là màu xanh. Qui trình điển hình để xây dựng và sử dụng macro như sau:

    1. Chạy Excel, mở file Excel chứa dữ liệu cần xử lý. Nếu chưa có thì dùng workbook mặc định trống ban đầu.

    2. Chọn menu Tools.Macro.Macros... để hiển thị cửa sổ Macro. Nhập tên macro cần tạo (thí dụ là Proc), chọn button Create để tạo mới nó, lúc này cửa sổ soạn code sẽ hiển thị, bạn hãy viết đoạn code sau đây vào :

    Sub Proc()
    Dim rg1 As Range
    Dim rg2 As Range
    'thiết lập các vùng cần xử lý
    Set rg1 = Range("Sheet1!A1")
    Set rg2 = Range("Sheet1!A3")
    'kiểm tra nội dung cell A1
    If rg1.Value > 2 Then
    'tô background màu đỏ
    rg2.Interior.Color = RGB(255, 0, 0)
    'chọn Font Helvetica, màu trắng, cở 12
    rg2.Font.Color = RGB(255, 255, 255)
    rg2.Font.Name = "Helvetica"
    rg2.Font.Size = 12
    Else
    'tô background màu xanh
    rg2.Interior.Color = RGB(0, 0, 255)
    'chọn Font Times, màu vàng, cỡ 12
    rg2.Font.Color = RGB(255, 255, 0)
    rg2.Font.Name = "Times New Roman"
    rg2.Font.Size = 12
    End If
    End Sub

    3. Chọn menu File.Close and Return... để quay về cửa sổ wooksheet Excel. Chọn worksheet Sheet1, nhập thử nội dung vào cell A1 và A3, chọn menu Tools.Macro.Macros... để hiển thị cửa sổ Macro. Chọn macro Proc, chọn button Run để chạy nó và xem kết quả trên Sheet1.

    Q: Xin hướng dẫn code C tạo thanh cuộn và chạy trong môi trường DOS.

    A: Môi trường DOS rất yếu, nó không hỗ trợ giao diện đồ họa như trên Windows. Hiện nay MSDOS không còn được hỗ trợ bởi Microsoft nữa. Trước đây, người ta thường dùng môi trường lập trình Borland C++ để viết ứng dụng DOS chạy ở chế độ text/graphics. Ở chế độ đồ họa, Borland C++ chỉ hỗ trợ những chức năng đồ họa cơ bản như vẽ điểm, đoạn thẳng, đường cong,... Nếu muốn vẽ và quản lý các đối tượng giao diện cao cấp hơn, bạn phải tự viết đoạn code tường minh. Việc quản lý 1 đối tượng giao diện gồm 2 công việc chính: hiển thị hình ảnh đồ họa của đối tượng và xứ lý các sự kiện mà người dùng tác động lên đối tượng trong khi ứng dụng chạy. Thí dụ để quản lý thanh cuộn, bạn phải viết đoạn code hiển thị thanh cuộn (gồm 1 hình chữ nhật miêu tả thanh cuộn và 1 hình chữ nhật nhỏ miêu tả marker thể hiện vị trí và kích thước dữ liệu được hiển thị trong cửa sổ tương ứng so với toàn bộ dữ liệu cần hiển thị. Bạn cũng viết đoạn code xử lý sự kiện chuột, khi phát hiện người dùng ấn ở vị trí trong thanh cuộn, bạn sẽ thực hiện chức năng cuộn lên/cuộn xuống,... tùy vào vị trí ấn chuột so với marker của thanh cuộn.

    Q: Tôi dùng Visual FoxPro, chuyển được file *. DBF sang file Excel mới bằng lệnh:
    Export to <file_excel.xls> type XL5,
    nhưng không kết xuất ra được file Excel hiện hữu. 

    A: Đúng như bạn nói, bạn có thể dùng lệnh Export to hay Copy to của ngôn ngữ Foxpro để chuyển bảng dữ liệu từ file *.dbf thành 1 bảng tính Excel. Tuy nhiên dùng 1 trong 2 lệnh này có nhiều điểm yếu như nó chỉ lưu dữ liệu lên file Excel mới với định dạng khá cũ (mặc dù ứng dụng Excel mới vẫn xử lý được), nó không cho phép lưu dữ liệu lên file Excel đã có sẵn. Nếu muốn xử lý nhiều yêu cầu riêng tư một cách tự do, bạn nên dùng các đối tượng trong thư viện "Excel Automation" như Application, Workbooks, Worksheets,... Sau đây là đoạn code VFP dùng các đối tượng "Excel Automation" để đọc bảng dữ liệu trong file *.dbf rồi lưu bảng này vào 1 worksheet trong file Excel đã có sẵn:

    Clear All
    Set Safety Off
    * tạo đối tượng ứng dụng Excel
    oExcel = Createobject("Excel.application")
    *mở file Excel có sẵn
    oExcel.workbooks.Open ("C:\data\test.xls")
    *mở file DBF chứa bảng dữ liệu cần chuyển
    oExcel.workbooks.Open("c:\data\mydata.dbf")
    *copy bảng dữ liệu từ file DBF sang worksheet Excel
    oExcel.sheets(1).Copy(oExcel.workbooks("test.xls").sheets(1))
    *lưu file Excel
    oExcel.activeWorkbook.Save
    *dừng đối tượng Excel
    oExcel.quit
    Wait Clear

    ID: A1009_122