Форум программистов, компьютерный форум, киберфорум
Delphi для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.78/9: Рейтинг темы: голосов - 9, средняя оценка - 4.78
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
RAD 2009-XE2

Первый раз пишу класс

07.09.2018, 17:22. Показов 2032. Ответов 14
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Об этом вопросе я говорил и здесь.

Я пытаюсь первый раз написать класс. У меня не получается объявлять свойства property с зарезервированными словами read и write. Поля и методы класса я описывать умею на самом простом уровне. Покажу это на простом примере.

Пример. На форме Form1 расположены два текстовых поля Edit1 и Edit2. В текстовом поле Edit2 отображается тот же текст, что и в текстовом поле Edit1 (текст в Edit2 меняется вместе с редактированием текста в Edit1).

Самый простой способ решения данной задачи (без использования класса).
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Edit1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.Edit1Change(Sender: TObject);
begin
       Form1.Edit2.Text:=Form1.Edit1.Text;
end;
 
end.
Второй способ решения данной задачи (с использованием класса).
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    procedure Edit1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
type
 
       TMyClass = class(TObject)
                  Stroka:String;
       end;
 
var
       MyClass:TMyClass;
 
procedure TForm1.Edit1Change(Sender: TObject);
begin
       MyClass.Stroka:=Form1.Edit1.Text;
       Form1.Edit2.Text:=MyClass.Stroka;
end;
 
initialization
 
       MyClass:=TMyClass.Create;
 
finalization
 
       FreeAndNil(MyClass);
 
end.
Я написал такое решение задачи только для того, чтобы показать, что я примитивно работать с полями класса умею.


Я сейчас прекращаю решать данную задачу, и запишу ещё один примитивный код, который не работает.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
type
  TMyClass = class(TObject)
    StringStroka:String;
 
    function GetField:Integer;
    procedure SetField(Value:Integer);
 
    property Stroka:String read GetField write SetField;
  end;
 
 
function TMyClass.GetField;
begin
  //
end;
 
procedure TMyClass.SetField(Value:Integer);
begin
  //
end;
 
var
       MyClass:TMyClass;
 
initialization
 
       MyClass:=TMyClass.Create;
 
finalization
 
       FreeAndNil(MyClass);
 
end.
Для написания этого кода я пользовался книгой В. В. Фаронов, Delphi, Программирование на языке высокого уровня, издательство ПИТЕР, 2010, страница 179 и статьёй.

Код методов function TMyClass.GetField и procedure TMyClass.SetField(Value:Integer) класса я оставил пустым, так как я ещё до конца не решил, что мне в них надо писать.

Компилятор выдаёт ошибки


Всё. Дальше я сам ничего сделать не могу. Природу этих ошибок я не понимаю. И не понимаю, обязательно ли в методе procedure TMyClass.SetField(Value:Integer) нужен параметр Value:Integer.

Помогите, пожалуйста, разобраться.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.09.2018, 17:22
Ответы с готовыми решениями:

Пишу класс
Пишу класс Comp для работы с комплексными числами. Питаюсь мнимую и действительную часть реализовать через свойства но не все получается ...

первый раз пишу программу. Ребята как она пишется? кому не сложно создайте
Написать программу, которая переводит число из 3-й системы счисления в 9-ю, не переводя все число в 10-ю. Выполнить отладку программы с...

Посоветуйте, подскажите...пишу свой первый сайт
Уважаемые гости...Посоветуйте, подскажите...пишу свой первый сайт http://www.pefepat.narod.ru/ . Сайт еще в разработке, и чтобы встать на...

14
5971 / 4547 / 1094
Регистрация: 29.08.2013
Сообщений: 28,168
Записей в блоге: 3
07.09.2018, 17:40
Цитата Сообщение от _Саша_ Посмотреть сообщение
Природу этих ошибок я не понимаю
Stroka у тебя какого типа?

а
Delphi
1
2
function GetField:Integer;
procedure SetField(Value:Integer);
какого типа?

Цитата Сообщение от _Саша_ Посмотреть сообщение
Помогите, пожалуйста, разобраться.
хватит писать в делфи7
используйте нормальную версию и литературу
1
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
07.09.2018, 20:27  [ТС]
Цитата Сообщение от qwertehok Посмотреть сообщение
хватит писать в делфи7
используйте нормальную версию
Подскажите, пожалуйста, в какой версии лучше всего писать.
Цитата Сообщение от qwertehok Посмотреть сообщение
и литературу
Посоветуйте мне, пожалуйста, нормальную литературу.


Я исправил Integer на String и всё заработало.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
type
  TMyClass = class(TObject)
    StringStroka:String;
 
    function GetField:String;
    procedure SetField(Value:String);
 
    property Stroka:String read GetField write SetField;
  end;
 
 
function TMyClass.GetField;
begin
  //
end;
 
procedure TMyClass.SetField(Value:String);
begin
  //
end;
 
var
       MyClass:TMyClass;
 
initialization
 
       MyClass:=TMyClass.Create;
 
finalization
 
       FreeAndNil(MyClass);
 
end.

Подскажите, пожалуйста,
Delphi
1
procedure SetField(Value:Integer);
параметр Value, откуда он берётся?
0
5971 / 4547 / 1094
Регистрация: 29.08.2013
Сообщений: 28,168
Записей в блоге: 3
08.09.2018, 12:46
Цитата Сообщение от _Саша_ Посмотреть сообщение
в какой версии лучше всего писать.
сейчас можно бесплатно скачать Xe10.2 на сайте embarcadero

Цитата Сообщение от _Саша_ Посмотреть сообщение
Посоветуйте мне, пожалуйста, нормальную литературу.
раз у вас вопросы типа
Цитата Сообщение от _Саша_ Посмотреть сообщение
параметр Value, откуда он берётся?
то вам надо начинать с нуля, читать про процедуры и функции
0
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
09.09.2018, 18:15  [ТС]
Вот пример программы. На форме Form1 расположен комбинированный список ComboBox1 и два текстовых поля Edit1 и Edit2. Элементами комбинированного списка ComboBox1 являются числа от 0 до 10. В начале выполненя программы значения текстовых полей нули. Во время выполнения программы при смене элемента списка в текстовом поле Edit1 отображается выбранный элемент, второе текстовое поле является сумматором сменяемых выбранных элементов списка ComboBox1.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
type
      TMyClass = class(TObject)
        IntItemIndex:Integer;
        IntCountNumbers:Integer;
 
        procedure SetItemIndex(Value:Integer);
 
        property ItemIndex:Integer write SetItemIndex;
      end;
 
