Visual2000 · Архив статей Колесова & Павловой

Visual Basic 6.0 упрощает разработку для Web
Часть 3. Создание DHTML-приложений

Андрей Колесов, Ольга Павлова

Дополнительно смотрите:

© 1999, Андрей Колесов, Ольга Павлова
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале "КомпьютерПресс" № 05/99, c.62-66.

ВНИМАНИЕ! Данный вариант статьи содержит ряд небольших, но важных исправлений и дополнений к ранее опубликованному варианту, связанными с созданием программного примера для дистибуции. Кроме того, решены проблемы, которые ранее не было (возможно они возникли после обновления Windows и VB 6.0).

Загрузить программные приложения (12 Кб, VB-WEB3.ZIP) Все файлы ZIP-файла необходимо разместить в каталоге C:\VB-DB\VB6-WEB\EXAM3-1\. Подробнее о запуске примера см. файл README3.TXT.



В этой статье мы покажем возможности...

В этой статье мы покажем возможности Visual Basic 6.0 по созданию DHTML-приложений, которые структурно представляют собой комбинацию динамических HTML-страниц и программного кода на VB. Напомним, что работа этих приложений основана на DHTML-технологии, реализованной в Internet Explorer начиная с версии 4.0.

Идея нашего проекта такова. Пусть имеется некая база данных, в которой хранятся сведения о сотрудниках фирмы. Мы создадим приложение с использованием двух DHTML-страниц: на первой будет вводиться запрос на поиск сведений о сотруднике (рис. 1), а на вторую будет выдаваться соответствующая персональная информация (рис. 2).

Рис. 1.

Рис. 2.

Мы будем использовать базу NWind.mdb, входящую в состав VB6. [Дополнение от 25.04.00] Чтобы не приходилось заботиться об указании точных путей к файлам, скопируйте ее в корневой каталог C:\VB-DB\. Сам проект будет размещаться в каталоге C:\VB-DB\VB6-WEB\EXAM3-1\. Как выяснилось, DHTML-приложения является довольно чувствительным к изменению адресом файлов проекта.

В ходе выполнения этого примера мы рассмотрим общую логику создания приложения, его структуру, познакомимся с работой встроенного HTML-конструктора, создадим Webстраницу с использованием формы, состоящей из нескольких вкладок. И в итоге получим приложение, которое будет работать...

В начало статьи

Структура DHTML-приложения

Загрузите VB6 и в окне New Project выберите элемент DHTML Application. Обратите внимание, что панель инструментов Toolbox приняла вид, специально адаптированный для данного типа приложений (рис. 3).

Рис. 3.

В окне проекта сразу появились две группы элементов - модули и конструкторы HTMLфайлов (рис. 4). В папке Modules автоматически создается модуль modDHTML, который содержит две процедуры - GetProperty и PutProperty - с уже сформированным кодом для управления взаимодействием HTML-модулей данного приложения (мы не будем дальше корректировать содержимое модуля, поэтому можно закрыть этот узел дерева проекта).

Рис. 4.

Мы будем иметь дело Конструктором, содержащим модули, в каждом из которых находится ссылка на базовый HTML-файл и необходимый для него программный код (соответствующий файл на диске имеет расширение DSR). Дважды щелкните элемент DHTMLpage1, после чего на экране появится окно Конструктора. Далее замените в окне Properties свойство Name этого элемента на HRintro и сохраните (Save As) весь проект под именем DHTMLex1.vbp.

В начало статьи

Проектирование первой HTML-страницы - Intro.htm

Приступим к формированию первого DHTML-элемента. На панели инструментов Конструктора щелкните кнопку DHTML Page Designer Properties (рис. 5). В появившемся окне HRintro Properties установите переключатель "Save HTML in an external file", чтобы сохранить саму HTML-страницу в виде внешнего файла. Этот вариант лучше, чем вариант с сохранением страницы во внутреннем VB-формате, так как позволяет в нужный момент использовать любой внешний редактор, в том числе текстовый, для коррекции содержимого файла.

Рис. 5.

Далее нажмите кнопку New и сохраните создаваемый файл в текущем каталоге вашего проекта под именем Intro.htm. Для завершения процедуры щелкните OK в окне HRintro Properties (рис. 6).

Рис. 6.

