Công cụ bảo vệ mã nguồn .NET mạnh nhất, không thể unpack, miễn phí cho các khách hàng đầu tiên đăng ký.
Từ 1 tới 3 trên tổng số 3 kết quả

Đề tài: Tạo một lớp điều khiển GridView trong VS2015 theo OOP.

Threaded View

  1. #1
    Ngày gia nhập
    02 2014
    Nơi ở
    TP.HCM
    Bài viết
    929

    Mặc định Tạo một lớp điều khiển GridView trong VS2015 theo OOP.

    Đề tài này cố gắng đi chi tiết về cách thức lập trình Windows, mình sẽ đi từng bước một.
    Đề bài : Xây dựng lớp điều khiển khung lưới có các chức năng và yêu cầu sau:
    1. Nhập xuất dữ liệu cho từng ô lưới.
    2. Mỗi một ô có thể có Font chữ hiển thị text riêng, cũng như màu nền màu chữ khác với các ô khác
    3. Mỗi ô cũng có chức năng soạn thảo như một textbox. Các phím chức năng có thể hoạt động khác cho phù hợp với điều khiển
    4. Có sử dụng thanh cuộn ngang và dọc.
    5. Yêu cầu không nháy hình khi hoạt động, dùng kỹ thuật vẽ trên bộ nhớ, không đưa thêm các điều khiển có cửa sổ vào khung lưới.
    6. ....... bạn nào có ý tưởng thì thêm vào.

    Chúng ta có thể nhận thấy cần phải có ít nhất 4 lớp đầu tiên cho công việc này. Phần mã bên dưới tạo mã khung cho chương trình gồm hàm điểm nhập, 1 lớp chứa các hàm toàn cục, 1 lớp cửa sổ chương trình test, khởi động 4 lớp thiết yếu CCell, CColumn, CItem, CGrid.

    Visual C++ Code:
    1. #include <windows.h>
    2.  
    3. class CGlobal
    4. {
    5. public:
    6.     // Thay đổi màu một đối tượng
    7.     static bool ChangeColor(HWND hwnd, COLORREF & crColor)
    8.     {
    9.         CHOOSECOLOR     cc;
    10.         COLORREF        arColor[16];
    11.  
    12.         ZeroMemory(&cc, sizeof(cc));
    13.         cc.lStructSize = sizeof(cc);
    14.         cc.hwndOwner = hwnd;
    15.         cc.lpCustColors = (LPDWORD)arColor;
    16.         cc.Flags = CC_FULLOPEN | CC_RGBINIT;
    17.         cc.rgbResult = crColor;
    18.         if (ChooseColor(&cc) && crColor != cc.rgbResult)
    19.         {
    20.             crColor = cc.rgbResult;
    21.             return true;
    22.         }
    23.         return false;
    24.     }
    25. };
    26. class CCell
    27. {
    28. private:
    29.     // Hàm cục bộ
    30. public:
    31.     // Khởi tạo - hủy
    32.     // Thuộc tính
    33.     // Phương thức Get
    34.     // Phương thức Set
    35.     // Hàm công cộng
    36. };
    37. class CColumn
    38. {
    39. private:
    40.     // Hàm cục bộ
    41. public:
    42.     // Khởi tạo - hủy
    43.     // Thuộc tính
    44.     // Phương thức Get
    45.     // Phương thức Set
    46.     // Hàm công cộng
    47. };
    48. class CItem
    49. {
    50. private:
    51.     // Hàm cục bộ
    52. public:
    53.     // Khởi tạo - hủy
    54.     // Thuộc tính
    55.     // Phương thức Get
    56.     // Phương thức Set
    57.     // Hàm công cộng
    58. };
    59. class CGrid
    60. {
    61. private:
    62.     // Hàm cục bộ
    63. public:
    64.     // Khởi tạo - hủy
    65.     // Thuộc tính
    66.     // Phương thức Get
    67.     // Phương thức Set
    68.     // Hàm công cộng
    69. };
    70. class CWindow
    71. {
    72.     enum
    73.     {
    74.         // Định danh MenuItem
    75.         IDM_FILE_NEW = 10001, IDM_FILE_OPEN, IDM_FILE_SAVE, IDM_FILE_CLOSE, IDM_FILE_EXIT,
    76.         IDM_COLOR_BACKGROUND,
    77.     };
    78. private:
    79.     HWND        m_hwnd = NULL;
    80.     DWORD       m_crBack = RGB(64, 128, 128);
    81.    
    82.     // Thủ tục xử lý sự kiện
    83.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    84.     {
    85.         if (msg == WM_CREATE)
    86.         {
    87.             LPCREATESTRUCT  pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    88.             CWindow * pWindow = reinterpret_cast<CWindow*>(pcs->lpCreateParams);
    89.             SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pWindow));
    90.             return pWindow->OnCreate(pcs->hInstance, hwnd);
    91.         }
    92.         CWindow * pWindow = reinterpret_cast<CWindow*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    93.         switch (msg)
    94.         {
    95.         case WM_SIZE:           return pWindow->OnSize(lparam);
    96.         case WM_COMMAND:        return pWindow->OnCommand(wparam, lparam);
    97.         case WM_CLOSE:          return pWindow->OnClose(wparam, lparam);
    98.         case WM_DESTROY:        return pWindow->OnDestroy();
    99.         }
    100.         return DefWindowProc(hwnd, msg, wparam, lparam);
    101.     }
    102.     // Các bộ xử lý sự kiện
    103.     LRESULT OnCreate(HINSTANCE instance, HWND hwnd)
    104.     {
    105.         m_hwnd = hwnd;
    106.         return 0;
    107.     }
    108.     LRESULT OnSize(LPARAM lparam)
    109.     {
    110.         return 0;
    111.     }
    112.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    113.     {
    114.         switch (LOWORD(wparam))
    115.         {
    116.         case IDM_FILE_NEW:              MenuClick_New(); return 0;
    117.         case IDM_FILE_OPEN:             MenuClick_Open(); return 0;
    118.         case IDM_FILE_SAVE:             MenuClick_Save(); return 0;
    119.         case IDM_FILE_CLOSE:            MenuClick_Close(); return 0;
    120.         case IDM_FILE_EXIT:             MenuClick_Exit(); return 0;
    121.         case IDM_COLOR_BACKGROUND:      MenuClick_BackGround(); return 0;
    122.         }
    123.         return DefWindowProc(m_hwnd, WM_COMMAND, wparam, lparam);
    124.     }
    125.     LRESULT OnClose(WPARAM wparam, LPARAM lparam)
    126.     {
    127.         DestroyWindow(m_hwnd);
    128.         return 0;
    129.     }
    130.     LRESULT OnDestroy()
    131.     {
    132.         PostQuitMessage(0);
    133.         return 0;
    134.     }
    135.     // Các hàm xử lý trình đơn
    136.     void MenuClick_New()
    137.     {
    138.     }
    139.     void MenuClick_Open()
    140.     {
    141.     }
    142.     void MenuClick_Save()
    143.     {
    144.     }
    145.     void MenuClick_Close()
    146.     {
    147.     }
    148.     void MenuClick_Exit()
    149.     {
    150.         SendMessage(m_hwnd, WM_CLOSE, 0, 0);
    151.     }
    152.     void MenuClick_BackGround()
    153.     {
    154.         if (CGlobal::ChangeColor(m_hwnd, m_crBack))
    155.         {
    156.             DeleteObject((HBRUSH)SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (long)CreateSolidBrush(m_crBack)));
    157.             InvalidateRect(m_hwnd, NULL, TRUE);
    158.         }
    159.     }
    160.     HMENU BuildMenu()
    161.     {
    162.         HMENU   hMenu = CreateMenu();
    163.         HMENU   hFile = CreatePopupMenu();
    164.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFile, TEXT("&File"));
    165.         AppendMenu(hFile, MF_STRING, IDM_FILE_NEW, TEXT("&New"));
    166.         AppendMenu(hFile, MF_STRING, IDM_FILE_OPEN, TEXT("&Open..."));
    167.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_SAVE, TEXT("&Save..."));
    168.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_CLOSE, TEXT("&Close"));
    169.         AppendMenu(hFile, MF_SEPARATOR, 0, NULL);
    170.         AppendMenu(hFile, MF_STRING, IDM_FILE_EXIT, TEXT("&Exit"));
    171.  
    172.         HMENU   hColor = CreatePopupMenu();
    173.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hColor, TEXT("&Color"));
    174.         AppendMenu(hColor, MF_STRING, IDM_COLOR_BACKGROUND, TEXT("&BackGround..."));
    175.  
    176.         return hMenu;
    177.     }
    178. public:
    179.     int Create(HINSTANCE hInst)
    180.     {
    181.         // Đăng ký lớp
    182.         WNDCLASS    w;
    183.         w.cbClsExtra = 0;
    184.         w.cbWndExtra = 0;
    185.         w.hbrBackground = CreateSolidBrush(m_crBack);
    186.         w.hCursor = LoadCursor(NULL, IDC_ARROW);
    187.         w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    188.         w.hInstance = hInst;
    189.         w.lpfnWndProc = WndProc;
    190.         w.lpszClassName = TEXT("TestGridview");
    191.         w.lpszMenuName = NULL;
    192.         w.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    193.         if (!RegisterClass(&w))
    194.             return 0;
    195.         // Tạo cửa sổ
    196.         HWND    hwnd = CreateWindow(w.lpszClassName, w.lpszClassName, WS_OVERLAPPEDWINDOW,
    197.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, BuildMenu(), hInst, this);
    198.         if (!hwnd)
    199.             return 0;
    200.         ShowWindow(hwnd, SW_SHOW);
    201.         UpdateWindow(hwnd);
    202.         // Vòng lặp thông điệp
    203.         MSG     msg;
    204.         while (GetMessage(&msg, NULL, 0, 0))
    205.         {
    206.             TranslateMessage(&msg);
    207.             DispatchMessage(&msg);
    208.         }
    209.         return msg.wParam;
    210.     }
    211. };
    212. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
    213. {
    214.     CWindow     Window;
    215.     return Window.Create(hInst);
    216. }

    - - - Nội dung đã được cập nhật ngày 23-07-2020 lúc 02:32 PM - - -

    _ Muốn sử dụng một Grid thì trước tiên ta phải tạo cửa sổ cho nó, vậy chúng ta cần viết hàm tạo CGrid::Create
    _ Điều khiển có thể được di chuyển, thay đổi kích cỡ từ bên ngoài nên ta cho nó một hàm di chuyển CGrid::Move
    _ Điều khiển có thể bị bên ngoài cưỡng ép vẽ lại, để đáp ứng chúng ta cho nó một hàm vẽ lại CGrid::Refresh

    Một cửa sổ điều khiển như ô lưới nên chặn và xử lý những thông điệp nào, phần này cần làm ly cafe cho nó lòi ra:
    _ WM_CREATE : Không cần bàn cãi khi phải có nó.
    _ WM_SIZE : Sắp xếp lại kích thước, vị trí thanh cuộn, và tất cả ColumnHeader lẫn các Cell
    _ WM_SETFOCUS : Cần thiết để vẽ lại Cell nóng trước đó, và sẵng sàng nhận phím nhấn
    _ WM_KILLFOCUS : Vẽ nguội lại Cell nóng, bỏ nhận phím
    _ WM_ERASEBKGND : Cần xử lý vì chúng ta tối ưu việc vẽ màn hình tốt nhất. Chúng ta cho lớp cửa sổ không bút vẽ nền, dùng Bitblt 1 lần vẽ chồng DC cửa sổ.
    _ WM_PAINT : Đáp ứng khi Windows yêu cầu vẽ.
    _ WM_LBUTTONDOWN : Nhận tọa độ chuột, xác định Cell nào sẽ được nhận dữ liệu phím nhấn, cũng xác định ký tự head chuỗi chọn
    _ WM_MOUSEMOVE : Thay đổi hình ảnh Cursor phù hợp với vị trí, cũng vẽ lại các chuỗi chọn nếu cần.
    _ WM_LBUTTONUP : Xác định last chuỗi chọn nếu có chuẩn bị cho Cut, Copy...
    _ WM_CONTEXTMENU : Xuất Popup Menu
    _ WM_COMMAND : Xử lý các tùy chọn Menu
    _ WM_KEYDOWN : Xử lý các phím chức năng
    _ WM_CHAR : Xử lý các phím ký tự
    _ WM_VSCROLL : Xử lý khi kéo thanh cuộn dọc
    _ WM_HSCROLL : Xử lý khi kéo thanh cuộn ngang
    _ WM_MOUSEWHEEL : Xử lý khi chuột bánh xe quay
    _ WM_TIMER : Quản lý on/off con nháy Caret trong ô soạn thảo.
    Nhiêu đó thôi từ từ nghĩ ra sau.

    Giải thích thêm các khác biệt trong VS2015 so với các phiên bản trước và với C++ standar. Các khởi tạo khi khai báo các trường là được phép, cách khai báo này gán giá trị trước hơn cả gán giá trị ở đầu phương thức khởi tạo, và đượng nhiên nó trước bên trong thân phương thức.

    Visual C++ Code:
    1. #include <windows.h>
    2. #include <vector>
    3. using namespace std;
    4.  
    5. class CGlobal
    6. {
    7. public:
    8.     // Thay đổi màu một đối tượng
    9.     static bool ChangeColor(HWND hwnd, COLORREF & crColor)
    10.     {
    11.         CHOOSECOLOR     cc;
    12.         COLORREF        arColor[16];
    13.  
    14.         ZeroMemory(&cc, sizeof(cc));
    15.         cc.lStructSize = sizeof(cc);
    16.         cc.hwndOwner = hwnd;
    17.         cc.lpCustColors = (LPDWORD)arColor;
    18.         cc.Flags = CC_FULLOPEN | CC_RGBINIT;
    19.         cc.rgbResult = crColor;
    20.         if (ChooseColor(&cc) && crColor != cc.rgbResult)
    21.         {
    22.             crColor = cc.rgbResult;
    23.             return true;
    24.         }
    25.         return false;
    26.     }
    27.     static int GetCellHeight(HDC hdc)
    28.     {
    29.         TEXTMETRIC  tm;
    30.         GetTextMetrics(hdc, &tm);
    31.         return tm.tmHeight + tm.tmExternalLeading + 4;
    32.     }
    33.     static int GetHeaderHeight(HDC hdc)
    34.     {
    35.         return GetCellHeight(hdc) + 2;
    36.     }
    37. };
    38. class CCell
    39. {
    40. private:
    41.     // Hàm cục bộ
    42. public:
    43.     // Khởi tạo - hủy
    44.     // Thuộc tính
    45.     // Phương thức Get
    46.     // Phương thức Set
    47.     // Hàm công cộng
    48. };
    49. class CColumn
    50. {
    51. private:
    52.     // Hàm cục bộ
    53. public:
    54.     // Khởi tạo - hủy
    55.     // Thuộc tính
    56.     // Phương thức Get
    57.     // Phương thức Set
    58.     // Hàm công cộng
    59. };
    60. class CItem
    61. {
    62. private:
    63.     // Hàm cục bộ
    64. public:
    65.     // Khởi tạo - hủy
    66.     // Thuộc tính
    67.     // Phương thức Get
    68.     // Phương thức Set
    69.     // Hàm công cộng
    70. };
    71. class CGrid
    72. {
    73. private:
    74.     HWND                m_hwnd = NULL;                  // Thẻ cửa sổ
    75.     COLORREF            m_back = RGB(64, 128, 128);     // Màu nền
    76.     bool                m_noheader = false;             // Điều khiển có Header hay không ?
    77.     vector<CColumn*>    m_columns;                      // Các ColumnHeader
    78.     vector<CItem*>      m_items;                        // Các Items dòng
    79.  
    80.     // Thủ tục xử lý sự kiện
    81.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    82.     {
    83.         if (msg == WM_CREATE)
    84.         {
    85.             LPCREATESTRUCT  pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    86.             CGrid * pGrid = reinterpret_cast<CGrid*>(pcs->lpCreateParams);
    87.             SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pGrid));
    88.             return pGrid->OnCreate(hwnd);
    89.         }
    90.         CGrid * pGrid = reinterpret_cast<CGrid*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    91.         switch (msg)
    92.         {
    93.         case WM_SIZE:           return pGrid->OnSize(lparam);
    94.         case WM_SETFOCUS:       return pGrid->OnSetFocus();
    95.         case WM_KILLFOCUS:      return pGrid->OnKillFocus();
    96.         case WM_ERASEBKGND:     return pGrid->OnEraseBackGround();
    97.         case WM_PAINT:          return pGrid->OnPaint();
    98.         case WM_LBUTTONDOWN:    return pGrid->OnLButtonDown(lparam);
    99.         case WM_MOUSEMOVE:      return pGrid->OnMouseMove(lparam);
    100.         case WM_LBUTTONUP:      return pGrid->OnLButtonUp(lparam);
    101.         case WM_CONTEXTMENU:    return pGrid->OnContextMenu(wparam, lparam);
    102.         case WM_COMMAND:        return pGrid->OnCommand(wparam, lparam);
    103.         case WM_KEYDOWN:        return pGrid->OnKeyDown(wparam, lparam);
    104.         case WM_CHAR:           return pGrid->OnChar(wparam);
    105.         case WM_VSCROLL:        return pGrid->OnVScroll(wparam);
    106.         case WM_HSCROLL:        return pGrid->OnHScroll(wparam);
    107.         case WM_MOUSEWHEEL:     return pGrid->OnMouseWheel(wparam);
    108.         case WM_TIMER:          return pGrid->OnTimer(wparam);
    109.         }
    110.         return DefWindowProc(hwnd, msg, wparam, lparam);
    111.     }
    112.     // Các bộ xử lý sự kiện
    113.     LRESULT OnCreate(HWND hwnd)
    114.     {
    115.         m_hwnd = hwnd;
    116.         // Chưa hiển thị các thanh cuộn
    117.         SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
    118.         SetScrollRange(hwnd, SB_HORZ, 0, 0, FALSE);
    119.         return 0;
    120.     }
    121.     LRESULT OnSize(LPARAM lparam)
    122.     {
    123.         Refresh();
    124.         return 0;
    125.     }
    126.     LRESULT OnKillFocus()
    127.     {
    128.         Refresh();
    129.         return 0;
    130.     }
    131.     LRESULT OnSetFocus()
    132.     {
    133.         Refresh();
    134.         return 0;
    135.     }
    136.     LRESULT OnEraseBackGround()
    137.     {
    138.         return -1;
    139.     }
    140.     LRESULT OnPaint()
    141.     {
    142.         PAINTSTRUCT ps;
    143.         BeginPaint(m_hwnd, &ps);
    144.         EndPaint(m_hwnd, &ps);
    145.         Refresh();
    146.         return 0;
    147.     }
    148.     LRESULT OnLButtonDown(LPARAM lparam)
    149.     {
    150.         SetFocus(m_hwnd);
    151.         return 0;
    152.     }
    153.     LRESULT OnMouseMove(LPARAM lparam)
    154.     {
    155.         return 0;
    156.     }
    157.     LRESULT OnLButtonUp(LPARAM lparam)
    158.     {
    159.         return 0;
    160.     }
    161.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    162.     {
    163.         return DefWindowProc(m_hwnd, WM_COMMAND, wparam, lparam);
    164.     }
    165.     LRESULT OnContextMenu(WPARAM wparam, LPARAM lparam)
    166.     {
    167.         return DefWindowProc(m_hwnd, WM_CONTEXTMENU, wparam, lparam);
    168.     }
    169.     LRESULT OnKeyDown(WPARAM wparam, LPARAM lparam)
    170.     {
    171.         return DefWindowProc(m_hwnd, WM_KEYDOWN, wparam, lparam);
    172.     }
    173.     LRESULT OnChar(WPARAM wparam)
    174.     {
    175.         return 0;
    176.     }
    177.     LRESULT OnVScroll(WPARAM wparam)
    178.     {
    179.         return 0;
    180.     }
    181.     LRESULT OnHScroll(WPARAM wparam)
    182.     {
    183.         return 0;
    184.     }
    185.     LRESULT OnMouseWheel(WPARAM wparam)
    186.     {
    187.         return 0;
    188.     }
    189.     LRESULT OnTimer(WPARAM wparam)
    190.     {
    191.         return 0;
    192.     }
    193.     // Các hàm vẽ lên DC bộ nhớ
    194.     void FillBack(HDC hdc, RECT rect)
    195.     {
    196.         // Tô nền DC
    197.         HBRUSH  hbr = CreateSolidBrush(m_back);
    198.         FillRect(hdc, &rect, hbr);
    199.         DeleteObject(hbr);
    200.     }
    201.     void DrawHeader(HDC hdc, RECT rect)
    202.     {
    203.         rect.bottom = rect.top + CGlobal::GetHeaderHeight(hdc);
    204.         if (m_columns.empty())
    205.             FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DFACE));
    206.         else
    207.         {
    208.             rect.right += 2;    // Vẽ tràn ra ngoài để mất biên phải - thẩm mỹ
    209.             DrawFrameControl(hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
    210.             rect.right -= 2;
    211.             DrawColumns(hdc, rect);
    212.         }
    213.     }
    214.     void DrawColumns(HDC hdc, RECT rect)
    215.     {
    216.     }
    217.     void DrawItems(HDC hdc, RECT rect)
    218.     {
    219.     }
    220. public:
    221.     // Khởi tạo - hủy
    222.     CGrid()
    223.     {
    224.         m_columns.resize(0);
    225.         m_items.resize(0);
    226.     }
    227.     ~CGrid()
    228.     {
    229.         for (int i = m_columns.size() - 1; i >= 0; i--)
    230.             delete m_columns[i];
    231.         for (int i = m_items.size() - 1; i >= 0; i--)
    232.             delete m_items[i];
    233.     }
    234.     // Thuộc tính
    235.     // Phương thức Get
    236.     // Phương thức Set
    237.     // Hàm công cộng
    238.     // Các hàm công cộng
    239.     HWND Create(HINSTANCE instance, HWND parent, int left, int top, int width, int height)
    240.     {
    241.         // Sử dụng biến tĩnh để tránh đăng ký nhiều lần
    242.         static  bool    registered = false;
    243.         WNDCLASS        w;
    244.         w.lpszClassName = TEXT("GridviewClass32");
    245.         if (!registered)
    246.         {
    247.             w.cbClsExtra = 0;
    248.             w.cbWndExtra = 0;
    249.             w.hbrBackground = NULL;
    250.             w.hCursor = LoadCursor(NULL, IDC_ARROW);
    251.             w.hIcon = NULL;
    252.             w.hInstance = instance;
    253.             w.lpfnWndProc = WndProc;
    254.             w.lpszMenuName = NULL;
    255.             w.style = CS_HREDRAW | CS_VREDRAW;
    256.             if (!RegisterClass(&w))
    257.                 return NULL;
    258.             registered = true;
    259.         }
    260.         return CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME, w.lpszClassName, NULL,
    261.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN,
    262.             left, top, width, height, parent, NULL, instance, this);
    263.     }
    264.     void Move(int left, int top, int width, int height, BOOL redraw)
    265.     {
    266.         MoveWindow(m_hwnd, left, top, width, height, redraw);
    267.     }
    268.     void Refresh()
    269.     {
    270.         // Hàm dùng kỹ thuật vẽ trên DC bộ nhớ để chống nháy hình, chỉ vẽ chồng 1 lần duy nhất
    271.         RECT    r;
    272.         GetClientRect(m_hwnd, &r);
    273.         int     cx = r.right - r.left;
    274.         int     cy = r.bottom - r.top;
    275.         HDC     hdc = GetDC(m_hwnd);
    276.         HDC     hdcMem = CreateCompatibleDC(hdc);
    277.         HBITMAP hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
    278.         // Bắt đầu vẽ trên DC bộ nhớ
    279.         SelectObject(hdcMem, hBitmap);
    280.         SetBkMode(hdcMem, TRANSPARENT);
    281.         FillBack(hdcMem, r);        // Tô nền DC Memory
    282.         if (!m_noheader)
    283.             DrawHeader(hdcMem, r);  // Vẽ Header
    284.         if (!m_items.empty())
    285.         {
    286.             if (!m_noheader)
    287.                 r.bottom += CGlobal::GetHeaderHeight(hdcMem);
    288.             DrawItems(hdcMem, r);   // Vẽ các Items
    289.         }
    290.         // Vẽ từ DC bộ nhớ lên DC màn hình chỉ 1 lần duy nhất
    291.         BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
    292.         // Giải phóng các đối tượng
    293.         DeleteObject(hBitmap);
    294.         DeleteDC(hdcMem);
    295.         ReleaseDC(m_hwnd, hdc);
    296.     }
    297. };
    298. class CWindow
    299. {
    300.     enum
    301.     {
    302.         // Định danh MenuItem
    303.         IDM_FILE_NEW = 10001, IDM_FILE_OPEN, IDM_FILE_SAVE, IDM_FILE_CLOSE, IDM_FILE_EXIT,
    304.         IDM_OPTION_BACKGROUND,
    305.     };
    306. private:
    307.     HWND        m_hwnd = NULL;                  // Thẻ cửa sổ
    308.     COLORREF    m_crBack = RGB(128, 128, 128);  // Màu nền
    309.     CGrid       m_grid;                         // Một thể hiện lớp Grid
    310.    
    311.     // Thủ tục xử lý sự kiện
    312.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    313.     {
    314.         if (msg == WM_CREATE)
    315.         {
    316.             LPCREATESTRUCT  pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    317.             CWindow * pWindow = reinterpret_cast<CWindow*>(pcs->lpCreateParams);
    318.             SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pWindow));
    319.             return pWindow->OnCreate(pcs->hInstance, hwnd);
    320.         }
    321.         CWindow * pWindow = reinterpret_cast<CWindow*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    322.         switch (msg)
    323.         {
    324.         case WM_SIZE:           return pWindow->OnSize(lparam);
    325.         case WM_COMMAND:        return pWindow->OnCommand(wparam, lparam);
    326.         case WM_CLOSE:          return pWindow->OnClose(wparam, lparam);
    327.         case WM_DESTROY:        return pWindow->OnDestroy();
    328.         }
    329.         return DefWindowProc(hwnd, msg, wparam, lparam);
    330.     }
    331.     // Các bộ xử lý sự kiện
    332.     LRESULT OnCreate(HINSTANCE instance, HWND hwnd)
    333.     {
    334.         m_hwnd = hwnd;
    335.         m_grid.Create(instance, hwnd, 0, 0, 0, 0);
    336.         return 0;
    337.     }
    338.     LRESULT OnSize(LPARAM lparam)
    339.     {
    340.         // Cho Grid chiếm gần hết cửa sổ Test
    341.         m_grid.Move(20, 20, LOWORD(lparam) - 40, HIWORD(lparam) - 40, TRUE);
    342.         return 0;
    343.     }
    344.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    345.     {
    346.         switch (LOWORD(wparam))
    347.         {
    348.         case IDM_FILE_NEW:              MenuClick_New(); return 0;
    349.         case IDM_FILE_OPEN:             MenuClick_Open(); return 0;
    350.         case IDM_FILE_SAVE:             MenuClick_Save(); return 0;
    351.         case IDM_FILE_CLOSE:            MenuClick_Close(); return 0;
    352.         case IDM_FILE_EXIT:             MenuClick_Exit(); return 0;
    353.         case IDM_OPTION_BACKGROUND:     MenuClick_BackGround(); return 0;
    354.         }
    355.         return DefWindowProc(m_hwnd, WM_COMMAND, wparam, lparam);
    356.     }
    357.     LRESULT OnClose(WPARAM wparam, LPARAM lparam)
    358.     {
    359.         DestroyWindow(m_hwnd);
    360.         return 0;
    361.     }
    362.     LRESULT OnDestroy()
    363.     {
    364.         PostQuitMessage(0);
    365.         return 0;
    366.     }
    367.     // Các hàm xử lý trình đơn
    368.     void MenuClick_New()
    369.     {
    370.     }
    371.     void MenuClick_Open()
    372.     {
    373.     }
    374.     void MenuClick_Save()
    375.     {
    376.     }
    377.     void MenuClick_Close()
    378.     {
    379.     }
    380.     void MenuClick_Exit()
    381.     {
    382.         SendMessage(m_hwnd, WM_CLOSE, 0, 0);
    383.     }
    384.     void MenuClick_BackGround()
    385.     {
    386.         if (CGlobal::ChangeColor(m_hwnd, m_crBack))
    387.         {
    388.             DeleteObject((HBRUSH)SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (long)CreateSolidBrush(m_crBack)));
    389.             InvalidateRect(m_hwnd, NULL, TRUE);
    390.         }
    391.     }
    392.     HMENU BuildMenu()
    393.     {
    394.         HMENU   hMenu = CreateMenu();
    395.         HMENU   hFile = CreatePopupMenu();
    396.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFile, TEXT("&File"));
    397.         AppendMenu(hFile, MF_STRING, IDM_FILE_NEW, TEXT("&New"));
    398.         AppendMenu(hFile, MF_STRING, IDM_FILE_OPEN, TEXT("&Open..."));
    399.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_SAVE, TEXT("&Save..."));
    400.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_CLOSE, TEXT("&Close"));
    401.         AppendMenu(hFile, MF_SEPARATOR, 0, NULL);
    402.         AppendMenu(hFile, MF_STRING, IDM_FILE_EXIT, TEXT("&Exit"));
    403.  
    404.         HMENU   hOption = CreatePopupMenu();
    405.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hOption, TEXT("&Option"));
    406.         AppendMenu(hOption, MF_STRING, IDM_OPTION_BACKGROUND, TEXT("&BackGround..."));
    407.  
    408.         return hMenu;
    409.     }
    410. public:
    411.     int Create(HINSTANCE hInst)
    412.     {
    413.         // Đăng ký lớp
    414.         WNDCLASS    w;
    415.         w.cbClsExtra = 0;
    416.         w.cbWndExtra = 0;
    417.         w.hbrBackground = CreateSolidBrush(m_crBack);
    418.         w.hCursor = LoadCursor(NULL, IDC_ARROW);
    419.         w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    420.         w.hInstance = hInst;
    421.         w.lpfnWndProc = WndProc;
    422.         w.lpszClassName = TEXT("TestGridview");
    423.         w.lpszMenuName = NULL;
    424.         w.style = CS_HREDRAW | CS_VREDRAW;
    425.         if (!RegisterClass(&w))
    426.             return 0;
    427.         // Tạo cửa sổ
    428.         HWND    hwnd = CreateWindow(w.lpszClassName, w.lpszClassName, WS_OVERLAPPEDWINDOW,
    429.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, BuildMenu(), hInst, this);
    430.         if (!hwnd)
    431.             return 0;
    432.         ShowWindow(hwnd, SW_SHOW);
    433.         UpdateWindow(hwnd);
    434.         // Vòng lặp thông điệp
    435.         MSG     msg;
    436.         while (GetMessage(&msg, NULL, 0, 0))
    437.         {
    438.             TranslateMessage(&msg);
    439.             DispatchMessage(&msg);
    440.         }
    441.         return msg.wParam;
    442.     }
    443. };
    444. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
    445. {
    446.     CWindow     Window;
    447.     return Window.Create(hInst);
    448. }

    Tới đây điều khiển trông như hình bên dưới, chưa có gì cả.
    Attached Thumbnails Attached Thumbnails New Bitmap Image.png  
    Đã được chỉnh sửa lần cuối bởi MHoang : 22-07-2020 lúc 10:26 PM.

Quyền hạn của bạn

  • Bạn không thể gửi đề tài mới
  • Bạn không thể gửi bài trả lời
  • Bạn không thể gửi các đính kèm
  • Bạn không thể chỉnh sửa bài viết của bạn