procedure TMyClass.SetItemIndex(Value: Integer);
begin
  if Self.IntItemIndex=Form1.ComboBox1.ItemIndex then
        exit;
 
        Self.IntItemIndex:=Form1.ComboBox1.ItemIndex;
        inc(Self.IntCountNumbers,Self.IntItemIndex);
        Form1.Edit1.Text:=IntToStr(Self.IntItemIndex);
        Form1.Edit2.Text:=IntToStr(Self.IntCountNumbers);
end;
 
var
        MyClass:TMyClass;
 
 
procedure TForm1.FormCreate(Sender: TObject);
begin
        Form1.Edit1.Text:='0';
        Form1.Edit2.Text:='0';
end;
 
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
        MyClass.ItemIndex:=Form1.ComboBox1.ItemIndex;
end;
 
initialization
 
      MyClass:=TMyClass.Create;
      MyClass.IntItemIndex:=0;
      MyClass.IntCountNumbers:=0;
 
finalization
 
      FreeAndNil(MyClass);
 
end.
Метод класса procedure SetItemIndex(Value:Integer) должен быть с одним параметром. В моей программе параметр Value не используется.

Вопрос такой. Какой смысл в параметр Value, ведь я его не обязан использовать. И почему сделано так, что такие методы класса нельзя описывать без параметров, или более чем с одним параметром?
0
 Аватар для krapotkin
6849 / 4676 / 1464
Регистрация: 14.04.2014
Сообщений: 20,667
Записей в блоге: 21
09.09.2018, 20:58
Лучший ответ Сообщение было отмечено _Саша_ как решение

Решение

стоп. это не простой метод
этот метод обеспечивает функционирование такого свойства языка как property
property это просто подстановка вместо
aaa := Value
подставляется SetAAA(Value)
а вместо bbb := aaa подставляется bbb := GetAAA();

ясно же что параметр Value здесь необходим. это правая сторона выражения aaa := Value
1
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
09.09.2018, 21:28  [ТС]
krapotkin понял.

Значит, предыдущий код можно переписать более грамотно
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
type
      TMyClass = class(TObject)
        IntItemIndex:Integer;
        IntCountNumbers:Integer;
 
        procedure SetItemIndex(Value:Integer);
 
        property ItemIndex:Integer write SetItemIndex;
      end;
 
procedure TMyClass.SetItemIndex(Value: Integer);
begin
  if Self.IntItemIndex=Value then
        exit;
 
        Self.IntItemIndex:=Value;
        inc(Self.IntCountNumbers,Self.IntItemIndex);
        Form1.Edit1.Text:=IntToStr(Self.IntItemIndex);
        Form1.Edit2.Text:=IntToStr(Self.IntCountNumbers);
end;
 
var
        MyClass:TMyClass;
 
 
procedure TForm1.FormCreate(Sender: TObject);
begin
        Form1.Edit1.Text:='0';
        Form1.Edit2.Text:='0';
end;
 
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
        MyClass.ItemIndex:=Form1.ComboBox1.ItemIndex;
end;
 
initialization
 
      MyClass:=TMyClass.Create;
      MyClass.IntItemIndex:=0;
      MyClass.IntCountNumbers:=0;
 
finalization
 
      FreeAndNil(MyClass);
 
end.
0
5971 / 4547 / 1094
Регистрация: 29.08.2013
Сообщений: 28,168
Записей в блоге: 3
09.09.2018, 21:51
Цитата Сообщение от _Саша_ Посмотреть сообщение
procedure TMyClass.SetItemIndex(Value: Integer);
begin
* if Self.IntItemIndex=Value then
* * * * exit;
Self.IntItemIndex:=Value;
* * * * inc(Self.IntCountNumbers,Self.IntItemInd ex);
* * * * Form1.Edit1.Text:=IntToStr(Self.IntItemI ndex);
* * * * Form1.Edit2.Text:=IntToStr(Self.IntCount Numbers);
end;
вот это перепишите
классы обычно ничего не знают о форме и компонентах

и вот это
Цитата Сообщение от _Саша_ Посмотреть сообщение
initialization
MyClass:=TMyClass.Create;
* * * MyClass.IntItemIndex:=0;
* * * MyClass.IntCountNumbers:=0;
то же перепишите, есть конструктор класса
1
Злостный нарушитель
 Аватар для Verevkin
10340 / 5758 / 1269
Регистрация: 12.03.2015
Сообщений: 26,593
09.09.2018, 23:01
Может просто дать ТСу кусок рабочего исходника, где всё это есть?
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  //---------- Класс для перевода НЕХ-строки в адрес/данные и обратно ----------
  THexString = class
  private
    FRAWText: string;                // весь текст целиком, включая ":" и КС
    FData: TBytes;                   // Данные - только они и нач адрес хранятся, остальное вычисляется
    FAddress: Word;                 // Начальный адрес данных
    FHexFile: THexFile;             // Ссылка на объект-контейнер
 
    // Функции доступа к полям
    procedure SetData(const ANew: TBytes);                // Запись данных
    function GetText: string;                             // Чтение НЕХ-текста
    function GetTextLength: Integer;                      // длина переменной FRAWText (кол-во символов)
    procedure SetText(const ANew: string);                // Установка НЕХ-текста
    function GetChecksum: Byte;                           // Расчёт КС
    function GetDataSize: Byte;                           // Расчёт длины данных в байтах
    procedure SetDataSize(const ANew: Byte);              // Установка новой длины данных (нужно перед записью)
    function GetEOF: Boolean;                             // Флаг конца файла
    function GetKind: THexStringKind;                     // Тип данных строки
  protected
    function GetRAWByte(const ByteNumber: Byte): Byte;    // 2 символа строки ---> байт данных
    function GetRAWWord(const WordNumber: Byte): Word;    // 4 символа строки ---> слово данных ("ABCD" ---> 0xABCD)
 
    function GetDataAsText: string;
    function GetCRC32: DWORD;
  public
    constructor Create(AHexFile: THexFile);
    destructor Destroy; override;
    procedure Roll(const Offset: Byte); // удаление offset байт слева и сдвиг адреса на +offset
 
    // Свойства
    property Data: TBytes read FData write SetData;                           // Данные
    property Text: string read GetText write SetText;                         // НЕХ-строка, составленная из данных
    property DataAsText: string read GetDataAsText;
    property CRC32: DWORD read GetCRC32;                                      // CRC32 только данных!
    property RAWText: string read FRAWText;                                   // НЕХ-строка, заданная изначально
    property TextLength: Integer read GetTextLength;                          // длина переменной FRAWText (кол-во символов)
    property DataSize: Byte read GetDataSize write SetDataSize;               // Длина данных в байтах
    property Checksum: Byte read GetChecksum;                                 // Контрольная сумма
    property Address: Word read FAddress write FAddress;                      // Начальный адрес данных
    property EOF: Boolean read GetEOF;                                        // Флаг конца файла
    property Kind: THexStringKind read GetKind;                               // Тип данных строки
    property HexFile: THexFile read FHexFile write FHexFile;                  // Ссылка на объект-контейнер
    property RAWByte[const ByteNumber: Byte]: Byte read GetRAWByte;
    property RAWWord[const WordNumber: Byte]: Word read GetRAWWord;
  end;
