Не получается правильно построить проверку значений Topic is solved

Помощь в написании скриптов
vmech

Не получается правильно построить проверку значений  Topic is solved

31 Mar 2019, 03:43

Вобщем ситуация:
1. Есть поля типа Edit, допустим их три (3), в них нужно вводить только integer или float. И есть Button с включённым Default.
2. Если первое поле пустое, то при нажатии Enter фокус просто остается в этом поле.
3. Если в первом поле буквы, то при нажатии Enter выводится MsgBox, и фокус остаётся в этом поле.
4. Если в первом поле integer или float, то при нажатии Enter фокус передаётся на второе поле.
Реализация (частичная, ибо «не шмогла» я в каскадные проверки):

#NoEnv
Gui, Add, Edit, vPL Limit10 HwndhPL
Gui, Add, Edit, vPF Limit10 HwndhPF
Gui, Add, Edit, vPD Limit10 HwndhPD
Gui, Add, Button, Default gCalc, Расчёт!

uiCtrlHwnd := [hPL, hPF, hPD]
Return

Calc:
cRunVars := [0, 0, 0]
For idx, tCtrlHwnd in uiCtrlHwnd
{
GuiControlGet, tRunVar,, %tCtrlHwnd%
tRunVar := StrReplace(tRunVar,",",".")
If tRunVar Is not Number
If tRunVar Is Alpha
{
MsgBox, 0x2030, Ошибка!, "Недопустимое значение"
IfMsgBox, OK
ControlFocus,, ahk_id %tCtrlHwnd%
Return
}
Else
{
ControlFocus,, ahk_id %tCtrlHwnd%
Return
}
cRunVars[idx] := Abs(tRunVar)
}
... код непосредственно математики ...
Return

Всё работает почти как нужно, но на пустое поле выпадает MsgBox, как и на буквы в поле...
Я уже всю голову сломал переставляя местами проверки на Number и Alpha, и комбинируя их с отрицанием Not. Помогите сделать правильно, а то реально уже мозх кипит :)
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

31 Mar 2019, 06:27

Код надо оформлять тэгом.

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], cRunVars := []
Return

