Помощь новичкам

Да, знаю. Но, к примеру, в OpenGL это решили разбиением грани на треугольники. Они могут лежать не на общей плоскости, но каждый из них будет плоским.

Думаю, здесь надо пользоваться более высокоуровневой терминологией WPF.

Кстати - согласен - Polygon3D - не очень удачное название. Это просто замкнутая ломаная. Надо будет подумать над переименованием

Опять же, возвращаясь к OpenGL (ибо это то что я лучше всего знаю):

Там нету Polyline, есть LineStrip и LineLoop. И, по моему, чтоб понять эти названия надо меньший уровень знания английского, чем для Polyline.

Нужно ли в рекурсию передавать объект по ссылке? Вот такой пример со строкой. Так ли я понимаю, что первый раз строка передается в функцию F по ссылке, а все следующие рекурсивные вызовы это уже ссылка на предыдущую ссылку? Если это так, то это лучше, чем каждый раз передавать всю строку, или все же не нужно передавать по ссылке?

procedure F(const s: string; n: byte);
begin
  if n = 0 then exit;
  F(s, n - 1);
  Print(s[n]);
end;

begin
  var s := 'Hello World!';
  F(s, s.Length)
end.

const s: string - это неправильно - слово const осмысленно предназначено только для размерных данных. String и так ссылка

Ясно, но если объект изначально передается по ссылке, то каждый рекурсивный вызов будет передаваться та же ссылка или ссылка на предыдущую ссылку? То есть я думаю что же лучше, обернуть F какой-то внешней функцией в которую передать строку и сделать глобальной для F или не нужно?

  1. var s: string

  2. Ссылка на ссылку не создаётся, потому что в программе есть только одна F, принимающая ссылку на string. А значит если каким то магическим образом и передать туда ссылку на ссылку на string - её не смогло бы прочитать, потому что программа написана с учётом чётко определённого типа s.

  3. Как и сказал Admin, передавать ссылочные типа в качестве var-параметра бессмысленно тут.

Есть 2 случая когда передача var-параметра имеет смысл:

  1. Если вы передаёте value-тип, имеющий большой объём. Если передавать не в качестве var-параметра - value тип будет копироваться, и если копируется большой объём - это не эффективно. А ссылку передать надо меньший объём.
  2. Если при изменении переменной в подпрограмме она должна изменится и там, откуда её вызвали. Это уже подходит и ссылочным типам.

Помогите пожалуйста с задачей по рекурсии.

Summary

Проверить правильность выражения, заданного в виде непустой строки S. Выражение определяется следующим образом:

<выражение> ::= <цифра> | (<выражение><знак><выражение>)

<знак> ::= + | − | *

Если выражение составлено правильно, то вывести 0, в противном случае вывести номер первого ошибочного, лишнего или недостающего символа в строке S.

Что-то ничего путного в голову не приходит. Хоть что-нибудь какие-то идеи, алгоритм, рекурсивное определение, в лучшем случае код, если вам не лень.

Думаю, тут проще всего будет через немного модифицированную обратную польскую запись.

Напишите для начала код который бы считал выражения записанные в обратной польской записи, а затем модифицируйте так, чтоб вместо того чтоб возвращать значения - программа только проверяла чтоб синтаксис был правильным (ну и запрещала больше 2 чисел в одних скобочках).

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

Почему это не работает:

uses FormsABC;

begin
  
  MainForm.NetForm.Shown += (o,e)->
  begin
    System.Threading.Thread.Create(()->
    while true do
    begin
      writeln('drawing');
      var gr := MainForm.NetForm.CreateGraphics;
      gr.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Black), 10,10, 20,20);
      Sleep(100);
    end).Start;
  end;
  
end.

Хотя это работает:

{$reference System.Windows.Forms.dll}
{$reference System.Drawing.dll}
uses System.Windows.Forms;

