INTRODUCTION
Back in the late 1990s I was having trouble with a Borland Turbo C++ version 3.1
programming issue to make a Windows form auto-calculate after tabbing out of a numerical text box. In the early 1990s when I coded MS-DOS based procedural C
application development, I could call Borland's technical support line and they would help me out free of charge. By the time I had this particular problem though, everything had changed for the worse. They had a 900 number I had to call for technical support. It was very expensive - $5USD per minute. Ouch! Their technical support people wouldn't even speak to me until I gave them my credit card number and they had authorized it. I sent them one fax about my problem and another and then another after that, because they kept losing them. Not only did they not solve my problem, but they also had the nerve to charge my credit card $92USD just for the time they spent running around trying to find my faxes. I was absolutely livid - this was the high watermark of aggravation for me.
THE ISSUE I HAD
The
custom software work I did typically involved invoicing or order entry. The Windows form had to automatically recalculate the extended prices as well as totals. I knew how to do this with my old MS-DOS based programs. However, I was having a real tough time making this work in the object oriented (OOP) Windows environment. I knew the calculation had to be fired after the operator tabbed out of a numerical text box on the Windows form. I went online spending many hours researching this issue to no avail.
Nearing the end of my rope, I found an online newsgroup for Borland C++ programmers. I saw a post from a coder who was inquiring about a problem he had that was different from mine. I thought there might be a possibility that he could help me out with my problem since he was using Borland C++ version 4.5
software - a newer version than mine. He kindly sent me the code that showed how to fire an event in a Borland C++ version 4.5 Windows form after tabbing out of a text box. I studied it and was able to adapt it for my older Borland Turbo C++ version 3.1 compiler - thank goodness!
THE BORLAND C++ CODE THAT SOLVED IT
I honestly don't know what I would have done next had it not been for his help. It was imperative that I knew how to implement this programming technique. I knew from my days in the MS-DOS based programming world that customers would expect an invoice screen to automatically recalculate after numerical additions and/or changes had been made. Here are some code snippets that facilitate this operation from an actual Borland C++ 5.02 program I made:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
// declare the class.
//
// class TCbookDlg
// ~~~~~ ~~~~~~~~~~~~
class TCbookDlg : public TDialog {
public:
TCbookDlg(TWindow* parent, TResId resId, TCbookStruct& transfer);
TEdit *Edit1,*Edit2,*Edit3,*Edit4,*Edit5,*Edit6,*Edit7,*Edit8;
TEdit *Edit9,*Edit10,*Edit11,*Edit12,*Edit13,*Edit14,*Edit15;
// WMTab is the event to process specific math calculations
// upon receiving the WM_GETDLGCODE message.
LRESULT WMTab(WPARAM, LPARAM);
// WMChar is the event to process specific programming upon
// receiving inputed keystrokes in the text box.
LRESULT WMChar(WPARAM, LPARAM);
protected:
// declare member functions of the TCbookDlg class.
void CmOk();
void Choose();
void Delete();
void Mchk();
void PrnReg();
void BalForw();
void PrnEnv();
void New();
void SVendor();
void SPaymentDate();
void SCheckNo();
void Reset();
private:
// declare objects of the TCbookDlg class.
TPrinter* Printer;
TListBox* ListBox;
TComboBox* ComboBox;
TComboBox* ComboBox2;
TComboBox* ComboBox3;
TComboBox* ComboBox4;
TComboBox* ComboBox5;
TComboBox* ComboBoxV;
TComboBox* ComboBox6;
TButtonGadget* G1;
TButtonGadget* G2;
TButtonGadgetEnabler* Ge1;
TButtonGadgetEnabler* Ge2;
void SetupWindow();
// declare the character arrays.
char Pdate[MAXDAT];
char Pnumber[MAXINVNO];
char Paid_amount[MAXSELL];
char Pdescr[MAXNOTE2];
char Paid_amount_discount[MAXSELL];
char Pnetdebit[MAXSELL];
char Pcheck[MAXSELL];
char Vendor[MAXCOMPANY2];
char ExpCode[MAXPAIDDISCOUNTSUMODE];
char TranType[MAXSELL];
char TranPaid[MAXANS];
char Void[MAXANS];
char Pcredit[MAXSELL];
char Sdt[MAXDAT];
char Edt[MAXDAT];
char BalUpdated_amount[MAXSELL];
char CutOffDate[MAXDAT];
char CheckMemo[MAXNOTE];
char Paiddate[MAXDAT];
char TranCleared[MAXANS];
char Rcount[MAXPASS];
DECLARE_RESPONSE_TABLE(TCbookDlg);
};
// connect the TCbookDlg class member functions to their corresponding
// identifiers as set in the resource file (not included here).
DEFINE_RESPONSE_TABLE1(TCbookDlg, TDialog)
EV_COMMAND(IDOK, CmOk),
EV_COMMAND(IDC_PDELETE, Delete),
EV_COMMAND(IDC_MCHECK, Mchk),
EV_COMMAND(IDC_PRNREG, PrnReg),
EV_COMMAND(IDC_BALFORW, BalForw),
EV_COMMAND(IDC_PRNENV, PrnEnv),
EV_COMMAND(IDC_CNEW, New),
EV_COMMAND(IDC_RESET, Reset),
EV_COMMAND(IDC_SVENDOR, SVendor),
EV_COMMAND(IDC_SDATE, SPaymentDate),
EV_COMMAND(IDC_SCHECKNO, SCheckNo),
EV_LBN_SELCHANGE(IDC_LISTBOX, Choose),
// WM_GETDLGCODE fires this event (WMTab) in the class TCbookDlg.
EV_MESSAGE(WM_GETDLGCODE, WMTab),
// WM_CHAR fires this event (WMChar) in the class TCbookDlg.
EV_MESSAGE(WM_CHAR, WMChar),
END_RESPONSE_TABLE;
|
This programming runs when the operator inputs keystrokes (numbers) into the text box. It screens out non-numeric characters or characters that aren't periods and sets the text box to a numerical zero making the operator start over with valid input.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
LRESULT
TEdAmt::WMChar(WPARAM cmd, LPARAM cmd2)
{
int a;
DefaultProcessing();
for(a=0; a<MAXSELL; a++) Amount[a]=32;
GetSubText(Amount, 0, MAXSELL-1);
flag_variable = 1;
for(a=0; a<MAXSELL-1; a++) {
if( ( Amount[a]<46 || Amount[a]>57 ) && Amount[a]>32 ) {
Amount[a]=48;
Amount[MAXSELL-1]=0;
SetText(Amount);
SetSelection(0, MAXSELL-1);
}
}
return TRUE;
}
|
This code runs when the operator tabs out of a numerical based text box that accepts a dollar amount
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
|
LRESULT
TEdAmt::WMTab(WPARAM cmd, LPARAM cmd2)
{
// declare local variables used in the formatting and math processing.
int r,f,z,a,y;
if ( cmd == VK_TAB && flag_variable == 1 ) {
y=0;
if ( Amount[0]<=57 && Amount[1]<=57 && Amount[2]<=57 && Amount[3]<=57 && Amount[4]<=57 && Amount[5]<=57 && Amount[6]<=57 && Amount[7]<=57 && Amount[8]<=57 && Amount[9]<=57 ) y=1;
if ( y == 1 ) {
r=0;
do {
if(Amount[9]<46 || Amount[9]>57) {
for(f=9; f>0; f--) Amount[f]=Amount[f-1];
Amount[0]=32;
}
r++;
} while(r<10);
r=0;
if ( Amount[7]!=46 && Amount[8]!=46 && Amount[9]!=46 ) {
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=46;
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=48;
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=48;
r=1;
}
if ( Amount[9]==46 && r==0 ) {
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=48;
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=48;
r=1;
}
if ( Amount[8]==46 && r==0 ) {
for(f=0; f<9; f++) Amount[f]=Amount[f+1];
Amount[9]=48;
}
z=0;
if ( ( Amount[0]<48 || Amount[0]>57 ) && Amount[0]>32 ) z=1;
if ( ( Amount[1]<48 || Amount[1]>57 ) && Amount[1]>32 ) z=1;
if ( ( Amount[2]<48 || Amount[2]>57 ) && Amount[2]>32 ) z=1;
if ( ( Amount[3]<48 || Amount[3]>57 ) && Amount[3]>32 ) z=1;
if ( ( Amount[4]<48 || Amount[4]>57 ) && Amount[4]>32 ) z=1;
if ( ( Amount[5]<48 || Amount[5]>57 ) && Amount[5]>32 ) z=1;
if ( ( Amount[6]<48 || Amount[6]>57 ) && Amount[6]>32 ) z=1;
if ( Amount[7]!=46 ) z=1;
if ( ( Amount[8]<48 || Amount[8]>57 ) && Amount[8]>32 ) z=1;
if ( ( Amount[9]<48 || Amount[9]>57 ) && Amount[9]>32 ) z=1;
if(z==0) {
r=0;
do {
r++;
} while(Amount[r]==32 && r<10);
if(r<10) Amount[r-1]='$';
}
if ( z>0 ) {
for(a=0; a<MAXSELL; a++) Amount[a]=32;
Amount[6]=48;
Amount[7]=46;
Amount[8]=48;
Amount[9]=48;
}
Amount[MAXSELL-1]=0;
SetText(Amount);
flag_variable = 0;
Parent->SendMessage(WM_GETDLGCODE, 0, 0);
}
}
DefaultProcessing();
//return TRUE;
}
|
This is fired after the WM_GETDLGCODE message reaches the parent window. The math will be performed and the text box will be updated with the calculated result.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
|
LRESULT
TCbookDlg::WMTab(WPARAM cmd, LPARAM cmd2)
{
int a,r;
long int paidsum,paiddiscountsum,convert_to_integer[10];
char Updated_amount[MAXSELL];
ldiv_t n;
streambuf *inn = cin.rdbuf();
ifpstream ivfile;
for(a=0; a<MAXSELL; a++) Paid_amount[a]=32;
for(a=0; a<MAXSELL; a++) Paid_amount_discount[a]=32;
GetDlgItemText(IDC_PAID_AMOUNT, Paid_amount, MAXSELL);
GetDlgItemText(IDC_PAID_AMOUNT_DISCOUNT, Paid_amount_discount, MAXSELL);
for(a=0; a<MAXSELL-1; a++) {
convert_to_integer[a]=0;
if(Paid_amount[a]==48) convert_to_integer[a]=0;
if(Paid_amount[a]==49) convert_to_integer[a]=1;
if(Paid_amount[a]==50) convert_to_integer[a]=2;
if(Paid_amount[a]==51) convert_to_integer[a]=3;
if(Paid_amount[a]==52) convert_to_integer[a]=4;
if(Paid_amount[a]==53) convert_to_integer[a]=5;
if(Paid_amount[a]==54) convert_to_integer[a]=6;
if(Paid_amount[a]==55) convert_to_integer[a]=7;
if(Paid_amount[a]==56) convert_to_integer[a]=8;
if(Paid_amount[a]==57) convert_to_integer[a]=9;
}
paidsum = convert_to_integer[0]*100000000 + convert_to_integer[1]*10000000 + convert_to_integer[2]*1000000 + convert_to_integer[3]*100000 + convert_to_integer[4]*10000 + convert_to_integer[5]*1000 + convert_to_integer[6]*100 + convert_to_integer[8]*10 + convert_to_integer[9]*1;
for(a=0; a<MAXSELL-1; a++) {
convert_to_integer[a]=0;
if(Paid_amount_discount[a]==48) convert_to_integer[a]=0;
if(Paid_amount_discount[a]==49) convert_to_integer[a]=1;
if(Paid_amount_discount[a]==50) convert_to_integer[a]=2;
if(Paid_amount_discount[a]==51) convert_to_integer[a]=3;
if(Paid_amount_discount[a]==52) convert_to_integer[a]=4;
if(Paid_amount_discount[a]==53) convert_to_integer[a]=5;
if(Paid_amount_discount[a]==54) convert_to_integer[a]=6;
if(Paid_amount_discount[a]==55) convert_to_integer[a]=7;
if(Paid_amount_discount[a]==56) convert_to_integer[a]=8;
if(Paid_amount_discount[a]==57) convert_to_integer[a]=9;
}
paiddiscountsum = convert_to_integer[0]*100000000 + convert_to_integer[1]*10000000 + convert_to_integer[2]*1000000 + convert_to_integer[3]*100000 + convert_to_integer[4]*10000 + convert_to_integer[5]*1000 + convert_to_integer[6]*100 + convert_to_integer[8]*10 + convert_to_integer[9]*1;
paidsum = paidsum - paiddiscountsum;
for(a=0; a<MAXSELL-1; a++) Updated_amount[a]=32;
Updated_amount[9]=48;
Updated_amount[8]=48;
Updated_amount[7]=46;
Updated_amount[6]=48;
r=9;
do {
n=ldiv(paidsum,10L);
paidsum=n.quot;
if(n.rem==0) Updated_amount[r]=48;
if(n.rem==1) Updated_amount[r]=49;
if(n.rem==2) Updated_amount[r]=50;
if(n.rem==3) Updated_amount[r]=51;
if(n.rem==4) Updated_amount[r]=52;
if(n.rem==5) Updated_amount[r]=53;
if(n.rem==6) Updated_amount[r]=54;
if(n.rem==7) Updated_amount[r]=55;
if(n.rem==8) Updated_amount[r]=56;
if(n.rem==9) Updated_amount[r]=57;
r--;
if(r==7) r--;
} while(paidsum>0);
r=0;
do {
r++;
} while(Updated_amount[r]==32 && r<MAXSELL-1);
Updated_amount[r-1]='$';
Updated_amount[MAXSELL-1]=0;
Edit6->SetText(Updated_amount);
}
|
CONCLUSION
Just when you think all is lost, you will find an educational resource or a kind soul online to help you out. If you can't resolve it on your own, the internet is filled with nice people who are ready to give you a helping hand. It is by far the
best available resource. What with the problem I had, the internet could not have arrived soon enough to save me from the cost prohibitive (and not always useful) world of paid technical support. Thankfully, that option has gone the way of the typewriter.