Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > [ "Начинающим" ]
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 09.04.2014, 17:29
kasimka kasimka вне форума
Прохожий
 
Регистрация: 08.04.2014
Адрес: Брест
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию Заполнение TreeView по группам

Дано: таблица StringGrid (в ней содержиться названия классов: 5а,5б,6в,11а,9б и т.д.), дерево TreeView
Задача: добавить данные из таблицы в дерево
Условие: если в таблице есть хоть один 5 класс - должен быть создана корневой узел "5 классы" и в него добавлены все 5 классы, которые есть, и т.д. Классы с нестандартными именами должны быть добавлены в корневой узел "Другие классы".

Частично я реализовал это так:
Код:
...
var
  ClassesNodes: array[5..12] of TTreeNode;
...
  for i:=5 to 11 do
    for j:=1 to MainForm.StringGridClasses.RowCount-1 do
      begin
        if Pos(IntToStr(i),MainForm.StringGridClasses.Cells[1,j])=1 then
          if not ClassesNodes[i].IsVisible then
            begin
              ClassesNodes[i]:=TreeView.Items.Add(nil, IntToStr(i)+' классы');
              TreeView.Items.AddChild(ClassesNodes[i], MainForm.StringGridClasses.Cells[1,j]);
            end
          else 
            TreeView.Items.AddChild(ClassesNodes[i], MainForm.StringGridClasses.Cells[1,j]);
      end;
...
Классы 5-11 успешно добавлены по категориям:
-5 классы
---5 а
---5 б
---5 в
-10 классы
---10 а
---10 б
Но как добавить классы, которые не попали под категорию? Например, "секция карате", "группа продленного дня" и т.п.
Ответить с цитированием
  #2  
Старый 09.04.2014, 17:53
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Я бы здесь вообще не делал бы внешний цикл (тот который проходится по номерам классов). Просто проходишься одним циклом по строкам грида, вынимаешь из строки число и добавляешь в дерево в соответствующую категорию, а если не получилось вынуть число из строки - добавляешь в группу "Другие классы".
Осталось только написать функцию, которая пытается вынуть из начала строки число. Вот она:
Код:
function TryGetInt(const Str: String; out Int: Integer): Boolean;
var
  i: Integer;
begin
  i := 1;
  while (i <= Length(Str)) and (Str[i] in ['0'..'9']) do Inc(i);
  Result := TryStrToInt(Copy(Str, 1, i - 1), Int);
end;
Ответить с цитированием
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение:
kasimka (10.04.2014)
  #3  
Старый 09.04.2014, 18:02
Аватар для Alegun
Alegun Alegun вне форума
LMD-DML
 
Регистрация: 12.07.2009
Адрес: Богородское
Сообщения: 3,025
Версия Delphi: D7E
Репутация: 1834
По умолчанию

Оффтоп:
Интересно, а как добавляется напр. 11й класс, случайно к первоклашкам не попадает?

Можно проверять или если Pos возвращает ноль (цифирок нет в строке)
либо TryStrToInt не отвечает, то тогда эта строчка точно из другой оперы, в смысле это напр. "секция карате" и её надо определить в "Другие классы"
Ответить с цитированием
  #4  
Старый 09.04.2014, 18:08
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от Alegun
Оффтоп:
Интересно, а как добавляется напр. 11й класс, случайно к первоклашкам не попадает?
Ну моя функция TryGetInt добавит как и полагается - в группу 11-го класса, а у ТС, если бы внешний цикл у него начинался бы с первого класса, то именно так и было бы - типа опять в первый класс...
Ответить с цитированием
  #5  
Старый 09.04.2014, 21:03
kasimka kasimka вне форума
Прохожий
 
Регистрация: 08.04.2014
Адрес: Брест
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Цитата:
Сообщение от poli-smen
...добавляешь в дерево в соответствующую категорию...
В этом вся проблема: а как выйти на соответствующую категорию? Найти нужную ноду, куда методом AddChild без проблем можно добавить?
Внешний цикл именно для этого.
Индексация в дереве идет сверху вниз, заходя в каждую ветвь, а не по уровням (от поверхностных к более глубоким). По индексу на ноду не выйдешь (не получится быстро перебрать все корневые ноды), если их только не запоминать перед этим (массив нод мне понравился больше - кол-во корневых нод заранее известно и фиксированно). Организовывать поиск по имени ноды - лишнее время и циклы.
Я пробовал писать в цикле for кучу условий, которые позволяют обойтись одним циклом, но их выходило слишком много и компилятор начинало тошнить (Ошибка Access Violation).
Выход может заключаться в предварительной сортировке данных в таблице: от 5 к 11, а затем все остальное (1-4 классов нет в таблице)...

Последний раз редактировалось kasimka, 09.04.2014 в 21:16.
Ответить с цитированием
  #6  