Кликните здесь для просмотра всего текста

Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
unit uHexFile;
 
interface
 
uses
  //============================== Модули проекта ==============================
  uRoutines,
  //========================= Модули проекта с формами =========================
  //=============================== Левые модули ===============================
  //dwTypes, dwFiles,
  //=================== Системные модули, добавленные вручную ==================
  Math,
  //=================== Модули, добавленные IDE автоматически ==================
  Windows, Classes, Contnrs, SysUtils, Types, typinfo, Generics.Collections;
 
type
  //------------------------- Классы исключений --------------------------------
  EHexFileError = class(Exception);              // Общий предок (для идентификации on E: EHexFileError do)
  EHexInvalidSymbol = class(EHexFileError);      // Исключение - недопустимый символ в НЕХ-строке
  EHexIncorrectDataLen = class(EHexFileError);   // Исключение - Длина строки не соответствует обозначенной длине данных
  EHexIncorrectStringLen = class(EHexFileError); // Исключение - некорректная длина строки (< 11 символов)
  EHexIncorrectChecksum = class(EHexFileError);  // Исключение - Неверная КС
 
 
  THexStringKind =  // тип информации в НЕХ-строке (по 8 и 9 символам)
    (hskData,          // 0x00
     hskEOF,           // 0x01
     hskKey,           // 0x04 (данные = старшие 2 байта адреса ОЗУ)
     hskError,         // 0xED (defaced error)
     hskUnknown);      // 0x?? (остальные варианты)
 
  THexOptimizeResults = record
    OldFileSize: DWORD; // должен быть больше,
    NewFileSize: DWORD; // чем новый
    OldDataSize: DWORD; // должны быть равны
    NewDataSize: DWORD; // после оптимизации
    OldStrCount: int32; // исходное число строк
    NewStrCount: int32; // полученное число строк
    OldCRC32:    DWORD; // CRC32 данных должна совпасть
    NewCRC32:    DWORD; // с новой, если данные не изменились
  public
    function Ratio: Single;
    function Success: Boolean; // проверка по CRC32
  end;
 
{$REGION 'Класс для перевода НЕХ-строки в адрес/данные и обратно'}
type
  THexFile = class; // Заглушка для ссылки на объект-контейнер
 
  //---------- Класс для перевода НЕХ-строки в адрес/данные и обратно ----------
  THexString = class
  private
    FRAWText: string;                // весь текст целиком, включая ":" и КС
    FData: TBytes;                   // Данные - только они и нач адрес хранятся, остальное вычисляется
    FAddress: Word;                 // Начальный адрес данных
    FHexFile: THexFile;             // Ссылка на объект-контейнер
 
    // Функции доступа к полям
    procedure SetData(const ANew: TBytes);                // Запись данных
    function GetText: string;                             // Чтение НЕХ-текста
    function GetTextLength: Integer;                      // длина переменной FRAWText (кол-во символов)
    procedure SetText(const ANew: string);                // Установка НЕХ-текста
    function GetChecksum: Byte;                           // Расчёт КС
    function GetDataSize: Byte;                           // Расчёт длины данных в байтах
    procedure SetDataSize(const ANew: Byte);              // Установка новой длины данных (нужно перед записью)
    function GetEOF: Boolean;                             // Флаг конца файла
    function GetKind: THexStringKind;                     // Тип данных строки
  protected
    function GetRAWByte(const ByteNumber: Byte): Byte;    // 2 символа строки ---> байт данных
    function GetRAWWord(const WordNumber: Byte): Word;    // 4 символа строки ---> слово данных ("ABCD" ---> 0xABCD)
 
    function GetDataAsText: string;
    function GetCRC32: DWORD;
  public
    constructor Create(AHexFile: THexFile);
    destructor Destroy; override;
    procedure Roll(const Offset: Byte); // удаление offset байт слева и сдвиг адреса на +offset
 
    // Свойства
    property Data: TBytes read FData write SetData;                           // Данные
    property Text: string read GetText write SetText;                         // НЕХ-строка, составленная из данных
    property DataAsText: string read GetDataAsText;
    property CRC32: DWORD read GetCRC32;                                      // CRC32 только данных!
    property RAWText: string read FRAWText;                                   // НЕХ-строка, заданная изначально
    property TextLength: Integer read GetTextLength;                          // длина переменной FRAWText (кол-во символов)
    property DataSize: Byte read GetDataSize write SetDataSize;               // Длина данных в байтах
    property Checksum: Byte read GetChecksum;                                 // Контрольная сумма
    property Address: Word read FAddress write FAddress;                      // Начальный адрес данных
    property EOF: Boolean read GetEOF;                                        // Флаг конца файла
    property Kind: THexStringKind read GetKind;                               // Тип данных строки
    property HexFile: THexFile read FHexFile write FHexFile;                  // Ссылка на объект-контейнер
    property RAWByte[const ByteNumber: Byte]: Byte read GetRAWByte;
    property RAWWord[const WordNumber: Byte]: Word read GetRAWWord;
  end;
{$ENDREGION}
 