Замечание. К сожалению, встроенный HTML-редактор VB6 нельзя отнести к "продвинутым", поэтому внешняя помощь иногда не помешает. Более того, мы не рекомендуем вообще пользоваться этим редактором, и нижеследующий пример работы с ним служит подтверждением этого совета.

Содержимое текущей (для Конструктора) HTML-страницы можно просматривать и редактировать напрямую в редакторе, который вы определили по умолчанию (команда Tools|Options|Advanced). К нему можно обратиться, щелкнув кнопку Launch Editor на панели инструментов Конструктора. Мы же будем сейчас работать со средствами редактирования самого Конструктора и Launch Editor (в нашем случае это Notepad). Конструктор состоит их двух смежных окон: в правом находится собственно графический HTML-редактор, а в левом - дерево, которое отображает структуру HTML-страницы.

Для начала изменим цвет фона станицы. Для этого щелкнем кнопкой Launch Editor и откроем исходный HTML-код нашей страницы, который содержит всего одну сточку:

<body></body></html>

Заменим первый тег <body> на <head></head><body bgcolor="#87ceed">. Зачем здесь нужен тег <head>? Структура HTML-документа требует наличия двух частей — заголовка документа, описывамого тегом <head>, и тела документа, описываемым тегом <body>. Обе эти части располагаются внутри тега <html>. В случае отсутствия тега <head> Конструктор зачем-то дописывает свои строки в заголовок создаваемого временного HTML-файла во время выполнения приложения, в результате чего портится цвет фона выводимого окна. Если интересно - попробуйте указать <head> и посмотрите, что получится.

Выйдем из Notepad (сохранив изменения) и убедимся, что цвет фона стал голубым. Далее, используя средства форматирования (шрифт, размер и пр.), введите в правом поле встроенного редактора Конструктора нужный нам текст (рис. 1). Следите при этом за изменением структуры HTML-страницы в левом окне Конструктора.

Написав в последней строке слово "Сотрудники:", щелкните на панели инструментов элемент списка, который в данном случае называется Select, и разместите его на формируемой нами странице. В окне Properties установите свойство ID данного элемента как cboEmpNames, а свойству Value присвойте пустое значение. Затем аналогичным образом разместите на странице командную кнопку подтверждения SubmitButton и установите ее свойства ID и Value как btnGo и Выбор соответственно.

Замечание. Обратите внимание, что названия и смысловое содержание визуальных элементов DHTML-страниц и их свойств несколько отличаются от обычных VBэлементов. В частности, в VB идентификация элемента управления выполняется с помощью свойства Name, а в DHTML - ID.

Но это еще не все. Еще раз войдите в Launch Editor и удалите в тексте Intro.htm строку:

<OPTION selected value=Select>Select

Иначе у вас в качестве первого значения списка в процессе выполнения приложения будет появляться Select, нумерация списка будет нарушена и поиск по базе данных будет проходить неверно.

Мы закончили формирование первой DHTML-страницы (рис. 7), структура которой представлена деревом в левом окне Конструктора. А сам исходный текст файла Intro.htm должен иметь приблизительно такой вид, как на листинге 1.

Рис. 6.

В начало статьи

Формирование второй страницы - Entry.htm

Правой кнопкой мыши щелкните папку Designers в окне Project, в появившемся меню выберите команду Add, а затем - HTML Page. Здесь возникает вопрос: формировать страницу самим в среде Конструктора или использовать некоторую внешнюю заготовку?

Сейчас мы выберем второй вариант, поэтому в появившемся окне DHTMLpage1 Properties установим переключатель Save HTML in an external file, щелкнем кнопку Open, а затем откроем существующий файл Entry.htm. Далее в окне Properties заменим свойство Name элемента DHTMLpage1 на HRentry и сохраним новый модуль на диске.

Разверните Конструктор во весь экран и внимательно посмотрите на структуру HTML- страницы и на ее внешний вид. Для лучшей наглядности элементов дизайна страницы, щелкните кнопку Show Table Borders на панели инструментов (рис. 8).

Рис. 8.

На странице видны четыре группы графических элементов, обозначенных прямоугольниками с серой границей. На дереве страницы им соответствуют папки dvTab1Sel, dvTab2Sel, dvTabPage1 и dvTabPage2, а в коде HTM-файла границы этих фреймов определяются тегами DIV, которые имеют приблизительно такой вид (для dvTab1Sel):

