SubClassWndProc (C++)

From RAD Studio Code Examples
Jump to: navigation, search

Description

This example shows how to use the WndProc method and the WindowProc property to subclass a custom control's window procedure. This example subclasses the window procedure of a TListBox descendant to respond to a user-defined message called WM_STYLEMESSAGE. The subclassed window procedure can be turned on or off by pressing an option button.

Code

class TMyListBoxDescendant : public TListBox
{
__published:	 IDE-managed Components
	void __fastcall SubClassWndProc(Messages::TMessage &Message);
	void __fastcall ToggleSubClass(bool On);
	void __fastcall OnDrawItemProc(
	  TWinControl *Control, int Index, const TRect &Rect,
	  TOwnerDrawState State);
private:	// User declarations
public:		// User declarations
	__fastcall TMyListBoxDescendant(TComponent* Owner);
};

TForm1 *Form1;
TMyListBoxDescendant *MyListBoxDescendant1;
Graphics::TBitmap *bitmap0;

const WM_STYLEMESSAGE = WM_USER + 2000;

__fastcall TMyListBoxDescendant::TMyListBoxDescendant(TComponent* Owner)
	: TListBox(Owner)
{
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
  PostMessage(
	MyListBoxDescendant1->Handle,
	WM_STYLEMESSAGE,
	Integer(lbOwnerDrawFixed),
	0);
}

void __fastcall TForm1::Button2Click(TObject *Sender)
{
  PostMessage(
	MyListBoxDescendant1->Handle,
	WM_STYLEMESSAGE,
	Integer(lbStandard),
	0);
}

void __fastcall TForm1::SubClassRadioGroup1Click(TObject *Sender)
{
  MyListBoxDescendant1->ToggleSubClass(SubClassRadioGroup1->ItemIndex == 0);
}

void __fastcall TMyListBoxDescendant::SubClassWndProc(Messages::TMessage &Message)
{
  if (Message.Msg == WM_STYLEMESSAGE)
	Style = (TListBoxStyle)Message.WParam;
  else
	WndProc(Message);
}

void __fastcall TMyListBoxDescendant::ToggleSubClass(bool On)
{
  if (On)
	WindowProc = SubClassWndProc;
  else
	WindowProc = WndProc;
}

#include <memory>       //For STL auto_ptr class

void __fastcall TMyListBoxDescendant::OnDrawItemProc(TWinControl *Control, int Index,
	  const TRect &Rect, TOwnerDrawState State)
{
  Graphics::TBitmap *bitmap; // Temporary variable for the item's bitmap
  int Offset = 2;   // Default text offset width

  // Note that you draw on the list box's canvas, not on the form
  TCanvas *canvas = dynamic_cast<TListBox *>(Control)->Canvas;
  canvas->FillRect(Rect); // Clear the rectangle.
  bitmap = dynamic_cast<Graphics::TBitmap *>((dynamic_cast<TListBox *>(Control))->Items->Objects[Index]);
  if (bitmap)
  {
	canvas->BrushCopy(
	  Bounds(Rect.Left + Offset, Rect.Top, bitmap->Width, bitmap->Height),
	  bitmap, Bounds(0, 0, bitmap->Width, bitmap->Height), clRed); // Render bitmap.
	Offset += bitmap->Width + 4;   // Add four pixels between bitmap and text.
  }
  // Display the text
  canvas->TextOut(Rect.Left + Offset, Rect.Top, dynamic_cast<TListBox *>(Control)->Items->Strings[Index]);
}

__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  MyListBoxDescendant1 = new TMyListBoxDescendant(Form1); // The owner cleans this up.
  MyListBoxDescendant1->Visible = True;
  MyListBoxDescendant1->Parent = Form1;
  MyListBoxDescendant1->Visible = True;
  MyListBoxDescendant1->Left =
	SubClassRadioGroup1->Left + SubClassRadioGroup1->Width + 30;;
  MyListBoxDescendant1->Top = SubClassRadioGroup1->Top;
  MyListBoxDescendant1->Height = SubClassRadioGroup1->Height;
  MyListBoxDescendant1->OnDrawItem =
	MyListBoxDescendant1->OnDrawItemProc;

  static std::auto_ptr<Graphics::TBitmap> _bitmap0Cleaner(bitmap0 = new Graphics::TBitmap);
  ImageList1->GetBitmap(0, bitmap0);
  MyListBoxDescendant1->Items->AddObject("Butterfly", bitmap0);

  SubClassRadioGroup1->Items->Add("SubClassWndProc");
  SubClassRadioGroup1->Items->Add("WndProc");
  SubClassRadioGroup1->ItemIndex = 2;
}

Uses