{$REGION 'Класс для загрузки из- и сохранения в НЕХ-файл'}
  TOptimizeProgressEvent = procedure (Sender: THexFile; const AProgress: int32) of object;
  //------------ Класс для загрузки из- и сохранения в НЕХ-файл ----------------
  THexFile = class(TObjectList<THexString>)
  private
    FFileName: string;
    //FChanged: TDateTime;
    FLastStringDataMaxSize: DWORD;                                              // последний рассчитанный максимальный размер данных среди строк
    FOnOptimizeProgress: TOptimizeProgressEvent;                                // событие для обновления ProgressBar при оптимизации
    // Функции для доступа к полям
    function GetFileSize: DWORD;                                                // размер файла (текста)
    function GetDataSize: Cardinal;                                             // Количество данных в байтах
    function GetDataPercent: Single;                                            // % данных в файле
    function GetCRC32: DWORD;                                                   // хэш ВСЕХ данных!
  public
    constructor Create; reintroduce;
    // Методы
    function New(const AData: TBytes; const AAddress: Word): THexString;        // Добавление НЕХ-строки
    procedure LoadFromStream(AStream: TStream);                                 // Загрузка из стрима
    function LoadFromFile(const AFileName: string): Boolean;                    // Загрузка из файла
    procedure SaveToStream(AStream: TStream);                                   // Сохранение в стрим
    function SaveToFile(const AFileName: string): Boolean;                      // Сохранение в файл
    function GetStringDataMaxSize: DWORD;                                       // максимальная длина данных среди строк в файле
    function Optimize(const MaxDataPerLine: Byte): THexOptimizeResults;         // оптимизация (перераспределение памяти)
    procedure ShowAsStrings(AStrings: TStrings);                                // копирование в текстовый список
 
    // Свойства
    property FileName: string read FFileName;
    property FileSize: DWORD read GetFileSize;                                  // размер файла (текста)
    property DataSize: DWORD read GetDataSize;                                  // Количество данных в байтах
    property DataPercent: Single read GetDataPercent;                           // % данных в файле
    property LastStringDataMaxSize: DWORD read FLastStringDataMaxSize;          // последний рассчитанный максимальный размер данных среди строк
    property CRC32: DWORD read GetCRC32;                                        // хэш ВСЕХ данных!
 
    // события
    property OnOptimizeProgress: TOptimizeProgressEvent read FOnOptimizeProgress write FOnOptimizeProgress;
  end;
{$ENDREGION}
 
{  THexStringInfo = record
    HexString: THexString;
    ID: Integer;
  end;
  PHexStringInfo = ^THexStringInfo;     }
 
const
//  HEXSTRINGINFO_SIZE = SizeOf(THexStringInfo);
  NOT_AVAILABLE = 'n/a';
 
function KindToStr(const AKind: THexStringKind): string; inline;
function MemToHex(const AData; const ASize: UInt32): string;
 
// результат слияния двух НЕХ-строк
type
  THexMergeResult =
    (hmrImpossible, // слияние невозможно
     hmrPartial,    // слияние частичное (данные перераспределены)
     hmrFull);      // слияния полное (строка 2 влезла в первую полностью)
 
function HexMerge(hs0, hs1: THexString; const MaxDataPerLine: Byte = 255): THexMergeResult;
 
implementation
 
const
  HEX_DIGITS_SET: TSysCharSet = ['0'..'9', 'A'..'F', 'a'..'f']; // 16-чные цифры
  HEX_DIGITS: array[$0..$F] of Char = '0123456789ABCDEF';
 
{$REGION 'service'}
function KindToStr(const AKind: THexStringKind): string; inline;
begin
  Result:= Copy(GetEnumName(TypeInfo(THexStringKind), int32(AKind)), 4, 16);
end;
 
function MemToHex(const AData; const ASize: UInt32): string;
var
  idx: int32;
  p: PByte;// absolute AData;
begin
  p:= @AData;
  SetLength(Result, ASize * 2);
  for idx:= 1 to ASize do
    begin
      Result[2 * idx - 1]:= HEX_DIGITS[p^ shr 4];
      Result[2 * idx - 0]:= HEX_DIGITS[p^ and $F];
      inc(p);
    end;
end;
 
function HexMerge(hs0, hs1: THexString; const MaxDataPerLine: Byte = 255): THexMergeResult;
var
  partsize: int32;
begin
  // проверки потом объединить в одну большую if (.....) then Exit(hmrImpossible);
 
  // проверка, что обе строки - это строки с данными
  if (hs0.Kind <> hskData) or (hs1.Kind <> hskData)
    then Exit(hmrImpossible);
 
  // проверка, что обе строки непустые.
  // Надо ли? на всякий случай, удалить не трудно.
  if (hs0.DataSize = 0) or (hs1.DataSize = 0) or
     (hs0.DataSize >= MaxDataPerLine) // или строка 0 заполнена до предела
    then Exit(hmrImpossible);
 
  // проверка того что адрес второй строки больше адреса первой
  // ровно на длину данных первой строки.
  if (hs1.Address - hs0.Address <> hs0.DataSize)
    then Exit(hmrImpossible);
 
  // строка 0 полностью поместится в строку 1
  if hs0.DataSize + hs1.DataSize <= MaxDataPerLine
    then begin
           hs0.Data:= hs0.Data + hs1.Data;
           Result:= hmrFull;
         end
    // строка 0 влезает в строку 1 только частично ----> перераспределение данных
    else begin
           partsize:= MaxDataPerLine - hs0.DataSize; // столько байт влезет в конец hs0
           hs0.Data:= hs0.Data + Copy(hs1.Data, 0, partsize);
           hs1.Roll(partsize); // сдвиг адресе с потерей данных, которые были скопированы в пред. строке
           Result:= hmrPartial;
         end;
end;
{$ENDREGION}
 
{$REGION 'THexOptimizeResults'}
{ THexOptimizeResults }
 
function THexOptimizeResults.Ratio: Single;
begin
  result:= NewFileSize / OldFileSize;
end;
{$ENDREGION}
 
{$REGION 'THexString'}
function THexOptimizeResults.Success: Boolean;
begin
  Result:= OldCRC32 = NewCRC32;
end;
 