Старый 09.04.2014, 22:17
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от kasimka
В этом вся проблема: а как выйти на соответствующую категорию? Найти нужную ноду, куда методом AddChild без проблем можно добавить?
Ноду получаем из того же массива ClassesNodes по индексу полученному функцией TryGetInt.
Цитата:
Сообщение от kasimka
Внешний цикл именно для этого.
Внешний цикл не нужен - TryGetInt вместо него
Цитата:
Сообщение от kasimka
Я пробовал писать в цикле for кучу условий, которые позволяют обойтись одним циклом, но их выходило слишком много и компилятор начинало тошнить (Ошибка Access Violation).
Ошибка Access Violation появляется не от того, что компилятор тошнит, а от того, что ты где-то делаешь неправомерное обращение к памяти.
Цитата:
Сообщение от kasimka
Выход может заключаться в предварительной сортировке данных в таблице: от 5 к 11, а затем все остальное (1-4 классов нет в таблице)...
Вот примерная реализация того о чём я писал (с моей функцией TryGetInt вместо внешнего цикла и без кучи условий):
Код:
procedure TMainForm.Button1Click(Sender: TObject);
var
  ClassesNodes: array[5..12] of TTreeNode;
  i, Int: Integer;
begin
  TreeView.Items.BeginUpdate;
  try
    TreeView.Items.Clear;
    
    for i := 5 to 11 do ClassesNodes[i] := TreeView.Items.AddChild(nil, IntToStr(i) + ' классы');
    ClassesNodes[12] := TreeView.Items.AddChild(nil, 'Другие классы');

    for i := 1 to StringGridClasses.RowCount - 1 do
    begin
      if not TryGetInt(StringGridClasses.Cells[1, i], Int) or (Int < 5) or (Int > 12) then Int := 12;
      TreeView.Items.AddChild(ClassesNodes[Int], StringGridClasses.Cells[1, i]);
    end;
  finally
    TreeView.Items.EndUpdate;
  end;
end;
Ответить с цитированием
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение:
kasimka (10.04.2014)
  #7  
Старый 10.04.2014, 13:41
kasimka kasimka вне форума
Прохожий
 
Регистрация: 08.04.2014
Адрес: Брест
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Теперь понял, спасибо! Но есть один недостаток: корневые узлы создаются вне зависимости от того есть ли в них необходимость, т.е. не должно быть пустых корневых узлов, в которых не будет дочерних узлов.

Access Violation вылазил при таком быдлокоде: при более трех вложенных(не вложенных тоже) условиях на проверку первого символа ошибка и случалась. По одному работали все. Поэтому я и сделал вывод, что компилятору не понравилось именно количество условий и их ветвлений внутри цикла for:
Код:
цикл for от 1 до кол-ва строк таблицы-1
начало цикла
если первый символ 5
  если нода из массива[5] невидима
    добавить корневую и присвоить массиву[5]
  иначе
    добавить дочернюю
иначе
  если первый символ 6
    если нода из массива[6] невидима
      добавить корневую и присвоить массиву[6]
    иначе
      добавить дочернюю
  иначе
...
       иначе
         если невидима нода из массива[12]
            добавить корневую и присвоить массиву[12]
         иначе
            добавить дочернюю
конец цикла

Последний раз редактировалось kasimka, 10.04.2014 в 13:53.
Ответить с цитированием
  #8  
Старый 10.04.2014, 14:03
Аватар для poli-smen
poli-smen poli-smen вне форума
Профессионал
 
Регистрация: 06.08.2012
Адрес: Кривой Рог
Сообщения: 1,791
Версия Delphi: Delphi 7, XE2
Репутация: 4415
По умолчанию

Цитата:
Сообщение от kasimka
Теперь понял, спасибо! Но есть один недостаток: корневые узлы создаются вне зависимости от того есть ли в них необходимость, т.е. не должно быть пустых корневых узлов, в которых не будет дочерних узлов.
Если пустые узлы не нужны - их легко можно удалить:
Код:
    // После заполнения удаляем пустые узлы:
    for i := Low(ClassesNodes) to High(ClassesNodes) do
    begin
      if not ClassesNodes[i].HasChildren then ClassesNodes[i].Delete;
    end;
  finally
    TreeView.Items.EndUpdate;
  end;
end;
Ответить с цитированием
Этот пользователь сказал Спасибо poli-smen за это полезное сообщение:
kasimka (10.04.2014)
  #9  
Старый 10.04.2014, 14:06
kasimka kasimka вне форума
Прохожий
 
Регистрация: 08.04.2014
Адрес: Брест
Сообщения: 7
Версия Delphi: Delphi 7
Репутация: 10
По умолчанию

Спасибо огромное!
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 21:08.


 

Сайт

Форум

FAQ

Соглашения

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2025