Правильное ведение структуры проекта?

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Правильное ведение структуры проекта?

Сообщение BIT » 19.01.2018 14:23:07

Вот уже программирую (самоучка) больше 15 лет но никак не могу научится правильному введению структуры проекта(
Покажите пожалуйста ваши варианты ведения структуры проекта, просто у меня всегда получается каша в которой потом сложно даже самому разобраться)
Если можно видео урок, скрин, или расписать как это же все таки правильно делать.
Имею введу папки, unit, class, функции, структуры и т.п
В интернете этого ничего нет(
Аватара пользователя
BIT
новенький
 
Сообщения: 25
Зарегистрирован: 29.12.2017 15:44:58

Re: Правильное ведение структуры проекта?

Сообщение serbod » 19.01.2018 15:13:02

Это такое дело.. Пока новичок, оно нафиг не надо. А когда делаешь серьезные вещи, оно само приходит.

Есть официальный Object Pascal Style Guide - начни с него.
Аватара пользователя
serbod
постоялец
 
Сообщения: 341
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Правильное ведение структуры проекта?

Сообщение BIT » 20.01.2018 01:10:30

serbod писал(а):Это такое дело.. Пока новичок, оно нафиг не надо. А когда делаешь серьезные вещи, оно само приходит.

Есть официальный Object Pascal Style Guide - начни с него.

Спасибо большое ! А то надоело уже просто быдлокодить)) Сори за ворожение)

Добавлено спустя 25 минут 7 секунд:
Прочитал от начало и до конца но это я соблюдаю с самого начала а что нет ctrl+D
Вообщем как я понимаю нет никаких стандартов по введению проекта, под каждый проект своя логика .
Аватара пользователя
BIT
новенький
 
Сообщения: 25
Зарегистрирован: 29.12.2017 15:44:58


Re: Правильное ведение структуры проекта?

Сообщение BIT » 20.01.2018 10:13:10

Вот например я так пишу всегда, Это пример главного Unit.
Достаточно понятен код или стоит изменить свой стиль написания кода?
Код: Выделить всё
{ TForm1 }
//Откроем проект через диалог - Вызываем функцию  Вывод каталога в TreeView1
procedure TForm1.ToolButton1Click(Sender: TObject);
begin
  MenuItem12.Click;
end;
//Сохранить  ToolBar1
procedure TForm1.ToolButton3Click(Sender: TObject);
begin
  MenuItem13.Click;
end;
//Поиск  ToolButton4
procedure TForm1.ToolButton4Click(Sender: TObject);
begin
  MenuItem6.Click;
end;
//Кнопка собрать на ToolBar1
procedure TForm1.ToolButton5Click(Sender: TObject);
begin
  MenuItem33.Click;
end;
//Дизайнер формы добавить имя компонента в TreeView2 при создание компонента
procedure TForm1.ToolButton6Click(Sender: TObject);
begin
  Decorat.DecoratorCreateComponent('Edit');
  TreeView2.Items.AddChild(TreeView2.Items.Item[0],
    'Edit' + IntToStr(TreeView2.Items.Item[0].Count)).ImageIndex := 2394;
end;
//Отмена  ToolBar1
procedure TForm1.ToolButton7Click(Sender: TObject);
begin
  MenuItem37.Click;
end;
//Вернуть  ToolBar1
procedure TForm1.ToolButton8Click(Sender: TObject);
begin
  MenuItem38.Click;
end;
//При создание фоормы
procedure TForm1.FormCreate(Sender: TObject);
begin
  DoubleBuffered := True;
  //Загрузим настроки из INI приложения при старте программы
  Form1.Width := StrToInt(INIRead('Otions.ini', 'Form', 'Form1.Width',
    IntToStr(Form1.Width)));
  Form1.Height := StrToInt(INIRead('Otions.ini', 'Form', 'Form1.Height',
    IntToStr(Form1.Height)));
  Form1.Left := StrToInt(INIRead('Otions.ini', 'Form', 'Form1.Left',
    IntToStr(Form1.Left)));
  Form1.Top := StrToInt(INIRead('Otions.ini', 'Form', 'Form1.Top', IntToStr(Form1.Top)));
  Panel1.Width := StrToInt(INIRead('Otions.ini', 'Panel1', 'Panel1.Width',
    IntToStr(Panel1.Width)));
  {Свойста проекта}
  //Запускать ли игру Fals True
  ValueListEditor1.Strings[0] := ('Запускать L2.exe=True');
  // ValueListEditor1.ItemProps[0].EditStyle:= esPickList;
  ValueListEditor1.ItemProps[0].PickList.Add('True');
  ValueListEditor1.ItemProps[0].PickList.Add('False');
  //Путь до игры
  ValueListEditor1.ItemProps[1].EditStyle := esEllipsis;
  ValueListEditor1.ItemProps[1].ReadOnly := True;
  //Загрузить настройки проекта при старте
  ValueListEditor1.Strings[1] := ('Путь к L2.exe=');
  ValueListEditor1.Refresh;
  ValueListEditor1.AutoSizeColumn(0);
  //Дизайнер
  Decorat := TDecorat.Create();
end;
//При загрузки формы
procedure TForm1.FormShow(Sender: TObject);
begin
  LoadComponent();
  hltSynedit1 := TSynFacilComplet.Create(self);  //my highlighter
  Synedit1.Highlighter := hltSynedit1;  //optional if we are going to use SelectEditor()
  hltSynedit1.LoadFromFile('Log.xml');  //load syntax
  hltSynedit1.SelectEditor(Synedit1);  //assign to editor
end;
//Открыть окно создания проекта
procedure TForm1.MenuItem10Click(Sender: TObject);
begin
  Form4.ShowModal;
end;
//Откроем проект через диалог - Вызываем функцию  Вывод каталога в TreeView1
procedure TForm1.MenuItem12Click(Sender: TObject);
var
  g: integer;