{ THexString }
 
constructor THexString.Create(AHexFile: THexFile);
begin
  FHexFile:= AHexFile; // Ссылка на объект-контейнер
  SetLength(FData, 0);
  FAddress:= $0000;
end;
 
destructor THexString.Destroy;
begin
  SetLength(FData, 0); // возможная
  FData:= nil;         // очистка памяти
  inherited;
end;
 
function THexString.GetChecksum: Byte;
var
  Index: Integer;
begin
  // Расчёт КС
  if Self.DataSize <> 0
    then Result:= (Self.DataSize and $FF)   + // Длина данных
                  ((Address shr 8) and $FF) + // Ст. байт адреса
                  (Address and $FF)           // Мл. байт адреса
    else begin // EOF (:00000001FF)
           Result:= $FF;
           Exit;
         end;
 
  // Плюс тип строки (байт перед массивом данных)
  Inc(Result, RAWByte[3]); // он всегда 3-й от нуля
 
  // Плюс сумма данных
  for Index:= 0 to Self.DataSize - 1 do
    Inc(Result, FData[Index]);
 
  Result:= Byte($100 - Result); // Перевод в доп. код.
end;
 
function THexString.GetCRC32: DWORD;
begin
  Result:= AnyToCRC32(FData, Length(FData));
end;
 
function THexString.GetDataAsText: string;
begin
  if Self.DataSize = 0
    then Exit('');
  Result:= MemToHex(Self.FData[0], Self.DataSize);
end;
 
function THexString.GetDataSize: Byte;
begin
  // Расчёт длины данных в байтах
  Result:= Length(FData) and $FF;
end;
 
function THexString.GetEOF: Boolean;
begin
  // Флаг конца файла
  //Result:= Self.DataSize = 0;
  Result:= Self.Kind = hskEOF;
end;
 
function THexString.GetKind: THexStringKind;
begin
  case RAWByte[3] of
    $00: Result:= hskData;
    $01: Result:= hskEOF;
    $04: Result:= hskKey;
    $ED: Result:= hskError;
  else   Result:= hskUnknown;
  end;
end;
 
function THexString.GetRAWByte(const ByteNumber: Byte): Byte;
var
  bytecount: int32;
begin
  bytecount:= (TextLength - 1) div 2;
  Result:= $ED; // default (dafaced error)
  if ByteNumber < bytecount
    then Result:= StrToIntDef('$' + Copy(FRAWText, 2 + 2 * ByteNumber, 2), Result);
end;
 
function THexString.GetRAWWord(const WordNumber: Byte): Word;
var
  wordcount: int32;
begin
  wordcount:= (TextLength - 1) div 4;
  Result:= $ACED; // default (dafaced error)
  if WordNumber < wordcount
    then Result:= StrToIntDef('$' + Copy(FRAWText, 2 + 4 * WordNumber, 4), Result);
end;
 
function THexString.GetText: string;
var
  Index: Integer;
begin
  if Self.DataSize = 0
    then Result:= ':00000001FF' // EOF
    else begin
           Result:= ':' +                                  // Префикс
                    IntToHex(Self.DataSize and $FF, 2) +   // Длина данных
                    IntToHex(Self.FAddress, 4) +           // Адрес
                    IntToHex(Self.RAWByte[3], 2);          // Тип строки
                    //'00';                                  // Тип строки
 
           for Index:= 0 to Self.DataSize - 1 do           // Данные
             Result:= Result + IntToHex(FData[Index], 2);
 
           Result:= Result + IntToHex(Self.Checksum, 2);   // КС
         end;
end;
 
function THexString.GetTextLength: Integer;
begin
  Result:= FRAWText.Length;
end;
 
procedure THexString.Roll(const Offset: Byte);
var
  count: Byte;
begin
  // удаление offset байт слева и сдвиг адреса на +offset
  count:= min(Offset, Self.DataSize);
  inc(FAddress, count);
  Delete(FData, 0, count);
end;
 
procedure THexString.SetText(const ANew: string);
var
  Index, Len, dLen: Integer;
  dChecksum: Byte;         // Для подсчёта суммы
  rChecksum: Byte;         // Сумма, взятая из НЕХ-строки для сравнение с расчётной
  Digits: string;
