Controlling the RichTextCtrl Insert State

Environment: NT 4.0 SP4, VC6.0

Every RichTextCtrl has its own insert state that is independent of the global insert
state as well as the insert state of all other RichTextCtrls. That would be fine if you
had some way to read and change the state. But you don’t. The RichTextCtrl has no
property to check the state, and it has no message to check the state.

The RichEditCtrl always starts with insert mode on and then toggles every time the user
presses the Insert key. So we have to keep track of using the insert key.

In this example the state of the insert key is shown in the statusbar, (dimmed or not).
It is possible to change the state by pressing the insert key or by doubleclicking on the
status pane for the overwrite status. (doubleclicking the NUM or CAP pane will also change
the keyboard state)

Step 1:

Keep track of the use of the insert key:


void COverWriteView::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_INSERT)
{
BOOL bShift = GetKeyState(VK_SHIFT) < 0;
BOOL bCtrl = GetKeyState(VK_CONTROL) < 0;
if (!bShift && !bCtrl)
((CChildFrame *) GetParent())->ChangeOverwrite();
}
CRichEditView::OnKeyDown(nChar, nRepCnt, nFlags);
}

Step 2:

Create the status bar in the ChildFrame


static UINT Indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_SEPARATOR,
ID_INDICATOR_OVERWRITE,
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_SEPARATOR,
};

// CChildFrame message handlers

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
if (!m_wndStatus.CreateEx(this,SBT_TOOLTIPS ,
WS_CHILD | WS_VISIBLE | CBRS_BOTTOM ,IDS_STATUS))
{
TRACE0("Failed to create status bar in child frame\n");
return CMDIChildWnd::OnCreateClient(lpcs, pContext);
}
m_wndStatus.SetIndicators(Indicators,sizeof(Indicators)/sizeof(UINT));

// Setting the pane infos
m_wndStatus.SetPaneInfo(0, m_wndStatus.GetItemID( 0 ),SBPS_STRETCH, NULL );
m_wndStatus.SetPaneInfo(1, m_wndStatus.GetItemID( 1 ),SBPS_STRETCH, NULL );
m_wndStatus.SetPaneInfo(2, m_wndStatus.GetItemID( 2 ),SBT_OWNERDRAW, 19 );
m_wndStatus.SetPaneInfo(3, m_wndStatus.GetItemID( 3 ),SBT_OWNERDRAW, 18 );
m_wndStatus.SetPaneInfo(4, m_wndStatus.GetItemID( 4 ),SBT_OWNERDRAW, 22 );
m_wndStatus.SetPaneInfo(5, m_wndStatus.GetItemID( 5 ),SBPS_NOBORDERS, 14 );

m_wndStatus.GetStatusBarCtrl().SetTipText(5, "Doubleclick for Info");
m_wndStatus.SetStatusBarFlag(0);

return CMDIChildWnd::OnCreateClient(lpcs, pContext);
}

Step3:

Show the status in the status bar


void COverwriteStatus::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
CRect cRect(&lpDrawItemStruct->rcItem);
int nOldBkMode = dc.SetBkMode(TRANSPARENT);

// Show only the animation, if the selected measure is identical with the running Id
COLORREF cOldFgColor = dc.GetTextColor();
COLORREF cTxColor = RGB(0,0,0);

switch(lpDrawItemStruct->itemID)

{
case 2: // Insert/Overwrite
{
if (((CChildFrame *)GetParent())-> IsOverwrite ()) cTxColor = RGB(0,0,0);

// This method can only be used, if there is only one Edit-Window
// if ( ::GetKeyState(VK_INSERT) & 0x0001) cTxColor = RGB(0,0,0);
else cTxColor = RGB(128,128,128);
break;
}
case 3: // Caps-Lock
{
if ( ::GetKeyState(VK_CAPITAL) & 0x0001) cTxColor = RGB(0,0,0);
else cTxColor = RGB(128,128,128);
break;
}
case 4: // Num-Lock
{
if ( ::GetKeyState(VK_NUMLOCK) & 0x0001) cTxColor = RGB(0,0,0);
else cTxColor = RGB(128,128,128);
break;
}
}
dc.SetTextColor(cTxColor);
CString cText = GetPaneText(lpDrawItemStruct->itemID);
dc.DrawText(cText,cRect, DT_LEFT);
dc.SetTextColor(cOldFgColor);
dc.SetBkMode(nOldBkMode);
dc.Detach();
}

Step 4:

Change the insert state by double click of the status pane


void COverwriteStatus::OnLButtonDblClk(UINT nFlags, CPoint point)
{
int nPane = GetPaneAtPosition(point);
switch (nPane)
{
case 2:
ChangeInsert();
break;
case 3:
ChangeCapsLock();
break;
case 4:
ChangeNumLock();
break;
case 5:
{
SetStatusBarFlag(1);
((COverWriteApp * )AfxGetApp())->OnAppAbout();
SetStatusBarFlag(0);
}
break;
}
CStatusBar::OnLButtonDblClk(nFlags, point);
}

int COverwriteStatus::GetPaneAtPosition(CPoint& point)
{
CRect rect;
for (int i = 0, n = GetCount(); i < n; i++)
{
GetItemRect(i, rect);
if (rect.PtInRect(point)) return i;
}
return -1;
}

void COverwriteStatus::ChangeInsert()
{
keybd_event( VK_INSERT, 0x0, KEYEVENTF_EXTENDEDKEY , 0 );
keybd_event( VK_INSERT, 0x0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
}

Download demo project – 55 KB

Download source – 24 KB

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read