I'm unfamiliar with Visual Studio, .Net and windows in general, but have been tasked with writing a program that has a windows form. The program pretty much works now, but I have on thing that is bugging me.
I wrote the following function to only allow a number to be input into a TextBox:
private: System::Void tbPDX_KeyPress(System::Object^ sender, System::Windows::Forms::KeyPressEventArgs^ e) {
if(e->KeyChar == '.'){
if( this->tbPDX->Text->Contains(".") && !this->tbPDX->SelectedText->Contains(".") )
e->Handled = true;
}
// Allow negative numbers
else if(e->KeyChar == '-'){
if((!System::String::IsNullOrWhiteSpace(this->tbPDX->Text)) && !(this->tbPDX->Text->IndexOf('-') == -1))
e->Handled = true;
}
// Accept only digits ".", "-" and the Backspace character
else if(!Char::IsDigit(e->KeyChar)&& e->KeyChar != 0x08){
e->Handled = true;
}
}
This works fine for decimal points, but it's not perfect for negatives. For instance I can type 0-.0. Is there a way of checking that the position of the character being entered is at the beginning of the String^? From what I can see it's only possible to see the string before the character was entered?
With a little tweak I ended up using the method suggested by Hans Passant.
Here's my final function:
private: System::Void tbPDX_KeyPress(System::Object^ sender, System::Windows::Forms::KeyPressEventArgs^ e) {
if(e->KeyChar == '.'){
if( this->tbPDX->Text->Contains(".") && !this->tbPDX->SelectedText->Contains(".") )
e->Handled = true;
}
// Allow negative numbers
else if(e->KeyChar == '-' && !(this->tbPDX->Text->Contains("-"))){
e->Handled = true;
tbPDX->Text = "-" + tbPDX->Text;
}
// Accept only digits ".", "-" and the Backspace character
else if(!Char::IsDigit(e->KeyChar)&& e->KeyChar != 0x08){
e->Handled = true;
}
}
Related
I have a CO2 sensor on my Arduino Mega and sometimes randomly when I'm reading the CO2 measurement, the sensor will return a "?". The question mark causes my program to crash and return "input string was not in a correct format".
I haven't tried anything because I don't know what approach would be the best for this. The CO2 sensor returns the measurement in the form of "Z 00000" but when this question mark appears it shows that all that returned was a "\n". Currently, I have the program just reading the 5 digits after the Z.
if (returnString != "")
{
val = Convert.ToDouble(returnString.Substring(returnString.LastIndexOf('Z')+ 1));
}
What I expect to return is the digits after Z which works but every so often I will get a random line return which crashes everything.
According to the C# documentation the ToDouble method throws FormatException whenever the input string is invalid. You should catch the exception to avoid further issues.
try {
val = Convert.ToDouble(returnString.Substring(returnString.LastIndexOf('Z')+ 1));
}
catch(FormatException e) {
//If you want to do anything in case of an error
//Otherwise you can leave it blank
}
Also I'd recommend using some sort of statemachine for parsing the data in your case, that could discard all invalid characters. Something like this:
bool z_received = false;
int digits = 0;
int value = 0;
//Called whenever you receive a byte from the serial port
void onCharacter(char input) {
if(input == 'Z') {
z_received = true;
}
else if(z_received && input <= '9' && input >= '0') {
value *= 10;
value += (input - '0');
digits++;
if(digits == 5) {
onData(value);
value = 0;
z_received = false;
digits = 0;
}
}
else {
value = 0;
z_received = false;
digits = 0;
}
}
void onData(int data) {
//do something with the data
}
This is just a mock-up, should work in your case if you can direct the COM port's byte stream into the onCharacter function.
In the following code there is already check for nullptr in (1):
int msg;
struct x * var[2];
if ((var[0] = get_x()) == nullptr) { // (1)
return;
}
if (var[0]->data != 11) { // (2) <<< V595
msg = 1;
printf("msg1");
}
if (var[0] && var[0]->data == 12) { // (3) <<< V595
msg = 2;
return;
}
but I still get error: V595. Why?
I agree that there is an exceeding check for nullptr in (3).
Analyzer considers this piece of code abnormal. First, the pointer is being deferenced, and after that it is being verified. Even if it cannot be equal to NULL, it looks very suspicious. There's a possibility that wrong variable is used or checked.
So it is possible that the wrong variable is used, and the corrected version of code could look like:
if (FOO->data != 11) {
msg = 1;
printf("msg1");
}
if (var[0] && var[0]->data == 12) {
msg = 2;
return;
}
Or, probably, the condition is incorrect:
if (var[0]->data != 11) {
msg = 1;
printf("msg1");
}
if (FOO && var[0]->data == 12) {
msg = 2;
return;
}
Anyway, the analyzer doesn't like it, and it issues a warning. To eliminate such warnings, remove unnecessary checks which overload the code and confuse other programmers and the analyzer. In this case the analyzer will not issue the warning:
if ((var[0] = get_x()) == nullptr) {
return;
}
if (var[0]->data != 11) {
msg = 1;
printf("msg1");
}
if (var[0]->data == 12) {
msg = 2;
return;
}
If you don't want to remove this check, use one of the following ways to suppress warnings:
Suppression of false alarms
Mass Suppression of Analyzer Messages
I have written a code that have a if condition. After checking if then I want to show the results in a TexBox. The if statement is satisfied for more than one case and then I need to append them.
For example:
for (i=1;i<10;i++){
if (i > 8){
String^ Num = Convert::ToString(i);
textbox1->Text = Num;
}
}
The answer is 10. But I want to have 8,9,10.
How Could I have such a answer?
String^ Num = "";
for (i=1;i<10;i++){
if (i > 8){
Num = Convert::ToString(i);
if(Num == "")//first iteration so don't add ", "
{
textbox1-> += Num;
}
else
{
textbox1->Text += ", " + Num;
}
}
The default behavior of the string::operator+ is to concatenate so += will just concatenate whatever is already in the string with what the new value is. So assuming the Text field is a string this should work. Apologies for the lack of explanation.
How can we do validation for percentage numbers in textbox .
I need to validate these type of data
Ex: 12-3, 33.44a, 44. , a3.56, 123
thanks in advance
sri
''''Add textbox'''''
<asp:TextBox ID="PERCENTAGE" runat="server"
onkeypress="return ispercentage(this, event, true, false);"
MaxLength="18" size="17"></asp:TextBox>
'''''Copy below function as it is and paste in tag..'''''''
<script type="text/javascript">
function ispercentage(obj, e, allowDecimal, allowNegative)
{
var key;
var isCtrl = false;
var keychar;
var reg;
if (window.event)
{
key = e.keyCode;
isCtrl = window.event.ctrlKey
}
else if (e.which)
{
key = e.which;
isCtrl = e.ctrlKey;
}
if (isNaN(key)) return true;
keychar = String.fromCharCode(key);
// check for backspace or delete, or if Ctrl was pressed
if (key == 8 || isCtrl)
{
return true;
}
ctemp = obj.value;
var index = ctemp.indexOf(".");
var length = ctemp.length;
ctemp = ctemp.substring(index, length);
if (index < 0 && length > 1 && keychar != '.' && keychar != '0')
{
obj.focus();
return false;
}
if (ctemp.length > 2)
{
obj.focus();
return false;
}
if (keychar == '0' && length >= 2 && keychar != '.' && ctemp != '10') {
obj.focus();
return false;
}
reg = /\d/;
var isFirstN = allowNegative ? keychar == '-' && obj.value.indexOf('-') == -1 : false;
var isFirstD = allowDecimal ? keychar == '.' && obj.value.indexOf('.') == -1 : false;
return isFirstN || isFirstD || reg.test(keychar);
}
</script>
You can further optimize this expression. Currently its working for all given patterns.
^\d*[aA]?[\-.]?\d*[aA]?[\-.]?\d*$
If you're talking about checking that a given text is a valid percentage, you can do one of a few things.
validate it with a regex like ^[0-9]+\.?[0-9]*$ then just convert that to a floating point value and check it's between 0 and 100 (that particular regex requires a zero before the decimal for values less than one but you can adapt it to handle otherwise).
convert it to a float using a method that raises an exception on invalid data (rather than just stopping at the first bad character.
use a convoluted regex which checks for valid entries without having to convert to a float.
just run through the text character by character counting numerics (a), decimal points (b) and non-numerics (c). Provided a is at least one, b is at most one, and c is zero, then convert to a float.
I have no idea whether your environment support any of those options since you haven't actually specified what it is :-)
However, my preference is to go for option 1, 2, 4 and 3 (in that order) since I'm not a big fan of convoluted regexes. I tend to think that they do more harm than good when thet become to complex to understand in less than three seconds.
Finally i tried a simple validation and works good :-(
function validate(){
var str = document.getElementById('percentage').value;
if(isNaN(str))
{
//alert("value out of range or too much decimal");
}
else if(str > 100)
{
//alert("value exceeded");
}
else if(str < 0){
//alert("value not valid");
}
}
I have a list of items (potentially large) from which the user must select one. I'd like to allow the user to type the first few letters of the desired item to jump to the correct place in the list. By default, each keypress jumps to the first item starting with that letter, so you can't type the first several letters. Is there any straightforward way to do this? Any CodeProject or other such example?
I've looked for hours, and found any number of samples for IAutocomplete, but that won't help here because I need to guarantee that the result is in the list.
The only way I can think to do this is to derive from CListBox, capture the keystrokes myself, find the item, run a timer so that new keystrokes after a sufficient pause will start a new search... since I'm not an MFC jock, this is daunting. Any tips much appreciated.
One clarifying note: my ultimate goal is actually to get this keyboard behavior for a ComboBox of DropDownList style (i.e. no edit box). The lack of an edit box rules out most autocomplete code, and the need for ComboBox functionality means I can't use CListCtrl by itself.
After much unnecessary pain, I've discovered that the real correct answer is simply to use LBS_SORT. Simply by specifying this style, the basic vanilla listbox supports the incremental search keyboard shortcut style I wanted. Without LBS_SORT (or CBS_SORT for a combobox), you get the irritating and almost-useless jump-to-first-letter-only behavior. I didn't try LBS_SORT because my list contents were added in sorted order anyway.
So the dozen or so hours of investigating custom controls, etc., all for naught because the Microsoft documentation makes no mention of this important behavioral difference in the description of LBS_SORT!!
Thanks to everyone who contributed.
I've implemented such a functionality in core Win32. Heres the code.
Somewhere in your message loop that processes the list box insert:
switch(message)
{
case WM_CHAR:
if(HandleListBoxKeyStrokes(hwnd, wParam) == FALSE)
return FALSE;
....
Heres the code (propably not fully complete):
/* ======================================================================== */
/* ======================================================================== */
#define RETURNr(a, b) // homegrown asserts
BOOLEAN HandleListBoxKeyStrokes(HWND hwnd, UINT theKey)
{
#define MAXCHARCACHEINTERVALL 600.0 // Max. milisecs time offset to consider as typed 'at once'
static char sgLastChars[255] = {'0'};
static double sgLastCharTime = 0.;
static HWND sgLasthwnd = NULL;
if(GetSecs() - sgLastCharTime > MAXCHARCACHEINTERVALL ||
sgLasthwnd != hwnd)
*sgLastChars = 0;
if(theKey == ' ' && *sgLastChars == 0)
return TRUE;
sgLastCharTime = GetSecs();
sgLasthwnd = hwnd;
AppendChar(sgLastChars, toupper(theKey));
if(strlen(sgLastChars) > 1)
{
LONG l = GetWindowLong(hwnd, GWL_STYLE);
Char255 tx;
GetClassName(hwnd, tx, sizeof(tx));
if( (! stricmp(tx, "Listbox") &&
! (l & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL)) ) ||
(! stricmp(tx, "ComboBox") && // combo Box support
l & CBS_DROPDOWNLIST &&
! (l & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) ) )
{
long Count, l, BestMatch = - 1, BestMatchOff = 0;
long LBcmdSet[] = {LB_GETCOUNT, LB_GETTEXTLEN , LB_GETTEXT};
long CBcmdSet[] = {CB_GETCOUNT, CB_GETLBTEXTLEN, CB_GETLBTEXT};
long *cmdSet = (! stricmp(tx, "ComboBox")) ? CBcmdSet : LBcmdSet;
RETURNr((Count = SendMessage(hwnd, cmdSet[0], 0, 0)) != LB_ERR, 0);
for(int i = 0; i < Count; i++)
{
RETURNr((l = SendMessage(hwnd, cmdSet[1], i, 0)) != LB_ERR, TRUE);
RETURNr( l < sizeof(tx), TRUE);
RETURNr((l = SendMessage(hwnd, cmdSet[2], i, (LPARAM)&tx)) != LB_ERR, TRUE);
strupr(tx);
if(! strncmp(tx, sgLastChars, strlen(sgLastChars)))
{
SelListBoxAndNotify(hwnd, i);
return FALSE;
}
char *p;
if(p = strstr(tx, sgLastChars))
{
int off = p - tx;
if(BestMatch == -1 || off < BestMatchOff)
{
BestMatch = i;
BestMatchOff = off;
}
}
}
// If text not found at start of string see if it matches some part inside the string
if(BestMatch != -1)
SelListBoxAndNotify(hwnd, BestMatch);
// Nothing found - dont process
return FALSE;
}
}
return TRUE;
}
/* ======================================================================== */
/* ======================================================================== */
void SelListBoxAndNotify(HWND hwnd, int index)
{
// i am sorry here - this is some XVT-toolkit specific code.
// it has to be replaced with something similar for native Win32
WINDOW win = xvtwi_hwnd_to_window(hwnd);
WINDOW parent = xvt_vobj_get_parent(win);
xvt_list_set_sel(win, index, 1);
EVENT evt;
memset(&evt, 0, sizeof(evt));
evt.type = E_CONTROL;
evt.v.ctl.id = GetDlgCtrlID(hwnd);
evt.v.ctl.ci.v.lbox.dbl_click = FALSE;
xvt_win_dispatch_event(parent, &evt);
}
/* ======================================================================== */
/* ======================================================================== */
double GetSecs(void)
{
struct timeb timebuffer;
ftime(&timebuffer);
return (double)timebuffer.millitm +
((double)timebuffer.time * 1000.) - // Timezone needed for DbfGetToday
((double)timebuffer.timezone * 60. * 1000.);
}
/* ======================================================================== */
/* ======================================================================== */
char AppendChar(char *tx, char C)
{ int i;
i = strlen(tx);
tx[i ] = C;
tx[i + 1] = 0;
return(C);
}
Can you use a CListView CListCtrl instead? They work like that by default.