begin
  if OpenDialog1.Execute then
    // if ExtractFileName(OpenDialog1.FileName) = 'Projects.luse' then
  begin
    TreeViewObject := TStringList.Create;
    for i := 0 to TreeViewObject.Count - 1 do
    begin
      if TreeView1.Items.Item[i].Data <> nil then
        Dispose(PString(TreeView1.Items.Item[i].Data));
    end;
    TreeView1.Items.Clear;
    FilePathToTreeNode(TreeView1, nil, ExtractFilePath(OpenDialog1.FileName) +
      '', True);
    with TStringList.Create do
    begin
      LoadFromFile(OpenDialog1.FileName);
      for g := 0 to Count - 1 do
        ValueListEditor1.Cells[1, g + 1] := Strings[g];
    end;
    ProjectDir := ExtractFilePath(OpenDialog1.FileName);
    ValueListEditor1.Enabled := True;
  end;
end;
//Сохранить в файл Активный  SynEdit
procedure TForm1.MenuItem13Click(Sender: TObject);
begin
  if ExtendedNotebook1.ControlCount <> 0 then
  begin
    SynEditComadeTab('SaveFile', '');
    ExtendedNotebook1.ActivePage.ImageIndex := 1349;
    // ToolButton3.ImageIndex := 772;
  end;
end;
//Закрыть вкладку
procedure TForm1.MenuItem16Click(Sender: TObject);
begin
  SynEditComadeTab('CloseTab', '');
end;
//Удалить файл
procedure TForm1.MenuItem21Click(Sender: TObject);
begin
  DeleteFile(string(TreeView1.Selected.Data));
  TreeView1.Selected.Free;
end;
//Копировать
procedure TForm1.MenuItem22Click(Sender: TObject);
begin
  SynEditComadeTab('Copy', '');
end;
//Вставить
procedure TForm1.MenuItem23Click(Sender: TObject);
begin
  SynEditComadeTab('Paste', '');
end;
//Выделить все
procedure TForm1.MenuItem24Click(Sender: TObject);
begin
  SynEditComadeTab('SelectAll', '');
end;
//Удалить выделеное
procedure TForm1.MenuItem25Click(Sender: TObject);
begin
  SynEditComadeTab('ClearSelection', '');
end;
//Окно создания шаблона кода
procedure TForm1.MenuItem26Click(Sender: TObject);
begin
  Form2.ShowModal;
end;
//Создать папку  в   TreeView1
procedure TForm1.MenuItem28Click(Sender: TObject);
var
  NodeCaption: string; //для получения заголовка нового узла
  NewNode: TTreeNode; //для создания нового узла
begin
  //сначала очистим заголовок:
  NodeCaption := '';
  //теперь, если пользователь не ввел заголовок нового узла, выходим:
  if not InputQuery('Ввод заголовка',
    'Введите заголовок раздела', NodeCaption) then
    exit;
  //если мы здесь, то заголовок есть. создаем родительский узел:
  NewNode := TreeView1.Items.Add(nil, NodeCaption);
  //присваиваем ему картинку под индексом 0:
  //папка
  NewNode.ImageIndex := 1108;
  NewNode.SelectedIndex := 1108;
end;
//Создать файл в   TreeView1
procedure TForm1.MenuItem29Click(Sender: TObject);
var
  NodeCaption: string;
  NewNode: TTreeNode;
  u: Pointer;
begin
  PageControl1.ActivePageIndex := 0;
  //Активировать вкладку редактор
  if ExtractFileExt(string(TreeView1.Selected.Data)) = '' then
  begin
    NodeCaption := '';
    if not InputQuery('Новый класс',
      'Введите имя класса без расширения', NodeCaption) then
      exit;
    if NodeCaption > '' then
    begin
      NewNode := TreeView1.Items.AddChild(TreeView1.Selected, NodeCaption);
      if NewNode.Parent = nil then
        NewNode.ImageIndex := 0
      //Файл
      else
      begin
        if (NewTab(ExtractFileName(NodeCaption)) = True) then
        begin
          SynEditComadeTab('Hint', string(TreeView1.Selected.Data) +
            '' + NodeCaption + '.uc');
          SynEditComadeTab('SaveFile', '');
          SynEditComadeTab('LoadFile', string(TreeView1.Selected.Data) +
            '' + NodeCaption + '.uc');
          NewNode.Data := nil;
          string(u) := string(TreeView1.Selected.Data) + '' + NodeCaption + '.uc';
          NewNode.Data := u;
          NewNode.ImageIndex := 804;
          NewNode.SelectedIndex := 785;
          TreeView1.Selected.Expand(True);
          NewNode.MakeVisible;
          TreeView1.Selected := NewNode;
        end;
      end;
    end;
  end;
end;
//Редактирование компонента
procedure TForm1.MenuItem30Click(Sender: TObject);
begin
  //ShowMessage((SenderToolButton as TToolButton).Caption);
  if (ExtractFileExt((SenderToolButton as TToolButton).Caption) > '') and
    (NewTab(ExtractFileName((SenderToolButton as TToolButton).Caption)) = True) then
  begin
    SynEditComadeTab('LoadFile', (SenderToolButton as TToolButton).Caption);
    SynEditComadeTab('Hint', (SenderToolButton as TToolButton).Caption);
  end;
end;
//Удалить компонент
procedure TForm1.MenuItem31Click(Sender: TObject);
begin
  case QuestionDlg('Удалить компонент',
      'Вы точно хотите удалить выбронный компонент?',
      mtCustom, [mrYes, 'Да', mrNo, 'Нет', 'IsDefault'], '') of
    mrYes:
    begin
      if ExtractFileExt((SenderToolButton as TToolButton).Caption) > '' then
      begin
        DeleteDirectory(ExtractFilePath(
          (SenderToolButton as TToolButton).Caption), False);
        (SenderToolButton as TToolButton).Free;
        QuestionDlg('Удален',
          'Компонент удален безвозвратно!',
          mtCustom, [mrOk, 'Ок'], '');
      end;
    end;
  end;
end;
//Кнопка собрать копиляция в меню
procedure TForm1.MenuItem33Click(Sender: TObject);
var
  CompilT: CompilThread;
