Какая структура данных лучше всего подходит для VirtualStringTree?

Я думаю, все, кто когда-либо использовал VirtualStringTree Delphi, согласятся, что это отличный контроль. Это" виртуальный " контроль (ваши данные должны храниться где-то еще), поэтому я подумал, Какая структура данных лучше всего подходит для такой задачи? ИМО, что структура данных должна поддерживать иерархию, она должна быть быстрой и легко расширяемой. Самой простой реализацией будет использование записи, и это то, что предлагает большая часть документации, которую можно найти. Но что, если тебе нужно что-то сделать? быстрый поиск, подсчет итогов и т. д.? Какую структуру данных вы используете вместе с VirtualStringTree?

EDIT1: Я использую Delphi 2010.

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

EDIT2: Получил 1 ответ, поэтому я попытаюсь прокомментировать свое мнение. Спасибо, Дорин за ваш ответ, но Я не думаю, что ваша структура очень удобна. 1) он не имеет дела с иерархией. 2) наличие отдельных TStringList или TList для каждого узла не очень эффективно IMO. С помощью этой реализации я могу только искать данные текущего узла, но не могу эффективно искать во всем дереве.

Я думаю, что эта структура данных должна быть как дерево. Он должен иметь узлы с возможностью добавления дочерних элементов. Тогда я просто мог бы получить данные узла в событии OnInitNode, проверить, есть ли у моего узла дети, установить флаг ivsHasChildren, если да, то в событии OnInitChildren установите правильный счетчик детей. Позже в событии OnGetText я мог просто получить необходимые данные из моей структуры узла и установить его в CellText на основе индекса столбца. Моя идея состоит в том, чтобы иметь отдельную структуру данных и выполнять все необходимые операции с ней без необходимости использовать VirtualStringTree. Надеюсь, кто-то ... понял мою точку зрения :).

EDIT3: Я нашел довольно интересный блок JclTrees, который на первый взгляд может быть использован для достижения того, что я ищу. Он принадлежит JCL с библиотека. Отсутствие достойной документации затрудняет быстрое исследование ее функциональности. Возможно, я загляну в него глубже, когда у меня будет больше времени.

3 ответов


хорошо, потому что данные ответы не решили мои проблемы, я написал свою собственную структуру данных дерева, которая имитирует TVirtualStringTree и обрабатывает все проблемы, которые я упомянул в своем вопросе. Теперь я могу использовать только свою структуру данных, и все изменения в ней автоматически обновят VirtualStringTree. Я думаю, что я загружу исходный код где-нибудь позже и опубликую ссылку здесь. Спасибо за ответы.

EDIT: я загрузил источник в код Google: svTrees. Есть небольшая демонстрация, которая показывает, как это работает.


вы не указали свою версию Delphi, поэтому:

Я предлагаю использовать записи (я не уверен, в какой версии Delphi они добавили методы для записей, я перешел с D7 на D2010), поэтому у вас может быть что-то вроде:

type
  TMyRecordWithMethods = record
    function GetMeAResult: Integer;
    procedure DoSomething(const AInParam: Integer; var AOutParam: Integer);
  end;

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

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

uses ..., Generics.Collections;

type
  TMyNode = class(TObject)// you can leave this out if you like
    MyIntList: TList<Integer>; // you can do lookups, you have to implement your own saving/loading methods
    MyStringList: TStringList or TList<string>; // you can do lookups in both cases, use TStringList for save/load of data
  end;

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

type
  TMyFileHeader = record
    CountItems: Integer; // number of items in the tree
    ...
  end;

const
  szMyFileHeader = SizeOf(TMyFileHeader);

type
  TMyItemEntry = record
    CountInt: Integer; // number of integer values
    ...
  end;

const
  szMyItemEntry = SizeOf(TMyItemEntry);

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

псевдо-код, извините, не время для частичного кода : -\

a) сохранение содержимого:

  • сохранить количество элементов в переменной TMyFileHeader и записать его в файл

  • для каждого элемента в дереве сохраните список целых чисел, сохраните список строк

b) загрузка содержимого:

  • read file header -- так что вы знаете, сколько элементов вам нужно прочитать из файла

  • do a for Index: = 0 для подсчета -1 прочитайте элемент из файл

Примечание: Вы можете сохранить список строк из каждого элемента непосредственно в текущую позицию в потоке файлов, однако было бы разумно сохранить его непосредственно с помощью:

FileStream.WriteBuffer(PChar(AStringList.Text)^, Length(AStringList.Text) * SizeOf(Char));

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


Вы можете использовать TXMLDocument.

Если вы хотите больше контроля над тем, что вы кладете туда, я бы предложил вам создать xsd, описывающий структуру, которую вы хотите, и использовать мастер привязки данных XML для создания кода Delphi, который вы можете использовать.

схемы

alt text

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
    <xs:complexType name="itemType">
        <xs:sequence>
            <xs:element name="id" type="xs:int"/>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="itemlist" type="itemlistType" minOccurs="0"/>
        </xs:sequence>
    </xs:complexType>
    <xs:complexType name="itemlistType">
        <xs:sequence>
            <xs:element name="item" type="itemType" minOccurs="0" maxOccurs="unbounded"/>
        </xs:sequence>
    </xs:complexType>
    <xs:element name="root">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="itemlist" type="itemlistType"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

даст вам эти интерфейсы для работы в delphi

  IXMLRoot = interface(IXMLNode)
    ['{16C6C960-58B7-400C-9E46-7ACC7BEF276F}']
    { Property Accessors }
    function Get_Itemlist: IXMLItemlistType;
    { Methods & Properties }
    property Itemlist: IXMLItemlistType read Get_Itemlist;
  end;

{ IXMLItemlistType }

  IXMLItemlistType = interface(IXMLNodeCollection)
    ['{59F80BAC-887E-48DF-8288-95276BF9DCE7}']
    { Property Accessors }
    function Get_Item(Index: Integer): IXMLItemType;
    { Methods & Properties }
    function Add: IXMLItemType;
    function Insert(const Index: Integer): IXMLItemType;
    property Item[Index: Integer]: IXMLItemType read Get_Item; default;
  end;

{ IXMLItemType }

  IXMLItemType = interface(IXMLNode)
    ['{1218DD35-C3EF-40E6-831A-1A4AA0782C36}']
    { Property Accessors }
    function Get_Id: Integer;
    function Get_Name: WideString;
    function Get_Itemlist: IXMLItemlistType;
    procedure Set_Id(Value: Integer);
    procedure Set_Name(Value: WideString);
    { Methods & Properties }
    property Id: Integer read Get_Id write Set_Id;
    property Name: WideString read Get_Name write Set_Name;
    property Itemlist: IXMLItemlistType read Get_Itemlist;
  end;