begin
  // Установка текста
 
  { Формат НЕХ-строки:
 
    :0100230032AA
    :00000001FF
 
    01 - длина данных
    0023 - начальный адрес
    00 - тип строки
    32 - данные
    AA - контрольная сумма.
 
    :|01|0023|00|32|AA
    :|08|0013|00|C2AF020AF1D2AF32|C4 }
 
  // Длина строки должна быть = длина данных (закодирована во 2-м и 3-м символах) * 2 + 11,
  // начинаться на ":", состоять из 16-чных символов, начиная со 2-го символа,
  // и КС (закодирована 2-мя последними символами) должна совпадать с расчётной
  // по байтам, закодированным со 2-го по N-2-й символами.
 
  Len:= Length(ANew);
 
  if Len < 11
    then raise EHexIncorrectStringLen.Create('Некорректная длина строки (< 11 символов).');
 
  if ANew[1] <> ':'
    then raise EHexInvalidSymbol.Create('Недопустимый символ "' + ANew[1] + '" в позиции 1.');
 
  // Проверка на 16-чные цифры
  for Index:= 2 to Len do
    if not CharInSet(ANew[Index], HEX_DIGITS_SET)
      then raise EHexInvalidSymbol.Create('Недопустимый символ "' + ANew[Index] + '" в позиции ' + IntToStr(Index) + '.');
 
  // Проверка длины строки на соответствие указанной длине данных (закодирована во 2-м и 3-м символах)
  dLen:= StrToInt('$' + Copy(ANew, 2, 2));
  if dLen * 2 + 11 <> Len
    then raise EHexIncorrectDataLen.Create('Длина строки не соответствует обозначенной длине данных.');
 
  // Вычисление и проверка КС
  Digits:= Copy(ANew, 2, Len - 3); // Копирую всё, кроме ":" и КС (последнего байта)
  dChecksum:= $00;
  for Index:= 1 to Length(Digits) div 2 do
    Inc(dChecksum, StrToInt('$' + Copy(Digits, (Index * 2) - 1, 2))); // 1, 3, 5,...
  dChecksum:= Byte($100 - dChecksum);
 
  rChecksum:= Byte(StrToInt('$' + Copy(ANew, Len - 1, 2)));
  if dChecksum <> rChecksum
    then raise EHexIncorrectChecksum.Create('Неверная контрольная сумма (0x' + IntToHex(rChecksum, 2) +
                                     ').'#13#10'Ожидалось 0x' + IntToHex(dChecksum, 2));
 
  // Ну, и наконец, если все проверки не выявили ошибок,
  // выделяю начальный адрес и данные
  FAddress:= Word(StrToInt('$' + Copy(ANew, 4, 4))); // адрес
  Digits:= Copy(ANew, 10, dLen * 2); // Кусок строки с данными
  SetLength(FData, dLen);
  for Index:= 1 to Length(Digits) div 2 do
    FData[Index - 1]:= StrToInt('$' + Copy(Digits, (Index * 2) - 1, 2));
 
  FRAWText:= ANew; // оригинал строки
end;
 
procedure THexString.SetDataSize(const ANew: Byte);
begin
  // Установка новой длины данных (нужно перед записью)
  SetLength(FData, ANew);
end;
 
 
procedure THexString.SetData(const ANew: TBytes);
begin
  // Запись данных
  // Self.DataSize:= Cardinal(Length(AData)); // Проверить, нужно ли выделение памяти или оно автоматическое!!!
  Self.FData:= Copy(ANew); // Копирование, именно копирование!
  FRAWText:= GetText(); // переформирование буфера с сырым текстом
end;
{$ENDREGION}
 
{$REGION 'THexFile'}
{ THexFile }
 
function THexFile.New(const AData: TBytes; const AAddress: Word): THexString;
begin
  // Добавление НЕХ-строки
  Result:= THexString.Create(Self);
  Result.Address:= AAddress;
  Result.Data:= AData;
  Self.Add(Result);
end;
 
 
function THexFile.Optimize(const MaxDataPerLine: Byte): THexOptimizeResults;
var
  idx, progress, old_progress: int32;
begin
  // оптимизация. Возвращает абсолютный коэффициент сжатия (Single)
  ZeroMemory(@result, sizeof(result));
 
  idx:= 0;
  old_progress:= 0;
  result.OldFileSize:= Self.FileSize;
  result.OldDataSize:= Self.DataSize;
  result.OldStrCount:= Self.Count;
  result.OldCRC32:= Self.CRC32;
 
  while idx < Count - 1 do
    begin
      case HexMerge(Self[idx], Self[idx + 1], MaxDataPerLine) of
        hmrImpossible: inc(idx);
        hmrFull:       Self.Delete(idx + 1);
      else inc(idx);  // hmrPartial
      end;
 
      // прогресс выполнения
      if Assigned(FOnOptimizeProgress)
        then begin
               progress:= Round(100.0 * idx / count);
               if old_progress <> progress
                 then begin
                        FOnOptimizeProgress(Self, progress);
                        old_progress:= progress;
                      end;
             end;
    end;
 
  result.NewFileSize:= Self.FileSize;
  result.NewDataSize:= Self.DataSize;
  result.NewStrCount:= Self.Count;
  result.NewCRC32:=    Self.CRC32;
 
  //Assert(result.OldDataSize = result.NewDataSize);
end;
 
constructor THexFile.Create;
begin
  inherited Create(true);
end;
 
function THexFile.GetCRC32: DWORD;
var
  ms: TMemoryStream;
  idx: int32;
begin
  ms:= TMemoryStream.Create();
  try
    for idx:= 0 to Count - 1 do
      if Self[idx].Kind = hskData
        then ms.WriteData(Self[idx].Data, Self[idx].DataSize);
 
    Result:= AnyToCRC32(ms.Memory, ms.Size);
  finally
    ms.Free();
  end;
end;
 
function THexFile.GetDataPercent: Single;
var
  fs: DWORD;
begin
  fs:= GetFileSize();
  if fs <> 0
    then Result:= 100 * Self.DataSize / fs
    else Result:= 0;
end;
 
function THexFile.GetDataSize: Cardinal;
var
  Index: Integer;
begin
  // Количество данных в байтах
  Result:= 0;
  for Index:= 0 to Self.Count - 1 do
    if Self[Index].Kind = hskData //<> hskKey
      then Inc(Result, Self[Index].DataSize);
end;
 
function THexFile.GetFileSize: DWORD;
var
  item: THexString;
begin
  Result:= 0;
 
  if Count = 0
    then Exit;
 
  for item in Self do
    inc(Result, item.TextLength);
  inc(Result, (Count - 1) * 2);
end;
 
function THexFile.GetStringDataMaxSize: DWORD;
var
  hs: THexString;
begin
  Result:= 0;
  for hs in Self do
    Result:= max(hs.DataSize, Result);
  FLastStringDataMaxSize:= Result;
end;
 
function THexFile.LoadFromFile(const AFileName: string): Boolean;
var
  fs: TFileStream;
begin
  Result:= true;
  try
    fs:= TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite);
    try
      Self.LoadFromStream(fs);
      Self.FFileName:= AFileName;
    finally
      fs.Free();
    end;
  except on E: Exception do
    begin
      Result:= false;
      ShowExceptionDlg(E);
    end;
  end;
end;
 
procedure THexFile.LoadFromStream(AStream: TStream);
var
  Index: Integer;
  List: TStringList;
  Item: THexString;
begin
  // Загрузка из стрима
  Self.Clear();
  List:= TStringList.Create();
  try
    List.LoadFromStream(AStream);
 
    for Index:= 0 to List.Count - 1 do
      begin
        Item:= THexString.Create(Self);
        Item.Text:= List[Index];
        Self.Add(Item);
      end;
 
    FFileName:= '';
  finally
    List.Free();
  end;
end;
 
function THexFile.SaveToFile(const AFileName: string): Boolean;
var
  fs: TFileStream;
begin
  Result:= true;
  try
    fs:= TFileStream.Create(AFileName, fmCreate or fmShareExclusive);
    try
      Self.SaveToStream(fs);
      Self.FFileName:= AFileName;
    finally
      fs.Free();
    end;
  except on E: Exception do
    begin
      Result:= false;
      ShowExceptionDlg(E);
    end;
  end;
end;
 
