355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Юрий Карпов » Пишем программу для создания книг FB2 (СИ) » Текст книги (страница 1)
Пишем программу для создания книг FB2 (СИ)
  • Текст добавлен: 17 октября 2016, 02:08

Текст книги "Пишем программу для создания книг FB2 (СИ)"


Автор книги: Юрий Карпов



сообщить о нарушении

Текущая страница: 1 (всего у книги 3 страниц)

Annotation

Подробный комментарий к исходному коду программы создающей книжку в формате FB2.

Пишем программу (в Delphi) для создания книг FB2

Введение

Начинаем

Читаем текстовый файл

Устанавливаем стиль заголовка

Редактирование строки

Создание FB2

Структура

Приложение

Unit1.dfm

Код файла Unit1.pas соответствующего Form1

genres.dfm

genres.pas

EditStr.dfm

EditStr.pas

authors.dfm

authors.pas

dm.pas

my_FB2.dpr

UmFB2.pas

notes

1

Пишем программу (в Delphi) для создания книг FB2

Введение

В начале было слово, и слово было 2 байта… Автор мне неизвестен.

Все началось с покупки электронной книжки LBook eReader V3.

Затем я убедился, что книги, лучше всего читаются в формате FB2.

Потом мне захотелось оцифровать книги моего любимого писателя Кальмана Миксата, и тут я увидел, что все не так просто…

Да я в этой «тусовке» недавно и возможно чёто не понимаю, но все свои проблемы я привык решать программным путем.

Состряпал программку, конечно еще сырую, а потом вспомнил опыт Линуса Торвальдса и подумал:

– А, кину я исходник в рунет, и может добрые люди выкормят, вырастят моего ребенка и выведут в люди.

Вы можете спросить, а чего же ты сам это не сделаешь? Во-первых, меня ждут другие "великие дела", во-вторых, я уверен, что коллективным разумом, можно сделать больше и быстрее…

Писал я в своем любимом Delphi (Delphi 6) – но думаю это не принципиально, перевести можно в любой язык.

Это не учебник Delphi и основы, я рассказывать не собираюсь, но постараюсь расписать как можно подробней.

В программе используются только стандартные компоненты Дельфи.

Начинаем

План работы:

* Берем текстовый файл

* Присваиваем строчкам стили

* Делаем файл FB2.

Общие принципы программы.

Содержание книги будет хранится в ListBox1.

Каждая строчка в ListBox1 будет содержать абзац текста и будет начинаться с идентификатора стиля абзаца, например:

// начало примера.

H1 | Кальман Миксат. ЧЕРНЫЙ ГОРОД

H2 | ЧАСТЬ ПЕРВАЯ

H3 | ГЛАВА ПЕРВАЯ.

S| В которой содержатся сведения и подробности, весьма важные для читателя

N| Пал Гёргей был самым примечательным вице-губернатором Спеша во времена Тёкёли

// конец примера.

Символ | отделяет информацию о стиле от строки текста. Теперь надо объяснить, что означают эти буковки.

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

S: Subtitle – подзаголовок.

N: Normal – обычный абзац.

Еще могут использоваться стили:

E: Epigraph – эпиграф

T: Text-author – автор цитаты / эпиграфа

P: Poem – стихи

–: None строка будет игнорироваться при записи FB2 файла.

Если потребуется Вы добавите еще…

Читаем текстовый файл

При чтении текстового файла, к каждой строчке прибавляется начало ' N| ' т. к. форматирование еще не сделано и все строки одинаково обычны.

// начало кода

procedure LoadTXT(FName: string);

var

L: TStringList;

i, j: integer;

s, ss: string;

begin

L:= TStringList.Create; // создаем временный список

L.LoadFromFile(fname); // читаем из файла // можно сделать грамотнее с помощью try

for i:= 0 to L.Count – 1 do// просматриваем текст

begin

s:= ''; ss:= L[i];

for j:= 1 to length(Ss) do

begin // просматриваем строку

case ss[j] of

'<': S:= S + '<'; // знак < вызывает сбой в читалке. т. к. она думает что дальше следует тэг

'>': S:= S + '>'; // заменяем, на всякий случай

'^': S:= S + '^'; // этот символ будет использован в служебных целях

'~': S:= S + '~'; // – // -

'&': S:= S + '&';

else S:= S + ss[j]; // иначе, претензий нет, символ добавляем к строке

end; // case

end; // обработка строки завершена

