Introduction
CFunctionEdit
is a custom control written using pure Win32 API that allows the user to input n-tuple data (mathematical functions, vectors, etc.).
Features
CFunctionEdit
does not restrict the tuple size, however changing the tuple size is not supported at runtime yet. Tuple size is determined when creating the control. Once the control is created, you can set and get the text, limit the text size for each tuple, change the font used to render the text, background color and define your own text formatting function for colorized and styled text rendering.
- Version 1.1 supports text selection and cut, copy, paste operations.
- Version 1.2 has popup menu and
readonly
style.
Initializing and Using the control
First, call the Init()
member of the class with the HINSTANCE
of your application. Init()
function merely registers the window class if it has not been registered yet. After that you can create an instance of the control with Create()
member function by supplying the appropriate parameters. You can either declare your CFunctionEdit
variable static or create dynamically with new
.
CFunctionEdit theEdit;
CFunctionEdit *pEdit;
void CreateControls()
{
CFunctionEdit::Init(hInstance);
theEdit.Create(50, 20, 100, 40, hwndParent);
pFunctionEdit = new CFunctionEdit;
pFunctionEdit->Create(50, 120, 100, 40, hwndParent);
}
After having created the control, you can change the contents with SetText()
and get them with GetText()
.
int CFunctionEdit::SetText(int nIndex, const TCHAR *szText);
int CFunctionEdit::GetText(int nIndex, TCHAR *szText);
Here nIndex
is the index of the tuple. Indexes start from 0 and go up to number of tuples minus one. An exception is, if index is equal to -1, given text is assigned to all the tuples in the control.
theEdit.SetText(-1, TEXT(""));
theEdit.GetText(0, szText);
You can limit the text size for each tuple with the SetTextLimit()
function.
for(int a = 0; a < nTupleCount; a++)
{
theEdit.SetTextLimit(a, 3);
}
CFunctionEdit
has the following style flags that have effect on input and rendering of the control:
#define FES_NUMERIC 1
#define FES_UPPERCASE 2
#define FES_LOWERCASE 4
#define FES_DISABLESPACE 8
#define FES_CENTERTEXT 16
#define FES_READONLY 32
By default FES_CENTERTEXT
, FES_DISABLESPACE
and FES_LOWERCASE
styles are set if you do not explicitly supply a style parameter with the Create()
function.
theEdit.SetStyle(FES_CENTERTEXT | FES_NUMERIC);
Visualization features
Background color can be changed with SetBackgroundColor()
function.
theEdit.SetBackgroundColor(RGB(255, 255, 255));
The font used to render the text can be changed with SetFont()
function.
theEdit.SetFont(TEXT("Courier New"), 24, ANSI_CHARSET);
Rendering the text and changing the default text formatting function
When the user changes the text buffer by pressing a key, FormatText()
function is called to format the text. This function is responsible for creating a list consisting of FORMATTEDTEXTBLOCK
structures. It first adds " ( " as bold style and then calls formatting function for each tuple and adds " ) " as the last FORMATTEDTEXTBLOCK
. The whole text rendered is a list of FORMATTEDTEXTBLOCK
s.
typedef struct _tagFormattedTextBlock
{
#ifndef UNICODE
std::string strBlock;
#else
std::wstring strBlock;
#endif
COLORREF clColor;
DWORD dwStyle;
} FORMATTEDTEXTBLOCK, *LPFORMATTEDTEXTBLOCK;
typedef std::list<FORMATTEDTEXTBLOCK> FormattedText;
As you see, FORMATTEDTEXTBLOCK
is used to define a string which has its own color and style. dwStyle
member can be zero or one of the following. (not the combination)
#define TEXTFORMAT_BOLD 1
#define TEXTFORMAT_ITALIC 2
#define TEXTFORMAT_UNDERLINE 4
This is the default formatting function:
LRESULT CFunctionEdit::DefFormatTextProc(int nIndex,
const TCHAR *szText, FormattedText &ft)
{
FORMATTEDTEXTBLOCK fmttext;
if(*szText == TEXT('\0')) return 0;
fmttext.dwStyle = 0;
fmttext.clColor = RGB(0, 0, 0);
fmttext.strBlock = szText;
ft.push_back(fmttext);
return 0;
}
This function merely adds the text as black-normal style to the FormattedText
list. You can parse the szText
passed to this function, and split the text into multiple FORMATTEDTEXTBLOCK
s each having different styles. I have supplied a custom formatting function within the class that renders numbers blue, punctuations bold-green, and other characters red.
Text Selection
You can make a selection with SetSelection()
.
int CFunctionEdit::SetSelection(TUPLEPOS start, TUPLEPOS end);
typedef struct _tagTuplePos
{
int nTupleIndex;
int nPosition;
} TUPLEPOS, *LPTUPLEPOS;
TUPLEPOS
structure identifies a unique position in the control. First member of the structure, nTupleIndex
, is the tuple index where we want the cursor to move. And nPosition
is the position of the cursor within this tuple.
TUPLEPOS selstart, selend;
selstart.nTupleIndex = 1;
selstart.nPosition = 0;
selend.nTupleIndex = 2;
selend.nPosition = 3;
theEdit.SetSelection(selstart, selend);
Retrieving the selection
Selected text can be retrieved by GetSelection()
.
theEdit.GetSelection(szBuffer);
Positioning the cursor
SetCaretPos()
function positions the cursor. Its prototype is:
int CFunctionEdit::SetCaretPos(TUPLEPOS tuplepos);
TUPLEPOS tuplepos;
tuplepos.nTupleIndex = 0;
tuplepos.nPosition = 0;
theEdit.SetCaretPos(tuplepos);
tuplepos.nTupleIndex = 1;
tuplepos.nPosition = 5;
theEdit.SetCaretPos(tuplepos);
Message Routing
Finally I want to say a few words about how the message routing is done in the class.
typedef struct _tagWindowListEntry
{
HWND hWnd;
CFunctionEdit *pEdit;
} WINDOWLISTENTRY, *LPWINDOWLISTENTRY;
typedef std::list<WINDOWLISTENTRY> WindowList;
We have a list that holds window handles and associated object pointers. Each time a window is created with Create()
function, the window handle and the pointer to the instance of the class is added to a global variable called Windows
which is of type WindowList
. So we know which handle belongs to which CFunctionEdit
object. When Windows sends a message to our WindowProc
, we find the associated CFunctionEdit*
with GetEditWindow()
function. This function traverses the list to find the object pointer of the given handle. Having found the pointer, we call the handler of that object.
MFC and Unicode
Although I haven't created the control to use in an MFC or Unicode project, I've tested it in a sample MFC-Unicode project and everything seemed to work fine. However it's too difficult for me to test all the functionality of the control and find out if special handling should be done for these types of projects.
Version history
- Version 1.0 : November 9, 2003
- Version 1.1 : November 10, 2003
- Positioning the cursor
- Selection
- Cut, Copy, Paste
- Version 1.2 : November 16, 2003
Readonly
style
- Popup menu
Support and Feedback
For any comments and suggestions send me an e-mail via e110870@metu.edu.tr.