procedure THexFile.SaveToStream(AStream: TStream);
var
  Index: Integer;
  List: TStringList;
begin
  // Сохранение
  List:= TStringList.Create();
  try
    for Index:= 0 to Self.Count - 1 do
      List.Add(Self[Index].Text);
 
    List.SaveToStream(AStream);
  finally
    List.Free();
  end;
end;
 
procedure THexFile.ShowAsStrings(AStrings: TStrings);
var
  idx: int32;
begin
  AStrings.BeginUpdate();
  try
    AStrings.Clear();
    for idx:= 0 to Count - 1 do
      AStrings.Add(Self[idx].Text);
  finally
    AStrings.EndUpdate();
  end;
end;
 
{$ENDREGION}
end.
1
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
10.09.2018, 00:29  [ТС]
Verevkin за исходники спасибо, но я пока лучше буду разбираться с моей программой. Там код маленький, а значит мне с ним проще разобраться.
qwertehok, учитывая Ваше второе замечание, я исправил код. Также я класс описал в другом модуле.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
unit Unit2;
 
interface
 
type
      TMyClass = class(TObject)
 
        IntItemIndex:Integer;
        IntCountNumbers:Integer;
 
        constructor Create;
        procedure SetItemIndex(Value:Integer);
 
        property ItemIndex:Integer write SetItemIndex;
      end;
 
implementation
 
uses
        SysUtils,
        Unit1;
 
constructor TMyClass.Create;
begin
        Inherited Create;
        Self.IntItemIndex:=0;
        Self.IntCountNumbers:=0;
end;
 
procedure TMyClass.SetItemIndex(Value: Integer);
begin
  if Self.IntItemIndex=Value then
        exit;
 
        Self.IntItemIndex:=Value;
        inc(Self.IntCountNumbers,Self.IntItemIndex);
        Form1.Edit1.Text:=IntToStr(Self.IntItemIndex);
        Form1.Edit2.Text:=IntToStr(Self.IntCountNumbers);
end;
 
end.
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses
        Unit2;
 
var
        MyClass:TMyClass;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
        Form1.Edit1.Text:='0';
        Form1.Edit2.Text:='0';
end;
 
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
        MyClass.ItemIndex:=Form1.ComboBox1.ItemIndex;
end;
 
initialization
 
        MyClass:=TMyClass.Create;
 
finalization
 
        FreeAndNil(MyClass);
 
end.
qwertehok, по поводу первого замечания, если я не ошибаюсь, то я его уже исправил. Или именно в этом коде надо самому что-то исправить.
0
пофигист широкого профиля
4769 / 3204 / 862
Регистрация: 15.07.2013
Сообщений: 18,611
10.09.2018, 02:46
_Саша_, ваш код нужно выбросить на помойку!
В методе класса не должно быть ссылок на экземпляр класса.! За исключением Self.
А уж упоминания форм - это вообще перебор! Это даже не двойка, а единица.
0
 Аватар для krapotkin
6849 / 4676 / 1464
Регистрация: 14.04.2014
Сообщений: 20,667
Записей в блоге: 21
10.09.2018, 06:20
методы класса прекрасно осведомлены о других методах и полях этого класса, поэтому не требуется писать
Self.AAA, нужно просто писать AAA

структура связанности модулей должна быть древовидной
если Unit1 uses Unit2 то не должен Unit2 uses Unit1
из этого правила конечно бывают исключения
но они называются костыли

Добавлено через 1 минуту
попробуйте словами описать то, что хотели сделать, тогда вам подскажут решение, чтобы в левых классах не упоминались никакие формы
0
Злостный нарушитель
 Аватар для Verevkin
10340 / 5758 / 1269
Регистрация: 12.03.2015
Сообщений: 26,593
10.09.2018, 08:14
Цитата Сообщение от _Саша_ Посмотреть сообщение
за исходники спасибо, но я пока лучше буду разбираться с моей программой. Там код маленький, а значит мне с ним проще разобраться.
Странный ты чел. Просил помочь, а помощь не принимаешь. Ну ладно, пойду пиво пить работать.

0
 Аватар для _Саша_
33 / 33 / 10
Регистрация: 28.12.2016
Сообщений: 99
10.09.2018, 16:02  [ТС]
Цитата Сообщение от krapotkin Посмотреть сообщение
попробуйте словами описать то, что хотели сделать,...
Главной целью создания данной темы было понять, как работают свойства и понять синтаксис
Delphi
1
property ItemIndex:Integer read GetItemIndex write SetItemIndex;
Благодаря, Вашему первому посту, я в этом вопросе на данный момент полностью разобрался.


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

Цитата Сообщение от krapotkin Посмотреть сообщение
... тогда вам подскажут решение, чтобы в левых классах не упоминались никакие формы
Я всего лишь программист-любитель, который пишет программу только для себя. Как пока умею, так и пишу.

У меня была написана программа, состоящая из модуля формы и 13 модулей, которые обрабатывали информацию введённую
на форме. Переменные (данные) были глобальными и хранились в отдельном модуле. Модуль формы ссылался на некоторые другие модули, часть из которых ссылалась на модуль формы (они брали информацию с формы) (костыли). Да, программа написана безграмотно, но она работает корректно, что было проверено десятки раз. Я её собираюсь дописывать, но чтобы в данных, подпрограммах и модулях не запутаться, я решил данные и подпрограммы объединить вместе в класс (переписать программу). Плюс к этому мне и свойства будут помогать, не нужно будет вызывать некоторые методы класса (они будут автоматически вызываться, как методы GetAAA и SetAAA(Value:тип)). У меня будет дерево классов. И в зависимости от того, какую задачу будет решать программа, программа будет работать с определённым наследником класса. Да, у меня методы класса будут обращаться к форме. Эти классы будут предназначены только для этой моей программы, в других программах их невозможно будет использовать. Что получится - не знаю. Но хочу попробовать.