L[i]:= ' N| ' + S; // в начало каждой строки вводим указатель стиля Normal

end; // обработка текста завершена

Form1.ListBox1.Items.Assign(L); // сбрасываем список в ListBox

L.Free; // удаляем временный список

end;

// конец кода

Если файл считан, теперь мы можем его форматировать.

Просматриваем текст книги, выделяем нужную строку, выбираем необходимый стиль и нажимаем кнопку

[>]

При этом вызывается процедура ChangeStyle(TmyStyle(RG.itemindex));

Как параметр она получает стиль из радио – списка RG.

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

Процедура считывает выделенную строку из списка ListBox1, удаляет сведения о типе и записывает строку на старое место с новым стилем.

// начало кода

procedure ChangeStyle(LStyle: TmyStyle);

var

n, curIndex: integer;

S: string;

begin

with Form1.ListBox1 do

begin

curIndex:= ItemIndex; // читаем текущий индекс в списке ListBox

if curIndex = -1 then exit; // если ничего не выделено выходим

S:= Items[curIndex]; // считываем текущую строку

n:= pos('|', s); // находим разделитель

/ / хотя это лишнее, n всегда = 4 / когда писал это еще не было ясно, утрясался формат…

// в окончательном варианте n можно удалить

delete(S, 1, n+1); // удаляем информацию о стиле

// Записывается строка с новым стилем. Приводить SetStyle не буду, она очень простенькая

Items[curIndex]:= SetStyle1(LStyle)+ S;

if ItemIndex < Items.Count – 1

then ItemIndex:= ItemIndex+1;

SetFocus; // активным снова становится список с содержимым книги.

end;

end;

// конец кода

(Одно предложение: можно, и не трудно, предоставить пользователю возможность возврата старого стиля)

Теперь о расстановке заголовков

Для этой работы предназначены три кнопки: [+] [H1] [-]. Вообще-то средняя кнопка будем менять свое название, и показывать этим текущий (в данном месте текста) стиль заголовка.

Посмотрим, как это делается:

При любом клике на ListBox вызывается процедура ShowHeadStyle ее параметром является индекс выделенной строки.

// начало кода

procedure ShowHeadStyle(n: integer);

var

LStyle: TmyStyle;

begin

LStyle:= ScanUpStyle(n); // получаем тип заголовка к которому относится эта строка

Form1.Button2.Caption:= SetStyle(LStyle); // меняем название кнопки

Form1.Button2.Tag:= integer(LStyle); // запоминаем этот стиль, чтобы потом меньше возиться.

end;

// конец кода

Теперь посмотрим, как мы получаем информацию о стиле.

Элементарно, Ватсон!

// начало кода

function ScanUpStyle(n: integer):TmyStyle;

var

i: integer;

LStyle: TmyStyle;

begin

with Form1.ListBox1 do

for i:= n downto 0 do

begin // просматриваем список от заданной строки вверх

GetStyle(Items[i], LStyle); // получаем стиль строки

if LStyle in [H1..H5] then

begin // если стиль строки заголовочный

result:= LStyle; // записываем его в результат

exit; // и выходим, нечего больше время терять!

end;

end; // если дошли до начала списка, а заголовков не найдено…

result:= H1; // присваиваем тип заголовка H1

end;

// конец кода

Устанавливаем стиль заголовка

Выбираем строку в тексте

И если указанный на кнопке стиль подходит, нажимаем ее.

При этом вызывается процедура ChangeStyle(TmyStyle(Button2.Tag));

Параметром ее будет ранее сохраненные сведения о текущем стиле заголовка.

Процедура ChangeStyle описана ранее.

Теперь кнопки [+] и [-]

Код процедур аналогичен, разница только в одной строчке

// начало кода

procedure TForm1.Button5Click(Sender: TObject);

var // кнопка плюс

LStyle: TmyStyle;

begin

LStyle:= TmyStyle(Button2.Tag); // получаем текущий стиль

if LStyle < H5 then ChangeStyle(Succ(LStyle)); // если он не слишком велик, прибавляем единицу

// а для кнопки минус, вот эта строчка. Вычитается единичка, если есть откуда вычитать

// if LStyle > H1 then ChangeStyle(Pred(LStyle));

end;

// конец кода

Редактирование строки

Двойной щелчок на строке и открывается окно редактирования

Текст можно исправить или строку разбить на несколько. После нажатия ОК все содержимое записывается в книгу с сохранением старого стиля.

Нажатием кнопок Bold и Italic можно получить соответствующее оформление выделенного текста

(т. е. если текст не выделен ничего не произойдет).

Тут два замечания: отмена такого форматирования возможна только вручную удалением соответствующих тегов, второе, не допустимо форматирование такого вида:

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

Концевые сноски.

Книга может содержать концевые сноски. Я поленился и сделал пока так: необходимые сноски записываются в файл EndNotes.txt и этот файл должен находится в папке программы.

Внимание! Каждая сноска – одна строка в файле.

В тексте книги в местах сносок надо расставить значки тильды – ~

Ударения.

В первой же книге, которую я делал, в одном слове мне потребовалось сделать ударение и поэтому пришлось ввести значок «крышки» ^

Создание FB2

Наконец добрались.

Казалось бы, что проще, бери строку за строкой и вперед…

// начало кода

with Form1.ListBox1 do

for i:= 0 to Count – 1 do // просматриваем текст абзац за абзацем

begin

S:= Items[i]; // считываем строку

Ss:= GetStyle(S, CurStyle); // получаем чистую строку и стиль

s:= ''; // подготавливаемся к преобразованию строки

if ss <> '' then

for j:= 1 to length(Ss) do

begin // просматриваем строку посимвольно

case ss[j] of

'~': begin // если это концевая сноска

S:= S + ''

+IntToStr(EndNotes_count)+'';

inc(EndNotes_count); // увеличиваем счетчик сносок

end;

'^': S:= S + '́'; // ставим ударение

else S:= S + ss[j]; // иначе записываем символ в итоговую строку

end; // case

end;

// тут я пока немножко пропущу

// анализ стилей

case CurStyle of // в зависимости от стиля абзаца

Norm,Epig,Citat: OutList.Add('

'+S+'

');

H1..H5: StyleStucture; // Heading

Sub: OutList.Add(''+s+''); // Subtitle

// конец кода

Давайте рассмотрим все по порядку:

Начнем со стихов. В стандарте FB2 используется три тега для работы со стихами, я использую только один стиль "P".

Для разделения стихов на строфы я предлагаю использовать пустые строки помеченные стилем "P".

// начало кода

if (CurStyle <> oldStyle) then // если предыдущий стиль отличен от текущего

begin // а нынешний стиль есть в данном списке, то значит надо начинать нужный блок.

case CurStyle of // начало блока

Poem: OutList.Add('');

Epig: OutList.Add('');

Citat: OutList.Add('');

end; // case начало блока

end;

// конец кода

А для обработки стиля используется следующие строки

// начало кода

case CurStyle of // в зависимости от стиля абзаца

Norm,Epig,Citat: OutList.Add('

'+S+'

');

Poem: begin

if S = ''

then OutList.Add('')

else OutList.Add(''+S+'');

end;

// конец кода

В случае Нормальное стиля, Эпиграфа и Цитаты, просто добавляются абзацы, а для стихов еще отслеживается пустая строка…

Как видите блоки не завершены. Эту функцию выполняет следующий код.

// начало кода

if (CurStyle <> oldStyle) and (CurStyle <> Auth) then

begin

case oldStyle of // завершение предыдущего блока

Poem: OutList.Add('');

Epig: OutList.Add('');

Citat: OutList.Add('');

end; // case завершение предыдущего блока

end;

// конец кода

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

В данном сочинении, я часто буду пользоваться таким приемом, отступлением от порядка следования текста в исходнике, что делать, человеческая логика и машинная не совсем совпадают.

Если Вы внимательно следите за процессом, то заметили " and (CurStyle <> Auth) " в предыдущем кусочке о начале блока, я это дело опустил, что бы не затуманивать описание.

Это достаточно забавный код призван выполнить требования формата:

// начало цитаты

Внутри тэгов , и возможно указать автора соответственно стихотворения, цитаты или эпиграфа. Для этого служит тэг . Этот тэг должен стоять в самом конце родительского тэга, то есть непосредственно перед его закрытием.

// конец цитаты

А теперь как это я сделал.

// начало кода

Auth: begin

OutList.Add(''+S+'');

if oldStyle in [Poem, Epig, Citat]

then CurStyle:= oldStyle;

// т. е. корректно отработается закрытие родительских блоков

end;

// конец кода

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

ДОПОТОПНАЯ КОСТЬ[1]

Аполлон Майков

Я с содроганием смотрел

На эту кость иного века…

И нас такой же ждет удел:

Пройдет и время человека…


Умолкнет славы нашей шум;

Умрут о людях и преданья;

Всё, чем могуч и горд наш ум,

В иные не войдет созданья.


Оледенелою звездой

Или потухнувшим волканом

Помчится, как корабль пустой,

Земля небесным океаном.


И, странствуя между миров,

Воссядет дух мимолетящий

На остов наших городов,

Как на гранит

неговорящий


Так разум в тайнах бытия

Читает нам… Но сердце бьется,

Надежду робкую тая -

Авось он, гордый, ошибется!



1857

Структура

Теперь, после лирического отступления, самое интересное: структурирование книги.

Книга может иметь разделение на части, главы, тома и книги, ну мало ли чего придумает автор…

В FB2 структура задается тэгами

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

Программе для обработки структуры понадобится стек (напомню, стек – это список с правилом "последний пришел – первый вышел")

Полученный код FB2, как эталоном, я проверяю программой «FictionBook Editor». Так вот, экзаменатору не нравится такая структура:

// начало примера

H1 | Кальман Миксат. ОСАДА БЕСТЕРЦЕ

S| (История одного чудака)

H2 | ВВЕДЕНИЕ

// конец примера

Т.е. между секциями не должно быть ничего лишнего…

А вот так будет все нормально:

// начало примера

H1 | Кальман Миксат. ОСАДА БЕСТЕРЦЕ

H1 | (История одного чудака)

H2 | ВВЕДЕНИЕ

// конец примера

Итак, когда при обработке списка ListBox1 встречается строка с типом от H1 до H5 вызывается процедура StyleStucture;

// начало кода

procedure StyleStucture;

begin

if CurStyle <> oldStyle then

begin // пока предположим, что предыдущий стиль был не заголовок

if SytleStack.Count = 0 then // если стек пуст

begin // записываем стиль в стек

SytleStack.Add(TObject(CurStyle))

end

else // если в стеке что-то есть

begin // значит надо проверить последний из заголовков

LastStyle:= TmyStyle(SytleStack.Last); // считываем последний стиль

case SubStyle(CurStyle, LastStyle) of // вычисляем разность текущий стиль минус последний

0: OutList.Add('

'); // стили равны, ничего особенного делать не надо

1: SytleStack.Add(TObject(CurStyle)); // новый стиль больше, добавляем его в стек

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

else // иначе, считаем что разность меньше нуля

begin

OutList.Add('');

while CurStyle <>LastStyle do

begin

SytleStack.Delete(SytleStack.Count-1); // уменьшаем стек

OutList.Add(''); // завершаем секции до тех пор пока

LastStyle:= TmyStyle(SytleStack.Last); // текущий стиль и стиль в стеке не сравняются.

end;

end;

end;// case

end;

OutList.Add('

'); // начинаем новую секцию

OutList.Add('');</p> <p>end;</p> <p>OutList.Add('<p>'+s+'</p>'); // записываем заголовок секции</p> <p>end; // StyleStucture;</p> <p>// конец кода</p> <p>Пожалуй, это самый тяжелый код в данном манускрипте, но он вроде работает, хотя я вижу в нем по крайней мере две неувязки, но что это, не скажу…</p> <p>Ну вот с обработкой книги почти закончили, мелкие подробности увидите в исходнике.</p> <p>Нажимаем пункт меню File – Save as FB2.</p> <p>И – ничего не получается. Запланированная шутка. Вылезла надпись "Заполнить поля" и фокус перенаправлен на начальную закладку.</p> <p>Напоминаю FB2 – это не только легкоусвояемый (легкоусваиваемый) текст, но и очень нужный и полезный заголовок книги.</p> <p>Давайте посмотрим, все таки, что происходит при выборе пункта Save as FB2</p> <p>// начало кода</p> <p>procedure TForm1.SaveasFB21Click(Sender: TObject);</p> <p>begin</p> <p>if not BookHaveName then // проверяем, все ли в порядке в заголовке</p> <p>begin // если нет, то происходит все то что Вы видели</p> <p>PageControl1.ActivePageIndex:= 0;</p> <p>ShowMessage('Fill the form.');</p> <p>exit;</p> <p>end;</p> <p>SaveDialog1.FileName:= form1.FB2_file.Text;</p> <p>if SaveDialog1.Execute then</p> <p>Make_fb2(SaveDialog1.FileName);</p> <p>end;</p> <p>// конец кода</p> <p>Посмотрим на процедуру BookHaveName</p> <p>// начало кода</p> <p>function BookHaveName: boolean;</p> <p>begin</p> <p>with Form1 do</p> <p>result:= (book_title.Text <> '') and</p> <p>(FB2_file.Text <> '') and</p> <p>(GenresBox.Count > 0);</p> <p>end;</p> <p>// конец кода</p> <p>Ничего особенного в этой функции нет. Единственно из-за чего я ее вытащил, это сказать, что Вы можете и скорее даже будете вынуждены, как-то изменить ее, чтобы контроль заполнения заголовка книги был более разумным.</p> <p>А я пока вернусь к заполнению заголовка.</p> <p>В программе Вы видите три закладки Title-info, Document-info и Publish-info. В формате FB2 есть еще кое-что, но я пока это игнорировал. Предоставляю Вам такую возможность. Код Вам в руки…</p> <p>Итак Title-info</p> <p>Поле Project – само заполнится при открытии текстового файла. При желании, Вы можете изменить, имя сохраняемого fb2 файла.</p> <p>Поле book-title действительно обязательно надо заполнить</p> <p>Теперь Genre – Жанр.</p> <p>Ага, тут немного интереснее, есть о чем погуторить.</p> <p>Нажимаем кнопку с тремя точками.</p> <p>И открывается окошко Жанры.</p> <p>Наша цель добавить один или несколько жанров в левый ListBox.</p> <p>Выберите подходящий жанр в правом ListBoxсике и нажмите кнопку Add</p> <p>В навигации по жанрам поможет верхний ComboBox</p> <p>О коде в этом unit мне говорить лень, ничего особенного, рутина.</p> <p>Интереснее, вот, что, информация для загрузки в эти Боксики находится в unit dm</p> <p>Посмотрите на нее, и поругайте мою лень. Дело в том, что я не уверен, что этот список жанров правилен. Второе, этот список, очевидно, не окончателен. А значит он не должен быть жестко зафиксирован в программе.</p> <p>Значит, так. Вам задание – переписать прогу, чтобы эти списки грузились или из текстового файла или из INI файла.</p> <p>Вернемся к заполнению заголовка</p> <p>Нам надо ввести данные об авторе / авторах и переводчике / переводчиках</p> <p>Так же нажимаем на соответствующую кнопочку с троеточием и работаем в открывшемся окне.</p> <p>Вы уже наверно заметили, что мне прискучило очень уж подробно расписывать код. Но в данном unit тоже ничего особенного, единственно, пришлось ввести структуру TPerson, я думаю Вы легко разберетесь зачем она мне нужна.</p> <p>Мне интереснее, совершенствование программы. Представьте ситуацию, Вы делаете 10 книг (или 100) одного автора и каждый раз делая новую книгу, заполняете опять и опять данные об этом человеке. Мне было бы лень. Ваши предложения?…</p> <p>Ну хорошо мы заполнили и Title-info и Document-info и Publish-info.</p> <p>Давайте-ка глянем, что там в коде записи файла FB2.</p> <p>// начало кода</p> <p>Procedure Make_fb2(S: string);</p> <p>begin //</p> <p>if Form1.ListBox1.Items.Count = 0 then exit;</p> <p>SytleStack.Clear; // подготовка стека стилей</p> <p>OutList.Clear; // подготовка выходного списка</p> <p>SaveDescription;</p> <p>SaveBodyFB2; // это мы уже в общем рассмотрели</p> <p>SaveEndnotes;</p> <p>OutList.Add('</FictionBook>'); // закрываем книгу</p> <p>OutList.SaveToFile(S); // Запись в файл</p> <p>showMessage('Done.'); // Сообщаем об удачном завершении</p> <p>end;</p> <p>// конец кода</p> <p>Как видите мы еще не рассмотрели две процедуры.</p> <p>// начало кода</p> <p>procedure SaveDescription;</p> <p>const</p> <p>max = 5; // может я захочу изменить число строк в массиве, тогда я изменю только одну цифру</p> <p>mas: array[1.. max] of string =</p> <p>(// массив для заголовочной части FB2 файла</p> <p>'<?xml version="1.0" encoding="windows-1251"?>', // как видите я делаю файл в кодировке Win</p> <p>// я не вижу смысла в применении юникода, но если речь идет не о русском языке,</p> <p>// то сделайте здесь изменение.</p> <p>'<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0"',</p> <p>' xmlns: l="http://www.w3.org/1999/xlink">',</p> <p>' <description>',</p> <p>' <title-info>'</p> <p>);</p> <p>var i: byte;</p> <p>begin</p> <p>// Выводим в выходной файл начало FB2 файла</p> <p>for i:= 1 to max do</p> <p>OutList.Add(Mas[i]);</p> <p>// конец кода</p> <p>Дальше просматриваем списки Жанров, Автором и Переводчиков и выводим оттуда информацию (если она там есть).</p> <p>Т.е. проверяем все заполненные поля форм описывающих книгу и выводим информацию в соответствующие секции заголовка книги.</p> <p>Будем считать, что с Description – покончили.</p> <p>Осталось только</p> <p>// начало кода</p> <p>procedure SaveEndnotes;</p> <p>var</p> <p>S: string;</p> <p>i: integer;</p> <p>begin</p> <p>if Form1.EndNotesList.Items.Count = 0 then exit;</p> <p>OutList.Add('<body name="notes"><title><p>Примечания</p>');

for i:= 0 to Form1.EndNotesList.Items.Count – 1 do

begin

S:= Form1.EndNotesList.Items[i];

OutList.Add('

<p>'+IntToStr(i+1)+'</p>');</p> <p>OutList.Add('

'+S+'

');

OutList.Add('

');

end;

OutList.Add('');

end;

// конец кода

Согласитесь, что здесь все просто, просматриваем список сносок и соблюдаем формат FB2. Но остается один маленький вопрос, а что если нам нужно будет вывести многострочную (точнее много абзачную) сноску. Да, возникает вопрос, приходят и варианты решения…

Ладно, кое-что в коде я пропустил. Но основные недостатки программы, я кажется описал. Правда, наверняка есть ляпы, которые я не заметил…

Наконец файл книги в формате FB2 создан.

На этом все? Ну нет, сейчас все авторы заканчивают книги словами «Продолжение следует». И я замыслил по крайней мере одно продолжение. Мне кажется оно просто необходимо.

Программа должна уметь не только создавать, но и читать файл FB2. Тогда можно растягивать удовольствие изготовления книги на несколько дней, и не потребуется каждый раз заново: читать текстовый файл, расставлять стили, форматировать строки и т. д. и все это с одной и той же книгой – ужас.

Но, как известно из математики, обратная задача всегда сложнее прямой. И т. к. я считаю, что на сегодня уже достаточно утомил Вас. Давайте рассказ о второй версии программы отложим.

Связаться со мной Вы сможете по адресу [email protected] (обратите внимание, 2 подчеркивания, т. к. [email protected] оказался уже занят). Предупреждаю сразу, я ленив, почту смотрю не каждый день, да и отвечать всем может и не смогу (я же не знаю сколько найдется желающих мне написать). Второе, эту почту я специально завел для этой программки, и если Вы, друзья мои завалите ее спамом или матом, я просто забуду туда дорогу.

Лицензионные условия таковы, пользуйтесь на здоровье, копируйте, переделывайте, если сможете заработать на этом деньги, буду только рад.

Карпов Юрий.

Кохтла-Ярве.

2010.

Итак.

Продолжение следует…

Приложение

Исходный код программы.

Выложил исходник на один сайт, но боюсь, что там ему и потерянному быть…

Поэтому, не буду ждать милости, справимся и сами.

Для начала, извлечем исходник из этого файла.

«Нет таких задач, которые не могли бы решить комму… (извиняюсь) программисты!»

Сделаем копию этого файла. Переименуем его как текст. В этом тексте найдем слово «Приложение». Удалим все до этого слова, да и немного далее, до начала исходного текста.

Теперь заменим все

и

на пустое место.

Еще заменим:

на пустое место.

& на &

< на <

> на >

«Цели определены, задачи поставлены, за работу товарищи…»


Программа состоит из 4 форм и 6 файлов pas, всего около 50 кбайт.

Далее, последует инструкция, как сделать программку.

Если Delphi 5 и выше то все просто.

Получившийся пирожок, нужно разрезать на отдельные файлы и назвать так как они подписаны

И запустить проект.

Иначе придется повозится.

В новой папочке создайте пустой проект Delphi.

На форме кликните правой кнопкой мыши и выберите View as Text

Скопируйте код формы из книги (не захватывая слова "начало кода" и "конец кода"). Вставьте его в открытое окно. Нажмите правую кнопку мыши и выберите View as Form. Если все сделано правильно Вы увидите форму.

Скопируйте код соответствующего unit. Замените им код в окне Code.

Хорошо, одна форма сделана.

Теперь создайте новую форму File – New – Form

И повторите предыдущие операции

Форм и соответствующих им Юнитов нужно сделать 4:

Unit1.dfm, genres.dfm, EditStr.dfm, authors.dfm

Unit1.pas, genres.pas, EditStr.pas, authors.pas

Файлы UmFB2.pas и dm.pas форм не имеют т.е. просто сделайте их из текстовых.

Итак, начали.

Unit1.dfm

// начало кода

object Form1: TForm1

Left = 187

Top = 98

Width = 722

Height = 463

Caption = 'Form1'

Color = clBtnFace

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -11

Font.Name = 'MS Sans Serif'

Font.Style = []

Menu = MainMenu1

OldCreateOrder = False

OnCreate = FormCreate

PixelsPerInch = 96

TextHeight = 13

object PageControl1: TPageControl

Left = 0

Top = 0

Width = 714

Height = 417

ActivePage = TabSheet2

Align = alClient

TabIndex = 3

TabOrder = 0

object TabSheet1: TTabSheet

Caption = 'title-info'

object Annotation: TMemo

Left = 0

Top = 273

Width = 706

Height = 116

Align = alClient

ScrollBars = ssVertical

TabOrder = 0

WordWrap = False

end

object Panel3: TPanel

Left = 0

Top = 0

Width = 706

Height = 273

Align = alTop

BevelOuter = bvNone

TabOrder = 1

object Lbook_title: TLabel

Left = 8

Top = 64

Width = 43

Height = 13

Caption = 'book-title'

end

object LProject: TLabel

Left = 8

Top = 8

Width = 36

Height = 13

Caption = 'Project:'

end

object LAnnotation: TLabel

Left = 16

Top = 240

Width = 51

Height = 13

Caption = 'Annotation'

end

object Lsequence: TLabel

Left = 16

Top = 176

Width = 49

Height = 13

Caption = 'Sequence'

end

object LLang: TLabel

Left = 376

Top = 176

Width = 27

Height = 13

Caption = 'Lang.'

end

object Lsrc_lang: TLabel

Left = 456

Top = 176

Width = 49

Height = 13

Caption = 'Src. Lang.'

end

object LTome: TLabel

Left = 200

Top = 176

Width = 27

Height = 13

Caption = 'Tome'

end

object book_title: TEdit

Left = 64

Top = 56

Width = 217

Height = 21

TabOrder = 0

end

object FB2_file: TEdit

Left = 8

Top = 24

Width = 273

Height = 21

TabOrder = 1

end

object Au: TGroupBox

Left = 296

Top = 8

Width = 185

Height = 153

Caption = ' Authors '

TabOrder = 2

object ListBox3: TListBox

Left = 8

Top = 15

Width = 169

Height = 106

ItemHeight = 13

TabOrder = 0

end

object Button10: TButton

Left = 152

Top = 124

Width = 25

Height = 25

Caption = '...'

TabOrder = 1

OnClick = Button10Click

end

end

object GroupBox1: TGroupBox

Left = 8

Top = 88

Width = 273

Height = 73

Caption = ' Genre '

ParentShowHint = False

ShowHint = False

TabOrder = 3

object GenresBox: TListBox

Left = 8

Top = 15

Width = 225

Height = 50

ItemHeight = 13

TabOrder = 0

end

object Button4: TButton

Left = 240

Top = 40

Width = 25

Height = 25

Caption = '…'

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -13

Font.Name = 'MS Sans Serif'

Font.Style = []

ParentFont = False

TabOrder = 1

OnClick = Button4Click

end

end

object GroupBox3: TGroupBox

Left = 480

Top = 8

Width = 185

Height = 153

Caption = ' Translator '

TabOrder = 4

object ListBox2: TListBox

Left = 8

Top = 15

Width = 169

Height = 106

ItemHeight = 13

TabOrder = 0

end

object Button7: TButton

Left = 152

Top = 124

Width = 25

Height = 25

Caption = '…'

TabOrder = 1

OnClick = Button7Click

end

end

object sequence: TEdit

Left = 40

Top = 192

Width = 169

Height = 21

TabOrder = 5

end

object tome: TEdit

Left = 216

Top = 192

Width = 33

Height = 21

TabOrder = 6

end

object Lang: TComboBox

Left = 376

Top = 192

Width = 65

Height = 21

ItemHeight = 13

TabOrder = 7

Text = 'ru'

Items.Strings = (

'ru'

'en')

end

object SLang: TComboBox

Left = 456

Top = 192

Width = 145

Height = 21

ItemHeight = 13

TabOrder = 8

end

object Button9: TButton

Left = 88

Top = 238

Width = 121

Height = 17

Caption = 'Load annotation'

TabOrder = 9

OnClick = Button9Click

end

end

end

object TabSheet3: TTabSheet

Caption = 'document-info'

ImageIndex = 2

object Lurl: TLabel

Left = 32

Top = 40

Width = 28

Height = 13

Caption = 'src-url'

end

object LID: TLabel

Left = 32

Top = 120

Width = 11

Height = 13

Caption = 'ID'

end

object Lversion: TLabel

Left = 24

Top = 200

Width = 34

Height = 13

Caption = 'version'

end

object url: TEdit

Left = 40

Top = 64

Width = 553

Height = 21

TabOrder = 0

end

object id: TEdit

Left = 40

Top = 144

Width = 241

Height = 21

TabOrder = 1

end

object version: TEdit

Left = 40

Top = 224

Width = 65

Height = 21

TabOrder = 2

Text = '1.0'

end

end

object TabSheet6: TTabSheet

Caption = 'publish-info'

ImageIndex = 3

object LISBN: TLabel

Left = 40

Top = 80

Width = 25

Height = 13

Caption = 'ISBN'

end

object LBook_name: TLabel

Left = 16

Top = 32

Width = 54

Height = 13

Caption = 'Book name'

end

object Lpublisher: TLabel

Left = 16

Top = 128

Width = 42

Height = 13

Caption = 'publisher'

end

object Lcity: TLabel

Left = 32

Top = 200

Width = 16

Height = 13

Caption = 'city'

end

object Lyear: TLabel

Left = 280

Top = 200

Width = 20

Height = 13

Caption = 'year'

end

object isbn: TEdit

Left = 80

Top = 72

Width = 217

Height = 21

TabOrder = 0

end

object Book_name: TEdit

Left = 80

Top = 24

Width = 561

Height = 21

TabOrder = 1

end

object publisher: TEdit

Left = 80

Top = 120

Width = 553

Height = 21

TabOrder = 2

end

object year: TEdit

Left = 312

Top = 196

Width = 57

Height = 21

TabOrder = 3

end

object city: TEdit

Left = 80

Top = 192

Width = 145

Height = 21

TabOrder = 4

end

end

object TabSheet2: TTabSheet

Caption = 'Content'

ImageIndex = 1

object Panel1: TPanel

Left = 0

Top = 0

Width = 706

Height = 41

Align = alTop

TabOrder = 0

end

object Panel2: TPanel

Left = 0

Top = 41

Width = 265

Height = 348

Align = alLeft

BevelOuter = bvNone

TabOrder = 1

object Button12: TButton

Left = 216

Top = 123

Width = 33

Height = 25

Caption = '>'

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -21

Font.Name = 'MS Sans Serif'

Font.Style = []

ParentFont = False

TabOrder = 0

OnClick = Button12Click

end

object RG: TRadioGroup

Left = 16

Top = 72

Width = 177

Height = 193

Caption = ' Styles '

ItemIndex = 0

Items.Strings = (

'Normal'

'Epigraph'

'Text-author'

'Subtitle'

'Poem'

'Citation'

'None')

TabOrder = 1

end

object GroupBox2: TGroupBox

Left = 16

Top = 0

Width = 177

Height = 65

Caption = ' Heading '

TabOrder = 2

object Button1: TButton

Left = 16

Top = 24

Width = 25

Height = 25

Caption = '-'

Font.Charset = DEFAULT_CHARSET

Font.Color = clWindowText

Font.Height = -24

Font.Name = 'MS Sans Serif'

Font.Style = []

ParentFont = False

TabOrder = 0

OnClick = Button1Click

end

object Button2: TButton

Left = 72

Top = 24

Width = 33

Height = 25

Caption = 'H1'

TabOrder = 1

OnClick = Button2Click

end

object Button5: TButton

Left = 128

Top = 24

Width = 25

Height = 25


    Ваша оценка произведения:

Популярные книги за неделю