Журнал LinuxFormat - перейти на главную

LXF74-75:Gambas

Материал из Linuxformat
Перейти к: навигация, поиск
Gambas

Содержание

Cекреты и хитрости

В последней статье этой серии король графического интерфейса д-р Марк Александр Бейн (Dr Mark Alexander Bain) раскрывает свои секреты в работе с этим похожим на Visual Basic языком программирования.

Последние пару месяцев мы с вами рассматривали отдельные аспекты программирования на Gambas. В этот раз я бы хотел рассмотреть все те очень полезные секреты и маленькие хитрости, которые нельзя отнести к какой-то определенной категории. Мы с вами напишем программу для редактирования конфигурационных файлов и по ходу дела рассмотрим все тонкие моменты в действии.

Всегда оставляйте путь для отступления

Я говорил это раньше и повторю ещё раз: перед тем, как добавлять что-нибудь в вашу Gambas-форму, реализуйте возможность корректно закрыть её. Это может быть кнопка или пункт меню, по нажатию на которые выполняется код

ME.Close.

Объединяйте ваши процедуры в модули

При создании новой функции или подпрограммы подумайте, не вынести ли вам её в отдельный модуль. Ведь в этом случае вы с лёгкостью сможете воспользоваться ею при создании другого приложения. Давайте своим модулям понятные названия. Имена Module1 и Module2 могут показаться вполне нормальными в первый момент, но вскоре они станут абсолютно темными. Одновременно старайтесь помещать похожие функции и подпрограммы в один и тот же модуль.

Например, вы можете поместить всё, что относится к работе с базами данных, в модуль Data.

Не забывайте о зависимостях при повторном использовании кода

Если вы используете ранее написанный код для нового приложения, не забудьте подключить компоненты, от которых зависит этот код. Например, если вы используете модуль для подключения к базе данных, вам потребуется компонент gb.db, и так далее.

Создавайте необязательные параметры функций и используйте для них значения по умолчанию

В процессе работы над проектом вы часто будете создавать функции, которым не требуются никакие параметры. Вот, например, простая подпрограмма для подключения к базе данных (не набирайте её, она приведена тут только для пояснения идеи!):

PUBLIC conn AS NEW Connection
PUBLIC SUB make_connection()
WITH conn
.Host = "localhost"
END WITH
conn.Open
END

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

PUBLIC SUB make_connection(hostName AS String)
WITH conn
.Host = hostName
END WITH
conn.Open
END

Теперь сервер не прошит в коде процедуры, но зато вам придётся всегда указывать его при вызове этой подпрограммы. Фактически, ваше приложение обрушится, если вы вдруг вызовете процедуру подключения к базе данных, не указав ей обязательный параметр, например вот так:

make_connection("localhost")

Но вы можете соединить лучшие свойства обоих вариантов, использовав необязательный параметр со значением по умолчанию.

PUBLIC SUB make_connection(OPTIONAL hostName AS String = "localhost")
WITH conn
.Host = hostName
END WITH
conn.Open
END

Теперь подпрограмма будет работать правильно вне зависимости от того, указали вы ей, к какому серверу присоединяться, или нет (в этом случае будет выполнено подключение к localhost).

Ловите ошибки, и не давайте им уронить вашу программу

Если вы попробуете добавить последнюю функцию, которую я только что рассматривал, в своё приложение и запустите её, то оно обязательно обрушится. Это произойдёт потому, что я не передал достаточно сведений объекту conn — кроме имени сервера, ему требуются ещё и тип базы данных, её название, а также имя пользователя и пароль.

Не особенно приятно видеть, как ваша программа рушится из-за таких простых вещей. Гораздо лучше обработать ошибку, информировать о ней пользователя и корректно завершить работу, а лучше — дать возможность пользователю сделать то, что он всё еще может сделать. Для этого вам потребуется оператор TRY. Вот пример готовой процедуры подключения к базе данных, с обработкой ошибок и необязательными параметрами со значениями по умолчанию:

PUBLIC SUB make_connection(OPTIONAL dbname AS String = "customers",
OPTIONAL dbtype AS String = "mysql", OPTIONAL dbhost AS String
= "localhost", OPTIONAL dbusername AS String = "bainm" OPTIONAL
dbpassword AS String = "mypassword")
WITH conn
.Type = dbtype
.Host = dbhost
.Login = dbusername
.Password = dbpassword
.Name = dbname
END WITH
TRY conn.Open
IF ERROR THEN
message ("Cannot Open Database. Error = " & Error.Text)
END IF
END

Теперь, даже если подсоединение к базе данных окажется по какой-то причине невозможным, приложение просто выдаст сообщение об ошибке и продолжит работу. Не используя при этом базу данных, разумеется.

Используйте свойства

Если вам необходимо просто задавать и считывать значения, то вас полностью устроят обычные переменные. Но свойства (property) имеют особенности, которые порой делают их очень полезными. К ним относятся функция _Read и подпрограмма _Write. Итак, попробуйте угадать, в какой момент они выполняются? Вот определение свойства Host:

PUBLIC PROPERTY Host AS String
PRIVATE localHost AS String
PRIVATE FUNCTION Host_Read() AS String
IF (localHost = "") THEN
localhost = "localhost"
END IF
RETURN localHost
END
PRIVATE SUB Host_Write(ipHost AS String)
localHost = ipHost
END

Обратите внимание, единственным публичным элементом является Host, всё остальное закрыто от пользователя этого модуля. Посмотрите, как в функции Host_Read определяется значение для этого свойства по умолчанию.

Изучите параметры командной строки

В наших примерах все значения параметров (таких как название базы данных или идентификатор пользователя) были зашиты внутри программы. Но вы не обязаны делать так же, если вам это не нравится. Изменяющиеся значения можно запросто передавать в параметрах командной строки. Конечно, вам придётся написать немножко кода, что-бы обработать их правильно. Всё, что вы набрали в командной строке приложения Gambas, называется аргументом и хранится в массиве Application.Args. Вот простой пример работы с ним (эту функцию можно поместить в модуль Startup).

PUBLIC SUB Main()
input_variables_1
END
PRIVATE SUB input_variables_1()
DIM i AS Integer
FOR i = 1 TO application.Args.count
IF (Application.Args[i]) THEN
message (Application.Args[i])
END IF
NEXT
END

Если затем вы создадите исполняемое приложение и запустите его из консоли, передав несколько параметров командной строки, оно отобразит серию сообщений, по одному на каждый параметр. Это не самое полезное приложение на свете, но оно даёт представление о том, с какой стороны подходить к обработке параметров.

Следующий пример немного более осмысленный. Эта программа ожидает, что вы передадите ей два параметра (в нужном порядке), и сохраняет их значения в глобальных переменных:

PUBLIC TargetUrl AS String
PUBLIC Database AS String
PUBLIC SUB Main()
input_variables_2
message (TargetUrl & " " & Database)
END
PRIVATE SUB input_variables_2()
TargetUrl = Application.Args[1]
Database = Application.Args[2]
END

Как я уже говорил, в данном случае порядок имеет значение. А вот если вы используете флаги, то это уже не столь важно:

PUBLIC TargetUrl AS String
PUBLIC Database AS String
PUBLIC SUB Main()
input_variables_3
message (TargetUrl & " " & Database)
END
PRIVATE SUB input_variables_3()
DIM i AS Integer
DIM j AS Integer
FOR i = 1 TO Application.Args.Count
SELECT CASE Application.Args[i]
CASE "-u"
TargetUrl=Application.Args[i+1]
CASE "-d"
Database=Application.Args[i+1]
END SELECT
NEXT
END

Теперь вы можете вызвать своё приложение как myapp -u /localhost -d mysql или как myapp -d mysql -u /localhost, результат при этом не изменится.

Запуск Gambas без графического интерфейса пользователя

Я думаю, вы уже обратили на это внимание, когда читали предыдущую хитрость — вы не обязаны использовать Gambas только для приложений с графическим интерфейсом. Вы можете также создавать консольные приложения или приложения командной строки. Фактически, при создании нового приложения Gambas вы должны указать, потребуется ли вам графический интерфейс (по умолчанию считается, что потребуется).

Если вы выберете создание консольного приложения, то обнаружите, что в свойствах проекта папки Forms нет вообще — и это правильно, ведь вам не нужен GUI. Но кроме всего прочего, это значит, что вам негде отображать информацию, кроме как в стандартном потоке вывода, на консоли.

КЛИШЕ ПОНЕВОЛЕ

Прошу прощения за включение в этот учебник набившего оскомину примера «Hello World», но таковы условия моего контракта: я должен представить его хоть раз в каждом цикле статей. Это очередная директива Европарламента.

Вот обязательная программа «Hello, World» на Gambas:

PUBLIC SUB Main()
sayHello
END
PRIVATE SUB sayHello()
PRINT "Hello World"
END

Консольные приложения могут использовать все компоненты Gambas, кроме графических, конечно.

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

Мы с вами уже видели, как использовать в Gambas параметры командной строки. Это прекрасно работает и с графическим интерфейсом, и с консольным приложением. В графической форме обычно есть ещё и поля ввода для передачи приложению дополнительной информации. В консоли вы можете использовать в тех же целях оператор INPUT:

PUBLIC SUB Main()
DIM m AS Float
m=doMultiply()
PRINT m
END
PRIVATE FUNCTION doMultiply() AS Float
DIM x AS Float
DIM y AS Float
PRINT "Enter x:"
INPUT x
PRINT "Enter y:"
INPUT y
RETURN x*y
END

Превращение консольного приложения в графическое и наоборот

Когда Gambas задаёт вам вопрос, проект графического или консольного приложения ему создавать, вы вправе поинтересоваться — в чём разница? Ответ прост — разница в одном единственном компоненте Gambas — gb.qt. Если вы подключите его к проекту консольного приложения, то вам будет доступен графический интерфейс. И наоборот, если в графическом проекте вы отключите gb.qt, то получите проект консольной программы. Проще простого.

Извлечение информации из файлов

В предыдущей статье мы рассматривали, как получить информацию из базы данных. Посмотрим сегодня, как прочитать её из обычного файла. Всё, что вам надо сделать — это открыть файл в одном из четырёх режимов: read (чтение), write (запись), create (создание) или append (дописывание в конец). Думаю, довольно просто догадаться, что делает каждый из этих методов, хотя разницу между записью и созданием стоит уточнить. Режим записи write очистит и запишет заново уже существующий файл. Режим создания create может создать файл, если таковой отсутствует, но если он уже есть — действует в точности как write. Вот простой пример:

DIM lLine AS String
DIM pFile AS File
OPEN "/etc/passwd" FOR READ AS #pFile
WHILE NOT Eof(pFile)
LINE INPUT #pFile, lLine
PRINT lLine
WEND
CLOSE #pFile

Этот код читает файл /etc/passwd и отображает на экране его содержимое.

Используйте динамические массивы Gambas на всю катушку

Этот заголовок может немного ввести вас в заблуждение, ведь на самом деле в Gambas любые массивы — динамические. Давайте рассмотрим, как их можно использовать. Определение массива выглядит так:

DIM mArray AS NEW String[]

Здесь создаётся массив строк, не содержащий ни одного элемента. Пока он остаётся пустым, вы не можете присваивать ему никаких значений. Например, вот так:

mArray[0]="some data"

вы получите ошибку «Выход за границы массива» (out of bounds). Вместо этого нужно использовать метод Add:

mArray.Add("some data")

Это вызов добавить ещё один элемент в конец массива. Но вы так же можете добавлять элементы с начала:

mArray.Add("put this on the first line",0)

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

mArray.Add("in the middle",4)

Индексы массивов начинаются с нуля, поэтому элемент с индексом 4 станет пятым по счёту, а всего в массиве теперь будет 11 строк. Уверен, что вы сразу же попробуете написать

mArray.Add("to see what happens",1004)

Gambas просто добавит новую строчку после последнего элемента.

Быстрое измерение массива

Если уж мы говорим о числе элементов, то давайте зададимся вопросом — а насколько велик вот этот массив? Ответ прост. Массивы Gambas имеют два свойства — mArray.count и mArray.length. Оба этих свойства обозначают одно и то же и возвращают общее число элементов в массиве.

Вы можете использовать любое из них для того, чтобы перебрать все элементы:

DIM mArray AS NEW String[]
DIM i AS Integer
FOR i = 1 TO 10
mArray.Add(i)
NEXT
FOR i = 1 TO mArray.Count
message(mArray[i-1])
NEXT

Этот код просто создаёт массив из десяти элементов, а затем показывает каждый элемент в отдельном сообщении. Вас может удивить, что в качестве индекса я использовал i-1, а не i. Но, как я упоминал раньше, индексы массива начинаются с нуля, так что в массиве с десятью элементами они нумеруются от 0 до 9, а не от 1 до 10. Если вам не нравится i-1, то можно использовать другой способ:

FOR i = 0 TO mArray.Count - 1
message(mArray[i])
NEXT

На этот раз мы начинаем с нуля и останавливаемся на индексе номер mArray.Count — 1, то есть на индексе номер девять (поскольку mArray.Count равно десяти).

Добавление нескольких элементов

Да, я знаю, что вы хотите сказать: вам вовсе не хочется добавлять элементы по-одному. Вы просто хотите сразу создать нужное число элементов, и затем заполнять их в том порядке, в каком сочтёте нужным. Нет проблем!

DIM mArray AS NEW String[]
mArray.Resize(10)
mArray[5] = "some info"

В этом примере я создал массив, определил его размер равным 10 элементам (при помощи метода Resize) и задал значение шестого по счету элемента (обратите внимание, как я мужественно справился с соблазном использовать Пятый элемент!).

Интересно, что вы так же можете уменьшить размеры массива. Для этого надо воспользоваться методами Resize или Remove. Как работает Resize вы можете догадаться, а Remove — это просто обратный метод для Add, то есть он удаляет последний элемент или элемент с индексом, который ему передали.

Массив подсказок

ИСПОЛЬЗОВАНИЕ РАЗДЕЛИТЕЛЕЙ

Если вы сохраняете свои данные в файле, вам потребуется какой-нибудь символ для отделения различных секций друг от друга. Запятая – довольно частый выбор, но вам следует избегать ее: если кто-нибудь случайно введет в текстовое поле строку с запятой, в вашей «базе данных» появится лишнее поле. Используйте что-нибудь более редкое, например, вертикальную черту (|).

Существует несколько приятных методов, которые вы можете найти очень полезными при использовании массивов Gambas. Первый из них — это Sort. Посмотрите на это:

DIM mArray AS NEW Integer[]
DIM i AS Integer
FOR i = 1 TO 10
mArray.Add(i)
NEXT
mArray.Sort(gb.Descent)
PRINT (mArray[0])
mArray.Sort(gb.Ascent)
PRINT (mArray[0])

Этот код заполняет массив из десяти элементов цифрами от 1 до 10. Затем он сортирует его по убыванию и по возрастанию, отображая на месте первого элемента 10 и 1 соответственно. Любопытно будет посмотреть, что изменится, если заменить определение массива на String[]. На этот раз программа выведет 9 и 1. Почему? Потому что Gambas правильно определяет тип переменных в массиве, и сортирует числа в арифметическом порядке, а строки — в лексикографическом. Второй интересный метод массивов Gambas — это Reverse (обратить). Догадались, что он делает? И последний — это Find (найти). Вам требуются объяснения? Думаю, нет. Давайте вместо этого просто разберём пример:

DIM nArray AS NEW String[]
DIM dArray AS NEW String[]
DIM lArray AS NEW String[]
DIM lLine AS String
DIM pFile AS File
OPEN "/etc/passwd" FOR READ AS #pFile
WHILE NOT Eof(pFile)
LINE INPUT #pFile, lLine
lArray = Split (lLine,":")
nArray.Add(lArray[0])
dArray.Add(lArray[5])
WEND
CLOSE #pFile
PRINT dArray[nArray.Find(System.User)]

Этот пример использует код для чтения данных из файла, который мы рассматривали раньше. На этот раз имена пользователей и их домашние каталоги из /etc/passwd загружаются в массивы. В конце по имени пользователя ищется соответствующий ему идентификатор, а по нему в свою очередь отображается домашний каталог.

Здесь есть только одна строчка кода, которую мне кажется нужным объяснить: lArray = Split (lLine, «:»). Он разбивает строку lLine на отдельные элементы, используя указанный разделитель (в данном случае — двоеточие. Обратите внимание на врезку «Советы» выше), а затем загружает части строки в массив lArray.

Сохранение пользовательских настроек

Теперь мы знаем, как получить доступ к параметрам командной строки из приложения Gambas. Это позволит пользователю задавать режим работы, если только он согласиться вводить целиком все опции каждый раз, когда запускает нашу программу. Нельзя ли это автоматизировать? Конечно, ключом к решению является конфигурационный файл, который считывается при старте приложения. Затем значения, перечисленные в конфигурационном файле, заменяют установки по умолчанию, принятые в программе.

А НАПОСЛЕДОК Я СКАЖУ…

Полный исходный код разрабатываемого в этом учебнике приложения вы можете найти на компакт-диске. Он сочетает в себе все приемы и трюки, которые мы обсуждали, и показывает, насколько легкими становятся сложные задачи, если под рукой есть Gambas.

Мой последний совет — документируйте все, что вы делаете. Это относится не только к Gambas. Не пренебрегайте комментариями. То, что кажется вам очень логичным в момент кодирования, может перестать быть таковым, когда вы вернетесь к своей работе через пару недель. Впрочем, так происходит всегда и везде. Сейчас у вас хотя бы есть Gambas, который немного упростит вашу жизнь.

Персональные инструменты
купить
подписаться
Яндекс.Метрика