Quote Originally Posted by wysota View Post
So can't the validator do it?

I don't really see a problem... Just make the call from the validator instead of the widget.
Validator Can, but musn't, because validation may be VERY time consuming !!! i.e ( I'm in Spain, so dates will be like DD/MM/YY or DD/MM/YYYY. See this code, is my "smart date validator" ( limits years to 19xx, 2xxxx, accepts two formats DD/MM/YY or DD/MM/YYYY and accepts "smart input" )

Qt Code:
  1. MDateValidator::MDateValidator ( QObject * parent ) : QRegExpValidator ( QRegExp ( "[0-9]{1,2}[/\\.]{0,1}[0-9]{1,2}[/\\.]{0,1}[0-9]{2,4}" ), parent ) {}
  2.  
  3. QValidator::State MDateValidator::validate ( QString & input, int & pos ) const
  4. {
  5. // Empty date => We accept it
  6. if ( input.length() == 0 ) return Acceptable;
  7.  
  8. // Must follw minimal specifications...
  9. if ( QRegExpValidator::validate ( input, pos ) == Invalid )
  10. return Invalid;
  11.  
  12. // 0 : We allow ".", but change it by "/"
  13. input.replace ( '.', "/" );
  14.  
  15. // PreparacionInput prepare
  16. // 1 : day must be 1..31. If first digit is between 4..9 => we change it to 04/09
  17. if ( input.left ( 1 ) > "3" )
  18. {
  19. input = "0" + input;
  20. pos++;
  21. }
  22.  
  23. // If they introduce one-digit day and a bar we add the leading "0"
  24. if ( ( input.length() == 2 ) && ( input.mid ( 1, 1 ) == "/" ) )
  25. {
  26. input.insert ( 0, "0" );
  27. pos++;
  28. }
  29.  
  30. // We do know the day, so we can make a first validation
  31. int Dia = input.mid ( 0, 2 ).toInt();
  32. if ( Dia > 31 ) return Invalid;
  33. if ( ( Dia == 0 ) && ( input.length() < 2 ) ) return Intermediate;
  34.  
  35. // Append bar if they press the first month's day without pushing bar...
  36. if ( ( input.length() > 2 ) && ( input.mid ( 2, 1 ) != "/" ) )
  37. {
  38. input.insert ( 2, "/" );
  39. pos++;
  40. }
  41.  
  42. // If there is no month, they are OK, by now...
  43. if ( input.length() < 4 ) return Intermediate;
  44.  
  45. // If they enter a month before October without the leading zero, we put it
  46. if ( ( input.length() == 5 ) && ( input.mid ( 4, 1 ) == "/" ) )
  47. {
  48. input.insert ( 3, "0" );
  49. pos++;
  50. }
  51.  
  52. // 2 : Month between 1 and 12, but considering the day...
  53. int Mes = input.mid ( 3, 2 ).toInt();
  54. if ( Mes > 12 ) return Invalid;
  55. switch ( Mes )
  56. {
  57. // 30 day months
  58. case 4 : // April
  59. case 5 : // June
  60. case 9 : // September
  61. case 11 : // November
  62. if ( Dia > 30 ) return Invalid;
  63. break;
  64. // Special case : February, we don't know the year, so 29 is possible...
  65. case 2 :
  66. if ( Dia > 29 ) return Invalid;
  67. break;
  68. default :
  69. break;
  70. }
  71.  
  72. // 3 : a month beginning by 2..9, We have to insert a leading 0
  73. if ( input.mid ( 3, 1 ).toInt() > 1 )
  74. {
  75. input.insert ( 3, "0" );
  76. pos++;
  77. }
  78.  
  79. // We append month / year separation, if the put first year's digit without the bar
  80. if ( ( input.length() > 5 ) && ( input.mid ( 5, 1 ) != "/" ) )
  81. {
  82. input.insert ( 5, "/" );
  83. pos++;
  84. }
  85.  
  86. // 4 : Year could begin by 1 ( 19xx ) or 2 ( 2xxx )
  87. if ( input.mid ( 6, 1 ).toInt() > 2 )
  88. {
  89. input.insert ( 6, "20" );
  90. pos += 2;
  91. }
  92.  
  93. // Two / four last digits are for the year...
  94. int Anyo = input.mid ( 6, 4 ).toInt();
  95. if ( Anyo < 1900 ) return Intermediate;
  96.  
  97. if ( MDate::IsValid ( Anyo, Mes, Dia ) )
  98. {
  99. // Here must be your suggested call / signal
  100. return Acceptable;
  101. }
  102. else
  103. return Invalid;
  104. }
To copy to clipboard, switch view to plain text mode 

While user enters the date, this validate method tests & corrects user input. But when he presses ENTER or TAB key, even if the date is a valid one, Business Logic may decide it's not a valid date ( i.e a day before today for a payment )

And here becomes the problem. I cannot assume a call to Business Logic EVERY time a date is Acceptable, because that call could be very time-expensive.

It's a "strange approach" and it doesn't work
OK, I accept perhaps is an "strange approach", but is working. And it's quick and efficient. Sometimes we must break "programming-guidelines" to obtain a better performance...

And I repeat that the problem is not in the validation style but in the fact that everything is working OK, but the cursor dissapears when between the focusout and the focusin I show a message on an external StatusBar. But when i show a modal message, all is running OK

Emit a signal from within the validator stating if the input is valid or not. If it's not, place the focus back in the lineedit owning the validator sending the signal.

...

IMO the problem is that the status bar might be stealing the focus, so it's better not to hack the focus but just set it back. And don't do the validation on focus loss - you only need to validate when something actually changes and that's what QValidator is responsible for.
But you will agree with me that I will have the same problem. When I emit the signal, I receive a "invalid" response and move the focus, "I'm fuc***"

I agree with you that StatusBar is stealing the focus, But I don't understand why...

I'm calling a method like this in the focusout event ( pseudo-code )

Qt Code:
  1. void MQEntryFormPrivate::FieldExit ( QWidget * Sender )
  2. {
  3. QWidget * pNext = Sender;
  4.  
  5. // If is valid, we step to the next widget, else we remain
  6. if ( BusinessObject()->ValidateField ( Sender ) )
  7. pNext = this->GetNextFocus ( Sender );
  8.  
  9. // Some irrelevant stuff here...
  10.  
  11. pNext->setFocus();
To copy to clipboard, switch view to plain text mode 

Inside business object's ValidateField code, user can show messages, activate & deactivate fields, launch queries, ....

You can make a line edit read only instead of disabling it, AFAIR. And you can always set the tab order again, so losing the order is not that much of a problem.
Yes, a QlineEdit. But not a QComboBox, or QRadioButton... And I do need to control that kind of widgets too