begin
  //PageControl1.ActivePageIndex:=0;//Активировать вкладку редактор
  if TreeView1.Items.Count <> 0 then
  begin
    if GroupBox1.Visible = False then
    begin
      GroupBox1.Visible := True;
      MenuItem10.Checked := True;
    end;
    Form1.SynEdit1.Color := clWhite;
    CompilT := CompilThread.Create(True);
    CompilT.FreeOnTerminate := True;
    CompilT.Priority := tpLower;
    CompilT.Start;
    MenuItem13.Click;
    Form1.ToolButton5.Enabled := False;
    Timer1.Enabled := True;
    min := 0;
    sec := 0;
    GroupBox1.Height := 120;
    //Удалить маркер с ошибкой
    if (ActiveControl is TSynEdit) then
    begin
      for i := 0 to TSynEdit(ActiveControl).Lines.Count - 1 do
        TSynEdit(ActiveControl).Marks.ClearLine(i);
      TheLine := -1;
      TSynEdit(ActiveControl).Invalidate;
    end;
  end
  else
  begin
    SynEdit1.Lines[0] :=
      'Для компиляции проекта создайте его или откройте!';
    GroupBox1.Height := 120;
  end;
end;
//Форматирование кода
procedure TForm1.MenuItem34Click(Sender: TObject);
var
  i: integer;
  s: string;
  SRE: TStringList;
  Te: TSynEdit;
begin
  if Assigned(ExtendedNotebook1.ActivePage) then
  begin
    Te := SynEditComadeTab('SenderSynEdit', '');
    SRE := TStringList.Create;
    with TStringList.Create do
    begin
      Text := Te.Text;
      for i := 0 to Count - 1 do
      begin
        s := trim(strings[i]);
        //Удалить Где встречается //
        //  system.Delete(s, Pos('//', s), Length(s));
        //  system.Delete(s, Pos('debug', s), Length(s));
        // удалить лишние пробелы и табы
        while (s <> '') and (pos('  ', s) <> 0) do
          s := StringReplace(s, '  ', ' ', [rfreplaceall]);
        s := StringReplace(s, #9, ' ', [rfReplaceAll]);
        s := #9 + s;
        s := StringReplace(s, '}', #13'}'#13, [rfReplaceAll]);
        s := StringReplace(s, '{', #13'{'#13, [rfReplaceAll]);
        s := StringReplace(s, #9'function', #13'function', [rfReplaceAll]);
        s := StringReplace(s, #9'local', ' local', [rfReplaceAll]);
        s := StringReplace(s, #9'class', 'class', [rfReplaceAll]);
        s := StringReplace(s, #9'var', '  var', [rfReplaceAll]);
        if (Trim(strings[i]) = '') then
        else
        begin
          SRE.add(s);
        end;
      end;
    end;
    Te.Clear;
    Te.Text := SRE.Text;
    SRE.Free;
    ToolButton3.ImageIndex := 770;
    ExtendedNotebook1.ActivePage.ImageIndex := 770;
  end;
end;
//Копировать имя файлка вкладки в бувер
procedure TForm1.MenuItem35Click(Sender: TObject);
begin
  Clipboard.AsText := ExtendedNotebook1.ActivePage.Caption;
end;
//Отмена Menu
procedure TForm1.MenuItem37Click(Sender: TObject);
begin
  if ExtendedNotebook1.ControlCount <> 0 then
    SynEditComadeTab('Undo', '');
end;
//Повтор Menu
procedure TForm1.MenuItem38Click(Sender: TObject);
begin
  if ExtendedNotebook1.ControlCount <> 0 then
    SynEditComadeTab('Redo', '');
end;
//Копировать путь к файлу  вкладки
procedure TForm1.MenuItem40Click(Sender: TObject);
begin
  Clipboard.AsText := ExtendedNotebook1.ActivePage.Hint;
end;
//Закоментировать строку
procedure TForm1.MenuItem43Click(Sender: TObject);
begin
  if (ActiveControl is TSynEdit) then
  begin
    TSynEdit(ActiveControl).LineText := '//' + TSynEdit(ActiveControl).LineText;
  end;
end;
//Оптимизировать все
procedure TForm1.MenuItem50Click(Sender: TObject);
begin
  if Assigned(ExtendedNotebook1.ActivePage) then
    Optimization.Optimize.Full(Form1.SynEditComadeTab('SenderSynEdit', ''));
end;
//Открыть XdatEditor
procedure TForm1.MenuItem52Click(Sender: TObject);
var
  P: TProcessUTF8;
begin
  P := TProcessUTF8.Create(nil);
  P.ShowWindow := swoShow;
  P.Executable := 'ProgramXdatEditorXdatEditor.exe';
  P.Execute;
end;
//Вырезать
procedure TForm1.MenuItem53Click(Sender: TObject);
begin
  if ExtendedNotebook1.ControlCount <> 0 then
    SynEditComadeTab('Cut', '');
end;
//Закрыть все вкладки кроме этой
procedure TForm1.MenuItem54Click(Sender: TObject);
begin
  SynEditComadeTab('CloseFullTab', '');
end;
//Поиск MenuItem
procedure TForm1.MenuItem55Click(Sender: TObject);
begin
  MenuItem6.Click;
end;
//Открыть форму поиска
procedure TForm1.MenuItem6Click(Sender: TObject);
begin
  Form3.Show;
  if (ActiveControl is TSynEdit) then
  begin
    Form3.ComboBox1.Text := TSynEdit(ActiveControl).SelText;
  end;
end;
//Показать скрыть окно проекта
procedure TForm1.MenuItem7Click(Sender: TObject);
begin
  if Panel1.Visible = False then
  begin
    Panel1.Visible := True;
  end
  else
  begin
    Panel1.Visible := False;
  end;
end;
//Показать скрыть окно сообщения
procedure TForm1.MenuItem8Click(Sender: TObject);
begin
  if GroupBox1.Height = 0 then
  begin
    GroupBox1.Height := 120;
  end
  else
  begin
    GroupBox1.Height := 0;
  end;
end;
//открыть файл с ошибкой  + поиск текста в файла (Log)
procedure TForm1.SynEdit1DblClick(Sender: TObject);
begin
  i := 0;
  PageControl1.ActivePageIndex := 0;
  //Активировать вкладку редактор
  if (Trim(ExtractWord(1, SynEdit1.LineText, ['|'])) = 'ПРОСМОТР') then
  begin
    if ExtendedNotebook1.PageCount > 0 then
      for i := 0 to ExtendedNotebook1.PageCount - 1 do
        if Trim(ExtractWord(2, SynEdit1.LineText, ['|', '('])) =
          Trim(ExtendedNotebook1.Page[i].Hint) then
        begin
          ExtendedNotebook1.Pages[i].TabVisible := True;
          ExtendedNotebook1.ActivePageIndex := i;
          SynEditComadeTab('LineIndex',
            Trim(ExtractWord(2, SynEdit1.LineText, ['(', ')'])));
          exit;
        end;
    if (NewTab(ExtractFileName(Trim(ExtractWord(2, SynEdit1.LineText, ['|', '('])))) =
      True) then
    begin
      SynEditComadeTab('Hint', Trim(ExtractWord(2, SynEdit1.LineText, ['|', '('])));
      SynEditComadeTab('LoadFile', Trim(ExtractWord(2, SynEdit1.LineText, ['|', '('])));
      SynEditComadeTab('LineIndex', Trim(ExtractWord(2, SynEdit1.LineText, ['(', ')'])));
    end;
  end;
  //Поиск текста в файле результат открыть файл по клику (Log)
  if (Trim(ExtractWord(1, SynEdit1.LineText, ['|'])) = 'Файл') then
  begin
    if ExtendedNotebook1.PageCount > 0 then
      for i := 0 to ExtendedNotebook1.PageCount - 1 do
        if Trim(ExtractWord(2, SynEdit1.LineText, ['|', '*'])) =
          Trim(ExtendedNotebook1.Page[i].Hint) then
        begin
          ExtendedNotebook1.Pages[i].TabVisible := True;
          ExtendedNotebook1.ActivePageIndex := i;
          //SynEditComadeTab('LineIndex',
          //  Trim(ExtractWord(2, SynEdit1.LineText, ['(', ')'])));
          exit;
        end;
    if (NewTab(ExtractFileName(Trim(ExtractWord(2, SynEdit1.LineText, ['|', '*'])))) =
      True) then
    begin
      SynEditComadeTab('Hint', Trim(ExtractWord(2, SynEdit1.LineText, ['|', '*'])));
      SynEditComadeTab('LoadFile', Trim(ExtractWord(2, SynEdit1.LineText, ['|', '*'])));
      //SynEditComadeTab('LineIndex', Trim(ExtractWord(2, SynEdit1.LineText, [' ', ':'])));
    end;
  end;
end;
// Расцветка лога
procedure TForm1.SynEdit1SpecialLineColors(Sender: TObject; Line: integer;
  var Special: boolean; var FG, BG: TColor);
begin
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] = 'Готово!') then
  begin
    Special := True;
    BG := $0072F968;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] =
    'Компиляция проекта: ...') then
  begin
    Special := True;
    BG := clYellow;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] = 'Запуск игры...') then
  begin
    Special := True;
    BG := clAqua;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] =
    'Файл скомпилирован в папку проекта!') then
  begin
    Special := True;
    BG := $0072F968;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] = 'Готово!') then
  begin
    Special := True;
    BG := $0072F968;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] =
    'Для компиляции проекта создайте его или откройте!') then
  begin
    Special := True;
    BG := clYellow;
  end;
  if ((line mod 1) = 0) and (SynEdit1.Lines[0] =
    'Ошибка: Неудалось скомпилировать файл..') then
  begin
    Special := True;
    BG := clred;
    FG := clWhite;
  end;