<DIV id=dvTab1Sel style="HEIGHT: 25px; LEFT:
        110px; POSITION: absolute; TOP: 72px; WIDTH:
        153px; Z-INDEX: 100">
<p><FONT size=2>Сотрудник</FONT></p>
</DIV>

С помощью этих фреймов мы будем формировать две вкладки на выходной форме нашего приложения: dvTabxSel будут использоваться в качестве заголовка, а dvTabPagex — содержимого.

Здесь следует подчеркнуть, что редактор DHTML-Конструктора в VB 6.0 реально годится только для создания довольно простых проектов. (Мы использовали для создания второй страницы MS FrontPage Expess 2.0.) В принципе, некоторое подобие формы, приведенной на рисунке 8, можно создать и в VB 6 (в том числе и сформировать таблицы для dvTabPagex, хотя работа с таблицами в редакторе тоже реализована не очень удачно). Но для оформления фреймов с помощью тегов <DIV> придется корректировать код HTM- файла вручную.

В начало статьи

Написание программного кода

Начнем писать код с входного модуля HRintro. Чтобы попасть в окно кода, нужно щелкнуть правой кнопкой мыши этот элемент в окне Project и выбрать команду View Code. В первую очередь нужно сформировать процедуру BaseWindow_onLoad - именно это событие выполняется в момент загрузки страницы:

Private Sub BaseWindow_onload()
   ' Описание соединения с используемой базой данных
   ' используется в обоих DSR-модулях - HRintro.dsr и HRentry.dsr
   Dim DBname$
   DBname$ = "c:\vb-db\Nwind.mdb"
   ConnectionString = "Provider=Microsoft.Jet.OLEDB.3.51;Persist Security Info=False;Data Source=" + DBname$
  
   ' формирование списка сотрудников
   Call LoadComboBox
End Sub

[Дополнение 25.04.00] Здесь мы описали строковую переменную ConnectionString, которую будем далее использовать для доступа к базе данных в обоих DSR-конструкторах. Сама переменная должна быть описисана как глобальная (Public) в модуле modDHTML.bas. Здесь же происходит обращение к процедуре LoadComboBox (см. листинг 2), в которой выполняется обращение к базе данных Nwind.mbd и формирование списка фамилий сотрудников для элемента управления cboEmpNames (Select). Далее введем следующий код для кнопки "Выбор":

Private Function btnGo_onclick() As Boolean
  
  If cboEmpNames.selectedIndex >=0 Then
    ' фиксация фамилии выбранного сотрудника
    PutProperty BaseWindow.Document, "EmpID", _
                cboEmpNames(cboEmpNames.selectedIndex).Value
    ' обращение к выходной странице Entry.htm
    BaseWindow.navigate "Entry.htm"
  End If
End Function
ВНИМАНИЕ! [25.04.00] При повторном тестировании примера мы обнаружили, что программа выдает ошибку при обращении к процедурам PutProperty (в Function btnGo_onclick) и GetProperty (в Sub PopulateTabs). Это стандартные процедуры, сформированные автоматически при создании модуля modDHTML.bas, такие конструкции соответствуют примерам в составе VB 6.0 и раньше они работали. (Примеры самого VB6 также перестали работать в этом месте). Ошибка связана с какой-то проблемой при передаче параметра BaseWindow.Document (тип объекта As HTMLDocument). Возможно, это связано с какими-то обновлениями ПО. Мы решили эту проблему, изменив код приложения, который можно найти в загружаемом проекте-примера.

Если из списка выбран некий сотрудник, производится передача его идентификатора в модуль modDHTML через автоматически сформированную процедуру PutProperty. Далее активизируется страница Entry.htm. (На самом деле запускается на выполнение модуль HRentry.dsr, но почему-то Microsoft решила для обращения к нему использовать не его имя, а название исходной страницы.)

Далее формируем код для выходной HTML-страницы - HRentry. Откроем ее окно кода и введем для события BaseWindow_onLoad:

Private Sub BaseWindow_onload()
  ' Инициализация страницы Entry.htm
  ' Заполнение формы данными
  Call PopulateTabs
  'Формирование выходной формы из двух вкладок:
  Call TabsOnScreen
End Sub

