Обсуждение Программирование на Delphi/Pascal

Награды
7
но я же создал свой тип данных и delphi ругается. Может в другое место нужно вставить описание TMyData?
Может быть прочесть чего она там ругается?
Если я ставлю описание функции туда, где описана процедура нажатия кнопки, то ругается так:
[Error] Unit1.pas(20): Undeclared identifier: 'TMyData'
В примере кода, приведённом тобой, на строке 20 ничего нет. Приведи код который не компилируется, а не тот код который у тебя в голове.
 
В примере кода, приведённом тобой, на строке 20 ничего нет. Приведи код который не компилируется, а не тот код который у тебя в голове.

Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    ListBox1: TListBox;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    function test (a: TMyData): TMyData;

  private
    { Private declarations }

  public

    { Public declarations }
  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
type
 TMyData = record
   X: integer;
   Y: integer;
   Str: string;
   end;

var
  MyData1, MyData2: TMyData;
begin
  MyData1.X := StrToInt (Edit1.Text);
  MyData1.Y := StrToInt (Edit2.Text);
  MyData1.Str := 'Тест.';
  Memo1.Lines.add ('Текущая позиция X: ' + IntToStr(MyData1.X));
  Memo1.Lines.add ('Текущая позиция Y: ' + IntToStr(MyData1.Y));
  Memo1.Lines.Add('Следующая позиция X: ' + IntToStr(MyData1.X+1));
  Memo1.Lines.Add (MyData1.Str);
  MyData1 := MyData2;
  Memo1.Lines.Add (MyData2.Str);
end;

function TForm1.test (a: TMyData): TMyData;
begin
//
end;
end.

Свой тип данных нужно описать не в процедуре, а в общем. Но как - не пойму.
 
Награды
7
Метод test класса TForm1 не может использовать тип TMyData поскольку тот находится за пределами его видимости. Надо определить тип TMyData в секции interface а не внутри одного из методов. Если ты определяешь тип внутри метода, то только внутри его он и будет доступен.

Вообще запомни одно простое правило - любой идентификатор должен быть объявлен до того как на него кто либо сошлётся. Из этого правила есть пара исключений, но чтобы ими пользоваться надо знать как это делается.
 
Метод test класса TForm1 не может использовать тип TMyData поскольку тот находится за пределами его видимости. Надо определить тип TMyData в секции interface а не внутри одного из методов. Если ты определяешь тип внутри метода, то только внутри его он и будет доступен.

Вообще запомни одно простое правило - любой идентификатор должен быть объявлен до того как на него кто либо сошлётся. Из этого правила есть пара исключений, но чтобы ими пользоваться надо знать как это делается.
Спасибо, разобрался.
если кому интересно:
Код:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TMyData = record
    X: integer;
    Y: integer;
    Str: string;
    end;
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Button1: TButton;
    Label1: TLabel;
    Label2: TLabel;
    ListBox1: TListBox;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
    function test (a: TMyData): TMyData;

  private
    { Private declarations }

  public

    { Public declarations }
  end;


var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);

var
  MyData1: TMyData;
begin
  MyData1.X := StrToInt (Edit1.Text);
  MyData1.Y := StrToInt (Edit2.Text);
  MyData1.Str := 'Тест.';
  Memo1.Lines.add ('Текущая позиция X: ' + IntToStr(MyData1.X));
  Memo1.Lines.add ('Текущая позиция Y: ' + IntToStr(MyData1.Y));
  Memo1.Lines.Add('Следующая позиция X: ' + IntToStr(MyData1.X+1));
  Memo1.Lines.Add (MyData1.Str);
  MyData1:= test (MyData1);
  Memo1.Lines.Add (MyData1.Str);
  Memo1.Lines.Add ('Позиция Y после функции: ' +IntTostr(MyData1.X));
end;

function TForm1.test (a: TMyData): TMyData;
begin
  a.X := a.X + 15;
  a.Str := 'текст после функции';
  Result:= a;
end;
end.
 
Награды
7
Код:
function TForm1.test (a: TMyData): TMyData;
begin
  a.X := a.X + 15;
  a.Str := 'текст после функции';
  Result:= a;
