Эмуляция текстовых полей

При программировании одной из штучек я столкнулся с проблемой получения значения, введенного в текстовое поле. Изучение доступной литературы ничего не дало, также как и обращение к одному из разработчиков — и тогда я немного приуныл.

Но… Через пару дней совершенно случайно у меня родилась идея как это можно немного подкорректировать. Идея в общем-то проста: поскольку в Icon существуют достаточно богатые возможности для отрисовки разных графических элементов (в том числе, и прямоугольников различных размеров и окраски) и средства захвата позиции курсора, находящегося в окне, то почему бы не сымитировать ввод в текстовое поле?

И тут нам потребуются те же геометрические познания, что были использованы при создании игр на Icon («горячо-холодно», «фие»), а именно, определение факта попадания курсора (при щелчке правой или левой кнопки мыши) в некоторую прямоугольную область.

Но сначала нужно нарисовать текстовое поле для чего используется следующая процедура:

procedure text_field(x,y,w,h)
Fg("gray")
DrawRectangle(x,y,w,h)
Fg("white")
DrawRectangle(x+2,y+2,w-4,h-4)
Fg("black")
end

рисующая два прямоугольника (разных цветов) один внутри другого и принимающая аргументы: x,y — координаты размещения левого верхнего угла текстового поля, w — ширина текстового поля, h — высота текстового поля.

Поле нарисовано, а теперь с помощью где-то выше упомянутых геометрических познаний перехватим курсор мыши, попавший в текстовое поле и установим позицию вывода строки (т.е. введенного в поле текста) прямо внутрь отрисованного текстового поля, а для получения значения текстового поля введем локальную переменную text, которая будет возвращена после того, как пользователь закончит ввод в текстовое поле.

Код процедуры:

procedure text_enter(x,y,w,h)
local text
repeat {
	case Event() of {
		&lpress|&rpress : {
			if x<=&x<=(x+w) & y<=&y<=(y+h) then {
				GotoXY(x+4,(y+h)-4)
			        text:=WRead()
			        GotoXY(0,0)
			        return text
			}
		}
	}
}
end

процедура принимает те же аргументы, что и предыдущая.

А теперь небольшая ложка дегтя: значение переменной text будет возвращено только после нажатия Enter!

Ну а теперь процедура в рабочем демо-примере, в качестве которого была выбрана задача на определение счастливого билета.

Известно, что билет счастливый в том случае, если сумма цифр из первой половины номера равна сумме цифр второй половины номера билета. Это условие можно записать с помощью следующих двух процедур:

procedure sum(s)
local i,r
r:=0
every i:=1 to (*s) do {
  r+:=s[i]
}
return r
end

procedure lucky(x)
local a
a:=(*x)/2
if sum(x[1+:a])=sum(x[(a+1):(*a)+1]) then return "Yes" else return "No"
end

Процедура sum принимает строку из цифр и вычисляет сумму для всей строки, а процедура lucky принимает строку с номером билета и сравнивая суммы первой половины строки с номером и второй строки с номером билета, выдает результат «Yes» или «No», в зависимости от того совпали суммы или нет.

Далее нам потребуется vib: сохранив все процедуры в отдельном файле, запускаем vib и создаем в нем новый файл, устанавливаем размеры окна 200*100 и помещаем на форму кнопку, сохраняем файл и закрываем vib.

Теперь нам vib не понадобиться и будем файл править вручную: в конце файла (или в начале) после фразы #===<>=== ищем вот такое описание [«button1:Button:regular::155,40,35,20:push»,button_cb1] и исправляем значения: button1 заменяем на ?, push на ?.

Далее исправляем координаты, стоящие после слова regular, на вот такие значения — 155,40 (если у вас другие стоят, конечно) и переходим к процедуре button_cb1, которую заменяем на следующий код:

procedure button_cb1(vidget, value)
case vidget.id of {
"?" : Notice(lucky(v))
}
end

После этих плясков с бубном вставляем после процедуры button_cb1 процедуры отрисовки текстового поля и определения «счастливости» билета, а затем в процедуру main перед установкой переменной paused в 1 ставим следующий код:

DrawString(10,25,"Number of bilet:")
text_field(130,10,60,20)
v:=text_enter(130,10,60,20)

а перед самой процедурой main определяем глобальную переменную v, в которой сохраниться результат, введенный в текстовое поле. И все.

Под спойлером полный код для гурманов.

############################################################################
#
#	File:     bilet.icn
#
#	Subject:  Program to ...
#
#	Author:   
#
#	Date:     July 29, 2012
#
############################################################################
#
#
#
############################################################################
#
#  Requires:
#
############################################################################
#
#  Links: vsetup
#
############################################################################

#  This vib interface specification is a working program that responds
#  to vidget events by printing messages.  Use a text editor to replace
#  this skeletal program with your own code.  Retain the vib section at
#  the end and use vib to make any changes to the interface.

link vsetup
global v
procedure main(args)
   local vidgets, root, paused

   (WOpen ! ui_atts()) | stop("can't open window")
   vidgets := ui()				# set up vidgets
   root := vidgets["root"]
   DrawString(10,25,"Number of bilet:")
   text_field(130,10,60,20)
   v:=text_enter(130,10,60,20)
   paused := 1					# flag no work to do
   repeat {
      # handle any events that are available, or
      # wait for events if there is no other work to do
      while (*Pending() > 0) | \paused do {
         ProcessEvent(root, QuitCheck)
         }
      # if  is set null, code can be added here
      # to perform useful work between checks for input
      }
end

procedure button_cb1(vidget, value)
case vidget.id of {
 "?" : Notice(lucky(v))	
}
end

procedure text_field(x,y,w,h)
Fg("gray")
DrawRectangle(x,y,w,h)
Fg("white")
DrawRectangle(x+2,y+2,w-4,h-4)
Fg("black")
end

procedure text_enter(x,y,w,h)
local text
repeat {
	case Event() of {
		&lpress|&rpress : {
			if x<=&x<=(x+w) & y<=&y<=(y+h) then {
				GotoXY(x+4,(y+h)-4)
			        text:=WRead()
			        GotoXY(0,0)
			        return text
			}
		}
	}
}
end

procedure sum(s)
local i,r
r:=0
every i:=1 to (*s) do {
 	r+:=s[i]
}
return r
end

procedure lucky(x)
local a
a:=(*x)/2
if sum(x[1+:a])=sum(x[(a+1):(*a)+1]) then return "Yes"  else return "No"
end

#===<>===	modify using vib; do not remove this marker line
procedure ui_atts()
   return ["size=200,100", "bg=pale gray"]
end

procedure ui(win, cbk)
return vsetup(win, cbk,
   [":Sizer:::0,0,200,200:",],
   ["?:Button:regular::155,40,35,20:?",button_cb1],
   )
end
#===<>===	end of section maintained by vib

И напоследок скриншоты:
bilet1_0_o

bilet2_0_o

Добавить комментарий