Calc: 
	For idx, tCtrlHwnd in uiCtrlHwnd
	{
		GuiControlGet, tRunVar, , %tCtrlHwnd%
		tRunVar := StrReplace(tRunVar,",","."), b := 0
		If tRunVar = 
			Break
		If !(b := IsIntegerOrFloat(tRunVar)) 
		{
			MsgBox, 0x2030, Ошибка!, "Недопустимое значение"  
			ControlSend, , {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd%
			Break
		}
		cRunVars[idx] := tRunVar
	}
	If b && idx < uiCtrlHwnd.Count()
		tCtrlHwnd := uiCtrlHwnd[++idx]
	ControlFocus, , ahk_id %tCtrlHwnd%
	If b
		MsgBox % "Сумма: " cRunVars[1] + cRunVars[2] + cRunVars[3]
	Return

IsIntegerOrFloat(var) {
	if var is integer
		Return 1
	if var is float
		Return 1
}
vmech

Re: Не получается правильно построить проверку значений

01 Apr 2019, 15:16

Вобщем я так и подумал, что без наворота костылей тут не обойтись... Но Ваш пример оказался не бесполезен, и навёл меня на мысль. Вот мой вариант, который в принципе меня полностью устраивает:

Code: Select all

For idx, tCtrlHwnd in uiCtrlHwnd
	{
		GuiControlGet, tRunVar,, %tCtrlHwnd%
		tRunVar := StrReplace(tRunVar,",",".")
		If (tRunVar = "") or (tRunVar = 0)
			{
			ControlFocus,, ahk_id %tCtrlHwnd%
			ControlSend,, {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd%
			Return
			}
		Else If tRunVar Is not Number
			{
			MsgBox, 0x2030, Ошибка!, % " Недопустимое значение: " . uiCtrlNames[idx]
			IfMsgBox, OK
				{
				ControlFocus,, ahk_id %tCtrlHwnd%
				ControlSend,, {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd%
				}
			Return
			} Else cRunVars[idx] := Abs(tRunVar)
	}
1. Break в теле цикла недопустим. Он прервёт цикл, и отправит незаполненный полностью массив cRunVars[] в расчёты. С соответствующими последствиями. Вот почему в теле цикла используется Return: он возвращает управление в основной тред до тех пор, пока массив не заполнится правильными значениями.
2. Входящие значения допустимы только целые и/или дробные положительные. Ноль недопустим. Отрицательные значения недопустимы. Вот почему функция Abs важна в строке cRunVars[idx] := Abs(tRunVar).
3. Вводить в код функцию IsIntegerOrFloat(var) нет никакой необходимости. Сдвоенную проверку на Integer и Float заменяет одна проверка на Number. Это чёрным по белому в документации.

А в целом спасибо за участие! Оно всё же помогло, хоть и отчасти. :)
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

01 Apr 2019, 16:16

Break в теле цикла недопустим. Он прервёт цикл, и отправит незаполненный полностью массив cRunVars[] в расчёты.
Не а, в моём коде вычисляется только когда весь массив заполнен.
Вводить в код функцию IsIntegerOrFloat(var) нет никакой необходимости.
Это удобнее делать в функции, там же например проверить отрицательное, и тоже вывести MsgBox.
Получается что отрицательное остаётся в форме, а в массив уходит положительное.
Хотя, всем этим условиям должно соответствовать только (tRunVar + 0 > 0).
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

01 Apr 2019, 16:32

Ну и в вашем случае некорректно приводить кусок кода, против моего полного, и рассказывать про "отправку в расчёты".

Без IsIntegerOrFloat.

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], cRunVars := []
Return

Calc: 
	For idx, tCtrlHwnd in uiCtrlHwnd
	{
		GuiControlGet, tRunVar, , %tCtrlHwnd%
		If (1, b := 0) && (tRunVar := StrReplace(tRunVar,",",".")) = ""
			Break
		If !(b := (tRunVar + 0 > 0)) 
		{
			MsgBox, 0x2030, Ошибка!, "Недопустимое значение"  
			ControlSend, , {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd%
			Break
		}
		cRunVars[idx] := tRunVar
	}
	If b && idx < uiCtrlHwnd.Count()
		tCtrlHwnd := uiCtrlHwnd[++idx]
	ControlFocus, , ahk_id %tCtrlHwnd%
	If b
		MsgBox % "Сумма: " cRunVars[1] + cRunVars[2] + cRunVars[3]
	Return
Или с одним Break:

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], cRunVars := []
Return

Calc: 
	For idx, tCtrlHwnd in uiCtrlHwnd {
		GuiControlGet, tRunVar, , %tCtrlHwnd%
		If !b := (tRunVar := StrReplace(tRunVar,",",".")) + 0 > 0
			Break
		cRunVars[idx] := tRunVar
	}
	If b && idx < uiCtrlHwnd.Count()
		tCtrlHwnd := uiCtrlHwnd[++idx]
	ControlFocus, , ahk_id %tCtrlHwnd%
	If (!b && tRunVar != "") {
		MsgBox, 0x2030, Ошибка!,%  "В поле: " idx ", недопустимое значение: " tRunVar
		ControlSend, , {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd% 
	}
	If b
		MsgBox % "Сумма: " cRunVars[1] + cRunVars[2] + cRunVars[3]
	Return
vmech

Re: Не получается правильно построить проверку значений

01 Apr 2019, 21:18

Можете пояснить механику работы выражения tRunVar + 0 > 0 ? Я не могу понять для чего нужен именно + 0 перед оператором сравнения. Спасибо.
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

02 Apr 2019, 04:08

Если в переменной буквы, они считаются как больше нуля, математическая операция вернёт пустую строку, пустота уже не больше нуля.
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

02 Apr 2019, 06:23

В последнем коде осталась лишняя часть.

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], cRunVars := []
Return

Calc: 
	For idx, Hwnd in uiCtrlHwnd {
		GuiControlGet, str, , %Hwnd%
		If !valid := (str := StrReplace(str,",",".")) + 0 > 0
			Break
		cRunVars[idx] := str
	}
	ControlFocus, , ahk_id %Hwnd%
	If (!valid && str != "") {
		MsgBox, 0x2030, Ошибка!,%  "В поле: " idx ", недопустимое значение: " str
		ControlSend, , {LCtrl Down}{A}{LCtrl Up}, ahk_id %Hwnd% 
	}
	Else If valid
		MsgBox % "Сумма: " cRunVars[1] + cRunVars[2] + cRunVars[3]
	Return
vmech

Re: Не получается правильно построить проверку значений

02 Apr 2019, 10:51

Вы всё же продолжаете постить неправильный код. Поясню последний раз. Задача у цикла For лишь одна - заполнить массив cRunVars[] правильными значениями, которые вводятся руками из формы GUI. До тех пор, пока это не сделано, код под Calc: дальше цикла For не исполняется. Потому что за циклом, до самого конца программы, идёт множество математических формул, использующих данные из cRunVars[], в том числе формирование ещё нескольких массивов на основе расчётов.

Я намеренно не привожу весь код, потому что не хочу. Он очень большой, входящих в cRunVars значений больше, чем 3. Все эти «пляски» с циклом только ради удобства пользования, потому что хочу предупредить процесс внесения данных в форму не только линейно, по порядку сверху-вниз, а вообще в произвольном порядке. И пока что мой вариант меня полностью устраивает: малой кровью хоть какой то порядок в царстве хаоса :)

Вот окончательный вариант кода:

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], uiCtrlNames := ["Длина", "Частота", "Диаметр"], cRunVars := []
Return

Calc:
For idx, tCtrlHwnd in uiCtrlHwnd
{
	GuiControlGet, tRunVar,, %tCtrlHwnd%
	If (tRunVar := StrReplace(tRunVar,",",".")) = ""
	{
		ControlFocus,, ahk_id %tCtrlHwnd%
		Return
	}
	Else If !(tRunVar + 0 > 0)
	{
		MsgBox, 0x2030, Ошибка!, % " Недопустимое значение: " . uiCtrlNames[idx]
		IfMsgBox, OK
		{
			ControlFocus,, ahk_id %tCtrlHwnd%
			ControlSend,, {LCtrl Down}{A}{LCtrl Up}, ahk_id %tCtrlHwnd%
		}
		Return
	} Else cRunVars[idx] := tRunVar
}

... математика ...

... вывод результатов ...

Return

Esc::
GuiClose:
ExitApp
На этом, пожалуй всё. Код работает как мне нужно. Благодарю за помощь!

ЗЫ. И да, у меня Break вместо Return в теле цикла таки прерывает его, и исполняется код, который следует за телом цикла. А нужно просто вернуться к ожиданию ввода значений в форму.
serzh82saratov
Posts: 137
Joined: 01 Jul 2017, 03:04

Re: Не получается правильно построить проверку значений

02 Apr 2019, 15:03

Мда, а вы всё же сказочный ... экземпляр.
Тут знаете ли помощь, а не стол заказов, и уж тем более как возможно постить неправильный код, на фоне:
не привожу весь код, потому что не хочу.
Вы если вопрос задаёте, потрудитесь сначала вникнуть в ответ.
Хотите правильно выстроить проверку условий, в итоге все у вас дураки, и в результате Return и ControlFocus дублирован, непонятно зачем нужный IfMsgBox. То есть по корявому переписываете мой код, и называете его неправильным, всё в лучших традициях самого умного и красивого. Вы вообще мой код запускали, или опытным взглядом сразу секёте что всё не так.
ЗЫ. И да, у меня Break вместо Return в теле цикла таки прерывает его, и исполняется код, который следует за телом цикла. А нужно просто вернуться к ожиданию ввода значений в форму.
Я вам уже второй раз объясняю, у меня не выполняются вычисления пока правильно не заполнены все поля.
Вас слово "Break" вводит в ступор? Какая разница как выходить из цикла, если из него всё равно выходить.
Если после цикла выполнится пара строк и будет возврат, это у вас в голове не укладывается?
Если не можете заключить в блок MsgBox, может вам так понятнее.

Code: Select all

#NoEnv
Gui, Add, Edit,	vPL Limit10 HwndhPL  
Gui, Add, Edit,	vPF Limit10 HwndhPF  
Gui, Add, Edit,	vPD Limit10 HwndhPD  
Gui, Add, Button, Default gCalc, Расчёт!
Gui, Show
uiCtrlHwnd := [hPL, hPF, hPD], cRunVars := []
Return

Calc: 
	For idx, Hwnd in uiCtrlHwnd {
		GuiControlGet, str, , %Hwnd%
		If !valid := (str := StrReplace(str,",",".")) + 0 > 0
			Break
		cRunVars[idx] := str
	}
	ControlFocus, , ahk_id %Hwnd%
	If (!valid && str != "") {
		MsgBox, 0x2030, Ошибка!,%  "В поле: " idx ", недопустимое значение: " str
		ControlSend, , {LCtrl Down}{A}{LCtrl Up}, ahk_id %Hwnd% 
	}
	If !valid
		Return
	... математика ...

	... вывод результатов ...
	Return

Return to “Помощь”

Who is online

Users browsing this forum: No registered users and 32 guests