Сегодня будет немного лирики. Оказалось, что малыш дома, это фактор, который здорово тормозит работу, особенно ту, которая на общественных началах. Она в списке приоритетов уходит далеко на второй план. Этим, отчасти, и вызвана некоторая пауза между нашими уроками.
И второй момент, как оказалось golos здорово заточен под Web, а вот Delphi не очень. Если говорить проще, то просто тормозит она безбожно в некоторых моментах. Всякие веб-решения гораздо легче и производительнее. Так я пока что работаю над фоновой загрузкой картинок к постам, и это не войдет в наш сегодняшний урок. Ну и многие другие ограничения пришлось преодолеть. Как любят говорить математики "отсюда легко видеть, что...". Так вот в итоге все легко, но иногда к этому решению приходится идти окольными путями.
Ну а теперь и про рефакторинг. То что мы набросали сначала, позволило нам запустить приложение, но имело отвратительную структуру и не поддавалось дальнейшему расширению. Поэтому мы с вами проведем некоторую реорганизацию кода, которая будет заключаться вот в чем:
- У нас появятся процедуры
GetNewRecords
и т.п., которые будут отвечать за выбор нужных постов из БД - У нас появится процедура
AddItems
, которая очистит ленту и добавит в нее новые посты, полученные предыдущими процедурами - У нас будет процедура
LoadComment
, которая загрузит выбранный пост по щелчку на нем в ленте постов вListView
- Процедура
GetRecordImage
работает с метаданными поста и позволяет получить ссылку на его картинку - Мы переработали вывод записей в ленту
А теперь подробнее. Мы добавили новую закладку в наш TabControl
и разметили на ней компонент AniIndicator
, он показывает крутящееся нечто, в момент когда программа занята. Мы используем его сдедующим образом. Открываем этот "экран", запускаем затратную по времени операцию. В операции не забываем обрабатывать поток сообщений при помощи Application.ProcessMessages
. После выполнения операции возвращаемся к основному экрану.
Кроме того, загрузка начального списка записей вынесена из FormCreate
в FormActivate
, как раз для того, чтобы после запуска у нас не получилось так что программа долго тупит и ничего не показывает.
Добавили закладку в наш TabControl
и разметили на ней компонент WebBrowser
. Туда будем грузить сам пост и комментарии к нему.
Обработчик выпадающего списка, где мы выбираем какую ленту постов грузить, теперь выглядит вот так:
procedure THeaderFooterwithNavigation.ThemeBoxChange(Sender: TObject);
begin
try
TabControl1.ActiveTab := xAnimation;
ListView.Items.Clear;
case ThemeBox.Selected.Index of
0: GetNewRecordsAction.Execute;
1: GetPopularRecordsAction.Execute;
end;
finally
TabControl1.ActiveTab := TabItem1;
end;
end;
по мере добавления новых режимов просто будем добавлять туда новые кейсы.
Вот так теперь выглядит выбор новых постов, обратите внимание, как изменился запрос к БД.
procedure THeaderFooterwithNavigation.GetNewRecords;
begin
if UniConnection.Connected then
begin
UniQuery.SQL.Clear;
UniQuery.SQL.Add('SELECT top(50) author, title, parent_permlink, permlink, MIN(tx_id) AS tx_id, '+
'(select top(1) id from Comments S where S.author = T.author and S.root_title = T.title order by id desc) as comment_id ' +
'FROM TxComments T '+
' where title <> '''' and parent_permlink <> ''bm-open'' and body not LIKE ''@@%'' '+
' GROUP BY author, title, parent_permlink, permlink '+
' order by tx_id desc');
AddItems;
end;
end;
Весь набор полученных данных сохраняется в компоненте запроса UniQuery
, мы оттуда их достаем и выводим в ленту:
procedure THeaderFooterwithNavigation.AddItems;
var
Item: TListViewItem;
I: integer;
begin
ListView.Items.Clear;
UniQuery.Open;
if UniQuery.RecordCount > 0 then
begin
UniQuery.First;
for I := 0 to UniQuery.RecordCount - 1 do
begin
if Pos('bm-', UniQuery.FieldByName('author').AsString) > 0 then
begin
UniQuery.Next;
continue;
end;
Item := ListView.Items.Add;
Item.ImageIndex := 0;
Item.Text := UniQuery.FieldByName('title').AsString;
Item.Detail := sLineBreak + 'Создано '+ '@' + UniQuery.FieldByName('author').AsString +
sLineBreak + 'в ' + DeTransliterate(UniQuery.FieldByName('parent_permlink').AsString);
Item.Data['author'] := UniQuery.FieldByName('author').AsString;
Item.Data['permlink'] := UniQuery.FieldByName('permlink').AsString;
Item.Data['parent_permlink'] := UniQuery.FieldByName('parent_permlink').AsString;
Item.Data['title'] := UniQuery.FieldByName('title').AsString;
Item.Data['tx_id'] := UniQuery.FieldByName('tx_id').AsString;
Item.Data['json_metadata'] := GetFieldByTx(UniQuery.FieldByName('tx_id').AsString, 'json_metadata');
Application.ProcessMessages;
UniQuery.Next;
end;
end;
end;
Кроме того, мы эти же данные дублируем в объекте Data
каждого элемента, чтобы впоследствии к ним обратиться. Например, вот так, при клике на элемент ListView
, мы получаем данные о tx_id
- ключе записи:
procedure THeaderFooterwithNavigation.ListViewItemClick(const Sender: TObject;
const AItem: TListViewItem);
begin
TabControl1.ActiveTab := xAnimation;
LoadComment(AItem.Data['tx_id'].AsString, AItem.Index);
end;
и передаем их в процедуру LoadComment
, которая уже и выводит сам пост в WebBrowser
:
procedure THeaderFooterwithNavigation.LoadComment(TxID: string; ItemId: integer);
var
html, body, title: string;
begin
if UniConnection.Connected then
begin
UniQuery.SQL.Clear;
UniQuery.SQL.Add('select body from TxComments where tx_id = ' + TxID);
UniQuery.Open;
UniQuery.First;
title := ListView.Items[ItemId].Data['title'].AsString;
body := UniQuery.FieldByName('body').AsString;
body := StringReplace(body, '< img ', '< img width="'+IntToStr(width - 40)+'" ', [rfReplaceAll, rfIgnoreCase]);
html := '<script src="https://cdn.rawgit.com/showdownjs/showdown/1.6.4/dist/showdown.min.js"></script>';
html := html + '<h1>'+ title + '</h1>';
html := html + '';
html := html + sLineBreak + body;
Web.LoadFromStrings(html, '');
TabControl1.ActiveTab := ViewDetails;
UniQuery.Close;
end;
end;
Мы здесь немного преобразуем часть элементов, так мы переписываем тэги img
так, чтобы ширина картинки была чуть меньше ширины формы и не "рвала" страницу. Но при отображении остается еще куча проблем, например отображение Markdown, нотак что это уже в следующем уроке.
Что имеем на текущий момент - мы можем загружать ленту постов и при клике на пост подгружать его для просмотра. Уже неплохо.
Ну и пару картинок:
Предыдущие шаги тут
Привет!
Этот пост был выбран Академией Голоса и попал в список программы поддержки качественных образовательных постов.
Ссылка на твой пост будет опубликована в отчете Академии.
Спасибо за полезный контент (ノ◕ヮ◕)ノ*:・゚✧
Молодец! Нужно дело делаешь. Успехов!
Это просто абзац какой-то! Как это можно знать, понимать и использовать?! Для меня это - что граната для обезьяны.
Не все технологии программирования очень сложные и имеют высокий уровень входа. Можно начинать с чего-то попроще, типа Питона. Ну это если хочется, конечно же )