end;
//Таймер копиляции
procedure TForm1.Timer1Timer(Sender: TObject);
begin
  sec := sec + 1;
  if sec = 60 then
  begin
    min := min + 1;
    sec := 0;
  end;
  if sec < 10 then
    secs := '0' + IntToStr(sec);
  if sec > 9 then
    secs := IntToStr(sec);
  if min < 10 then
    mins := '0' + IntToStr(min);
  if min > 9 then
    mins := IntToStr(min);
end;
//Обновим выброный элемент анимация визуальный редатор
procedure TForm1.Timer2Timer(Sender: TObject);
begin
  Decorat.ImgUpdate();
end;
//Создать кнопкку в визуальном редакторе
procedure TForm1.ToolButton10Click(Sender: TObject);
begin
  Decorat.DecoratorCreateComponent('Button');
  TreeView2.Items.AddChild(TreeView2.Items.Item[0],
    'Button' + IntToStr(TreeView2.Items.Item[0].Count)).ImageIndex := 2394;
end;
//Сохранить настроки в INI приложения при закрытие программы
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: boolean);
begin
  //    hltSynedit1.UnSelectEditor;   //release editor (only necessary if we are to call to SelectEditor(), again)
  //hltSynedit1.Free;  //destroy the highlighter
  INIWrite('Otions.ini', 'Form', 'Form1.Width', IntToStr(Form1.Width));
  INIWrite('Otions.ini', 'Form', 'Form1.Height', IntToStr(Form1.Height));
  INIWrite('Otions.ini', 'Form', 'Form1.Left', IntToStr(Form1.Left));
  INIWrite('Otions.ini', 'Form', 'Form1.Top', IntToStr(Form1.Top));
  INIWrite('Otions.ini', 'Panel1', 'Panel1.Width', IntToStr(Panel1.Width));
end;
//Обновить  TObject для автозапонения
procedure TForm1.ExtendedNotebook1Change(Sender: TObject);
begin
  if (ActiveControl is TSynEdit) then
  begin
    hlt.SelectEditor(TSynEdit(ActiveControl));  //assign to editor
  end;
end;
//Смысл в том, что хотим выделить таб, при нажатии на нем правой клавишей мыши (вызов меню)
procedure TForm1.ExtendedNotebook1MouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: integer);
var
  SelectPoint: TPoint;
begin
  SelectPoint.x := X;
  SelectPoint.y := Y;
  ExtendedNotebook1.ActivePageIndex := ExtendedNotebook1.IndexOfPageAt(SelectPoint);
end;
//При клике на элемент в  TreeView1 загрузить файл в таб
procedure TForm1.TreeView1DblClick(Sender: TObject);
var
  i: integer;