begin
  var f := new Form;
  
  f.Shown += (o,e)->
  begin
    System.Threading.Thread.Create(()->
    while true do
    begin
      writeln('drawing');
      var gr := f.CreateGraphics;
      gr.DrawLine(new System.Drawing.Pen(System.Drawing.Color.Black), 10,10, 20,20);
      Sleep(100);
    end).Start;
  end;
  
  Application.Run(f);
end.

Я много всего перепробовал, на контролах невозможно ничего нарисовать после запуска формы в FormsABC.

Конечно, для самой формы это не нужно. Но вот тут:
http://www.cyberforum.ru/pascalabc-net/thread2423478.html
У человека возникла проблема с PaintBox. До старта формы в нём нарисовать можно, а после - нет.

Видимо, поэтому: _MainForm.Controls.Add(_MainPanel);

На форму добавляется панель, на которой и размещаются компоненты. Она то и закрывает форму

Это не всё объясняет, но потом чуть больше покопаюсь.

А пока что…

constructor PaintBox.Create();
begin
  f := new PictureBox;
  (f as PictureBox).Image := new Bitmap(1280,1024);
  Graphics.Clear(Color.White);
  ParentControl.Add(f);
  CurrentControl := f;
  var p := f as PictureBox;
  p.Resize += PResize;
  p.Paint += PPaint;
  p.MouseDown += PMouseDown;
  p.MouseMove += PMouseMove;
  p.MouseUp += PMouseUp;
end;

new Bitmap(1280,1024);… По моему это костыль, при чём довольно кривой. И на 4к мониторе не прокатит.

Да и p можно было в начале конструктора объявить, и таким образом обойтись без лишних as.

Мы по этому поводу говорим, что все модули на основе Windows Forms устарели.

Модуль FormsABC - он вообще - вспомогательный, для первичного обучения компонентному программированию. С точки зрения обучения он у нас не пошёл, потому ничего там не развивается. Мы сейчас будем концентрироваться на модуле Controls, который можно будет подключать вместе с любым WPF-модулем.

Может тогда стоит добавить предупреждение компилятора, для всех модулей на GDI? А то вы говорите, но вне ЮФУ и этого форума никто и не узнает…

1 лайк

Вмонтировать в компилятор такое поведение - это какое-то непонятное решение.

Можно позволить помечать модули специальными атрибутами вроде ObsoleteUnitAttribute, для указания того, что они устаревшие. Например, можно так:

[[ObsoleteUnitAttribute]] // В двойных квадратных скобках, чтобы отличались от стандартных атрибутов.
unit Name;

end.

И чтобы при наличии данного атрибута выводилось предупреждение компилятора. И тогда не придётся

Можно, начать с этого:

uses System;

type
  /// Тип сообщения.
  MessageType = (Info, Warning, Error);
  /// Тип цели.
  TargetType = (ForUnit, ForLibrary, ForAll);
  
  /// Атрибут модуля/библиотеки.
  UnitLibraryAttribute = class(Attribute)
  private
    fMessage: string;
    fType: MessageType;
    fTarget: TargetType;
  
  public
    /// Сообщение, выводимое компилятором.
    property Message: string read fMessage;
    
    /// Тип сообщения.
    property &Type: MessageType read fType;
    
    /// Тип цели.
    property &Target: TargetType read fTarget;
    
    constructor(message: string; &type: MessageType; target: TargetType);
    begin
      fMessage := message;
      fType := &type;
      fTarget := target;
    end;
  end;
  
  /// Атрибут, указывающий, что используемый модуль/библиотека устарела.
  ObsoleteUnitLibraryAttribute = class(UnitLibraryAttribute)
  public
    constructor();
    begin
      inherited Create('Данный модуль/библиотека устарела.', MessageType.Warning, TargetType.ForAll);
    end;
  end;

begin
end.
1 лайк

Идея неплоха, но зачем

?

Ну, чтобы отличать от атрибутов, которые применяются к типам, методам, подпрограммам, параметрам… И подчеркнуть, что эти атрибуты специфичны для PascalABC.NET.

Нет, лучше не двойные квадратные скобки, а вот так:

{ (_x_) ObsoleteUnitAttribute (_x_) }
1 лайк

А что такое _x_?