• Chủ Nhật, 21/12/2003 16:36 (GMT+7)

    Câu hỏi :
    Xin hướng dẫn cách hiển thị 1 bitmap lên vùng client của ứng dụng SDI (Simple Document Interface) dùng Visual C++. Tôi viết 2 hàm dưới đây, khi biên dịch không báo lỗi nhưng khi chạy thì báo lỗi. Phần load file bitmap trên thanh menu ở class Document như sau : void CVisionsystemDoc::OnFileLoadbitmap(){ // TODO: Add your command handler code here static char BASED_CODE szFilter[] = “Bitmap Files (*.bmp);*.bmp||”; CString m_sBitmap; CFileDialog m_ldFile (TRUE, “.bmp”, m_sBitmap, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter); if (m_ldFile.DoModal()==IDOK) { m_sBitmap=m_ldFile.GetPathName(); HBITMAP hBitmap=(HBITMAP)::LoadImage (AfxGetInstanceHandle(), m_sBitmap, IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); if (hBitmap) { if(m_bmBitmap.DeleteObject()) m_bmBitmap.Detach(); m_bmBitmap.Attach(hBitmap); } } UpdateAllViews(NULL); } Phần hiển thị trên hàm OnDraw() của class View : void CVisionsystemView::OnDraw(CDC* pDC){ CVisionsystemDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here CBitmap *pOldBmp; BITMAP bm; //Tinh cau truc bitmap thong qua cau truc BITMAP pDoc->m_bmBitmap.GetObject(sizeof(BITMAP),&bm); //Tao memory DC CDC memDC; memDC.CreateCompatibleDC(pDC); //Chon dua bitmap vao memory DC pOldBmp=memDC.SelectObject(&(pDoc->m_bmBitmap)); //Dua hinh anh bitmap len view pDC->BitBlt(10,10,bm.bmWidth,bm.bmHeight,&memDC,0,0,SRCCOPY); memDC.SelectObject(pOldBmp); }

    Trả lời :
     

    Trong quá trình viết 1 ứng dụng, ta có thể mắc 3 loại lỗi khác nhau:

    • Lỗi từ vựng: sử dụng sai từ dành riêng, tên biến, tên hàm...

    • Lỗi cú pháp và ngữ cảnh: viết lệnh sai cú pháp, dùng biến hay hàm chưa được định nghĩa...

    • Lỗi run-time: lỗi giải thuật hay ngữ nghĩa, lỗi sử dụng tài nguyên không hợp lệ...

    Sau khi viết xong chương trình, ta dịch source code để tạo file khả thi, chương trình dịch sẽ phát hiện dễ dàng và báo lỗi từ vựng, cú pháp, ngữ cảnh, tuy nhiên nó không thể phát hiện được lỗi run-time, chỉ có con người mới có thể xác định và sửa chữa loại lỗi này.

    Cụ thể 2 hàm OnLoadImage() và OnDraw() do bạn viết không có lỗi từ vựng, cú pháp và ngữ cảnh nhưng có 2 lỗi run-time:

    • Để tạo 1 hộp thoại cho phép user chọn 1 file *.bmp, bạn dùng tham số szFilter, từng filter gồm 2 chuỗi được ngăn cách nhau bằng dấu ‘|’ chứ không phải dấu ‘;’ như bạn viết. Tuy nhiên lỗi này không gây lỗi run-time, nó chỉ hiển thị không đúng danh sách các file *.bmp như mong đợi.

    • Hàm OnDraw() luôn hiển thị hình bitmap được qui định trong biến thuộc tính m_bmBitmap, nếu biến này chưa được thiết lập giá trị trước thì hàm OnDraw sẽ gây lỗi run-time. Đây chính là nguyên nhân gây lỗi mà bạn miêu tả vì lúc chương trình được chạy, cửa sổ chương trình sẽ được tạo ra và hiển thị lên màn hình, hàm OnDraw() sẽ được gọi lần đầu để vẽ vùng client, nhưng lúc này bạn chưa chọn option để load file bitmap nên hàm OnLoadImage() chưa chạy, biến m_bmBitmap chưa có giá trị và hàm OnDraw() không thể chạy đúng. Để sửa lỗi này, bạn có thể tiến hành 2 thao tác sau:

    • Thêm 1 biến thuộc tính “m_fload” trong class Document, nó được gán trị FALSE trong hàm constructor của class Document và trước khi load file bitmap, mỗi lần load file thành công thì ta mới gán trị TRUE cho nó.

    • Trong hàm OnDraw(), bạn thêm lệnh kiểm tra thuộc tính m_fload, nếu là FALSE thì không làm gì cả, còn nếu là TRUE thì mới hiển thị ảnh bitmap.

    Source code sau khi được sửa chữa sẽ như sau:

    Phần load file bitmap trên thanh menu ở class Document như sau:

    void CVisionsystemDoc::OnFileLoadbitmap(){

      // TODO: Add your command handler code here

    static char BASED_CODE szFilter[] = “Bitmap Files (*.bmp)|*.bmp||”;

    CString m_sBitmap;

    CFileDialog m_ldFile (TRUE, “.bmp”, m_sBitmap, OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, szFilter);

      m_fload = FALSE;    // lệnh mới thêm

       if (m_ldFile.DoModal()==IDOK) {

           m_sBitmap=m_ldFile.GetPathName();

           HBITMAP hBitmap=(HBITMAP)::LoadImage (AfxGetInstanceHandle(), m_sBitmap, IMAGE_BITMAP,0,0, LR_LOADFROMFILE|LR_CREATEDIBSECTION);

           if (hBitmap) {

                   if(m_bmBitmap.DeleteObject())

                              m_bmBitmap.Detach();

                    m_bmBitmap.Attach(hBitmap);

                    m_fload = TRUE;// lệnh mới thêm

             }

       }

        UpdateAllViews(NULL);

    }

    Phần hiển thị trên hàm OnDraw() của class View:

    void CVisionsystemView::OnDraw(CDC*pDC)

    {

      CVisionsystemDoc* pDoc = GetDocument();

      ASSERT_VALID(pDoc);

      if (pDoc->m_fload ==FALSE) return;

      // lệnh mới thêm

      // TODO: add draw code for native data here

    …..

    …..

    }

    Chuyên mục: Lập trình