2010-08-01 32 views
7

Tôi muốn tạo lớp của riêng mình để xử lý việc tạo cửa sổ và quy trình cửa sổ nhưng tôi đã nhận thấy rằng quy trình cửa sổ phải tĩnh! Bây giờ tôi tự hỏi liệu nó có thể làm cho đối tượng thủ tục cửa sổ được định hướng không? Tôi đã đọc một số hướng dẫn trên cửa sổ hướng đối tượng, nhưng họ luôn luôn làm cho thủ tục tĩnh -.- whats việc sử dụng trong đó? :/Hướng đối tượng C++ win32?

Bất kỳ liên kết hoặc thông tin về cách để có được xung quanh vấn đề này sẽ được đánh giá,

nhờ

+0

Xem [ Phương pháp tốt nhất để lưu trữ con trỏ này để sử dụng trong WndProc ] (http://stackoverflow.com/questions/117792/best-method-for-storing-this-pointer-for-use-in-wndproc). –

+2

Đó là vì lý do này mà tôi luôn mong rằng 'WndProc' có tham số' void * user_data'. Nó sẽ làm cho việc tạo ra một wrapper dựa trên đối tượng dễ dàng hơn nhiều. –

+0

@Evan: vâng, nhưng nó cũng đã yêu cầu ai đó * sane * chịu trách nhiệm thiết kế API ... API Win32 sẽ là một con thú rất khác nếu đó là trường hợp. – jalf

Trả lời

11

Bạn có thể khắc phục điều đó bằng cách làm cho WndProc tĩnh ủy tất cả mọi thứ cho các thành viên:

// Forward declarations 
class MyWindowClass; 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 

std::map<HWND, MyWindowClass *> windowMap; 

// Your class 
class MyWindowClass { 
private: 
    HWND m_handle; 

    // The member WndProc 
    LRESULT MyWndProc(UINT message, WPARAM wParam, LPARAM lParam) { /* ... */ } 

public: 
    MyWindowClass() 
    { 
    /* TODO: Create the window here and assign its handle to m_handle */ 
    /* Pass &WndProc as the pointer to the Window procedure */ 

    // Register the window 
    windowMap[m_handle] = this; 
    } 
}; 

// The delegating WndProc 
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 
{ 
    std::map<HWND, MyWindowClass *>::iterator it = windowMap.find(hWnd); 
    if (it != windowMap.end()) 
    return it->second->MyWndProc(message, wParam, lParam); 
    return 0; 
} 
+1

+1, nhưng bạn cũng có thể muốn kiểm tra WM_DESTROY ở đó và xóa tay cầm khỏi bản đồ. – SoapBox

+0

ví dụ hay, trông thật tuyệt. Tôi sẽ cố gắng để thực hiện nó trong của riêng tôi, sử dụng tốt đẹp của std :: bản đồ để tìm các xử lý phù hợp – Kaije

+0

@SoapBox Nó là không đầy đủ trong nhiều cách, cảm ơn cho ghi chú này mặc dù. –

3

Nếu bạn đang tìm kiếm hướng đối tượng Win32 API thì bạn nên tìm đến MFC và/hoặc WTL.

+0

Giải pháp quá mức cho nhiều mục đích. MFC có thể được * tương đối * mỏng, nhưng nó vẫn là một API lớn ở bên phải của riêng nó, và chuyển đổi từ một API khác là rất nhiều công việc. Nó cũng hoàn toàn không cần thiết nếu tất cả những gì bạn muốn làm là sử dụng một vài lớp C++ của riêng bạn trong khi viết mã cho Win32. "Khung đối tượng" cũ của tôi cho Win32 có lẽ là khoảng 2 hoặc 3 mặt mã - ít hơn một lớp cơ sở, một số khởi tạo và một vòng lặp GetMessage/etc chính. – Steve314

+0

Vấn đề quan điểm –

+0

MFC là một khuôn khổ khó chịu, nhưng nó cũng được hỗ trợ và tương đối nổi tiếng trong thế giới Win32. – seand

1

Bạn có thể sử dụng tay cầm cửa sổ được chuyển đến WindowProc để lấy đối tượng bạn đã tạo cho cửa sổ cụ thể đó và ủy quyền xử lý sự kiện cho đối tượng đó.

ví dụ:

IMyWindowInterface* pWnd = getMyWindowObject(hWnd); 
pWnd->ProcessMessage(uMsg, wParam, lParam); 
+0

Âm thanh tốt, tôi nhận thấy rằng điều duy nhất trong thủ tục là xử lý, nhưng không chắc chắn làm thế nào để tìm cửa sổ của tôi thông qua nó. như trong ví dụ của bạn, hàm getMyWindowObject (hwnd), hàm đó có bao gồm việc lặp qua các cửa sổ đang mở của tôi để xem trình xử lý có khớp không? bởi vì nếu có, nếu tôi đã xử lý một WM_MOUSEMOVE hoặc WM_TIMER, sẽ không tẻ nhạt trên bộ vi xử lý? – Kaije

+0

Tốt nhất bạn nên đặt cược nó để sử dụng một số hình thức hashtable để băm từ HWND để trỏ đến cửa sổ-đối tượng của bạn - đó là tra cứu nhanh. Trừ khi bạn có một số lượng lớn các cửa sổ đang mở, tôi mong đợi một vòng lặp thông qua tất cả các cặp (HWND, đối tượng *) sẽ đủ nhanh chóng tho '. –

6

Kỹ thuật chung của việc cho phép một trường hợp cửa sổ để được đại diện bởi dụ như lớp là để tận dụng SetWindowLongPtr và GetWindowLongPtr để liên kết con trỏ cá thể lớp của bạn với cửa sổ xử lý. Dưới đây là một số mã mẫu để giúp bạn bắt đầu. Nó có thể không biên dịch mà không có một vài chỉnh sửa. Nó chỉ có nghĩa là một tham chiếu.

Cá nhân, tôi đã ngừng phân lớp lớp cửa sổ của riêng mình cách đây vài năm khi tôi phát hiện ra lớp mẫu CWindow và CWindowImpl của ATL. Họ quan tâm đến việc thực hiện tất cả các mã hóa trần tục này cho bạn để có thể tập trung vào việc viết các phương thức xử lý các thông điệp cửa sổ. Xem mã ví dụ tôi đã viết here.

Hy vọng điều này sẽ hữu ích.

class CYourWindowClass 
{ 
private: 
    HWND m_hwnd; 

public: 
    LRESULT WndProc(UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     switch (uMsg) 
     { 
      case WM_CREATE: return OnCreate(wParam, lParam); 
      case wM_PAINT: return OnPaint(wParam, lParam); 
      case WM_DESTROY: 
      { 
       SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL); 
       m_hwnd = NULL; 
       return 0; 
      } 
     } 
     return DefWindowProc(m_hwnd, uMsg, wParam, lParam); 

    } 

    CYourWindowClass() 
    { 
     m_hwnd = NULL; 
    } 

    ~CYourWindowClass() 
    { 
     ASSERT(m_hwnd == NULL && "You forgot to destroy your window!"); 
     if (m_hwnd) 
     { 
      SetWindowLong(m_hwnd, GWLP_USERDATA, 0); 
     } 
    } 

    bool Create(...) // add whatever parameters you want 
    { 
     HWND hwnd = CreateWindow("Your Window Class Name", "Your Window title", dwStyle, x, y, width, height, NULL, hMenu, g_hInstance, (LPARAM)this); 
     if (hwnd == NULL) 
      return false; 

     ASSERT(m_hwnd == hwnd); 
     return true; 
    } 


    static LRESULT __stdcall StaticWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 
    { 
     CYourWindowClass* pWindow = (CYourWindowClass*)GetWindowLongPtr(hwnd, GWLP_USERDATA); 

     if (uMsg == WM_CREATE) 
     { 
      pWindow = ((CREATESTRUCT*)lParam)->lpCreateParams; 
      SetWindowLongPtr(hwnd, GWLP_USERDATA, (void*)pWindow); 
      m_hWnd = hwnd; 
     } 

     if (pWindow != NULL) 
     { 
      return pWindow->WndProc(uMsg, wParam, lParam); 
     } 

     return DefWindowProc(hwnd, uMsg, wParam, lParam); 
    }; 


}; 
+0

Luôn tự hỏi lpParam là gì đối với chức năng CreateWindowEx, nhưng tôi hỗ trợ điều này có thể là cách làm cho nó dễ bị tổn thương, vì ai đó có thể sử dụng GetWindowLong để lấy dữ liệu người dùng của bạn: P – Kaije

2

Chỉ để thêm vào câu trả lời của Brian nhưng đối với khung win32 thân thiện hơn với người mới bắt đầu, hãy xem Win32++. Thư viện chính nó không phải là toàn diện trong các tính năng so với MFC hoặc QT nhưng đó là một sự cân bằng các nhà thiết kế được thực hiện vào đầu để giữ cho thư viện dễ hiểu và dễ sử dụng.

Nếu bạn vẫn quan tâm đến chủ đề này, tôi đặc biệt khuyến khích bạn xem xét nó vì nó sử dụng một kỹ thuật khác để lưu con trỏ 'this' bằng cách sử dụng lưu trữ cục bộ luồng.

Các vấn đề liên quan