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 2 trên tổng số 2 kết quả

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

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

    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ông cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.
    Đã được chỉnh sửa lần cuối bởi MHoang : 22-07-2020 lúc 10:26 PM.

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

    Mã số 3, phân tích sau
    Visual C++ Code:
    1. #include <windows.h>
    2. #include <vector>
    3. #include <time.h>
    4. using namespace std;
    5.  
    6. #ifdef UNICODE
    7. #define String  wstring
    8. #else
    9. #define String  string
    10. #endif // UNICODE
    11.  
    12. typedef struct
    13. {
    14.     // Các thuộc tính mà Grid đề xuất cho Column và Cell sử dụng
    15.     HFONT       Font = CreateFont(18, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Courier New"));
    16.     //HFONT     Font = CreateFont(18, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("Times New Roman"));
    17.     //HFONT     Font = CreateFont(18, 0, 0, 0, FW_BOLD, 0, 0, 0, 0, 0, 0, 0, 0, TEXT("MS Sans serif"));
    18.     DWORD       Align = DT_SINGLELINE | DT_VCENTER | DT_CENTER;     // Align chung
    19.     int         Margin = 10;                                        // Margin chung
    20.     COLORREF    BackColumn = GetSysColor(COLOR_3DLIGHT);            // Màu nền chung cho các Columns
    21.     COLORREF    ForeColumn = GetSysColor(COLOR_BTNTEXT);            // Màu chữ chung cho các Columns
    22.     COLORREF    NormalBackCell = RGB(0, 255, 255);                  // Màu nền chung cho các Cells
    23.     COLORREF    NormalForeCell = RGB(255, 0, 0);                    // Màu chữ chung cho các Cells
    24.     COLORREF    SelectBackCell = RGB(255, 0, 255);                  // Màu nền chung của các Cells chọn
    25.     COLORREF    SelectForeCell = RGB(255, 255, 0);                  // Màu chữ chung của các Cells chọn
    26.     COLORREF    SelectBackText = RGB(0, 0, 255);                    // Màu nền chung của text chọn
    27.     COLORREF    SelectForeText = RGB(192, 192, 255);                // Màu chữ chung của text chọn
    28.     COLORREF    CaretColor = RGB(0, 0, 0);                          // Màu vẽ Caret chung
    29. } SHAREPROP, *PSHAREPROP;
    30. class CGlobal
    31. {
    32. public:
    33.     // Thay đổi màu một đối tượng
    34.     static bool ChangeColor(HWND hwnd, COLORREF & crColor)
    35.     {
    36.         CHOOSECOLOR     cc;
    37.         COLORREF        arColor[16];
    38.  
    39.         ZeroMemory(&cc, sizeof(cc));
    40.         cc.lStructSize = sizeof(cc);
    41.         cc.hwndOwner = hwnd;
    42.         cc.lpCustColors = (LPDWORD)arColor;
    43.         cc.Flags = CC_FULLOPEN | CC_RGBINIT;
    44.         cc.rgbResult = crColor;
    45.         if (ChooseColor(&cc) && crColor != cc.rgbResult)
    46.         {
    47.             crColor = cc.rgbResult;
    48.             return true;
    49.         }
    50.         return false;
    51.     }
    52.     static int GetCellHeight(HDC hdc)
    53.     {
    54.         TEXTMETRIC  tm;
    55.         GetTextMetrics(hdc, &tm);
    56.         return tm.tmHeight + tm.tmExternalLeading + 4;
    57.     }
    58.     static int GetHeaderHeight(HDC hdc)
    59.     {
    60.         return GetCellHeight(hdc) + 2;
    61.     }
    62. };
    63. class CColumn
    64. {
    65. private:
    66.     bool        m_selffont = false;     // 1: Sử dụng font chữ riêng ?
    67.     bool        m_selfalign = false;    // 2: Sử dụng canh chỉnh riêng ?
    68.     bool        m_selfmargin = false;   // 3: Sử dụng khoảng chừa lề riêng ?
    69.     bool        m_selfback = false;     // 4: Sử dụng màu nền riêng ?
    70.     bool        m_selffore = false;     // 5: Sử dụng màu chữ riêng ?
    71.     HFONT       m_font = NULL;          // 6: Font riêng
    72.     DWORD       m_align = 0;            // 7: Align riêng
    73.     int         m_margin = 0;           // 8: Margin riêng
    74.     COLORREF    m_back = 0;             // 9: Màu nền riêng
    75.     COLORREF    m_fore = 0;             // 10: Màu chữ riêng
    76.     PSHAREPROP  m_pshare = NULL;        // 11: Con trỏ tới các thuộc tính dùng chung
    77.     String      m_text = TEXT("");      // 12: Chuỗi text hiển thị
    78.     int         m_width = 0;            // 13: Chiều rộng column theo pixel
    79.    
    80. public:
    81.     // Khởi tạo - hủy
    82.     CColumn(PSHAREPROP pshare, String text, int width)
    83.     {
    84.         m_pshare = pshare;
    85.         m_text = text;
    86.         m_width = width;
    87.     }
    88.     ~CColumn()
    89.     {
    90.         // Hủy font riêng nếu có
    91.         if (m_font)
    92.             DeleteObject(m_font);
    93.     }
    94.     // Thuộc tính
    95.     __declspec(property(get = _getSelfFont, put = _setSelfFont)) bool       SelfFont;   // 1
    96.     __declspec(property(get = _getSelfAlign, put = _setSelfAlign)) bool     SelfAlign;  // 2
    97.     __declspec(property(get = _getSelfMargin, put = _setSelfMargin)) bool   SelfMargin; // 3
    98.     __declspec(property(get = _getSelfBack, put = _setSelfBack)) bool       SelfBack;   // 4
    99.     __declspec(property(get = _getSelfFore, put = _setSelfFore)) bool       SelfFore;   // 5
    100.     __declspec(property(get = _getFont, put = _setFont)) HFONT              Font;       // 6
    101.     __declspec(property(get = _getAlign, put = _setAlign)) DWORD            Align;      // 7
    102.     __declspec(property(get = _getMargin, put = _setMargin)) int            Margin;     // 8
    103.     __declspec(property(get = _getBack, put = _setBack)) COLORREF           Back;       // 9
    104.     __declspec(property(get = _getFore, put = _setFore)) COLORREF           Fore;       // 10
    105.     __declspec(property(get = _getSharePtr, put = _setSharePtr)) PSHAREPROP SharePtr;   // 11
    106.     __declspec(property(get = _getText, put = _setText)) String             Text;       // 12
    107.     __declspec(property(get = _getWidth, put = _setWidth)) int              Width;      // 13
    108.     // Phương thức Get
    109.     bool _getSelfFont() { return m_selffont; }          // 1
    110.     bool _getSelfAlign() { return m_selfalign;}         // 2
    111.     bool _getSelfMargin() { return m_selfmargin; }      // 3
    112.     bool _getSelfBack() { return m_selfback; }          // 4
    113.     bool _getSelfFore() { return m_selffore; }          // 5
    114.     HFONT _getFont() { return m_font; }                 // 6
    115.     DWORD _getAlign() { return m_align; }               // 7
    116.     int _getMargin() { return m_margin; }               // 8
    117.     COLORREF _getBack() { return m_back; }              // 9
    118.     COLORREF _getFore() { return m_fore; }              // 10
    119.     PSHAREPROP _getSharePtr() { return m_pshare; }      // 11
    120.     String _getText() { return m_text; }                // 12
    121.     int _getWidth() { return m_width; }                 // 13
    122.     // Phương thức Set
    123.     void _setSelfFont(bool self) { m_selffont = self; }             // 1
    124.     void _setSelfAlign(bool self) { m_selfalign = self; }           // 2
    125.     void _setSelfMargin(bool self) { m_selfmargin = self; }         // 3
    126.     void _setSelfBack(bool self) { m_selfback = self; }             // 4
    127.     void _setSelfFore(bool self) { m_selffore = self; }             // 5
    128.     void _setFont(HFONT font) { m_font = font; }                    // 6
    129.     void _setAlign(DWORD align) { m_align = align; }                // 7
    130.     void _setMargin(int margin) { m_margin = margin; }              // 8
    131.     void _setBack(COLORREF color) { m_back = color; }               // 9
    132.     void _setFore(COLORREF color) { m_fore = color; }               // 10
    133.     void _setSharePtr(PSHAREPROP pshare) { m_pshare = pshare; }     // 11
    134.     void _setText(String text) { m_text = text; }                   // 12
    135.     void _setWidth(int width) { m_width = width; }                  // 13
    136.     // Hàm công cộng
    137.     void Draw(HDC hdc, RECT rect)
    138.     {
    139.         // Vẽ khung như button
    140.         DrawFrameControl(hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
    141.         rect.left += 2;
    142.         rect.right -= 2;
    143.         rect.top += 2;
    144.         rect.bottom -= 2;
    145.         // Tô màu nền
    146.         HBRUSH  hbr = CreateSolidBrush(m_selfback ? m_back : m_pshare->BackColumn);
    147.         FillRect(hdc, &rect, hbr);
    148.         DeleteObject(hbr);
    149.         // Tính khoảng canh lề
    150.         rect.left += (m_selfmargin ? m_margin : m_pshare->Margin) - 2;
    151.         rect.right -= (m_selfmargin ? m_margin : m_pshare->Margin) - 2;
    152.         // Vẽ text
    153.         SetTextColor(hdc, m_selffore ? m_fore : m_pshare->ForeColumn);
    154.         if (m_selffont)
    155.             SelectObject(hdc, m_font);
    156.         DrawText(hdc, m_text.c_str(), -1, &rect, m_selfalign ? m_align : m_pshare->Align);
    157.         if (m_selffont)
    158.             SelectObject(hdc, m_pshare->Font);
    159.     }
    160. };
    161. class CCell
    162. {
    163. private:
    164.     // Hàm cục bộ
    165. public:
    166.     // Khởi tạo - hủy
    167.     // Thuộc tính
    168.     // Phương thức Get
    169.     // Phương thức Set
    170.     // Hàm công cộng
    171. };
    172. class CItem
    173. {
    174. private:
    175.     // Hàm cục bộ
    176. public:
    177.     // Khởi tạo - hủy
    178.     // Thuộc tính
    179.     // Phương thức Get
    180.     // Phương thức Set
    181.     // Hàm công cộng
    182. };
    183. class CGrid
    184. {
    185. private:
    186.     SHAREPROP           m_shareprop;                    // Các thuộc tính dùng chung
    187.     HWND                m_hwnd = NULL;                  // Thẻ cửa sổ
    188.     COLORREF            m_back = RGB(64, 128, 128);     // Màu nền
    189.     bool                m_noheader = false;             // Điều khiển có Header hay không ?
    190.     vector<CColumn*>    m_columns;                      // Các ColumnHeader
    191.     vector<CItem*>      m_items;                        // Các Items dòng
    192.  
    193.     // Thủ tục xử lý sự kiện
    194.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    195.     {
    196.         if (msg == WM_CREATE)
    197.         {
    198.             LPCREATESTRUCT  pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    199.             CGrid * pGrid = reinterpret_cast<CGrid*>(pcs->lpCreateParams);
    200.             SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pGrid));
    201.             return pGrid->OnCreate(hwnd);
    202.         }
    203.         CGrid * pGrid = reinterpret_cast<CGrid*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    204.         switch (msg)
    205.         {
    206.         case WM_SIZE:           return pGrid->OnSize(lparam);
    207.         case WM_SETFOCUS:       return pGrid->OnSetFocus();
    208.         case WM_KILLFOCUS:      return pGrid->OnKillFocus();
    209.         case WM_ERASEBKGND:     return pGrid->OnEraseBackGround();
    210.         case WM_PAINT:          return pGrid->OnPaint();
    211.         case WM_LBUTTONDOWN:    return pGrid->OnLButtonDown(lparam);
    212.         case WM_MOUSEMOVE:      return pGrid->OnMouseMove(lparam);
    213.         case WM_LBUTTONUP:      return pGrid->OnLButtonUp(lparam);
    214.         case WM_CONTEXTMENU:    return pGrid->OnContextMenu(wparam, lparam);
    215.         case WM_COMMAND:        return pGrid->OnCommand(wparam, lparam);
    216.         case WM_KEYDOWN:        return pGrid->OnKeyDown(wparam, lparam);
    217.         case WM_CHAR:           return pGrid->OnChar(wparam);
    218.         case WM_VSCROLL:        return pGrid->OnVScroll(wparam);
    219.         case WM_HSCROLL:        return pGrid->OnHScroll(wparam);
    220.         case WM_MOUSEWHEEL:     return pGrid->OnMouseWheel(wparam);
    221.         case WM_TIMER:          return pGrid->OnTimer(wparam);
    222.         }
    223.         return DefWindowProc(hwnd, msg, wparam, lparam);
    224.     }
    225.     // Các bộ xử lý sự kiện
    226.     LRESULT OnCreate(HWND hwnd)
    227.     {
    228.         m_hwnd = hwnd;
    229.         // Chưa hiển thị các thanh cuộn
    230.         SetScrollRange(hwnd, SB_VERT, 0, 0, FALSE);
    231.         SetScrollRange(hwnd, SB_HORZ, 0, 0, FALSE);
    232.         return 0;
    233.     }
    234.     LRESULT OnSize(LPARAM lparam)
    235.     {
    236.         Refresh();
    237.         return 0;
    238.     }
    239.     LRESULT OnKillFocus()
    240.     {
    241.         Refresh();
    242.         return 0;
    243.     }
    244.     LRESULT OnSetFocus()
    245.     {
    246.         Refresh();
    247.         return 0;
    248.     }
    249.     LRESULT OnEraseBackGround()
    250.     {
    251.         return -1;
    252.     }
    253.     LRESULT OnPaint()
    254.     {
    255.         PAINTSTRUCT ps;
    256.         BeginPaint(m_hwnd, &ps);
    257.         EndPaint(m_hwnd, &ps);
    258.         Refresh();
    259.         return 0;
    260.     }
    261.     LRESULT OnLButtonDown(LPARAM lparam)
    262.     {
    263.         SetFocus(m_hwnd);
    264.         return 0;
    265.     }
    266.     LRESULT OnMouseMove(LPARAM lparam)
    267.     {
    268.         return 0;
    269.     }
    270.     LRESULT OnLButtonUp(LPARAM lparam)
    271.     {
    272.         return 0;
    273.     }
    274.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    275.     {
    276.         return DefWindowProc(m_hwnd, WM_COMMAND, wparam, lparam);
    277.     }
    278.     LRESULT OnContextMenu(WPARAM wparam, LPARAM lparam)
    279.     {
    280.         return DefWindowProc(m_hwnd, WM_CONTEXTMENU, wparam, lparam);
    281.     }
    282.     LRESULT OnKeyDown(WPARAM wparam, LPARAM lparam)
    283.     {
    284.         return DefWindowProc(m_hwnd, WM_KEYDOWN, wparam, lparam);
    285.     }
    286.     LRESULT OnChar(WPARAM wparam)
    287.     {
    288.         return 0;
    289.     }
    290.     LRESULT OnVScroll(WPARAM wparam)
    291.     {
    292.         return 0;
    293.     }
    294.     LRESULT OnHScroll(WPARAM wparam)
    295.     {
    296.         return 0;
    297.     }
    298.     LRESULT OnMouseWheel(WPARAM wparam)
    299.     {
    300.         return 0;
    301.     }
    302.     LRESULT OnTimer(WPARAM wparam)
    303.     {
    304.         return 0;
    305.     }
    306.     // Các hàm vẽ lên DC bộ nhớ
    307.     void FillBack(HDC hdc, RECT rect)
    308.     {
    309.         // Tô nền DC
    310.         HBRUSH  hbr = CreateSolidBrush(m_back);
    311.         FillRect(hdc, &rect, hbr);
    312.         DeleteObject(hbr);
    313.     }
    314.     void DrawHeader(HDC hdc, RECT rect)
    315.     {
    316.         rect.bottom = rect.top + CGlobal::GetHeaderHeight(hdc);
    317.         if (m_columns.empty())
    318.             FillRect(hdc, &rect, GetSysColorBrush(COLOR_3DFACE));
    319.         else
    320.         {
    321.             rect.right += 2;    // Vẽ tràn ra ngoài để mất biên phải - thẩm mỹ
    322.             DrawFrameControl(hdc, &rect, DFC_BUTTON, DFCS_BUTTONPUSH);
    323.             rect.right -= 2;
    324.             DrawColumns(hdc, rect);
    325.         }
    326.     }
    327.     void DrawColumns(HDC hdc, RECT rect)
    328.     {
    329.         int     xStart = 0;
    330.         int     numcolumns = m_columns.size();
    331.         for (int i = 0; i < numcolumns; xStart += m_columns[i++]->Width)
    332.         {
    333.             rect.left = xStart;
    334.             rect.right = rect.left + m_columns[i]->Width;
    335.             m_columns[i]->Draw(hdc, rect);
    336.         }
    337.     }
    338.     void DrawItems(HDC hdc, RECT rect)
    339.     {
    340.     }
    341. public:
    342.     // Khởi tạo - hủy
    343.     CGrid()
    344.     {
    345.         m_columns.resize(0);
    346.         m_items.resize(0);
    347.     }
    348.     ~CGrid()
    349.     {
    350.         for (int i = m_columns.size() - 1; i >= 0; i--)
    351.             delete m_columns[i];
    352.         for (int i = m_items.size() - 1; i >= 0; i--)
    353.             delete m_items[i];
    354.         DeleteObject(m_shareprop.Font);
    355.     }
    356.     // Thuộc tính
    357.     __declspec(property(get = _getColumns)) vector<CColumn*> & Columns;
    358.     // Phương thức Get
    359.     vector<CColumn*> & _getColumns() { return m_columns; }
    360.     // Phương thức Set
    361.     // Các hàm công cộng
    362.     HWND Create(HINSTANCE instance, HWND parent, int left, int top, int width, int height)
    363.     {
    364.         // Sử dụng biến tĩnh để tránh đăng ký nhiều lần
    365.         static  bool    registered = false;
    366.         WNDCLASS        w;
    367.         w.lpszClassName = TEXT("GridviewClass32");
    368.         if (!registered)
    369.         {
    370.             w.cbClsExtra = 0;
    371.             w.cbWndExtra = 0;
    372.             w.hbrBackground = NULL;
    373.             w.hCursor = LoadCursor(NULL, IDC_ARROW);
    374.             w.hIcon = NULL;
    375.             w.hInstance = instance;
    376.             w.lpfnWndProc = WndProc;
    377.             w.lpszMenuName = NULL;
    378.             w.style = CS_HREDRAW | CS_VREDRAW;
    379.             if (!RegisterClass(&w))
    380.                 return NULL;
    381.             registered = true;
    382.         }
    383.         return CreateWindowEx(WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME, w.lpszClassName, NULL,
    384.             WS_CHILD | WS_VISIBLE | WS_BORDER | WS_HSCROLL | WS_VSCROLL | WS_CLIPCHILDREN,
    385.             left, top, width, height, parent, NULL, instance, this);
    386.     }
    387.     void Move(int left, int top, int width, int height, BOOL redraw)
    388.     {
    389.         MoveWindow(m_hwnd, left, top, width, height, redraw);
    390.     }
    391.     void Refresh()
    392.     {
    393.         // 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
    394.         RECT    r;
    395.         GetClientRect(m_hwnd, &r);
    396.         int     cx = r.right - r.left;
    397.         int     cy = r.bottom - r.top;
    398.         HDC     hdc = GetDC(m_hwnd);
    399.         HDC     hdcMem = CreateCompatibleDC(hdc);
    400.         HBITMAP hBitmap = CreateCompatibleBitmap(hdc, cx, cy);
    401.         // Bắt đầu vẽ trên DC bộ nhớ
    402.         SelectObject(hdcMem, hBitmap);
    403.         SelectObject(hdcMem, m_shareprop.Font);
    404.         SetBkMode(hdcMem, TRANSPARENT);
    405.         FillBack(hdcMem, r);        // Tô nền DC Memory
    406.         if (!m_noheader)
    407.             DrawHeader(hdcMem, r);  // Vẽ Header
    408.         if (!m_items.empty())
    409.         {
    410.             if (!m_noheader)
    411.                 r.top += CGlobal::GetHeaderHeight(hdcMem);
    412.             DrawItems(hdcMem, r);   // Vẽ các Items
    413.         }
    414.         // Vẽ từ DC bộ nhớ lên DC màn hình chỉ 1 lần duy nhất
    415.         BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
    416.         // Giải phóng các đối tượng
    417.         DeleteObject(hBitmap);
    418.         DeleteDC(hdcMem);
    419.         ReleaseDC(m_hwnd, hdc);
    420.     }
    421.     // Cộng thêm 1 column vào cuối Header
    422.     void AddColumn(const PTCHAR columntext, int columnwidth)
    423.     {
    424.         m_columns.push_back(new CColumn(&m_shareprop,columntext, columnwidth));
    425.         Refresh();
    426.     }
    427.     // Cộng thêm nhiều columns 1 lần
    428.     void AddColumns(const PTCHAR * pcolumntext, int * pcolumnwidth, int count)
    429.     {
    430.         for (int i = 0; i < count; i++)
    431.             m_columns.push_back(new CColumn(&m_shareprop, pcolumntext[i], pcolumnwidth[i]));
    432.         Refresh();
    433.     }
    434.     // Chèn thêm 1 column tại chỉ mục
    435.     void InsertColumn(int index, const PTCHAR columntext, int columnwidth)
    436.     {
    437.         if (index < 0)
    438.             return;
    439.         if (index < (int)m_columns.size())
    440.             m_columns.insert(m_columns.begin() + index, new CColumn(&m_shareprop, columntext, columnwidth));
    441.         else
    442.             m_columns.push_back(new CColumn(&m_shareprop, columntext, columnwidth));
    443.         Refresh();
    444.     }
    445.     // Chèn thêm nhiều column từ chỉ mục
    446.     void InsertColumns(int index, const PTCHAR * pcolumntext, int * pcolumnwidth, int count)
    447.     {
    448.         if (index < 0)
    449.             return;
    450.         if (index < (int)m_columns.size())
    451.         {
    452.             for (int i = 0; i < count; i++)
    453.                 m_columns.insert(m_columns.begin() + index, new CColumn(&m_shareprop, pcolumntext[i], pcolumnwidth[i]));
    454.         }
    455.         else
    456.         {
    457.             for (int i = 0; i < count; i++)
    458.                 m_columns.push_back(new CColumn(&m_shareprop, pcolumntext[i], pcolumnwidth[i]));
    459.         }
    460.         Refresh();
    461.     }
    462.     // Xóa column tại chỉ mục
    463.     void DeleteColumn(int index)
    464.     {
    465.         if (0 <= index && index < (int)m_columns.size())
    466.             m_columns.erase(m_columns.begin() + index);
    467.         Refresh();
    468.     }
    469.     // Xóa tất cả column
    470.     void DeleteAllColumns()
    471.     {
    472.         for (int i = m_columns.size() - 1; i >= 0; i--)
    473.             m_columns.erase(m_columns.begin() + i);
    474.         Refresh();
    475.     }
    476. };
    477. class CWindow
    478. {
    479.     enum
    480.     {
    481.         // Định danh MenuItem
    482.         IDM_FILE_NEW = 10001, IDM_FILE_OPEN, IDM_FILE_SAVE, IDM_FILE_CLOSE, IDM_FILE_EXIT,
    483.         IDM_OPTION_BACKGROUND,
    484.     };
    485. private:
    486.     HWND        m_hwnd = NULL;                  // Thẻ cửa sổ
    487.     COLORREF    m_crBack = RGB(128, 128, 128);  // Màu nền
    488.     CGrid       m_grid;                         // Một thể hiện lớp Grid
    489.    
    490.     // Thủ tục xử lý sự kiện
    491.     static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
    492.     {
    493.         if (msg == WM_CREATE)
    494.         {
    495.             LPCREATESTRUCT  pcs = reinterpret_cast<LPCREATESTRUCT>(lparam);
    496.             CWindow * pWindow = reinterpret_cast<CWindow*>(pcs->lpCreateParams);
    497.             SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pWindow));
    498.             return pWindow->OnCreate(pcs->hInstance, hwnd);
    499.         }
    500.         CWindow * pWindow = reinterpret_cast<CWindow*>(static_cast<LONG_PTR>(GetWindowLongPtr(hwnd, GWLP_USERDATA)));
    501.         switch (msg)
    502.         {
    503.         case WM_SIZE:           return pWindow->OnSize(lparam);
    504.         case WM_COMMAND:        return pWindow->OnCommand(wparam, lparam);
    505.         case WM_CLOSE:          return pWindow->OnClose(wparam, lparam);
    506.         case WM_DESTROY:        return pWindow->OnDestroy();
    507.         }
    508.         return DefWindowProc(hwnd, msg, wparam, lparam);
    509.     }
    510.     // Các bộ xử lý sự kiện
    511.     LRESULT OnCreate(HINSTANCE instance, HWND hwnd)
    512.     {
    513.         m_hwnd = hwnd;
    514.         m_grid.Create(instance, hwnd, 0, 0, 0, 0);
    515.         srand((UINT)time(NULL));
    516.         return 0;
    517.     }
    518.     LRESULT OnSize(LPARAM lparam)
    519.     {
    520.         // Cho Grid chiếm gần hết cửa sổ Test
    521.         m_grid.Move(20, 20, LOWORD(lparam) - 40, HIWORD(lparam) - 40, TRUE);
    522.         return 0;
    523.     }
    524.     LRESULT OnCommand(WPARAM wparam, LPARAM lparam)
    525.     {
    526.         switch (LOWORD(wparam))
    527.         {
    528.         case IDM_FILE_NEW:              MenuClick_New(); return 0;
    529.         case IDM_FILE_OPEN:             MenuClick_Open(); return 0;
    530.         case IDM_FILE_SAVE:             MenuClick_Save(); return 0;
    531.         case IDM_FILE_CLOSE:            MenuClick_Close(); return 0;
    532.         case IDM_FILE_EXIT:             MenuClick_Exit(); return 0;
    533.         case IDM_OPTION_BACKGROUND:     MenuClick_BackGround(); return 0;
    534.         }
    535.         return DefWindowProc(m_hwnd, WM_COMMAND, wparam, lparam);
    536.     }
    537.     LRESULT OnClose(WPARAM wparam, LPARAM lparam)
    538.     {
    539.         DestroyWindow(m_hwnd);
    540.         return 0;
    541.     }
    542.     LRESULT OnDestroy()
    543.     {
    544.         PostQuitMessage(0);
    545.         return 0;
    546.     }
    547.     // Các hàm xử lý trình đơn
    548.     void MenuClick_New()
    549.     {
    550.         if (!m_grid.Columns.empty())
    551.             m_grid.DeleteAllColumns();
    552.  
    553.         TCHAR       szText[MAX_PATH];
    554.         int     cRand = rand() % 7 + 4;     // khoảng [4,10]
    555.         for (int c = 0; c < cRand; c++)
    556.         {
    557.             wsprintf(szText, TEXT("Column %d"), c + 1);
    558.             m_grid.AddColumn(szText, rand() % 151 + 100);   // khoảng [100,250]
    559.         }
    560.         EnableMenuItem(GetMenu(m_hwnd), IDM_FILE_CLOSE, MF_ENABLED);
    561.     }
    562.     void MenuClick_Open()
    563.     {
    564.     }
    565.     void MenuClick_Save()
    566.     {
    567.     }
    568.     void MenuClick_Close()
    569.     {
    570.     }
    571.     void MenuClick_Exit()
    572.     {
    573.         SendMessage(m_hwnd, WM_CLOSE, 0, 0);
    574.     }
    575.     void MenuClick_BackGround()
    576.     {
    577.         if (CGlobal::ChangeColor(m_hwnd, m_crBack))
    578.         {
    579.             DeleteObject((HBRUSH)SetClassLongPtr(m_hwnd, GCLP_HBRBACKGROUND, (long)CreateSolidBrush(m_crBack)));
    580.             InvalidateRect(m_hwnd, NULL, TRUE);
    581.         }
    582.     }
    583.     HMENU BuildMenu()
    584.     {
    585.         HMENU   hMenu = CreateMenu();
    586.         HMENU   hFile = CreatePopupMenu();
    587.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFile, TEXT("&File"));
    588.         AppendMenu(hFile, MF_STRING, IDM_FILE_NEW, TEXT("&New"));
    589.         AppendMenu(hFile, MF_STRING, IDM_FILE_OPEN, TEXT("&Open..."));
    590.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_SAVE, TEXT("&Save..."));
    591.         AppendMenu(hFile, MF_STRING | MF_GRAYED, IDM_FILE_CLOSE, TEXT("&Close"));
    592.         AppendMenu(hFile, MF_SEPARATOR, 0, NULL);
    593.         AppendMenu(hFile, MF_STRING, IDM_FILE_EXIT, TEXT("&Exit"));
    594.  
    595.         HMENU   hOption = CreatePopupMenu();
    596.         AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT_PTR)hOption, TEXT("&Option"));
    597.         AppendMenu(hOption, MF_STRING, IDM_OPTION_BACKGROUND, TEXT("&BackGround..."));
    598.  
    599.         return hMenu;
    600.     }
    601. public:
    602.     int Create(HINSTANCE hInst)
    603.     {
    604.         // Đăng ký lớp
    605.         WNDCLASS    w;
    606.         w.cbClsExtra = 0;
    607.         w.cbWndExtra = 0;
    608.         w.hbrBackground = CreateSolidBrush(m_crBack);
    609.         w.hCursor = LoadCursor(NULL, IDC_ARROW);
    610.         w.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    611.         w.hInstance = hInst;
    612.         w.lpfnWndProc = WndProc;
    613.         w.lpszClassName = TEXT("TestGridview");
    614.         w.lpszMenuName = NULL;
    615.         w.style = CS_HREDRAW | CS_VREDRAW;
    616.         if (!RegisterClass(&w))
    617.             return 0;
    618.         // Tạo cửa sổ
    619.         HWND    hwnd = CreateWindow(w.lpszClassName, w.lpszClassName, WS_OVERLAPPEDWINDOW,
    620.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, BuildMenu(), hInst, this);
    621.         if (!hwnd)
    622.             return 0;
    623.         ShowWindow(hwnd, SW_SHOW);
    624.         UpdateWindow(hwnd);
    625.         // Vòng lặp thông điệp
    626.         MSG     msg;
    627.         while (GetMessage(&msg, NULL, 0, 0))
    628.         {
    629.             TranslateMessage(&msg);
    630.             DispatchMessage(&msg);
    631.         }
    632.         return msg.wParam;
    633.     }
    634. };
    635. int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpCmd, int nShow)
    636. {
    637.     CWindow     Window;
    638.     return Window.Create(hInst);
    639. }
    Attached Thumbnails Attached Thumbnails New Bitmap Image.png  
    Công cụ bảo vệ mã nguồn .NET mạnh nhất hiện tại, miễn phí cho các khách hàng đầu tiên đăng ký.

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