Цитата Сообщение от krapotkin Посмотреть сообщение
методы класса прекрасно осведомлены о других методах и полях этого класса, поэтому не требуется писать
Self.AAA, нужно просто писать AAA
Я пишу Self.AAA для того, чтобы не запутаться, где поле, свойство, метод данного класса, а где переменные и подпрограммы.
Цитата Сообщение от northener Посмотреть сообщение
_Саша_, ваш код нужно выбросить на помойку!
...
А уж упоминания форм - это вообще перебор! Это даже не двойка, а единица.
Пока мой код меня устраивает, пусть он и безграмотный, и написан на единицу, потому что я понимаю, что в нём написано и понимаю, как он работает.
Цитата Сообщение от northener Посмотреть сообщение
...
В методе класса не должно быть ссылок на экземпляр класса.! За исключением Self.
...
Так я в методах класса к экземпляру MyClass класса TMyClass и не ссылаюсь.
Цитата Сообщение от Verevkin Посмотреть сообщение
Странный ты чел. Просил помочь, а помощь не принимаешь. Ну ладно, пойду пиво пить работать.
Я приношу перед Вами свои извинения, и постараюсь в следующий раз более аккуратно подбирать слова. Я также Вам обещаю, что когда я набирусь знаний по классам и научусь воспринимать большие куски кода, не мною написанные, я в Вашем коде обязательно разберусь.



Я улучшил код своей программы, в моём понимании, добавив секции класса.
Модуль описания класса
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
unit Unit2;
 
interface
 
type
      TMyClass = class(TObject)
        protected
           IntItemIndex:Integer;
           IntCountNumbers:Integer;
        public
           constructor Create;
        protected
           procedure SetItemIndex(Value:Integer);
        public
           property ItemIndex:Integer write SetItemIndex;
      end;
 
implementation
 
uses
        SysUtils,
        Unit1;
 
constructor TMyClass.Create;
begin
        Inherited Create;
        Self.IntItemIndex:=0;
        Self.IntCountNumbers:=0;
end;
 
procedure TMyClass.SetItemIndex(Value: Integer);
begin
  if Self.IntItemIndex=Value then
        exit;
 
        Self.IntItemIndex:=Value;
        inc(Self.IntCountNumbers,Self.IntItemIndex);
        Form1.Edit1.Text:=IntToStr(Self.IntItemIndex);
        Form1.Edit2.Text:=IntToStr(Self.IntCountNumbers);
end;
 
end.

Модуль формы программы
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
 
type
  TForm1 = class(TForm)
    ComboBox1: TComboBox;
    Edit1: TEdit;
    Edit2: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure ComboBox1Change(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
var
  Form1: TForm1;
 
implementation
 
{$R *.dfm}
 
uses
        Unit2;
 
var
        MyClass:TMyClass;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
        Form1.Edit1.Text:='0';
        Form1.Edit2.Text:='0';
end;
 
procedure TForm1.ComboBox1Change(Sender: TObject);
begin
        MyClass.ItemIndex:=Form1.ComboBox1.ItemIndex;
end;
 
initialization
 
        MyClass:=TMyClass.Create;
 
finalization
 
        FreeAndNil(MyClass);
 
end.
0
 Аватар для krapotkin
6849 / 4676 / 1464
Регистрация: 14.04.2014
Сообщений: 20,667
Записей в блоге: 21
10.09.2018, 16:33
Лучший ответ Сообщение было отмечено _Саша_ как решение

Решение

есть принятые соглашения, которые помогают читать ваш код и вам и особенно другим
Например, не-Public поля класса начинаются с большой буквы F
FIntItemIndex, FIntCountNumbers. Это кстати и поможет вам не писать все время Self

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

если вы хотите, чтобы при изменении свойства в вашем классе, что-то происходило вовне, вам требуется как огромном количестве известных вам уже классов Delphi сделать СОБЫТИЕ onChange
Delphi
1
2
3
4
5
6
7
8
9
10
11
TMyClass = class
private
  FOnChange: TNotifyEvent;
  IntItemIndex: integer;
  FIntCountNumbers: integer;
public
  property IntItemIndex: integer read FIntItemIndex write SetIntItemIndex;
  property IntCountNumbers: integer read FIntCountNumbers;
 
  property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
тогда методе SetItemIndex будет выглядеть так
Delphi
1
2
3
4
5
6
7
8
9
10
procedure TMyClass.SetItemIndex(Value: Integer);
begin
  if FIntItemIndex=Value then
        exit;
 
  FIntItemIndex:=Value;
  inc(FIntCountNumbers, FIntItemIndex);
  if Assigned(FOnChange) then
    FOnChange(Self);
end;
а у класса формы появится другой метод. (имя из головы берем)
Delphi
1
2
3
4
5
6
procedure TForm1.OnMyChange(Sender:TObject);
var m:TMyClass absolute Sender;
begin
  Edit1.Text:=IntToStr(m.IntItemIndex);
  Edit2.Text:=IntToStr(m.IntCountNumbers);
end;
тогда
Delphi
1
2
3
4
5
6
7
8
9
procedure TForm1.FormCreate(Sender:TObject);
begin
  MyClass:=TMyClass.Create;
  MyClass.OnChange:=OnMyChange;
end;
procedure TForm1.FormDestroy(Sender:TObject);
begin
  FreeAndNil(MyClass);
end;
ну и вместо глобальной переменной MyClass я бы все-таки перенес ее полем в класс формы
т.к. обработчик будет вызывать форму, значит она должна уже быть создана...

при этом я вообще не понимаю, что за хитроумная логика в строке inc(FIntCountNumbers, FIntItemIndex);
имхо дичь какая-то, но мало ли...
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
10.09.2018, 16:33
Помогаю со студенческими работами здесь

Дважды вычислить значение выражение, первый раз используя процедуру, а второй раз-функцию
Может кто-нибудь сможет решить задачку!!! Дважды вычислить значение выражения, первый раз используя процедуру, а второй раз -функцию. ...

Сокеты ну и Networkstream, раз пишу в .Нет наверное сюда ;)
Если кратко то вопрос таков можно ли при вызове BeginRead у NetworkStream вызывать Write или BeginWrite... Если подробней пишу...

Пишу проект по PYTHON, 8 класс
нужно составить практическую часть для одноклассников(анкеты, задачи и т.п)

Класс можно сконструировать, но это не первый класс в файле
Класс MainForm можно сконструировать, но это не первый класс в файле. В Visual Studio конструктор должен использовать первый класс в файле....

Пишу свой класс по работе с датой и временем
Вот код &lt;?php class TimePassed extends DateTime{ //класс объявляем и наследуем public function...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
15
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru