Отправляет email-рассылки с помощью сервиса Sendsay

Web-Мастеринг - с нуля до профи

  Все выпуски  

нет.


Информационный Канал Subscribe.Ru

Познавательное программирование

(comp.soft.prog.urisprog)

Выпуск 21


Здравствуйте, Уважаемые подписчики!

На практике при разработке класса, служащего коллекцией объектов, часто приходится учитывать взаимоотношения использующихся в реализации классов, управление памятью и необходимость определить итератор по содержимому коллекции.
- Бьерн Страуструп.


На заметку

В прошлом выпуске в этом разделе была допущена ошибка - менять индекс массива с его именем можно только в C++ и, судя по всему, только при операциях с одномерными массивами.

Недавно на информатике в институте делал очень интересную задачку на Си. Решил привести её тут. Предполагается, что решающий должен обходиться только числами, без использования строк. Кстати, решил я её ровно за полчаса. Вы можете сами попробовать её решить, а потом скажете, за сколько времени справились вы. Возможно, вы воспользуетесь более изящным алгоритмом, чем я, тогда я смогу опубликовать здесь и ваше решение на всеобщее одобрение. Я помещаю эту задачу здесь, так как считаю её условие на редкость оригинальным, а решение - изящным.

/*22. "5"
Задано натуральное число n. Найти и напечатать все такие числа,
не превосходящие n, которые делятся на каждую из своих цифр.
В программе определить функцию, позволяющую выяснить, делится ли заданное
натуральное число на каждую из своих цифр.
*/

#include "conio.h"
#include "stdio.h"

int scal(int n);
int test(int n);

int scal(int n)
{
int r=n;
if(r>=10) r=r%10;
return r;
}

int test(int n)
{
int i,r,t,res;
r=n;
res=0;
while(r>0)
{
t=scal(r);
if(t!=0&&n%t!=0) res=1;
r/=10;
}
return res;
}

int main(void)
{
int i;
int n=100;
clrscr();
for(i=1;i if (test(i)==0) printf("%d ",i);
return 0;
}



Вопрос - ответ

Открыт раздел "Вопрос - ответ". Ваши вопросы по программированию вы можете прислать по адресу urisff@inbox.ru и остальные подписчики помогут вам найти решение.

Статьи

(Из-за очереди публикуемых статей, присланных уважаемым Сергеем Гусевом, я поместил сразу две статьи, которые закончат серию статей о БД в Delphi.
Уже ждут публикации в следующих выпусках другие интересные статьи.)

Базы Данных с нуля

Фильтрация набора данных

Фильтрация набора данных предназначена для отбора записей удовлетворяющих условию установленного фильтра. Delphi позволяет осуществлять два вида фильтрации: фильтрация по выражению и фильтрация по диапазону.

При использовании фильтра по выражению в набор данных попадают записи, удовлетворяющие выражению фильтра. Фильтрация по выражению применима ко всем полям БД, даже к индексированным. Для задания условия фильтра используется свойство Filter. Но, при задании условия фильтра, набор данных не будет содержать записи, удовлетворяющие условию фильтра. Для того чтобы включить режим фильтрации нужно воспользоваться свойством Filtered логического типа. Это свойство "включает" и "выключает" фильтрацию. По умолчанию это свойство имеет значение False и условия фильтра игнорируются.

Фильтр представляют собой строковое выражение, в состав которого входят имена полей, операции сравнения, возможные арифметические и логические операции, круглые и квадратные скобки. Квадратные скобки, в основном, применяются тогда, когда имя поле БД содержит пробелы.

В качестве операторов сравнения используются отношения: < (меньше), > (больше), = (равно), >= (больше или равно), <= (меньше или равно), <> (не равно). В качестве арифметических операций используются: + (сложение), - (вычитание), * (умножение), / (деление). А в качестве логических операторов: AND, OR, NOT, то есть логические И, ИЛИ, НЕ.

Фильтрацию можно проводит также и на этапе разработки приложения через Инспектор объектов. Если выражение фильтра содержит ошибку, то это приводит к возникновению исключительной ситуации. Для дополнительной обработки процесса фильтрации можно использовать событие onFilterRecord.

В качестве параметров фильтрации можно использовать следующие параметры:

  • foCaseInsensitive - Регистр букв не учитывается.
  • foNoPartialCompare - Проверки на полное соответствие содержимого поля.

По умолчанию все параметры отключены. Для того чтобы отобразить все записи набора данных после фильтрации можно установить свойству Filtered значение False, либо в качестве условия фильтра указать пустое значение. Если известны только первые символы значения некоторого поля, то в этом случае нужно указать символ * (звездочка) после значения условия фильтрации. Рассмотрим пример простой фильтрации:

procedure TForm1.ButtonFilterClick(Sender: TObject);
Var Str: String;
begin
  Table1.Filtered:=True;
  Table1.FilterOptions:=[foCaseInsensitive];
  Str:=#39 + 'Москва' + #39;
  Table1.Filter:='Code >= 2 OR Town = ' + Str;
end;

procedure TForm1.ButtonNotFilterClick(Sender: TObject);
begin
  Table1.Filtered:=False;
end;

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

procedure TForm1.Button3Click(Sender: TObject);
Var Field1, Field2, Field3,
       Field4, Field5, Uslovie: String;
begin
  If Edit1.Text <> '' Then Edit1.Text:=Chr(39) + Edit1.Text + Chr(39);
  If Edit2.Text <> '' Then Edit2.Text:=Chr(39) + Edit2.Text + Chr(39);
  If Edit3.Text <> '' Then Edit3.Text:=Chr(39) + Edit3.Text + Chr(39);
  If Edit4.Text <> '' Then Edit4.Text:=Chr(39) + Edit4.Text + Chr(39);
  If Edit5.Text <> '' Then Edit5.Text:=Chr(39) + Edit5.Text + Chr(39);

  If CheckBox1.Checked Then
    Begin
       Field1:='Code';
       Uslovie:=Field1 + ' = ' + Edit1.Text;
    End;

  If CheckBox2.Checked Then
    Begin
       Field2:='Name';
       Uslovie:=Field2 + ' = ' + Edit2.Text;
    End;

  If CheckBox3.Checked Then
    Begin
       Field3:='Fam';
       Uslovie:=Field3 + ' = ' + Edit3.Text;
    End;

  If CheckBox4.Checked Then
    Begin
       Field4:='BirthDay';
       Uslovie:=Field4 + ' = ' + Edit4.Text;
    End;

  If CheckBox5.Checked Then
    Begin
       Field5:='Town';
       Uslovie:=Field5 + ' = ' + Edit5.Text;
    End;

  Table1.Filtered:=True;
  Table1.FilterOptions:=[foCaseInsensitive];
  Table1.Filter:=Uslovie;
end;

При использовании фильтрации по диапазону в набор данных попадают те записи, значения которых входят в диапазон заданного значения фильтра. Данный вид фильтрации работает быстрее, потому что производиться только для индексированных полей. При попытке произвести фильтрацию для не индексированного поля возникает исключительная ситуация. Для включения режима фильтрации используется поля метод ApplyRange, а для выключения - метод CancelRange.

Метод SetRangeStart устанавливает нижнюю границу диапазона, а метод SetRangeEnd - верхнюю границу диапазона. При использовании данных методов не нужно указывать никаких параметров, а для задания диапазона используется обычное присваивание. Не менее интересным свойством является свойство KeyExclusive логического типа. Если этому свойству установить значение False, то в набор данных попадут записи, у которых значения совпадают со значениями указанного диапазона, а если установить значение True, то в набор данных такие записи не попадут. Но не нужно забывать, что это свойство действительно отдельно для каждой границы значения указанного диапазона. Если не будет задана нижняя часть диапазона, то она будет равна максимально возможному значению, а если не задана верхняя граница, то она будет равно минимально возможному значению.

procedure TForm1.ButtonFilterClick(Sender: TObject);
begin
  Table1.IndexFieldNames:='Code';
  Table1.SetRangeStart;
  Table1.KeyExclusive:=False;
  Table1.FieldByName('Code').AsInteger:=2;
  Table1.SetRangeEnd;
  Table1.FieldByName('Code').AsInteger:=3;
  Table1.ApplyRange;
end;

procedure TForm1.ButtonNotFilterClick(Sender: TObject);
begin
  Table1.CancelRange;
end;

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

procedure TForm1.ButtonFilter1Click(Sender: TObject);
begin
  Table1.Filtered:=True;
  Table1.Filter:='Code >= 1 AND Code <= 3';
end;

procedure TForm1.ButtonFilter2Click(Sender: TObject);
begin
  Table1.Filtered:=True;
  Table1.Filter:='Code >= ' + edtMin.Text + 'AND Code <= ' + edtMax.Text;
end;

Для набора данных Query фильтрация может быть произведена двумя способами: при помощи специального SQL-запроса, либо одноименными методами, как у набора данных Table. Рассмотрим два аналогичных по результату вида фильтрации:

procedure TForm1.ButtonSQLFilter1Click(Sender: TObject);
begin
  Query1.Filtered:=True;
  Query1.Filter:='Code = 3';
end;

procedure TForm1.ButtonSQLFilter2Click(Sender: TObject);
begin
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM Base\Base.db WHERE Code=3');
  Query1.Open;
end;

Как видно из примера здесь нет ничего сложного. Нужно обратить внимание на одну из команд SQL-запроса WHERE. Данная команда как раз и отвечает за отбор записей из набора данных, а точнее она задает критерий отбора записей из набора данных. При задании выражения фильтрации оно также должно состоять из имен полей БД, арифметических и логических операций, различных скобок, а также специальных функций.

В SQL-запросе также можно применять сложные критерии отбора записей Базы Данных. При помощи оператора LIKE можно задать шаблон поиска записей для отбора из набора данных. Если известны только первые символы значения некоторого поля, то в этом случае нужно указать символ % (процент) в значении условия фильтрации, означающий неограниченное число символов. Для указания одного неизвестного символа нужно указать символ _ (подчеркивание). Рассмотрим пример, в котором отбираются все записи, в значении поля которых содержится некоторый символ:

procedure TForm1.ButtonSQLFilter1Click(Sender: TObject);
begin
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM Base\Base.db WHERE Town LIKE "%М%"');
  Query1.Open;
end;

Для отбора записей с нулевыми значениями в каком-либо поле Базы Данных используется оператор IS NULL. При помощи данного оператора также можно выполнять проверку на присутствие полей, в которых вообще отсутствует какое-либо значение. Рассмотрим пример:

// Выводим записи БД, в которых могут отсутствовать значения
procedure TForm1.ButtonFilterClick(Sender: TObject);
begin
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM Base\Base.db WHERE Town IS NULL');
  Query1.Open;

  If Query1.RecordCount > 0
     Then ShowMessage('В указанные поля не внесены значения ?');
end;

// Выводим записи, в которых нет пустых значений
procedure TForm1.ButtonFilterClick(Sender: TObject);
begin
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM Base\Base.db WHERE Town IS NOT NULL');
  Query1.Open;
end;

Для отбора записей входящих в диапазон заданных значений существует оператор BETWEEN. При помощи данного оператора также можно осуществить фильтрацию набора данных по диапазону.

procedure TForm1.Button3Click(Sender: TObject);
begin
  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT * FROM Base\Base.db');
  Query1.SQL.Add('WHERE BirthDay BETWEEN "01.04.03" AND "02.10.04"');
  Query1.Open;
end;


Любые комментарии, жалобы, пожелания и сообщения об ошибках настоятельная просьба присылать на e-mail.

Гусев Сергей.
e-mail: satanzone@yandex.ru
site: http://icops.narod.ru


Базы Данных с нуля

Работа с QuickReport

При работе с Базой Данных почти всегда требуется организация вывода некоторых данных на печать. Как раз для этого и были придуманы отчеты. Отчетом является некоторый печатный документ, который содержит текущее содержание Базы Данных. Хотя в отчете можно отобразить и не только информацию из Базы Данных, но и совершенно другие данные.

В Delphi для создания отчетов используется генератор отчетов QuickReport. Компоненты, предназначенные для создания отчетов находятся на странице QReport Палитры Компонентов. Многие компоненты на этой странице являются визуальными и почти не отличаются от аналогичных компонентов на других страницах Палитры Компонентов.

Главным элементом отчета является компонент QuickRep, который представляет собой фундамент будущего отчета, на котором располагаются остальные элементы отчета. Обычно компонент QuickRep располагают на отдельной форме. Этот компонент при помещении на форму представляет собой страницу формата А4 в натуральную величину. Первоначально он имеет имя QuickRep1 и при желании ему можно задать любое имя.

Для того чтобы в отчете отображалось текущее содержание Базы Данных, компонент отчета нужно связать с набором данных TTable или TQuery. Именно для этого служит свойство DataSet.

QuickRep1.DataSet:=Table1;
QuickRep2.DataSet:=Query1;

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

Для создания полос используется свойство Band типа TQuickRepBands. Наличием той или иной полосы можно управлять путем установки логического значения соответствующего подсвойства. Вот список всех полос:

   HasPageHeader - Верхний колонтитул;
   HasTitle - Заголовок отчета;
   HasColumnHeader - Заголовок столбца отчета;
   HasDetail - Область отображения самих данных;
   HasSummary - Итогоги отчета;
   HasPageFooter - Нижний колонтитул.

Полосы так же можно добавлять в отчет и при помощи компонента полосы QRBand. При этом тип полосы устанавливается при помощи свойства BandType.

Параметры страницы отчета определяются свойством Page типа TQRPage. С помощью этого свойства можно установить размер и ориентацию страницы, высоту и ширину страницы, отступы от границ страницы. Эти же свойства можно изменить и при помощи диалогового окна Report Setting. Данное окна можно вызвать двойным щелчком мыши по странице отчета, или командой контекстного меню.

Для печати отчета предназначен метод Print. При вызове данного метода происходит печать отчета без каких-либо запросов и диалоговых окон. Так же существует возможность предварительного просмотра отчета при помощи метода Preview. В результате вызова этого метода на экране появляется специальное окно, в котором отображается отчет со всем его содержимым. При этом, если отчет связан с набором данных, то отчет всегда будет отображать текущее состояние набора данных.

// Печать отчета.
QuickRep1.Print;
// Предварительный просмотр отчета.
QuickRep2.Preview;

Ну, а теперь перейдем к созданию отчета. Для этого нужно создать новый проект. Я предлагаю создать в проекте всего две формы. На первой форме будет располагаться сетка для отображения содержимого Базы Данных и кнопка для печати отчета. На второй форме будет находиться сам отчет. На главную форму проекта нужно положит компоненты: набор данных - Table, источник данных - DataSource, сетку - DBGrid и кнопку Button1.

procedure TForm1.FormCreate(Sender: TObject);
begin
   // Закрываем набор данных
   Table1.Close;
   // Задаем псевдоним (алиас) Базы Данных
   Table1.DatabaseName:='DBDEMOS';
   // Задаем имя Базы Данных
   Table1.TableName:='Animals.dbf';
   // Связываем источник данных с набором данных
   DataSource1.DataSet:=Table1;
   // Задаем сетке источник данных
   DBGrid1.DataSource:=DataSource1;
   // Открываем набор данных
   Table1.Open;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
   // Предварительный просмотр отчета
   Form2.QuickRep1.Preview;
end;

Теперь перейдем к созданию формы с отчетом. На форму положим компонент QuickRep. С помощью свойства Band укажем наличие таких полос как: PageHeader - верхний колонтитул, Title - заголовок отчета, ColumnHeader - заголовки столбцов отчета, Detail - область отображения данных, PageFooter - нижний колонтитул. На полосы PageHeader, PageFooter, Title и ColumnHeader положим компоненты QRLabel и зададим соответствующие заголовки, то есть названия полей Базы Данных для наглядности. А на полосу Detail положим четыре компонента QRDBText.

procedure TForm2.FormCreate(Sender: TObject);
begin
   // Связываем компоненты TQRDBText с набором данных
   QRDBText1.DataSet:=Form1.Table1;
   QRDBText2.DataSet:=Form1.Table1;
   QRDBText3.DataSet:=Form1.Table1;
   QRDBText4.DataSet:=Form1.Table1;

   // Задаем компонентам TQRDBText соответствующие поля Базы Данных
   QRDBText1.DataField:='Name';
   QRDBText2.DataField:='Size';
   QRDBText3.DataField:='Weight';
   QRDBText4.DataField:='Area';
end;

И на данном этапе создания отчета проект можно компилировать. Самой первой на экран должна появиться форма с сеткой, в которой отображается содержимое Базы Данных. При нажатии на кнопку "Создать отчет" на экране появиться окно предварительного просмотра только что созданного отчета. В данном окне можно распечатать отчет сохранить или загрузить другой отчет.

Как видно, верхний и нижний колонтитул будут распечатаны один раз в верхней и нижней части отчета, но на каждом листе отчета. Заголовок отчета будет распечатан только один раз. Заголовки столбцов с полосы ColumnHeader будут печататься на каждом листе. А данные базы на полосе Detail будут всегда располагаться под заголовками столбцов на каждом листе. Если выполнить фильтрацию, сортировку или другие операции с Базой Данных, то все эти или иные изменения всегда будут отображены в отчете.


Любые комментарии, жалобы, пожелания и сообщения об ошибках настоятельная просьба присылать на e-mail.

Гусев Сергей.
e-mail: satanzone@yandex.ru
site: http://icops.narod.ru



Все вопросы, пожелания и предложения ссылкообмена ведущему рассылки, прошу слать на e-mail: urisff@inbox.ru
Все статьи публикуются здесь только с разрешения (или рекомендации) автора.
Если вы хотите опубликовать здесь свою статью, то сделайте это, переслав её мне. В случае, если вы будете использовать приведённые в этой рассылке материалы, не забудьте сделать ссылку на эту рассылку.

Ведущий рассылки:
Набатников Иван
urisff@inbox.ru
http://WWW.URiS.TK



http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу


В избранное