Как видите, здесь производится обращение к двум процедурам: PopulateTabs (листинг 3) выполняет поиск данных в базе данных на основе идентификатора, получаемого с помощью процедуры GetProperty, а TabsOnScreen (листинг 4) выводит графическое изображение формы с двумя вкладками на экран. Чтобы завершить написание кода, нужно еще сформировать процедуры dvTab1Sel_onClick и dvTab2Sel_onClick (листинг 5), которые обеспечивают перерисовку вкладок после щелчка их заголовков.

В начало статьи

Тестирование приложения

Теперь запустите созданное нами приложение и убедитесь, что все работает, как было задумано. Однако обратите внимание на следующие моменты:

  1. При первом запуске приложения появится окно Project Properties с открытой вкладкой Debugging (рис. 9). Обратите внимание, что там нужно установить переключатель Start Component, а в списке рядом с ним выделен HRintro (с загрузки этой страницы должна начинаться работа приложения).

  2. Для работы с базой данных Nwind.mdb необходимо установить ссылку к библиотеке Microsoft ActiveX Data Objects Library: с помощью команды Project|References отметьте библиотеку ADO Library 1.5 или 2.0.

  3. Откомпилированное приложение можно создать только в виде ActiveX-сервера — EXE или DLL.

4. При переносе исходных модулей приложения могут нарушиться связи между модулями из-за изменения путей в именах файлов. ВНИМАНИЕ! [25.04.00] К сожалению, оказалось, что коррекция связи DSR-модулей с исходными HTML-файлами НЕ решается простым повторым их открытием в Конструкторе. Для этого трубуется "ручная" коррекция DSR-модуля с помощью текстового редактора типа NotePad - нужно прописать точные адреса исходного и результирующего HTML-файлов в строке параметров SourceFile и BuildFile.

Рис. 9.

В начало статьи

ПРИЛОЖЕНИЯ к статье

В начало статьи

Листинг 1. Текст файла Intro.htm

</html>
<head>

</head>
<body bgcolor="#87ceeb" id="">
<!—METADATA TYPE="MsHtmlPageDesigner" startspan—>
<object id="DHTMLPage1" classid="clsid:
F10CB540-E882-11D2-AFCA-ABB579C55564" 
width=0 height=0></object>
<!—METADATA TYPE="MsHtmlPageDesigner" endspan—>
<P><STRONG>
<FONT size=5 style="BACKGROUND-COLOR: #87ceeb">
Выбор сотрудника</FONT></STRONG></P>
<P><FONT style="BACKGROUND-COLOR: #87ceeb">
Для просмотра информации о сотруднике
выберите фамилию из приведенного ниже 
списка и щелкните кнопку "Выбор".</FONT></P>
<P> Сотрудники:</P>
<P>
<SELECT id=cboEmpNames name=Select1
style="HEIGHT: 26px; LEFT: 147px; POSITION: 
absolute; TOP: 169px; WIDTH: 175px" 
value = Select1></SELECT>
<INPUT id=btnGo name=SubmitButton1
style="HEIGHT: 29px; LEFT: 331px; POSITION: 
absolute; TOP: 166px; WIDTH: 98px" type=submit value=Выбор>
</P>

</body></HTML>

В начало статьи

Листинг 2. Процедура формирования списка сотрудников

Private Sub LoadComboBox()
  ' формирование списка сотрудников
  '
  Dim con As New ADODB.Connection, rs As New ADODB.Recordset
  Dim sSQL As String, objEntry As Object, iCnt As Integer
  ' формирование запроса для открытия базы данных
  sSQL = "Select EmployeeID, FirstName + ' ' +" & _
         "LastName as Name from Employees"
  con.open ConnectionString
  rs.open sSQL, con, adOpenKeyset, adLockReadOnly
  ' формирование списка
  Do Until rs.EOF
    Set objEntry = Document.createElement("option")
    objEntry.Text = rs("Name")
    cboEmpNames.Add objEntry
    cboEmpNames(iCnt).Value = rs("EmployeeID")
    rs.MoveNext
    iCnt = iCnt + 1
  Loop
  rs.Close
  con.Close
End Sub

В начало статьи

Листинг 3. Процедура формирования полей выходной формы

Private Sub PopulateTabs()
  '
  'формирование полей выходной формы данными из
  ' базы данных по иденификатору сотрудника
  '
  Dim con As New ADODB.Connection, rs As New ADODB.Recordset
  Dim sSQL As String, iEmpID As Integer
  ' открываем базу данных C:\NWind.mdb
  con.open ConnectionString
  ' получаем идентификатор сотрудника, который
  ' определен на странице Inrto.htm
  iEmpID = GetProperty(BaseWindow.Document, "EmpID")
  ' SQL-запрос на поиск записи
  sSQL = "Select FirstName + ' ' + LastName as Name," & _
          " Address, City, Region, BirthDate, HireDate," & _
          " Title From Employees where EmployeeID = " & iEmpID
  ' поиск и чтение записи
  rs.open sSQL, con, adOpenKeyset, adLockReadOnly
  ' переписываем данные на форму
  txtName.Value = rs("Name")
  txtAddress.Value = rs("Address") & _
          vbCrLf & rs("city") & " " & rs("Region")
  txtDOH.Value = rs("HireDate")
  txtBirthDate.Value = rs("BirthDate")
  txtTitle.Value = rs("Title")
  rs.Close
  con.Close
End Sub

В начало статьи

Листинг 4. Процедура формирования вкладок

Private Sub TabsOnScreen()
  Dim iTop As Integer
  '
  'формирование выходной формы из двух вкладок:
  iTop = (dvTabPage1.Style.posTop - dvTab1Sel.Style.posHeight) + 2
  dvTab1Sel.Style.Top = iTop
  dvTab2Sel.Style.Top = dvTab1Sel.Style.Top
  dvTabPage2.Style.Top = dvTabPage1.Style.Top
  '
  dvTab2Sel.Style.Height = dvTab1Sel.Style.Height
  dvTab2Sel.Style.Left = dvTab1Sel.Style.posLeft + _
                         dvTab1Sel.Style.posWidth
  '
  tblPerInfo.Style.Top = tblEmp.Style.Top
  '
  ' изображение в красивом 3D-виде
  '
  With dvTab1Sel
    .Style.fontWeight = "bold"
    .Style.cursor = "hand"
    .Style.backgroundColor = "lightgrey"
    .Style.borderLeftStyle = "outset"
    .Style.borderLeft = "whitesmoke solid 2px"
    .Style.borderRight = "darkgray solid 2px"
    .Style.borderTop = "whitesmoke solid 2px"
    .Style.visibility = "visible"
  End With
  '
  With dvTab2Sel
    .Style.cursor = "hand"
    .Style.backgroundColor = "lightgrey"
    .Style.borderLeft = "whitesmoke solid 1px"
    .Style.borderRight = "darkgray solid 2px"
    .Style.borderTop = "whitesmoke solid 2px"
    .Style.borderBottom = "whitesmoke solid 2px"
  End With
  '
  With dvTabPage1
    .Style.backgroundColor = "lightgrey"
    .Style.Left = dvTab1Sel.Style.Left
    .Style.visibility = "Visible"
    .Style.borderTop = "whitesmoke solid 2px"
    .Style.borderLeft = "whitesmoke solid 2px"
    .Style.borderRight = "darkgray solid 3px"
    .Style.borderBottom = "darkgray solid 3px"
    .Style.zIndex = "-1"
  End With
  '
  With dvTabPage2
    .Style.backgroundColor = "lightgrey"
    .Style.Left = dvTab1Sel.Style.Left
    .Style.visibility = "Hidden"
    .Style.Height = dvTabPage1.Style.Height
    .Style.Width = dvTabPage1.Style.Width
    .Style.borderTop = "whitesmoke solid 2px"
    .Style.borderLeft = "whitesmoke solid 2px"
    .Style.borderRight = "darkgray solid 3px"
    .Style.borderBottom = "darkgray solid 3px"
  End With
End Sub

В начало статьи

Листинг 5. Процедуры управления переключением вкладок

Private Function dvTab1Sel_onclick() As Boolean
  ' переключение на первую вкладку
  dvTab1Sel.Style.fontWeight = "bold"
  dvTab2Sel.Style.fontWeight = "normal"
  dvTabPage1.Style.visibility = "visible"
  dvTabPage2.Style.visibility = "hidden"
  dvTab2Sel.Style.borderBottom = "whitesmoke solid 2px"
  dvTab1Sel.Style.borderBottom = "lightgrey solid 4px"
End Function

Private Function dvTab2Sel_onclick() As Boolean
  ' переключение на вторую вкладку
  dvTab2Sel.Style.fontWeight = "bold"
  dvTab1Sel.Style.fontWeight = "normal"
  dvTabPage2.Style.visibility = "visible"
  dvTabPage1.Style.visibility = "hidden"
  dvTab1Sel.Style.borderBottom = "whitesmoke solid 2px"
  dvTab2Sel.Style.borderBottom = ""
  dvTabPage2.Style.zIndex = "-1"
End Function

В начало статьи

Листинг 6. Текст файла Entry.htm

<html>

<head>
<meta http-equiv="Content-Type"
content="text/html; ">
<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
<title></title>

</head>

<body bgcolor="#87ceeb" id="bodyTag">

<h4 align="center"><FONT face="" size=4>Информация о сотрудниках</FONT></h4><FONT
face=Arial size=2>
<DIV id=dvTab1Sel
style="HEIGHT: 25px; LEFT: 110px; POSITION: absolute; TOP: 72px; WIDTH: 153px; Z-INDEX: 100">

<p><FONT face=Arial size=2>Сотрудник    
 </FONT> </p></DIV> 
<DIV id=dvTab2Sel
style="HEIGHT: 31px; LEFT: 351px; POSITION: absolute; TOP: 68px; WIDTH: 131px; Z-INDEX: 100">

<p><FONT face=Arial size=2> Личное дело
 </FONT> </p></DIV> 
<P> </P>
<P> </P>
<DIV id=dvTabPage1
style="HEIGHT: 235px; LEFT: 51px; POSITION: absolute; TOP: 110px; WIDTH: 454px; Z-INDEX: 100">
<P>
<TABLE border=0 height=88 id=tblEmp
style="HEIGHT: 88px; LEFT: 34px; POSITION: absolute; TOP: 8px; WIDTH: 323px; Z-INDEX: 100" 
width=323 name = Table1 background="">
    
    <TR>
        <TD align=left colSpan=2><FONT face="" size=2>Фамилия и адрес сотрудника</FONT>
        <TD>
    <TR>
        <TD align=left colSpan=2> 
        <TD>
    <TR>
        <TD align=right><FONT face="" size=2>Фамилия:</FONT></TD>
        <TD>
            <INPUT id=txtName name=TextField1
            style="HEIGHT: 22px; LEFT: 316px; TOP: 34px; WIDTH: 221px"></TD></TR>
    <TR>
        <TD align=right><FONT face="" size=2>Адрес:</FONT></TD>
        <TD><TEXTAREA cols=25 id=txtAddress name=TextArea1 rows=4 style="LEFT: 159px; 
  TOP: 75px"></TEXTAREA></TD></TR></TABLE></P></DIV></FONT> 
<P></P>
<DIV id=dvTabPage2
style="HEIGHT: 193px; LEFT: 55px; POSITION: absolute; TOP: 378px; WIDTH: 451px; Z-INDEX: 100">

<p><FONT face=Arial size=2> 
<TABLE border=0 height=112 id=tblPerInfo
style="HEIGHT: 112px; LEFT: 26px; POSITION: absolute; TOP: 23px; WIDTH: 352px; Z-INDEX: 100" 
width=352 name = Table1 background="">
    
    <TR>
        <TD width=1% colSpan =2 noWrap><FONT
            size=2>Персональная информация</FONT> 
        <TD id="">
    <TR>
        <TD noWrap align=right><FONT face=""
            size=2>Дата рождения:</FONT>
        <TD id="">
            <INPUT id=txtBirthDate name=TextField1
            style="HEIGHT: 22px; LEFT: 109px; TOP: 54px; WIDTH: 84px">
    <TR>
        <TD align=right noWrap><FONT face="" size=2>
          Дата приема на работу:</FONT></TD>
        <TD noWrap>
            <INPUT id=txtDOH name=TextField1 style="HEIGHT: 22px; 
              LEFT: 94px; TOP: 77px; WIDTH: 84px"
            readOnly 
           ></TD></TR>
    <TR>
        <TD align=right><FONT face="" size=2>Должность:</FONT></TD>
        <TD noWrap>
            <INPUT id=txtTitle name=TextField2
            style="HEIGHT: 22px; LEFT: 76px; TOP: 102px; WIDTH: 193px" 
            readOnly 
           ></TD></TR></TABLE></FONT>  </p>
<P></P></DIV> 
<P></P>
</body>
</html>

В начало статьи