🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: borland.public.cppbuilder.nativeapi
Article #12650

Re: Subclassing an edit control (quite long post)

#12650
From: Martin Golm
Date: Wed, 26 Nov 2003 15:36
322 lines
9592 bytes
"Ed Mulroy [TeamB]" wrote:
> 
> You have to create your own window procedure.  You do not have to create a
> window class.  How far you'll get with those specific items when subclassing
> an edit control is an issue that I cannot address.
> 
> There is an example in the Windows API help which subclasses an edit
> control.

Thanks Ed and Remy.
Now that subclassing itself seems to be working, I'd like to press the
subclassed edit control into my own class structure. Maybe you could
help me with it.
I currently have the following code:

#include <windows>
#include <list>
#include <string>

const char szWndClsName[] = "Test Main Window Class";
class tWindow;

class tApp
{
private:
  tWindow* main;
protected:
  void Init();
public:
  static HINSTANCE hInst;
  static int nCmdShow;
  int Run();
  tApp() : main(0) {}
  ~tApp();
};

class tWindow {
private:
  std::list<tWindow*> children;
protected:
  HWND hWnd;
  HDC hDC;
  std::string title;
  tWindow* parent;
  virtual void OnPaint();
public:
  void AddChild(tWindow* child);
  class tXWindow {};
  struct tAttr {
    unsigned int style;
    int left, top, height, width;
    COLORREF col;
    tAttr() : style(0), left(0), top(0), height(0), width(0),
col(0xC0C0C0) {}
  };
  tAttr attr;
  HWND GetHandle() const { return hWnd; }
  bool Show(int nCmdShow) { return ShowWindow(hWnd, nCmdShow); }
  void Update() { UpdateWindow(hWnd); }
  void Create();
  virtual LRESULT WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam);
  tWindow(tWindow* parent_, char* title_ = "");
  virtual ~tWindow();
};

tWindow :: tWindow(tWindow* parent_, char* title_) :
  hWnd(0),
  hDC(0),
  parent(parent_),
  title(title_) {
  if (parent) { //so this is a child window
    attr.style = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS;
    attr.left = attr.top = 10;
    attr.width = attr.height = 50;
  } else {
    attr.style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
    attr.left = attr.width = CW_USEDEFAULT;
    attr.top = attr.height = 0;
  }
}

tWindow :: ~tWindow() {
  for (std::list<tWindow*>::reverse_iterator iter(children.rbegin()),
       ende(children.rend()); iter != ende; ++iter)
    delete *iter;
  ReleaseDC(hWnd, hDC);
  DestroyWindow(hWnd);
}

void tWindow :: Create() {
  hWnd = CreateWindow(szWndClsName, title.c_str(), attr.style,
                      attr.left, attr.top, attr.width, attr.height,
                      parent ? parent->GetHandle() : 0, 0,
                      tApp::hInst, reinterpret_cast<void*>(this));
  if (!hWnd)
    throw tXWindow();
  hDC = GetDC(hWnd);
  if (!hDC)
    throw tXWindow();
  if (parent)
    parent->AddChild(this);
}

void tWindow :: AddChild(tWindow* child) {
  if (child)
    children.push_back(child);
}

LRESULT tWindow :: WndProc(UINT iMessage, WPARAM wParam, LPARAM lParam)
{
  switch (iMessage) {
    case WM_PAINT:
      {
        PAINTSTRUCT ps;
        BeginPaint(hWnd, &ps);
        OnPaint();
        EndPaint(hWnd, &ps);
      }
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      break;
  }
  return DefWindowProc(hWnd, iMessage, wParam, lParam);
}

void tWindow :: OnPaint() {
  RECT rect;
  GetClientRect(hWnd, &rect);
  HBRUSH brush = CreateSolidBrush(attr.col);
  FillRect(hDC, &rect, brush);
  DeleteObject(brush);
}

#ifdef STRICT
WNDPROC orgWndProc = 0;
#else
FARPROC orgWndProc = 0;
#endif
bool mCtrlDown = false;
bool mShiftDown = false;
bool mInsPressed = false;

LRESULT CALLBACK EditWindowProc(HWND handle, UINT iMessage,
                                WPARAM wParam, LPARAM lParam) {
  switch (iMessage) {
    case WM_MOUSEMOVE:
      mCtrlDown = false;
      mShiftDown = false;
      SendMessage(handle, EM_SETSEL, 0, 0);
      break;
    case WM_LBUTTONDOWN:
      MessageBox(handle, "text", "caption", MB_OK);
      return 0;
    case WM_GETDLGCODE:
      return DLGC_WANTALLKEYS;
    case WM_RBUTTONDOWN:
    case WM_RBUTTONUP:
    case WM_LBUTTONUP:
      return 0;
    case WM_DESTROY:
      SetWindowLong(handle, GWL_WNDPROC, (LONG)orgWndProc);
      break;
    case WM_KEYUP:
      switch (wParam) {
        case VK_CONTROL:
          mCtrlDown = false;
          return 0;
        case VK_SHIFT:
          mShiftDown = false;
          return 0;
      }
      break;
    case WM_KEYDOWN:
      switch (wParam) {
        case VK_LEFT:
        case VK_RIGHT:
        case VK_END:
        case VK_HOME:
          if (mShiftDown)
            return 0;
          break;
        case VK_CONTROL:
          mCtrlDown = true;
          break;
        case VK_SHIFT:
          mShiftDown = true;
          break;
        case VK_INSERT:
          if (mShiftDown || mCtrlDown)
            return 0;
          mInsPressed = true;
          SendMessage(handle, WM_CHAR, VK_SPACE, 0);
          SendMessage(handle, WM_KEYDOWN, VK_LEFT, 0);
          SendMessage(handle, WM_KEYUP, VK_LEFT, 0);
          mInsPressed = false;
          break;
        default:
          if (mShiftDown || mCtrlDown)
            return 0;
          break;
      }
      break;
    case WM_CHAR:
      if (mCtrlDown)
        return 0;
      if (wParam != VK_BACK) {
        DWORD selStart, selLength;
        SendMessage(handle, EM_GETSEL, (WPARAM)&selStart,
(LPARAM)&selLength);
        selLength = selStart + (mInsPressed ? 0 : 1);
        SendMessage(handle, EM_SETSEL, selStart, selLength);
        SendMessage(handle, EM_SCROLLCARET, 0, 0);
      }
      break;
  }
  return CallWindowProc(orgWndProc, handle, iMessage, wParam, lParam);
}

class tEdit : public tWindow {
protected:
  virtual void OnPaint() {}
  virtual void OnLButtonDown() {}
public:
  void Create();
  tEdit(tWindow* parent) : tWindow(parent, "") {}
};

void tEdit :: Create() {
  attr.style |= ES_AUTOHSCROLL | ES_LEFT | WS_TABSTOP;
  hWnd = CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", attr.style,
                        attr.left, attr.top, attr.width, attr.height,
                        parent ? parent->GetHandle() : 0, 0,
                        tApp::hInst, reinterpret_cast<void*>(this));
  if (!hWnd)
    throw tXWindow();
  #ifdef STRICT
  orgWndProc = (WNDPROC)SetWindowLong(hWnd, GWL_WNDPROC,
(LONG)EditWindowProc);
  #else
  orgWndProc = (FARPROC)SetWindowLong(hWnd, GWL_WNDPROC,
(LONG)EditWindowProc);
  #endif
  if (!orgWndProc)
    throw tXWindow();
  if (parent)
    parent->AddChild(this);
}

HINSTANCE tApp::hInst = 0;
int tApp::nCmdShow = 0;

int tApp :: Run() {
  Init();
  MSG msg;
  while (GetMessage(&msg, 0, 0, 0)) {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

void tApp::Init() {
  main = new tWindow(0, "test application");
  main->Create();
  tEdit* e = new tEdit(main);
  e->attr.left = 10;
  e->attr.top = 50;
  e->attr.height = 25;
  e->attr.width = 100;
  e->Create();
  main->Show(nCmdShow);
  main->Update();
}

tApp ::~tApp()  { delete main; }

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM
lParam) {
  tWindow* pWindow = reinterpret_cast<tWindow*>(GetWindowLong(hWnd, 0));
  if (!pWindow) {
    if (iMessage == WM_CREATE) {
      LPCREATESTRUCT lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam);
      pWindow = reinterpret_cast<tWindow*>(lpcs->lpCreateParams);
      SetWindowLong(hWnd, 0, reinterpret_cast<long>(pWindow));
      return pWindow->WndProc(iMessage, wParam, lParam);
    }
    return DefWindowProc(hWnd, iMessage, wParam, lParam);
  }
  return pWindow->WndProc(iMessage, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpszCmdLine, int nCmdShow) {
  tApp::hInst = hInstance;
  tApp::nCmdShow = nCmdShow;

  WNDCLASS wndclass;
  wndclass.style = CS_HREDRAW | CS_VREDRAW;
  wndclass.lpfnWndProc = ::WndProc;
  wndclass.cbClsExtra = 0;
  wndclass.cbWndExtra = sizeof(tWindow*);
  wndclass.hInstance = tApp::hInst;
  wndclass.hIcon = 0;
  wndclass.hCursor = LoadCursor(0, IDC_ARROW);
  wndclass.hbrBackground = 0;
  wndclass.lpszMenuName = 0;
  wndclass.lpszClassName = szWndClsName;
  if (!RegisterClass(&wndclass))
    return 0;
  return tApp().Run();
}

Now I'd like EditWindowProc to be a member function of tEdit so I can
call some of tEdit's member functions. Is there any way to achieve this?
(Static member functions could be a solutions, as there's momentarily
exactly one instance of tEdit in the whole app. But if there's a way
without using static member function I'd prefer that.)


Thanks,
Martin
Technical Details
Message-ID: <3FC4C880.15E477D2@gmx.de>
Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail
References: <3FC37DC6.8A69A621@gmx.de> <3fc39946@newsgroups.borland.com>

Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII-7-bit
X-Google-Thread: 10cc67,7f8523ddb948f0d0
X-Google-Attributes: gid10cc67,public
X-Google-ArrivalTime: 2003-11-26 07:39:58 PST
Message-ID: <3FC4C880.15E477D2@gmx.de>
Date: Wed, 26 Nov 2003 16:36:32 +0100
From: Martin Golm <golm@gmx.de>
X-Mailer: Mozilla 4.72 [en] (Win95; I)
X-Accept-Language: en
MIME-Version: 1.0
Newsgroups: borland.public.cppbuilder.nativeapi
Subject: Re: Subclassing an edit control (quite long post)
References: <3FC37DC6.8A69A621@gmx.de> <3fc39946@newsgroups.borland.com>
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
NNTP-Posting-Host: 62.158.112.70
X-Trace: newsgroups.borland.com 1069861046 62.158.112.70 (26 Nov 2003 07:37:26 -0700)
Lines: 323
Path: arc1-ca.pugleaf.net!archiver1.google.com!news2.google.com!fu-berlin.de!newsfeed01.sul.t-online.de!t-online.de!newsgroups.borland.com!not-for-mail