end;
end.
Тут есть одна принципиальная ошибка о которой ты даже не догадываешься, но которая стукнет тебя позже. Никогда не модифицируй параметры переданные в подпрограмму, если ты не собираешься их-же возвращать модифицированными вызывающему.

Т.е. по правильному вообще было бы написать так:
Код:
function TForm1.test ([COLOR=#008000]const[/COLOR] a: TMyData): TMyData;
begin
     [COLOR=#008000]Result[/COLOR].X := a.X + 15;
     [COLOR=#008000]Result[/COLOR].Str := 'текст после функции';
end;
 
Код:
function TForm1.test (a: TMyData): TMyData;
begin
  a.X := a.X + 15;
  a.Str := 'текст после функции';
  Result:= a;
end;
end.
Тут есть одна принципиальная ошибка о которой ты даже не догадываешься, но которая стукнет тебя позже. Никогда не модифицируй параметры переданные в подпрограмму, если ты не собираешься их-же возвращать модифицированными вызывающему.

Т.е. по правильному вообще было бы написать так:
Код:
function TForm1.test ([COLOR=#008000]const[/COLOR] a: TMyData): TMyData;
begin
     [COLOR=#008000]Result[/COLOR].X := a.X + 15;
     [COLOR=#008000]Result[/COLOR].Str := 'текст после функции';
end;

Спасибо! Учту. Но если мне еще будет нужен Result.Y, после функции? Тогда мне нужно будет
Код:
[COLOR=#008000]Result[/COLOR].Y := a.Y;
Так? Или лучше ввести внутри функции темповую переменную типа TMyData и работать с ней, а потом приравнять её к Result?
Или типа такого:
Код:
function TForm1.test (const a: TMyData): TMyData;
begin
  Result := a;
  Result.X := Result.X + 15;
  Result.Str := 'текст после функции';
end;

Тут есть одна принципиальная ошибка о которой ты даже не догадываешься, но которая стукнет тебя позже. Никогда не модифицируй параметры переданные в подпрограмму, если ты не собираешься их-же возвращать модифицированными вызывающему.
И кстати да! Именно так я и хотел - использовать параметры, переданные подпрограмме, дальше, в основном блоке. То есть, например, есть 2 мемо. В переменной хранятся номера текущих строк этих мемо(X,Y), а в Str записан результат ипользования данных из этих строк в другой подпрограмме. И отправив эту переменную в третью подпрограмму я анализирую ответ, хранящейся в Str и по результатам анализа или увеличиваю X на 1, или Y, или и X и Y.
Вообще хотелось бы узнать - правильно ли делать много подпрограмм, или лучше (правильнее) писать все в одной? Как мне кажется, удобнее, когда тело программы простое и короткое, состоящее из блоков (подпрограмм). Но может я и ошибаюсь...
 
Награды
7
Спасибо! Учту. Но если мне еще будет нужен Result.Y, после функции? Тогда мне нужно будет
Код:
[COLOR=#008000]Result[/COLOR].Y := a.Y;
Так?
Да, именно так.
Или лучше ввести внутри функции темповую переменную типа TMyData и работать с ней, а потом приравнять её к Result?
Нет смысла. Не нужно вводить дополнительные сущности, если в них нет необходимости.
Или типа такого:
Код:
function TForm1.test (const a: TMyData): TMyData;
begin
  Result := a;
  Result.X := Result.X + 15;
  Result.Str := 'текст после функции';
end;
Тоже можно, но имеет место двойное присваивание, что в общем некрасиво. В твоём случае это конечно по барабану, но представь себе последствия подобного подхода когда Result и a являются "толстыми" структурами данных, и когда подобная операция выполняется миллионы раз.

Смысл появляется только если у тебя эта запись скажем имеет 10 полей, но меняешь ты только 2..3. Или к примеру запись имеет поля которые ты никак не присваиваешь и более того у тебя стоит задача именно сохранить их значение с предыдущего. Тогда да, смело пиши: Result := a;

В целом, принцип один - избегай операций без которых можно обойтись.
Тут есть одна принципиальная ошибка о которой ты даже не догадываешься, но которая стукнет тебя позже. Никогда не модифицируй параметры переданные в подпрограмму, если ты не собираешься их-же возвращать модифицированными вызывающему.
И кстати да! Именно так я и хотел - использовать параметры, переданные подпрограмме, дальше, в основном блоке. То есть, например, есть 2 мемо. В переменной хранятся номера текущих строк этих мемо(X,Y), а в Str записан результат ипользования данных из этих строк в другой подпрограмме. И отправив эту переменную в третью подпрограмму я анализирую ответ, хранящейся в Str и по результатам анализа или увеличиваю X на 1, или Y, или и X и Y.
Вообще хотелось бы узнать - правильно ли делать много подпрограмм, или лучше (правильнее) писать все в одной? Как мне кажется, удобнее, когда тело программы простое и короткое, состоящее из блоков (подпрограмм). Но может я и ошибаюсь...
Немного не так. Ты можешь реализовать возврат результата двумя способами:

Первый:
Код:
function Increment(const Param1:Integer):Integer;
begin
   Result := Param1 + 1;
end;

Второй:
Код:
procedure Increment(var Param1:Integer);
begin
  Param1 := Param1 + 1;
end;

Третий:
Код:
function Increment(Param1:Integer):Integer;
begin
   Result := Param1 + 1;
end;


Все выполняют по сути дела одинаковую работу - увеличивают переданное число на 1 и возвращают его разными способами. Мы можем запросто написать

Код:
var
  A:Integer;
begin
  A := 1;
  A := Increment(A);
  // в этот момент A = 2
end;

Важно что ты явно указал что сам параметр переданный в функцию не будет модифицирован. А что с ним будет после того как функция отработала, это уже забота вызывающего кода.

Во втором случае ты явно указываешь что процедура Increment будет менять переданный ей параметр.

Код:
var
  A:Integer;
begin
  A := 1;
  Increment(A);
  // в этот момент A = 2
end;

А вот третий случай казалось бы ничем не отличается от первого.
Код:
var
  A:Integer;
begin
  A := 1;
  A := Increment(A);
  // в этот момент A = 2
end;

Но есть нюанс. В третьем случа компилятор позволит изменить тебе значение формального параметра Param1. Т.е. позволит написать тебе такой код который выполняет подобное присваивание:

Код:
function Increment(Param1:Integer):Integer;
begin
   Param1 := Param1 + 1;
end;

Может показаться что твои данные изменились, но на самом деле нет. На самом деле значение Param1 будет забыто при выходе из функции, а сама функция вернёт мусор, поскольку Result ничего не присваивалось.

Именно по этому следует вбить себе в подкорку две простые идеи:
1. Любой параметр переданный в подпрограмму должен явно указывать собираешься ты менять его или нет, т.е. иметь префикс либо const, либо var, либо out.
2. Никогда не пытайся модифицировать параметры не объявленные как var или out, в противном случае есть хорошие шансы наделать трудноуловимых ошибок. В случае же если ты следуешь пункту 1 то компилятор тебе просто не позволит этого сделать, но если ты вдруг забудешь, то хоть не напишешь говна.
3. Существует масса кода написанного с нарушением 1 и 2 и его пейсатели давно уже оправдали себя в своих собственных глазах. Это не повод повторять их ненадёжные методы.
 
1. WebBrowser.Navigate заставляет всплыть форму поверх других окон. Как лечить?

2. Как правильно сделать форму невидимой и скрыть ее с панели задач?

Делаю
Код:
procedure TForm1.ApplicationEvents1Activate(Sender: TObject);
begin
  Hide();
  WindowState := wsMinimized;
end;

При обычном запуске все отлично, при запуске из планировщика заданий в панели задач форма присутствует

Эти свойства похоже вообще бестолковые
Код:
  Application.ShowMainForm := false;
  Application.MainFormOnTaskbar := false;
 

FallAngel

Ословед
День добрый. Необходимо сделать нажатие кнопок в фоновом режиме Shift Ctrl и стрелка вниз.
Буду признателен, если выложите уже готовую программу, не важно на чем написана.
P.S. Программа необходима для имитации нажатия горячих кнопок.
 
Сверху