Клонирование компонента TStringGrid - PullRequest
1 голос
/ 06 октября 2009

Я начинаю изучать Delphi. Поэтому я решил написать приложение, как MS Excel с нуля. В новой форме Form1 я поместил компонент TPageControl, содержащий только 1 страницу. На этой странице я поместил TAdvStringGrid и TPanel с некоторыми кнопками (button1, button2) и меню Popup1 для определения некоторых действий в сетке, таких как копирование ячейки, копирование строки, удаление строки и т. Д. Для этого StringGrid также: Я определил некоторые свойства, такие как цвета, шрифты и т. Д. Я добавил панель инструментов с кнопкой в ​​основную форму, чтобы добавить дополнительные страницы в PageControl. Метод OnClick этой кнопки определяет два действия:
1) добавить новую Page2 в PageControl, и 2) добавить новую StringGrid в новую созданную Page2.

Эта новая (определенная во время выполнения) StringGrid, созданная на новой странице Tpagecontrol, должна наследовать (получать, копировать, клонировать, дублировать) свойства и методы родительского элемента StringGrid, уже определенные на первой странице во время разработки, и должна быть возможность вызвать меню PopUp1, как родительский элемент StringGrid. Как мы это делаем?

Вначале я подумал, что мне просто нужно скопировать свойства StringGrid с помощью assing (), но при использовании этого подхода всплывающее меню не появляется, если щелкнуть правой кнопкой мыши новый StringGrid ... и кнопки (button1). и button2) Form1 работают только с первым StringGrid, но не с новым добавленным. Я где-то читал, что для решения этой проблемы я мог бы дублировать компонент StringGrid, используя запись и чтение TMemoryStream (сохранить родительскую строковую сетку в потоке памяти, создать новую строковую сетку и затем прочитать этот поток памяти в новой созданной строковой сетке) так я и сделал, но когда программа выполняет этот метод клонирования компонента, я получаю ошибку во время выполнения. : - (

Я тщательно проверил справку. Ничего не найдено по этой теме. Кажется, что нет какой-либо библиотеки компонентов Delphi или сторонних компонентов, которые бы справились с такой задачей. Кто-нибудь может помочь, пожалуйста? : О)

Ответы [ 4 ]

2 голосов
/ 06 октября 2009

Я бы использовал tabcontrol вместо pagecontrol. Таким образом, вы получите несколько вкладок, но только одну страницу и сетку. Затем я создал бы некоторую структуру данных, чтобы хранить всю информацию о моей ячейке, и отобразил бы эту структуру в сетке. Таким образом, я могу иметь несколько структур, и позволить активной вкладке решать, какую структуру отображать. Вы также получите более слабую связь между вашим графическим интерфейсом и логикой, что упростит дальнейшие изменения. Например. если вам нужно ввести некоторые значения из другой электронной таблицы в ячейку текущей электронной таблицы, вы можете загрузить структуру и выбрать нужные значения. Нет необходимости создавать какой-либо графический интерфейс для второй таблицы.

Для компонента 3.party я рекомендую TMS FlexCell и TAdvSpreadGrid . Это даст вам большую часть того, что вам нужно.

1 голос
/ 06 октября 2009

Сложный выбор для ученика :), однако вам не нужно начинать потоковую передачу.

Посмотрите процедуру assign () для TPersistent, это процедура, которая вам необходима для простого копирования частей сетки. Например

for i := 0 to StringGrid1.RowCount - 1 do
  StringGrid2.Rows[i].Assign(StringGrid1.Rows[i]);

для легкого начала дифференцировать ваши сетки с помощью свойства Tag (StringGrid1.Tag: = 1, StringGrid2.Tag: = 2 и т. Д.

Всплывающее меню тоже довольно простое:

StringGrid2.popupmenu := stringGrid1.popupMenu Но тогда вы должны решить в Popup Routine, какая Сетка "Активна", что-то вроде

Tform1.popupMenuItem1Click(Sender: TObject)
  if Sender is TStringGrid then
    Case TStrigngGrid(Sender).Tag of
     1: // Grid 1
     2: // Grid 2

Вы можете использовать ту же простую логику с кнопками.

Как уже упоминалось, neftali лучше всего было бы поместить созданные сетки в ObjectList. Затем вы получите немного более сложную, но расширяемую:

Tform1.popupMenuItem1Click(Sender: TObject)
 var AGrid: TStringGrid;

  if Sender is TStringGrid then
     AGrid := MyListOfStringGrids[MyListOfStringGrids.IndexOf(Sender)];
       DoMenuItem1Stuff(AGrid);

Веселись

0 голосов
/ 06 октября 2009

"... и кнопки (button1 и button2) в Form1 работают только с первым StringGrid, но не с новым добавленным. Я где-то читал, что для решения этой проблемы ..."

Универсального метода для решения этой проблемы не существует. Delphi предлагает различные инструменты для ее решения.

  1. Вы можете создать список объектов (TObjectList), который содержит все StringGrid; На событии Button1 Click вы должны искать, какую сетку вы используете в данный момент. Например (BIS для других кнопок):

var  
  index:integer;  
  sg:TStringGrid;  
begin  
  ...  
  // search the active page   
  index := pageControl.ActivePageIndex;    //0, 1, 2,...  
  // USe this for search the StringGrid  
  sg := TStringGrid(OList.Objects[index]);  
  // the code that you have at the event bus woking with sg 
  // not stringgrid1, stringgrid2,...
  ...
  sg.Color :=      
  ...

Если вы не хотите использовать ObjectList, есть альтернативы. Вы можете использовать свойство Tag для всех StringGrids. Назначить 0, 1, 2, 3, ...
Извлеките индекс (активную страницу) и найдите TStringGrid, у которого свойство Tag имеет то же значение. Вы можете сделать это с помощью FindComponent . Первые методы лучше. ; -)

С уважением. П.Д .: Извините за мой плохой английский.

0 голосов
/ 06 октября 2009

Дорогие все, я пытаюсь выучить Delphi

Стиль Delphi - найти / создать / купить компонент, который выполняет свою работу, и использовать его во время разработки. Вы можете попробовать создать пользовательский компонент на основе сетки или использовать TFrame. См. Ссылки из Разработка пользовательских компонентов и файлы справки, поставляемые с Delphi.

Если вам действительно нужно динамически клонировать элемент управления, здесь - пример, который я нашел, который использует stream.ReadComponent.

...