-
Здравствуйте товарищи. Слёзно прошу вас помочь мне написать компонент, наследник TStringGrid. Этот компонент должен уметь читать RSS ленту новостей, используя парсер от Microsoft. Когда мы ставим компонент на форму, мы указываем в свойстве адрес ленты и при активации свойства Active например, он нам читает нововсти и заполняет их в свои ячейки. У меня получилось сделать обыкновенное приложение, не компонент, в этом приложении все делается с TMemo. А вот как это всё реализовать в компоненте, да тем более наследнике TStringGrid не представляю. Вот код моего приложения:
procedure TForm1.Button1Click(Sender: TObject); Var rss_doc: IXMLDOMDocument; node1: IXMLDOMNode; i:Integer; begin If not (OpenDialog1.Execute) then Exit; rss_doc:=CoDOMDocument.Create; rss_doc.async:=False; rss_doc.load(OpenDialog1.FileName);
if rss_doc.parseError.errorCode<>0 then begin ShowMessage('При загрузке файл произошла ошибка!'+#13#10+ 'Код ошибки: '+IntToStr(rss_doc.parseError.errorCode)+#13#10+ 'Текст ошибки: '+rss_doc.parseError.reason+#13#10+ 'Строка с ошибкой: '+IntToStr(rss_doc.parseError.line)+#13#10+ 'Символ в строке с ошибкой: '+IntToStr(rss_doc.parseError.linepos)); CoUnInitialize; Exit; end; node1:= rss_doc.selectSingleNode('//rss'); For i:=0 to node1.selectNodes('//item').length-1 do begin Memo1.Lines.Add('Заголовок'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('title').Text); Memo1.Lines.Add('Ссылка'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('link').Text); Memo1.Lines.Add('Описание'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('description').Text); If not (node1.selectnodes('//item').item[i].selectSingleNode('PubDate') = nil) then begin Memo1.Lines.Add('Дата публикации'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('PubDate').Text) end; If not (node1.selectnodes('//item').item[i].selectSingleNode('Author') = nil) then begin Memo1.Lines.Add('Автор'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('Author').Text); end; If not (node1.selectnodes('//item').item[i].selectSingleNode('lastBuildDate') = nil) then begin Memo1.Lines.Add('lastBuildDate'); Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('lastBuildDate').Text); end; end; end;
end.
-
1. Очевидно, что наследник должен иметь свойство FileName: string, с которого и будет происходить чтение. 2. Наверняка необходимо иметь свойство Active: boolean, по измененнию которого и начнётся заполнение грида.
Ну и практически весь код перенести в SetActive
-
А какими методами переносить новости потом в грид? Как переопределять при этом компонент?
-
какой ужос.....
стрингрид, я так понимаю, здесь только потому что "оно будет в таблице со строчками и колонками" ?
-
Оно в смысле RSS? Да оно должно заполняться в ячейки stringgrid.
-
зачем в ячейки? в смысле зачем в ячейки - это понятно. но зачем в ячейки стринггрида?
-
Вы сначала сделаете предложенные два свойства FileName,Active
TMyStringGrid = class(TCustomDrawGrid)
published
property FileName: string read fFileName write fFileName;
property Active: boolean read fActive write SetActive;
end; Далее, в конструкторе определим количество строк и столбцов в контроле
constructor Create;
begin
inherited Create;
ColCount := 5;
RowCount := 1;
end; Далее в момент активации заполняем грид
procedure SetActive(Value: boolean);
begin
if Value = fActive then Exit;
fActive := Value;
if fActive then begin
end;
end;
-
не проще ли написать к этому rss (и не только к этому кстати) файл трансформации и выполнить единственный метод transformnode и вывести результ в twebbrowser?
в табличке, с бантиками и шашечками.
-
Если человек хочет в гриде - не будем его переубеждать
-
Медвежолнок Пятачок, я бы может и рад был сделать так как ты предлагаешь, но у меня задание для стринггрида (препод настаивает). DimaBr спасибо за понимание и код, буду пробовать. Если что не получится приду опять))) Это единственный форум на котором ответили.
-
var s : TStrings; begin s := TStringList.Create; s.Add('Мама'); s.Add('мыла'); s.Add('раму.'); s.Add('Рама'); s.Add('чистая.'); StringGrid1.Rows[1].Assign(s); ..... s.Free;
-
на счёт метода s.Free (освобождение памяти), его нужно вызывать сразу после того как я все новости загоню?
-
Ещё закрался такой вопрос, в мемо всё передавалось в цикле: For i:=0 to node1.selectNodes('//item').length-1 do
begin
Memo1.Lines.Add('Заголовок');
Memo1.Lines.Add(node1.selectnodes('//item').item[i].selectSingleNode('title').Text); А как тоже самое передать в стринггрид через свойство Cells[i,j]? Чё-то уже лыжи не едут)
-
Код у тебя шикарный. Слишком. Сначала для получения границ for делается selectnodes затем на каждой итерации снова селект и взятие айтема по индексу. и разумеется никогда не вспоминаем, что нил в природе встречается. Не пробовал писать менее экстремально и не столь гламурно?
-
хех, я согласен с тобой, сам пока ещё не осознаю насколько влип))
-
1. делаем селектнодес для получения списка элементов ленты. результат сохраняем в ixmldomnodelist 2. делаем цикл от нуля до Pred(длина списка) 3. на каждой итерации цикла получаем различные атрибуты элемента списка. Через селектноде от текущего элемента списка. 4. получив полное описание элемента, рассовываем его в ячейки следующей строки грида (предварительно создав новую строку, если свободные строки грида уже закончились)
-
Получился следующий код (не без налёта гламура): unit RSStringGrid;
interface
uses SysUtils, Classes, Controls, Grids, MSXML, ActiveX, Dialogs;
type TRSStringGrid = class(TStringGrid) private fActiveRSS: boolean; fFileNameRSS: String; //procedure FileNameRSS(const Value:String); procedure SetActiveRSS(const Value: Boolean); { Private declarations } protected { Protected declarations } public { Public declarations } procedure ClearGrid(sg: TRSStringGrid); procedure Clear; constructor Create(AOwner: TComponent); override; published { Published declarations } property FileNameRSS: String read fFileNameRSS write fFileNameRSS; property ActiveRSS: boolean read fActiveRSS write SetActiveRSS default False; end;
procedure Register;
implementation
uses Variants;
procedure Register; begin RegisterComponents('BSP', [TRSStringGrid]); end;
{ TRSStringGrid }
procedure TRSStringGrid.Clear; Var i:Longint; begin for i:=0 to ColCount-1 do Cols[i].Clear; end;
procedure TRSStringGrid.ClearGrid(sg: TRSStringGrid); Var i,j: integer; begin For i:=1 to sg.RowCount do For j:=1 to sg.ColCount do begin sg.Cells[j,i]:=''; end; sg.RowCount:=2; sg.FixedRows:=1; end;
constructor TRSStringGrid.Create(AOwner: TComponent); begin inherited Create(AOwner); ColCount:=5; RowCount:=2; Height:=200; Width:=500; end;
procedure TRSStringGrid.SetActiveRSS(const Value: boolean); Var rss_doc:IXMLDOMDocument; Nodes:IXMLDOMNodeList; node1:IXMLDOMNode; i:Integer;
begin Cells[0,0]:='RSS'; Cells[1,0]:='Заголовок'; Cells[2,0]:='Ссылка'; Cells[3,0]:='Описание'; Cells[4,0]:='Дата'; If Value = fActiveRSS then Exit; fActiveRSS := Value; If fActiveRSS then begin rss_doc:=CoDOMDocument.Create; rss_doc.async:=False; rss_doc.load(fFileNameRSS);
node1:=rss_doc.selectSingleNode('//rss'); For i:=0 to node1.selectNodes('//item').length-1 do begin RowCount:=i+2; Cells[1,i+1]:=node1.selectnodes('//item').item[i].selectSingleNode('title').text; Cells[2,i+1]:=node1.selectnodes('//item').item[i].selectSingleNode('link').text; Cells[3,i+1]:=node1.selectnodes('//item').item[i].selectSingleNode('description').text; If not (node1.selectnodes('//item').item[i].selectSingleNode('pubDate') = nil) then begin Cells[4,i+1]:=node1.selectnodes('//item').item[i].selectSingleNode('pubDate').text; end; end; rss_doc:=nil; end; If fActiveRSS=False then Clear; end;
end. Пробовал делать со списком ixmldomnodelist, но там некоторые элементы читает по 2 раза. Например заголовок "РБС.Этот безумный мир" добавляет 2 раза. Т.е. с selectnodes поточнее получилось. Как лучше теперь реализовать свойство FileName, что-бы в нём по умолчанию был адрес сохранён, и там проверялось например если оно пусто (пользователь стёр адрес по умолчанию и ничего не добавил) выводилось например сообщение, а свойство ActiveRSS оставалось в False?
-
procedure TRSStringGrid.SetActiveRSS(const Value: boolean);
begin
...
If Value = fActiveRSS then Exit;
if Value and (fFileNameRSS = '') then begin
raise;
end;
if Value and not FileExists(fFileNameRSS) then begin
raise;
end;
fActiveRSS := Value;
.....
-
Спасибо вам, выручили меня, очень вам благодарен. Тему можно закрывать.
|