begin
  PageControl1.ActivePageIndex := 0;
  //Активировать вкладку редактор
  if ExtendedNotebook1.PageCount > 0 then
    for i := 0 to ExtendedNotebook1.PageCount - 1 do
      if string(TreeView1.Selected.Data) = ExtendedNotebook1.Page[i].Hint then
      begin
        ExtendedNotebook1.Pages[i].TabVisible := True;
        ExtendedNotebook1.ActivePageIndex := i;
        exit;
      end;
  try
    if (ExtractFileExt(trim(string(TreeView1.Selected.Data))) > '') then
      if (NewTab(ExtractFileName(string(TreeView1.Selected.Data))) = True) then
      begin
        SynEditComadeTab('Hint', string(TreeView1.Selected.Data));
        SynEditComadeTab('LoadFile', string(TreeView1.Selected.Data));
      end;
  finally
  end;
  // ShowMessage(string(TreeView1.Selected.Data));
end;
//Указать путь к игре в редакторе проета
procedure TForm1.ValueListEditor1ButtonClick(Sender: TObject; aCol, aRow: integer);
begin
  if aCol = 1 then
    if OpenDialog2.Execute then
      if ExtractFileName(OpenDialog2.FileName) = 'L2.exe' then
        ValueListEditor1.Strings[1] := ('Путь к L2.exe=' + OpenDialog2.FileName);
end;
//Сохранить настройки  проекта
procedure TForm1.ValueListEditor1EditingDone(Sender: TObject);
var
  info: TStringList;
begin
  info := TStringList.Create;
  info.Add(Form1.ValueListEditor1.Cells[1, 1]);
  info.Add(Form1.ValueListEditor1.Cells[1, 2]);
  info.SaveToFile(ProjectDir + 'Projects.le');
  Application.ProcessMessages;
end;
//Настройки визуального редактора компонента
procedure TForm1.ValueListEditor2KeyUp(Sender: TObject; var Key: word;
  Shift: TShiftState);
begin
  if Decorat.ButtonActive <> nil then
  begin
    Decorat.ButtonActive.Caption := ValueListEditor2.Cells[1, 2];
    Decorat.ImageUpdate.Width := StrToInt(Form1.ValueListEditor2.Cells[1, 4]);
    Decorat.ImageUpdate.Height := StrToInt(Form1.ValueListEditor2.Cells[1, 5]);
    Decorat.ImageUpdate.Top := StrToInt(Form1.ValueListEditor2.Cells[1, 6]);
    Decorat.ImageUpdate.Left := StrToInt(Form1.ValueListEditor2.Cells[1, 7]);
  end;
end;
//Вывод каталога в TreeView1 Пример:
//FilePathToTreeNode(TreeView1, nil, 'Папка' + '', True);
procedure TForm1.FilePathToTreeNode(aTreeView: TTreeView; aRoot: TTreeNode;
  Path: string; Recurse: boolean);
var
  NewNode: TTreeNode;
  SRec: TSearchRec;
begin
  if FindFirst(Path + '*.*', SysUtils.faAnyFile, SRec) = 0 then
    repeat
      if (sRec.Name = '.') or (sRec.Name = '..') then
        Continue;
      begin
        TreeViewObject.Add(PChar(Path + srec.Name));
        NewNode := aTreeView.Items.AddChildObject(aRoot, SRec.Name,
          PChar(TreeViewObject.Strings[i]));
        Inc(i);
      end;
      if Recurse and ((srec.Attr and SysUtils.faDirectory) <> 0) then
      begin
        FilePathToTreeNode(aTreeView, NewNode, Path + srec.Name + '', True);
        //папка
        NewNode.ImageIndex := 1108;
        NewNode.SelectedIndex := 1108;
      end
      else
      begin
        //Файл
        NewNode.ImageIndex := 804;
        NewNode.SelectedIndex := 785;
      end;
    until FindNext(SRec) <> 0;
  FindClose(SRec);
end;
//Запись в INI Пример:
//INIWrite('Otions.ini','Section', 'Key','тест');
procedure TForm1.INIWrite(FileName: string; Section: string; Key: string;
  Param: string);
begin
  if (FileExists(FileName)) then
  begin
    Inif := TINIFile.Create(FileName);
    INiF.WriteString(Section, Key, Param);
  end;
end;
//Чтение из INI Пример:
//INIRead('Otions.ini','Section', 'Key','тест');
function TForm1.INIRead(FileName: string; Section: string; Key: string;
  Param: string): string;
begin
  if (FileExists(FileName)) then
  begin
    Inif := TINIFile.Create(FileName);
    Result := INiF.ReadString(Section, Key, Param);
  end;
end;
//Создание вкладки
function TForm1.NewTab(TabCaption: string): boolean;
begin
  Tab := TTabSheet.Create(self);
  Tab.PageControl := ExtendedNotebook1;
  Tab.Caption := TabCaption;
  Tab.PageControl.ActivePage := Tab;
  Tab.ImageIndex := 1349;
  Tab.Visible := False;
  Tab.OnShow := @rTabShow;
  rSynEdit := TSynEdit.Create(Tab);
  rSynEdit.Parent := Tab;
  rSynEdit.Align := alClient;
  rSynEdit.OnUTF8KeyPress := @rUTF8KeyPress;
  rSynEdit.OnChange := @rChange;
  rSynEdit.OnMouseMove := @rMouseMove;
  rSynEdit.OnKeyUp := @rKeyUp;
  rSynEdit.OnKeyPress := @rKeyPress;
  rSynEdit.OnClick := @rOnClick;
  rSynEdit.OnSpecialLineMarkup := @GetLineColor;
  rSynEdit.RightEdge := 0;
  rSynEdit.BorderStyle := bsNone;
  rSynEdit.Color := clWhite;
  rSynEdit.Font := SynEdit1.Font;
  rSynEdit.MouseOptions := SynEdit1.MouseOptions;
  rSynEdit.Options := SynEdit1.Options;
  rSynEdit.Options2 := SynEdit1.Options2;
  rSynEdit.Text := 'class ' + TabCaption + ' extends UICommonAPI;' +
    #13#13#13 + 'defaultproperties{}';
  rSynEdit.Name := 'syed' + IntToStr(ExtendedNotebook1.PageCount);
  rSynEdit.PopupMenu := PopupMenu3;
  hlt := TSynFacilComplet.Create(self);  //my highlighter
  rSynEdit.Highlighter := hlt;  //optional if we are going to use SelectEditor()
  hlt.LoadFromFile('UnrealScript.xml');  //load syntax
  hlt.SelectEditor(rSynEdit);  //assign to editor
  hlt.IconList := ImageList1;
  Result := True;
  Tab.Visible := True;
end;
//Команды выполнения для компонента TSynEdit и PageControl1
function TForm1.SynEditComadeTab(Comade, Param: string): TSynEdit;
var
  syed: TSynEdit;
  x1, x2, i, pageindex: integer;
begin
  //Проверка существования Page TSynEdit
  if Assigned(ExtendedNotebook1.ActivePage) then
  begin
    syed := TSynEdit(ExtendedNotebook1.ActivePage.Components[0]);
    // Если все ОК выполняем команды
    case Comade of
      //Тут хранится путь к файлу
      'Hint': ExtendedNotebook1.ActivePage.Hint := Param;
      //Загрузим текст
      'Text': syed.Text := Param;
      //Загрузим текст из файла
      'LoadFile': syed.Lines.LoadFromFile(UTF8ToSys(Param));
      //Сохраним текст в файл
      'SaveFile': syed.Lines.SaveToFile(UTF8ToSys(ExtendedNotebook1.ActivePage.Hint));
      //Вставить текст в позицию курсора
      'SelText': syed.SelText := Param;
      //Перейти на Index строки
      'LineIndex':
      begin
        syed.TopLine := StrToInt(Param) - 10;
        //x1 := PosEx(Trim(syed.Lines[StrToInt(Param)]), Trim(syed.Text));
        //x2 := PosEx(Trim(syed.Lines[StrToInt(Param)]), Trim(syed.Text)) +length(Trim(syed.Lines[StrToInt(Param)]));
        //syed.SelStart := x1;
        //syed.SelEnd := x2;
        syed.CaretY := StrToInt(Param);
        // syed.SetFocus;
        m := TSynEditMark.Create(syed);
        m.Line := StrToInt(Param);
        m.ImageList := ImageList1;
        m.ImageIndex := 1526;
        m.Visible := True;
        syed.Marks.Add(m);
        TheLine := StrToInt(Param);
        syed.Invalidate;
      end;
      //Копировать
      'Copy': syed.CopyToClipboard;
      //Вставить
      'Paste': syed.PasteFromClipboard;
      //Вырезать
      'Cut': syed.CutToClipboard;
      //Выделить все
      'SelectAll': syed.SelectAll;
      //Удалить выделеное
      'ClearSelection': syed.ClearSelection;
      //Отмена
      'Undo': syed.Undo;
      //Вернуть
      'Redo': syed.Redo;
      //Отправим Sender SynEdit
      'SenderSynEdit': Result := syed;
      //Закрыть активную вкладку
      'CloseTab':
      begin
        ExtendedNotebook1.ActivePage.Free;
      end;
      //Закрыть все табы кроме ативного
      'CloseFullTab':
      begin
        pageindex := ExtendedNotebook1.ActivePageIndex;
        for i := ExtendedNotebook1.PageCount - 1 downto 0 do
          if pageindex <> i then
            ExtendedNotebook1.Page[i].Free;
      end;
      else
        ShowMessage(Comade + 'Comade Не известнена!');
    end;
  end;
end;
//SynFacilComplet
procedure TForm1.rKeyUp(Sender: TObject; var Key: word; Shift: TShiftState);
begin
  hlt.KeyUp(Sender, Key, Shift);
end;
//SynFacilComplet
procedure TForm1.rUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
begin
  if (ActiveControl is TSynEdit) then
  begin
    hlt.SelectEditor(TSynEdit(ActiveControl));  //assign to editor
    hlt.UTF8KeyPress(Sender, UTF8Key);
  end;
end;
//Загрузить компоненты
procedure TForm1.LoadComponent();
var
  Pic: TPortableNetworkGraphic;
  i: integer;
  PascalFiles, FilePathComponent: TStringList;
begin
  ImageList2.Clear;
  PascalFiles := TStringList.Create;
  FilePathComponent := TStringList.Create;
  try
    FindAllFiles(PascalFiles, 'components', '*.lc', True);
    // ... тут читаем файл в StringList:
    if PascalFiles.Text > '' then
      Form1.ToolBar2.ButtonList.Clear;
    for i := 0 to PascalFiles.Count - 1 do
    begin
      ToolBar2.ButtonList.Add(TToolButton.Create(Self));
      FilePathComponent.LoadFromFile(PascalFiles.Strings[i]);
      Pic := TPortableNetworkGraphic.Create;
      if FileExists(ExtractFilePath(PascalFiles.Strings[i]) + 'icon.png') = True then
      begin
        Pic.LoadFromFile(ExtractFilePath(PascalFiles.Strings[i]) + 'icon.png');
        ImageList2.Add(Pic, nil);
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].Hint := FilePathComponent.Strings[0];
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].Caption := PascalFiles.Strings[i];
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].Parent := ToolBar2;
        ToolBar2.Images := ImageList2;
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].ImageIndex := i;
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].PopupMenu := ComponentMenu;
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].OnMouseDown := @rToolMouseDown;
        ToolBar2.Buttons[ToolBar2.ButtonCount - 1].OnClick := @rToolOnClick;
      end;
      Pic.Free;
    end;
  finally
    PascalFiles.Free;
    FilePathComponent.Free;
  end;
end;
//Получаем  Sender и заносим в переменную SenderToolButton
procedure TForm1.rToolMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: integer);
begin
  SenderToolButton := Sender;
end;
//Обработка нажатия на компонент
procedure TForm1.rToolOnClick(Sender: TObject);
var
  FilePathComponent: TStringList;
begin
  if ExtendedNotebook1.ControlCount <> 0 then
  begin
    FilePathComponent := TStringList.Create;
    FilePathComponent.LoadFromFile((Sender as TToolButton).Caption);
    FilePathComponent.Strings[0] := '';
    SynEditComadeTab('SelText', FilePathComponent.Text);
    FilePathComponent.Free;
  end;
end;
//Обновить иконку не сохранено
procedure TForm1.rChange(ASender: TObject);
begin
  ToolButton3.ImageIndex := 770;
  ExtendedNotebook1.ActivePage.ImageIndex := 770;
end;
//Обновляем ссылку на   SynPluginSyncroEdit1
procedure TForm1.rMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
begin
  //(Sender as TWinControl).SetFocus;
  if (ActiveControl is TSynEdit) then
  begin
    SynPluginSyncroEdit1.Editor := TSynEdit(ActiveControl);
  end;
end;
//При загрузке Tab
procedure TForm1.rTabShow(Sender: TObject);
var
  MyObj: TComponent;
  SynMarkup: TSynEditMarkupHighlightAllCaret;
begin
  MyObj := ExtendedNotebook1.ActivePage.Components[0];
  TSynEdit(MyObj).SetFocus;
  SynMarkup := TSynEditMarkupHighlightAllCaret(
    TSynEdit(MyObj).MarkupByClass[TSynEditMarkupHighlightAllCaret]);
  SynMarkup.MarkupInfo.FrameColor := clWindowFrame;
  SynMarkup.MarkupInfo.Background := $0080FF80;
  SynMarkup.WaitTime := 100; // millisec
  SynMarkup.Trim := True;     // no spaces, if using selection
  SynMarkup.FullWord := True;
  // only full words If "Foo" is under caret, do not mark it in "FooBar"
  SynMarkup.IgnoreKeywords := False;
  //Снять выделение ошибки
  TheLine := -1;
end;

procedure TForm1.rKeyPress(Sender: TObject; var Key: char);
begin
  // if (key=char(17))and(key=char(191)) then
end;
//Всплывающая Подсказкак функции
procedure TForm1.rOnClick(Sender: TObject);
begin
  if (ActiveControl is TSynEdit) then
  begin
    //Снять выделение ошибки
    TheLine := -1;
    TSynEdit(ActiveControl).Invalidate;
    //Всплывающая Подсказкак функции
    if (Trim(ExtractWord(0, TSynEdit(ActiveControl).LineText, [' ', '('])) =
      'OnRegisterEvent') then
    begin
      //  PopupNotifier1.Text:= 'Функции — это блок кода, который вы можете использовать в любом участке вашей программы неограниченное количество раз. Например, в программе ниже мы выводим 2 строки (без применения функций):';
      // PopupNotifier1.ShowAtPos(mouse.CursorPos.x,mouse.CursorPos.y);
    end;
    //PopupNotifier1.Visible:=false;
  end;
end;
// Подсветка строки с ощибкой
procedure TForm1.GetLineColor(Sender: TObject; Line: integer;
  var Special: boolean; Markup: TSynSelectedColor);
begin
  if Line <> TheLine then
    exit;
  Special := True;
  Markup.Background := clRed;
  // Выделить строку с номером TheLine красным цветом
  Markup.Style := [fsBold];
  // Выделить строку с номером TheLine красным цветом
end;
//вывести ошибку после компиляции
procedure TForm1.SynEditERROR();
var
  f, i: integer;
begin
  for f := SynEdit1.Lines.Count - 1 downto 0 do
  begin
    if pos('ПРОСМОТР|', SynEdit1.Lines[f]) > 0 then
    begin
      if ExtendedNotebook1.PageCount > 0 then
        for i := 0 to ExtendedNotebook1.PageCount - 1 do
          if Trim(ExtractWord(2, SynEdit1.Lines[f], ['|', '('])) =
            Trim(ExtendedNotebook1.Page[i].Hint) then
          begin
            ExtendedNotebook1.Pages[i].TabVisible := True;
            ExtendedNotebook1.ActivePageIndex := i;
            SynEditComadeTab('LineIndex',
              Trim(ExtractWord(2, SynEdit1.Lines[f], ['(', ')'])));
            exit;
          end;
      if (NewTab(ExtractFileName(Trim(ExtractWord(2, SynEdit1.Lines[f], ['|', '('])))) =
        True) then
      begin
        SynEditComadeTab('Hint', Trim(ExtractWord(2, SynEdit1.Lines[f], ['|', '('])));
        SynEditComadeTab('LoadFile',
          Trim(ExtractWord(2, SynEdit1.Lines[f], ['|', '('])));
        SynEditComadeTab('LineIndex',
          Trim(ExtractWord(2, SynEdit1.Lines[f], ['(', ')'])));
        // ShowMessage(Trim(ExtractWord(2, SynEdit1.Lines[f], ['|', '('])));
        exit;
      end;
    end;
  end;
end;

end.                                                                                                         


Добавлено спустя 21 секунду:
LearnMagic писал(а):https://www.bsuir.by/m/12_100229_1_98218.pdf
http://www.gunsmoker.ru/2011/01/blog-post.html

Спасибо читаю!

