Как в PascalABC.NET использовать EventHandler
, а именно: события public event SpeakStarted, SpeakCompleted, SpeakProgress, BookmarkReached, VoiceChange, PhonemeReached, VisemeReached, StateChanged
в unit Speech, namespace System.Speech.Synthesis?
event
используется так:
type
t1 = class
event ev: procedure(o: object; e: System.EventArgs);
procedure CallEv;
begin
var ev := ev;
if ev<>nil then ev(self, new System.EventArgs);
end;
end;
begin
var a := new t1;
a.ev += (o,e)->Writeln('Ивент вызван');
a.CallEv;
end.
EventHandler
объявлен так:
type EventHandler = procedure(o: object; e: System.EventArgs);
Но, обратите внимание, это не синоним типа, а объявление нового типа делегата.
Разница в том, что typeof(EventHandler) = typeof(EventHandler)
, потому что это 2 обращения к одному и тому же типу.
А каждый раз как вы пишете тип procedure(o: object; e: System.EventArgs)
- вы создаёте новый анонимный тип делегата.
Достаточно и правильно ли использовать ss.SpeakStarted += (o,e)->begin end
, чтобы реагировать на событие в следующем примере?
uses System.Speech.Synthesis;
{$reference System.Speech.dll}
begin
var ss: SpeechSynthesizer := new SpeechSynthesizer;
ss.SpeakStarted += (o,e)->begin end;
ss.Speak('');
end.
Как удалить ненужную переменную после её описания?
Ну, вы как бы отреагировали… И в ответ ничего не сделали. Я в своём примере сделал чтоб на консоль выводило строку в момент вызова, чтоб было визуально заметно когда ивент вызывается…
А если вы пытались сделать минимальный пример - лучше (o,e)->exit()
, немного короче получается.
Что значит удалить?
Если у меня в программе используется много оперативной памяти, а в какой-то момент она уже не будет нужна, как её освободить? Кроме того, возможно ли сделать так, что программа “забудет”, что некоторая переменная была инициализирована (при выполнении var
), и можно будет инициализировать переменную с новым типом, но с тем же названием?
Почему ss.SpeakAsync
читает строку, находящуюся только до ss.Speak
, а если ss.Speak
не существует в коде, то ss.SpeakAsync
вообще не работает?
uses System.Speech.Synthesis;
{$reference System.Speech.dll}
begin
var ss: SpeechSynthesizer := new SpeechSynthesizer;
ss.SpeakStarted += (o,e)->Writeln('Начало.');
ss.SpeakProgress += (o,e)->Writeln('Продолжение.');
ss.SpeakCompleted += (o,e)->Writeln('Конец.');
ss.SpeakAsync('Начальное предложение не читается, если ничего не читается синхронно позже.');
//ss.Speak('Второе предложение читается всегда, когда выполняется соответствующая строка.');
ss.SpeakAsync('Конечное предложение не читается, если ничего не читается синхронно позже, то есть вообще не читается.');
end.
А сборщик мусора на что? Откройте справку данного паскаля и внимательно перечитайте первую страницу.
Сборщик мусора сам удаляет все объекты, когда считает что они уже не нужны. А локальные переменные, которые нигде больше не сохранили, удаляются прямо при выходе из подпрограммы:
type
t1 = class
// Этот метод вызывается прямо перед удалением объекта
protected procedure Finalize; override :=
Writeln('Finalize');
end;
begin
var a := new t1;
Writeln(a);
end.
Достаточно чтоб переменная вышла из зоны видимости:
uses System.Speech.Synthesis;
{$reference System.Speech.dll}
begin
begin
var ss: SpeechSynthesizer := new SpeechSynthesizer;
ss.SpeakStarted += (o,e)->exit();
ss.Speak('abc');
end;
//Ошибка: Неизвестное имя, потому что тут ss уже не существует
ss.Speak('def');
end.
После этого можно объявлять и новую переменную, даже с таким же именем.
Ну, вы же понимаете что значит Async
? Оно успешно вызывается, но программа продолжает выполняться не ожидая окончания воспроизведения. И, в итоге, завершается до того как ss
успеет начать говорить.
Для такие тестовых программ - всегда добавляйте что то типа Readln
в конце программы. А в более сложных придётся думать по случаю.
Есть ли стандартная подпрограмма для вычисления корня n-ной степени? Если нет, то что лучше для вычисления: sign(x)*exp(ln(abs(x))/n)
, Sign(x)*Power(Abs(x),1/n)
, или что-то ещё?
Sign(x) * Abs(x) ** (1/n)
**
и Power
и так вызывают exp(ln())
(со своими оптимизациями), но и для Power
, и особенно для **
надо меньше скобок.
Кроме перечисленных вами, есть ещё операция возведения в степень ** (две звездочки подряд). В случае ** мало илии вообще не пользуются скобками.
Я использую
чтобы присвоить результат деления переменной типа integer, но выходит ошибка “Невозможно явно преобразовать тип real к типу integer”. Как мне доказать, что получится integer? .
Никак. Round(x) возвращает integer, Round(x, n) возвращает real.
Как в консоли обрабатывать нажатие клавиш, не прерывая ввод и не вызывая Console.ReadKey
?
Точнее через System.Convert
. Это паскалевские Round
, Ceil
и т.п. сразу конвертируют результат округления в integer
. Но сами операции округления на уровне процессора реализованы только для чисел с плавающей запятой. А конвертирование в целые для процессора отдельная операция.
Объясните подробнее.
Я хочу сделать так, чтобы можно было менять цвет текста консоли во время ввода значений с клавиатуры, но для этого нужны горячие клавиши, то есть обработка нажатий на клавиши.
То есть вы хотите чтоб, к примеру, вы могли вводить значение с помощью ReadInteger
, но когда пользователь держит Ctrl
- введённые цифры этого числа становились красными? Или как?
Попробуйте, лучше, объяснить свою ситуацию, то есть для какой задачи вам это нужно, а не как вы думаете это можно реализовать.
При нажатии определённой клавиши следующий символ не отображается, а следующая нажатая клавиша определяет цвет текста: “Y” — текст дальше вводится жёлтым, “B” — синим и т. д.
Для красоты.
Можно присвоить экземпляр своего класса переменной CurrentIOSystem
, если вы используете паскалевские подпрограммы чтения (как ReadInteger
), или передать в Console.SetIn
, если вы используется .Net-овские средства, как Console.ReadLine
.
При этом в обоих случаях использовать старые CurrentIOSystem
/Console.In
соответственно в своём класса, чтоб выполнять собственно чтение, но при этом поверх добавлять свои проверки, чтоб при нажатии некоторых клавиш переключался цвет текста.
Но это всё сложно и долго, в простых случаях, всё же, лучше использовать Console.ReadKey
.
Существует ли готовое решение, чтобы преодолеть проблему нехватки места в окне консоли при одновременном выводе больших строк (если текста слишком много, текст выше уходит за верх и пропадает), например, вывод сообщения “Для продолжения нажмите любую клавишу . . .” вместо текста в зависимости от размера части, которую необходимо вывести далее?
Текст сначала уходит из окна консоли (у которого Console.WindowHeight
строк), но остаётся в буфере (то есть можно прокрутить скролбар чтоб вернуть ту часть текста в видимость).
А полностью пропадает текст только если заполнено Console.BufferHeight
строк.
И то и то настраивается в настройках самой консоли. Но если вы хотите сделать что то программно - вы всегда можете переставлять курсор как вам угодно.
Почему некоторые символы в скомпилированной программе отличаются от этих же символов в окне вывода ИСP, например, “∈” превращается в “?”? Как это предотвратить?