Добавлено спустя 43 минуты 33 секунды:
Еще вопросом задался а можно ли обработчики визуальных компонентов главной формы перенести в отдельный unit?
Вот например в JavaScript Можно перехватить обработчик в pascal интересно можно это сделать?)
Я к тому что бы например все обработчики форм перенести в 1 unit
Указатели на функции думаю грамотка получится(
Может как то в классе можно указать procedure TForm1.Button1Click(Sender: TObject); overload; В другом Unit_555
Аватара пользователя
BIT
новенький
 
Сообщения: 25
Зарегистрирован: 29.12.2017 15:44:58

Re: Правильное ведение структуры проекта?

Сообщение LearnMagic » 20.01.2018 14:07:42

BIT писал(а):Еще вопросом задался а можно ли обработчики визуальных компонентов главной формы перенести в отдельный unit?

Можно, но не нужно и немного проблематично. Обработчик не посто procedure, а procedure of object. При вызове неявно передаётся Self.
При наследовании одной формы от другой, все обработчики из секции published позволяют использовать перекрытие в потомках без дополнительных описателей. Inherited ни кто не отменял.
По поводу оформления проектов см. главу 4 Стив Тейксейра, Ксавье Пачеко Delphi 5 Руководство разработчика
LearnMagic
новенький
 
Сообщения: 57
Зарегистрирован: 10.11.2016 23:13:38

Re: Правильное ведение структуры проекта?

Сообщение slyubez » 20.01.2018 16:44:37

Достаточно понятен код или стоит изменить свой стиль написания кода?

Гораздо правильнее сразу давать кнопкам нормальные названия, а не писать такие комментарии. Для этого лучше подучить английский язык.
slyubez
постоялец
 
Сообщения: 130
Зарегистрирован: 31.03.2015 08:44:07

Re: Правильное ведение структуры проекта?

Сообщение Deimos » 20.01.2018 18:14:19

BIT писал(а):Вот например я так пишу всегда, Это пример главного Unit.
Достаточно понятен код или стоит изменить свой стиль написания кода?


Читаем и понятен, но скажу на своем опыте. Не так давно Zub ткнул меня носом в ActionList, я посмотрел, и проникся...

Код: Выделить всё
//Поиск  ToolButton4
procedure TForm1.ToolButton4Click(Sender: TObject);
begin
  MenuItem6.Click;
end;


такие конструкции просто теряют смысл, что снижает кол-во "буков написания" и захламление кода, соответственно...
Deimos
постоялец
 
Сообщения: 157
Зарегистрирован: 17.01.2010 00:31:30

Re: Правильное ведение структуры проекта?

Сообщение Pavia » 20.01.2018 18:30:19

Папки. Каждый делает по своему. - общего не видел

Сейчас я бы сделал так.

dist // Папка с готовым дистрибутивом (программный продукт) содержащий установочный файл или образ диска.
build // папки сборки, хлам всякий DCU, *.a
doc // Документация
src // Папка с исходным кодом программ
tools // Исполняемые файлы утилит
data // Данные
3rdparty // Исходный код сторонних бибилотек и утилит. А так же ПО и данные от контр агентов.
it // Айти средства: скрипт сборки дистрибутива, скрипты бекапа, развёртывания среды разработчика, сервера сборки, VNC клиенты.

3rdparty\dist
3rdparty\libs
3rdparty\apps
3rdparty\data

tools - Портативные утилиты

для примера клиент северное приложение.
data\client
data\server
data\common
data\tests
data\gen_tests

src\client
src\server
src\common - общий исходный код
src\tests
src\gen_tests

Добавлено спустя 31 минуту 46 секунд:
BIT писал(а):unit, class, функции, структуры и т.п

В интернете этого полно. https://en.wikipedia.org/wiki/Coding_conventions
Книгу качественный код и коде стайл тут уже привели.
Ещё хочу добавить стандарт https://en.wikipedia.org/wiki/MISRA_C
Он хотя и для Си, но некоторые вещи можно позаимствовать.

По поводу классов. Их надо делать максимально не завистными этому посещено много книг.

Гамма Э., Хелм Р., Джонсон Р., Влиссидес Дж.-Приемы объектно-ориентированного проектирования (2001)
Фаулер Мартин (Fowler Martiп)-Рефакторинг - улучшение существующего кода-Символ-Плюс (2003)
Ошероув Рой.-Искусство автономного тестирования с примерами на С#(2014)

Но что хочу добавить. Лучше конечно учится на готовых проектах.

По дизайну мне понравилось руководство от гугла:
https://developer.android.com/guide/pra ... index.html
А так же гноме
https://developer.gnome.org/hig/stable/
Последний раз редактировалось Pavia 21.01.2018 12:16:54, всего редактировалось 1 раз.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 214
Зарегистрирован: 07.01.2011 12:46:51

Re: Правильное ведение структуры проекта?

Сообщение Mirage » 20.01.2018 23:41:28

По юнитам и классам, советую погуглить SOLID и DRY. Если 15 лет опыта, то понимание уже должно быть, оформится во что-то конкретное.
По директориям не так важно какие именно, важно чтобы не было все вперемешку - исходники, бинарники, временный мусор и т.д.
Ну и, конечно, чтобы все это было в гите. Не в свне, а именно гите, ибо 2018 год на дворе.
Mirage
энтузиаст
 
Сообщения: 829
Зарегистрирован: 06.05.2005 20:29:07
Откуда: Russia

Re: Правильное ведение структуры проекта?

Сообщение BIT » 21.01.2018 22:13:37

Теперь еще на 15 лет изучения все, что вы мне посоветовали спасибо! :lol:
Аватара пользователя
BIT
новенький
 
Сообщения: 25
Зарегистрирован: 29.12.2017 15:44:58

Re: Правильное ведение структуры проекта?

Сообщение serbod » 22.01.2018 11:11:27

Есть еще всякие алгоритмы, шаблоны проектирования, правила безопасности и прочий computer science. В обычных условиях не нужны, и голову ими забивать не надо. Согласно золотому правилу о преждевременной оптимизации. Но на масштабных проектах и при глубокой оптимизации столкнуться с этим все-таки придется.

Правила безопасности все же процитирую, там совсем немного, но польза огромная.
https://en.wikipedia.org/wiki/The_Power ... tical_Code
Аватара пользователя
serbod
постоялец
 
Сообщения: 341
Зарегистрирован: 16.09.2016 11:03:02
Откуда: Минск

Re: Правильное ведение структуры проекта?

Сообщение Python » 24.01.2018 23:15:28

Лично я выношу все алгоритмы, которые относятся именно к обработке данных в отдельный модуль и складываю их в папку Model (модель), отделяя его от представления (View), которые суть файлы форм и лежат в "корне" проекта.
От идеи создать большую библиотеку постоянно реиспользуемых функций я отказался - неудобно переносить на другую машину, потому у меня есть множество наработанных больше чем за десять лет алгоритмами, которые я просто копирую в специальный модуль в каждом новом проекте - common.pas. Это позволяет просто скопировать папку с проектом на другой компьютер и продолжиться работу (обычно для копирования применяю FreeFileSync, чтобы можно было без труда синхронизировать код, конечно, у GIT/Mercurial больше функций и для больших проектов на несколько человек альтернативы, собственно, нет, но для проекта, который ведёшь один, просто в нескольких местах, FreeFileSync вполне достаточен). Также этот метод решает проблему с тем, что временами приходится перелопачивать эти самые общие модули и они начинают работать немного не так, как ранее (например, добавлен новый функционал, добавлены новые аргументы для функций, но при этом параметры по умолчанию придумать не получается, или переименованы функции, чтобы лучше отражать назначение). Тем не менее, при устранении ошибок в общей библиотеке, приходится вспоминать, а не была ли такая же ошибка в целой куче других проектов? Так что у этого решения есть как плюсы, так и минусы (но для меня плюсов больше).
Python
новенький
 
Сообщения: 16
Зарегистрирован: 23.01.2018 21:50:17


Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 4

Рейтинг@Mail.ru