Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Базарная площадь
  
О разделе

Основная страница

Группы обсуждений


Тематический каталог обсуждений

Архив

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  07:56[Войти] | [Зарегистрироваться]
Обсуждение темы:
Вопросы оптимизации кода

Тема открыта по просьбе жителей Королевства и посвящена обсуждению вопросов оптимизации кода. Выставляйте свои лучшие и худшие тексты и не стесняйтесь их обсуждать. В споре рождается истина. Или, по крайней мере, оптимизация.

Количество сообщений на странице

Порядок сортировки сообщений
Новое сообщение вверху списка (сетевая хронология)
Первое сообщение вверху списка (обычная хронология)

Перейти на конкретную страницу по номеру


Всего в теме 737 сообщений

Добавить свое сообщение

Отслеживать это обсуждение


Смотрите также обсуждения:
Тестирование проекта. Отладка.
  • Подводные камни
  • Централизованная обработка ошибок
  • Бета-тестирование
  • Давайте учиться на ошибках.
  • Почему программисты допускают ошибки?
  • Автоматизированные тесты для GUI
  • О системах контроля ошибок

  • <<<... | 487—438 | 437—388 | 387—338 | ...>>>
    Всего сообщений в теме: 737; страниц: 15; текущая страница: 7


    № 437   02-06-2008 02:51 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 435« (Ins)
    ___________________________

    Первый паттерн - это классовая ссылка + виртуальный конструктор.
    Только сейчас заметил, что здесь ошибка. Factory Method предполагает, что реальный тип создаваемого объекта определяется внутри метода. А если вы уже вызвали виртуальный конструктор, то все, поздно. Тип объекта жестко определен и поменять его нельзя.


    № 436   02-06-2008 02:49 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 434« (Бел Амор)
    ___________________________

    Ну, в данном случае это легко исправляется путём замены явного указания класса на неявный Self... :)
    Так вот вас и спрашивают: зачем вам пусть и неявный, но неиспользуемый параметр?


    Ответ на »сообщение 435« (Ins)
    ___________________________

    Первый паттерн - это классовая ссылка + виртуальный конструктор. Второй реализуется с помощью перекрывания виртуальных NewInstance/FreeInstance, а единственной точкой входа по прежнему может оставаться конструктор. Встречный вопрос, а чем в реализации данных паттернов нам помогут class static методы? :)
    Если Delphi - единственный возможный язык в вашей организации (или у вас, как индивидуального разработчика), то конечно.
    Просто мне бы хотелось видеть решения, которые без особых усилий можно переписать на C#, Java, Python.


    № 435   02-06-2008 01:57 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 433« (panda)
    ___________________________
    И как тогда правильно реализовывать паттерны Factory Method и Singleton без class/static методов?

    Насколько я понял, в контексте речь шла только о замене классовыми методами отдельно лежащих функций, которые в данном случае обычно выступают как class static - не используют Self. "Не размазывать логику по юниту" - это может являться оправданием такого подхода, но у него есть и обратная сторона - перегрузка класса дополнительными сущностями, которые по сути к классу могут иметь весьма косвенное отношение. Что касается того, как реализовать Factory Method и Singletone - а зачем здесь в класс добавлять классовые методы, которые используются как статические? Первый паттерн - это классовая ссылка + виртуальный конструктор. Второй реализуется с помощью перекрывания виртуальных NewInstance/FreeInstance, а единственной точкой входа по прежнему может оставаться конструктор. Встречный вопрос, а чем в реализации данных паттернов нам помогут class static методы? :)

    Ответ на »сообщение 434« (Бел Амор)
    Понимаете в чем была проблема... Вы же сами пишите, что удаляете переменную типа форма, чтобы не использовать ее внутри методов, а использовать вместо этого Self. Это правильно (не в смысле "удалять", а в смысле "использовать Self") В случае с классовым методом - все должно быть симметрично. Разница лишь в том, что классовый метод работает с классом, а не с экземпляром. Если вы отказываетесь от работы с конкретным экземпляром внутри instance-метода, то почему вы не отказываетесь работать с конкретным классом внутри class-метода? В общем, моя претензия была только в этом, у меня нет претензий к классовым методам как таковым, если они не class static. Просто вы намеренно объявили процедуру именно как метод, подчеркнули это, но не воспользовались тем различием, что существует между методом и обычной процедурой.
     Ins


    № 434   02-06-2008 01:10 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 433« (panda)
    ___________________________

    >>> А вот неиспользование переданного параметра - это уже серьезный признак "дурно пахнущего" ((c) М. Фаулер) кода.

    Ну, в данном случае это легко исправляется путём замены явного указания класса на неявный Self... :)

    class function TForm2.ChooseAbon(Mask: String; Field: TField): Boolean;
    begin
      with Create(nil) do
      begin
        Result := (ShowModal = mrOk);
        if Result then
          Field.AsInteger := Query1.FieldByName('ID').AsInteger;
        Free;
      end;
    end;



    № 433   01-06-2008 23:33 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 428« (Ins)
    ___________________________

    Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?
    Если процедура спроектирована так, чтобы работать только с одним классом, то помещение метода в этот класс уменьшит размазывание логики по программе.


    Ответ на »сообщение 430« (Антон Григорьев)
    ___________________________

    Это всё - следствие того влияния, которое оказвют на программирование неряшливы спроектированные C++ и C#. Там действительно класс нагружен совершенно несвойственной ему функцией - быть пространством имён.
    Э... почему это? И как тогда правильно реализовывать паттерны Factory Method и Singleton без class/static методов?

    Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?
    Если процессорное время в данном случае настолько критично, то надо переходить с Delphi на "более другой" язык.
    А вот неиспользование переданного параметра - это уже серьезный признак "дурно пахнущего" ((c) М. Фаулер) кода.


    № 432   01-06-2008 09:04 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 431« (Бел Амор)
    ___________________________
    Этот подход используется только при показе форм. При этом потеря такого количества времени совершенно некритична.

    Это понятно. Но на мой взгляд смысл использования классового метода в приведенном примере притянут за уши. Достаточно трудно сформулировать общие рекомендации по использованию классовых методов, ситуации могут быть разными, боюсь, у меня это не получится. Но чисто мое субъективное мнение, что классовые методы по настоящему полезны тогда, когда они не повторяют поведение статик-методов из .NET или Java, а когда для них включается и начинает работать полиморфизм. Т.е. иерархия подразумевает наличие у класса потомков, чье поведение может отличаться, и к которым клиент обращается через интерфейс базового класса, имея на руках классовую ссылку:

    type
      TShape = class(...)
      public
        class function ClassAlias: String; virtual; abstract;
      end;
     
      TShapeClass = class of TShape;

      TLine = class(TShape)
      ...
      TRect = class(TShape)
      ...

    ...

    procedure RegisterShape(ShapeClass: TShapeClass);
    begin
      RegisterClassAlias(ShapeClass, ShapeClass.ClassAlias);
    end;

     Ins


    № 431   31-05-2008 13:46 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 430« (Антон Григорьев)
    ___________________________


    Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?

    Этот подход используется только при показе форм. При этом потеря такого количества времени совершенно некритична.

    Классовый метод не может иметь доступа ко всем членам класса, потому что он не привязывается ни к какому объекту и не имеет ссылки Self (точнее, Self у него есть, но это ссылка на класс, а не на объект). Соответственно, к скрытым методам вы можете обращаться только если передали явно указатель на объект. И тут возникает вопрос: а этот метод точно должен быть классовым? Может, его проще сделать обычным?

    Речь шла о применении классовх методов в контексте замены часто применяемой последовательности Create-ShowModal-Free на вызывающей стороне на всё то-же самое внутри классового метода. Объект создаётся внутри этого метода и речь шла о доступе к членам именно этого объекта. Продемонстрирую это примером из »вопрос КС №57348« Там как раз зашла речь о классовых методах.

    unit Unit2;

    interface

    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, DB, DBTables, StdCtrls, Grids, DBGrids;

    type
      TForm2 = class(TForm)
        DBGrid1: TDBGrid;
        btnOk: TButton;
        btnCancel: TButton;
        Edit1: TEdit;
        DataSource1: TDataSource;
        Query1: TQuery;
      public
        constructor Create(AOwner: TComponent); override;
        class function ChooseAbon(Mask: String; Field: TField): Boolean;
      end;

    //var
    //  Form2: TForm2;

    implementation

    {$R *.dfm}     

    constructor TForm2.Create(AOwner: TComponent);
    begin
      inherited;
      // Запросы и т.д.
    end;

    class function TForm2.ChooseAbon(Mask: String; Field: TField): Boolean;
    begin
      with TForm2.Create(Application) do
      begin
        Result := (ShowModal = mrOk);
        if Result then
          Field.AsInteger := Query1.FieldByName('ID').AsInteger;
        Free;
      end;
    end;

    end.

    Вызов:

      TForm2.ChooseAbon('Сидоров', Table1.FieldByName('AbonId'));

    Чем плох этот вариант? Python в том вопросе привёл свой вариант. Как бы сделали вы?

    >>> Когда есть навыки работы с процедурами, такие вопросы тоже не возникают.

    Ну почему сразу "отсутствие навыков работы с процедурами"? Хотим мы этого или не хотим, но в основном работа идёт с классами, и когда через некоторое время "после того, как...", встречается код:

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ChooseAbon('Сидоров', Table1.FieldByName('AbonId'));
    end;

    ...то первая мысль - это "ChooseAbon - метод класса TForm1"...

    Между тем, процедурное программирование тоже имеет свои сильные стороны, и надо не фанатично держаться за один подход, а в зависимости от ситуации использовать то или это.

    Согласен...


    № 430   31-05-2008 12:20 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 429« (Бел Амор)
    ___________________________

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

    Это всё - следствие того влияния, которое оказвют на программирование неряшливы спроектированные C++ и C#. Там действительно класс нагружен совершенно несвойственной ему функцией - быть пространством имён.

    1. Функция входит в состав класса и не вносит неоднородности. Всё объявлено в одном месте.

    Классовый метод имеет неявный параметр Self, через который ему передаётся ссылка на класс. Соответственно, при каждом вызове метода тратится дополнительное процессорное время и дополнительная память на передачу параметра, который потом не используется. Оно вам надо?

    2. Метод имеет доступ ко всем членам класса. Хотя доступ к закрытым членам в таких случаях требуется крайне редко, но тем не менее... И хотя в пределах модуля и действует полная видимость, но такой доступ из не-метода не очень красив. Кроме того, сейчас есть ключевое слово strict...

    Классовый метод не может иметь доступа ко всем членам класса, потому что он не привязывается ни к какому объекту и не имеет ссылки Self (точнее, Self у него есть, но это ссылка на класс, а не на объект). Соответственно, к скрытым методам вы можете обращаться только если передали явно указатель на объект. И тут возникает вопрос: а этот метод точно должен быть классовым? Может, его проще сделать обычным?

    3. При вызове не возникает вопросов "это метод или что?", "А где это объявлено?"

    Когда есть навыки работы с процедурами, такие вопросы тоже не возникают.

    Если указывать ещё и модуль, то нет большой разницы - указывать модуль или класс, и тогда вступает в силу пункт 1.

    Во-во, именно это я и имел ввиду, когда говорил о том, что классу придают несвойственные ему функции пространства имён. Вообще, всё это следствие моды на ООП, всё засунуть в объекты - это типа хорошо (Java и C# - жертвы такой моды). Между тем, процедурное программирование тоже имеет свои сильные стороны, и надо не фанатично держаться за один подход, а в зависимости от ситуации использовать то или это.


    № 429   31-05-2008 11:37 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 428« (Ins)
    ___________________________


    Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?

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

    1. Функция входит в состав класса и не вносит неоднородности. Всё объявлено в одном месте.
    2. Метод имеет доступ ко всем членам класса. Хотя доступ к закрытым членам в таких случаях требуется крайне редко, но тем не менее... И хотя в пределах модуля и действует полная видимость, но такой доступ из не-метода не очень красив. Кроме того, сейчас есть ключевое слово strict...
    3. При вызове не возникает вопросов "это метод или что?", "А где это объявлено?" Если указывать ещё и модуль, то нет большой разницы - указывать модуль или класс, и тогда вступает в силу пункт 1.

    А в принципе, вы правы, здесь есть над чем подумать...


    № 428   31-05-2008 06:38 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 427« (Бел Амор)
    ___________________________
    12. Вместо отдельнолежащих процедур часто удобно использовать классовые методы (см. class methods) Пример использования можно посмотреть здес: »вопрос КС №50002« (class function CheckPassword: Boolean).

    Хех :) А чем в приведенном случае классовый метод принципиально лучше, чем простая функция, не классовая и не метод?

    function CheckPassword: Boolean;
    begin
      with TCheckPasswordForm.Create(Application) do
      begin
        AllowTryCount := 3;
        Result := (ShowModal = mrOK);
        Free;
      end
    end;


    Это я к тому, что классовая функция - это прежде всего метод класса, а это значит, что ей передается в качестве параметра ссылка на класс, для которого он выполняется. Если этот параметр внутри функции никак не используется (явно или неявно), то смысла делать функцию классовой мало. Вот если бы у вас было как-нибудь так:

    TPasswordFormClass = class of TCheckPasswordForm;

    class function TCheckPasswordForm.CheckPassword: Boolean;
    begin
      with TPasswordFormClass(Self).Create(Application) do
      begin
        AllowTryCount := 3;
        Result := (ShowModal = mrOK);
        Free;
      end
    end;


    То это бы в корне меняло дело :) Тогда от такой формы можно было бы и потомков породить, а клиент мог бы обращаться к ним через интерфейс класса TCheckPasswordForm

    А еще классовые методы крайне полезны, когда они виртуальные. Эх, еще бы классовые конструкторы в язык добавить - точно не помешало бы... :)
     Ins


    № 427   27-05-2008 03:56 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 426« (Бел Амор)
    ___________________________

    Исправление ссылок:

    8. При полной компиляции проекта не должно быть ни одного предупреждения. Более подробно эта тема раскрыта здесь: »сообщение 208 в теме №383 на БП«
    10. Внутри процедуры переменную Result также можно использовать гораздо шире, чем это обычно делается. Вплоть до использования её в качестве переменной цикла. Но тут нужно быть очень осторожным и помнить, что переменная цикла после завершения цикла имеет неопределённое значение. Использовать переменную цикла, в качестве которой используется Result, вне цикла можно только при выходе из цикла по Exit, т.е. при выходе из процедуры нпосредственно из цикла. Этот вопрос рассматривался здесь: »сообщение 199 в теме №383 на БП«


    № 426   27-05-2008 03:38 Ответить на это сообщение Ответить на это сообщение с цитированием
    ...А найти эту тему я хотел для того, чтобы ответить здесь на »вопрос КС №62346«
    В нём автор попросил накидать ему побольше советов, что называется, "хороших и разных" и я посчитал, что эта тема наилучшим образом подходит для ответа на этот вопрос... Дальше последует поток сознания на самые разные темы. Очень кратенько, без особых обоснований, поскольку всё это уже неоднократно обсуждалось. Всё нижеследующее отражает моё личное мнение, с которым могут быть согласны далеко не все...

    1. На время отладки включать максимальный контроль: Range checking, Overflow checking и т.д.
    2. Начинать новый проект следует с отключения помещения новых форм в список автосоздаваемых. Форм - десятки, а датамодулей - единцы и их можно сделать автосоздаваемыми и вручную. Кроме того, часто имеет значение порядок их создания, поэтому может иметь смысл дата-модули создавать самому в конструкторе главной формы в нужном порядке. Написанное кодом всегда надёжнее того, что можно случайно зацепить мышкой в каком-либо списке.
    3. Сразу после добавления в проект новой формы следует удалить автоматически создаваемое объявление переменной для этой формы. Во-первых, это не будет провоцировать на использование таких переменных, во-вторых, это сразу выявит факт того, что форма по какой-либо причине попала в список автосоздаваемых, и в третьих, исключит возможность использования таких переменных "по запарке" (например, вместо Self).
    4. Создавать формы следует путём вызова конструктора, а не Application.CreateForm
    5. Переменные типа форм либо должны быть локальными, либо можно вообще обойтись без переменной, используя конструкцию with TForm1.Create(nil) do
    6. В качестве владельца коструктору формы лучше передавать nil. Это лучше, чем часто втавляемый на автомате Application тем, что если забыли освободить форму, то при контроле утечки памяти в случае использования в качестве владельца Application при завершении приложения такие формы будут автоматически освобождаться и информация о них не попадёт в отчёт. При использовании в качестве владельца nil такие формы доживут до отчёта и на них будет обращено внимание.
    7. Включение выдачи отчёта об утечке памяти при завершении программы в последних версиях Delphi осуществляется, в частности, включением в код программы строчки:

      ReportMemoryLeaksOnShutdown := True;

    8. При полной компиляции проекта не должно быть ни одного предупреждения. Более подробно эта тема раскрыта здесь: »сообщение 383 в теме №208 на БП«
    9. Внутри процедуры параметр, переданный без const или var можно использовать как локальную переменную. Об этом часто забывают.
    10. Внутри процедуры переменную Result также можно использовать гораздо шире, чем это обычно делается. Вплоть до использования её в качестве переменной цикла. Но тут нужно быть очень осторожным и помнить, что переменная цикла после завершения цикла имеет неопределённое значение. Использовать переменную цикла, в качестве которой используется Result, вне цикла можно только при выходе из цикла по Exit, т.е. при выходе из процедуры нпосредственно из цикла. Этот вопрос рассматривался здесь: »сообщение 383 в теме №199 на БП«
    11. Часто бывают удобными вложенные процедуры.
    12. Вместо отдельнолежащих процедур часто удобно использовать классовые методы (см. class methods) Пример использования можно посмотреть здес: »вопрос КС №50002« (class function CheckPassword: Boolean).


    № 425   27-05-2008 03:36 Ответить на это сообщение Ответить на это сообщение с цитированием
    Решил найти эту тему и по простоте своей душевной задал поиск 50 последних активных тем... Наивный... Оказывается, такая замечательная тема пребывает в забвении уже более года... И остановились здесь, оказывается, ещё на "Методе Geo"... Уж коли я сюда зашёл, заодно подкину идею небольшого усовершенсвования вышеупомянутого метода путём использования совместно с ним включаемых файлов: »вопрос КС №61819«


    № 424   28-02-2007 07:55 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 423« (Бел Амор)
    ___________________________
    >>> Я присоединяюсь к неоднократно высказывавшемуся предложению написать статью на эту тему
    Вообще-то у меня в планах был цикл статей по разработке и использованию собственных компонент, где я и собирался описать данный прием. Но это последнее обсуждение подтолкнуло к мысли, что не надо ждать, а надо написать небольшую статью прямо сейчас, так как очень много ценных мыслей разбросано в разных обсуждениях.

    Постараюсь найти время на это.
     Geo


    № 423   28-02-2007 07:40 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 422« (Geo)
    ___________________________
    >>> Посмотрите вот это обсуждение http://delphikingdom.ru/asp/articles_forum.asp?ArticleID=1296

    Спасибо за ссылку.

    А вот не надо было делать: "На самом деле подменить можно не только родительский класс, а вообще любой, у которого при текущих настройках список свойств в dfm не противоречит свойствам замещающего класса" ;-) Вы шаманите,

    Мы не шаманим, мы экспериментируем :)

    >>> а использую позднее связывание как документированную возможность ООП и Delphi.

    Речь вообще не об этом. Речь о том, что способ основан на предположении, что "дизайнер вообще не смотрит по сторонам, а занимается только тем кодим, который он сам вставил".
    До определенной степени это так. Но только до определенной. В будущем это может измениться.

    >>> Впрочем, смотрите обсуждение по ссылке, приведенной выше.

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


    № 422   28-02-2007 01:47 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 421« (Бел Амор)
    ___________________________
    >>> Возможность, которую использует этот метод, является недосмотром программистов Borland. Программисты CodeGear в любой момент могут это исправить (если еще не исправили)
    Посмотрите вот это обсуждение http://delphikingdom.ru/asp/articles_forum.asp?ArticleID=1296
    Там я постарался проанализировать "опасность" применения этого приемчика. Пересказывать не хочется, так как я тоам достаточно много написал.

    >>> Получаем исключение: "Property BevelKind does not exist"
    А вот не надо было делать: "На самом деле подменить можно не только родительский класс, а вообще любой, у которого при текущих настройках список свойств в dfm не противоречит свойствам замещающего класса" ;-) Вы шаманите, а использую позднее связывание как документированную возможность ООП и Delphi. Впрочем, смотрите обсуждение по ссылке, приведенной выше.
     Geo


    № 421   27-02-2007 16:00 Ответить на это сообщение Ответить на это сообщение с цитированием
    Хотелось бы высказать несколько мыслей по поводу метода, описанного в »вопрос КС №35814«
    Я не знаю, работает ли он на D2006, если кому несложно, проверьте, напишите сюда (у меня ее нет).

    1. Этот способ имеет смысл применять только до Delphi 7, поскольку в дальнейших версиях он полностью перекрывается возможностями class helper'ов.
    2. Возможность, которую использует этот метод, является недосмотром программистов Borland. Программисты CodeGear в любой момент могут это исправить (если еще не исправили).
    3. На самом деле подменить можно не только родительский класс, а вообще любой, у которого при текущих настройках список свойств в dfm не противоречит свойствам замещающего класса. А поскольку в dfm пишутся не все свойства, а только те, значение которых не совпадают со значениями, указанными в default, то открываются широчайшие возможности для махинаций. Причем, если потом изменить значения свойств, то эти свойства могут попасть в dfm и  вызвать конфликт. Приведу пример.
    Делаем форму, помещеаем на нее TPanel и TStaticText (свойства не меняем).

    unit Unit1;

    interface

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

    type
      TForm1 = class(TForm)
        Panel1: TPanel;
        StaticText1: TStaticText;
      end;

    var
      Form1: TForm1;

    implementation

    {$R *.dfm}

    end.


    Создаем второй модуль:

    unit Unit2;

    interface
    Uses ExtCtrls, Classes, Graphics;

    type
      TStaticText = class(TPanel)
      public
        Constructor Create(AOwner: TComponent); override;
      end;

    implementation

    constructor TStaticText.Create(AOwner: TComponent);
    begin
      inherited;
      color := clRed;
    end;

    end.


    Запускаем и получаем замечательно работающую форму с двумя панелями: обычной и красной.
    Теперь ищем свойство, которое есть в TStaticText, но нет в TPanel. Например, BevelKind.
    Теперь меняем в TStaticText BevelKind с bkNone на bkFlat. Запускаем... Получаем исключение: "Property BevelKind does not exist". Возвращаем его в bkNone - опять работает. Красота...
    Так что цитата, приведенная Антоном Григорьевым в обсуждении вопроса 35814 кажется мне изумительно уместной :)
    Способ достаточно интересный и неожиданный. По крайней мере он заслуживает того, чтобы о нем знать. Его даже можно иногда применять на старой Delphi. Но хорошо отдавая себе отчет в том, что ты делаешь. И применять его широко я бы не стал.


    № 420   27-02-2007 12:42 Ответить на это сообщение Ответить на это сообщение с цитированием
    В общем, вопрос решился следующим образом:
    Во вспомогательный модуль помещаем код:

    type
      TRadioGroup = class(ExtCtrls.TRadioGroup)
      protected
        procedure Paint; override;
        procedure SetEnabled(Value: Boolean);  override;
      end;

    procedure TRadioGroup.Paint;
    begin
      inherited;
      Canvas.Font.Style := [fsBold];
      Canvas.Font.Color := IfThen(Enabled, clWindowText, clGrayText);
      Canvas.TextOut(8, 0, Caption);
    end;

    procedure TRadioGroup.SetEnabled(Value: Boolean);
    begin
      inherited;
      Invalidate;
    end;


    Подключаем в соответствующих формах, указывая этот модуль в конце Uses секции interface.
    При переходе на свежую версию Delphi либо удаляем вушеуказанный код, либо преобразуем его в class helper. Так что это решение отвечает всем условиям задачи, сформулированным в »сообщение 411«.
    Единственно, что человеку, не посвященному в эту тайну, будет крайне тяжело понять, откуда там берется жирный заголовок. Но комментарии еще никто не отменял...
    Так что спасибо Ins'у и Geo, а также всем, принявшим участие в ломании копий, штакетника и прочего...


    № 419   27-02-2007 12:36 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 417« (Андрей Токинов)
    ___________________________
    >>> »вопрос КС №49421« опять замкнулся на »вопрос КС №35814«

    А кто-то, помнится, переживал, что вопрос 35814 где-то там затеряется и "его никто не найдет". По-моему, он идет на рекорд по цитируемости... :)


    № 418   27-02-2007 12:33 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 416« (panda)
    ___________________________

    >>> Пример, который привел Ins, в Вашем случае будет смотреться лучше всего

    Да, я считаю это оптимальным вариантом.



    № 417   27-02-2007 02:43 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 412« (Ins)
    ___________________________
    »вопрос КС №49421« опять замкнулся на »вопрос КС №35814«, что и требовалось доказать.
    Не все хорошее придумано в Borland :)


    № 416   26-02-2007 23:42 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 411« (Бел Амор)
    ___________________________

    Я был бы просто счастлив поучиться хорошему стилю у настояшего гуру...
    Пример, который привел Ins, в Вашем случае будет смотреться лучше всего (раз Вам надо минимум затрат).
    Но если надо получить действительно другой компонент во многих формах крупного проекта, то имеет смысл как раз и сделать этот другой компонент. Будет самый очевидный и наглядный способ (даже более наглядный, чем class helper).


    № 415   26-02-2007 16:35 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 414« (Ins)
    ___________________________

    >>> Для противников такого способа, есть запасной вариант, даже три!

    Прям хоть цитатник составляй:
    - Мистер Фикс, есть ли у вас план?
    - Есть ли у меня план... Есть ли у меня план... У меня есть три плана!!!

    >>> 1. Создание компонентов в рантайм

    Теряется наглядность

    >>> 2. Регистрация потомков в палитре

    Именно этого хотелось избежать

    А по поводу "противник-не противник": в данном конкретном случае, похоже, это - именно то, что надо.



    № 414   26-02-2007 15:40 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 413« (Бел Амор)
    ___________________________
    Вообще-то у меня есть некоторые соображения против использования такой подмены

    Для противников такого способа, есть запасной вариант, даже три!
    1. Создание компонентов в рантайм
    2. Регистрация потомков в палитре
    3. Подмена WindowProc
     Ins


    № 413   26-02-2007 15:32 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 412« (Ins)
    ___________________________

    >>> Такой вариант пойдет?

    Хех... Хитрый способ Geo... :)
    Вообще-то у меня есть некоторые соображения против использования такой подмены, но в данном конкретном случае этот способ очень даже к месту и выглядит очень симпатично.
    На первый взгляд неплохая замена моему в данной конкретной ситуации. Будем смотреть.
    Вариант номер один принят.


    № 412   26-02-2007 14:33 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 411« (Бел Амор)
    ___________________________
    Могли бы вы привести в качестве примера свой вариант решения данной конкретной задачи?

    Такой вариант пойдет?

    type
      TRadioGroup = class(ExtCtrls.TRadioGroup)
      protected
        procedure Paint; override;
      end;
    ...
    procedure TRadioGroup.Paint;
    begin
      inherited;
      Canvas.Brush.Color:=Color;
      Canvas.Font.Color:=clBlue;
      Canvas.TextOut(8,0,Self.Caption);
    end;

     Ins


    № 411   26-02-2007 14:14 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 410« (panda)
    ___________________________

    >>> Любите class helpers "и Ваши волосы будут мягкими и шелковистыми" ;)

    Я их полюблю... потом... когда перейду на D2006 или D2007...
    Я бы даже сказал, "как миленький..." (c) Карабас Барабас.
    А пока я работаю на Delphi 6

    >>> Какой ужас.

    Я был бы просто счастлив поучиться хорошему стилю у настояшего гуру...
    Могли бы вы привести в качестве примера свой вариант решения данной конкретной задачи?
    Мой вариант привел вас в ужас. Я бы хотел посмотреть на ваш. И поучиться мастерству (без шуток).
    Пара слов о том, "что, зачем и почему".
    Используется Delphi 6. Контролы старые (в стиле Win98).
    В радиогруппе шрифт надписи на рамке (Caption) совпадает со шрифтом подписей к радиокнопкам. Что в некоторых ситуациях достаточно неудобно, т.к. заголовок сливается с пунктами выбора. Возникает желание как-то этот заголовок выделить, например, жирным шрифтом. В новых контролах (WinXP), я так понимаю (поправьте, если я ошибаюсь), заголовок выделяется цветом и этой проблемы не существует.
    Возникает задача: реализовать выделение заголовка в радиогруппе так, чтобы все это нормально работало при использовании D6. При переходе под D2006 произойдет отказ от этого метода. У меня - путем простого удаления всех вызовов процедуры BoldCaption в проекте (их с десяток на весь проект). И это все. Прошу предложить более рациональный вариант. Мой изложен в »сообщение 406«


    № 410   25-02-2007 23:45 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 400« (Бел Амор)
    ___________________________

    Какой ужас.
    Любите class helpers "и Ваши волосы будут мягкими и шелковистыми" ;)


    № 409   24-02-2007 15:10 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 407« (Geo), »сообщение 408« (Cepгей Poщин)
    ___________________________

    Хорошо, мне понятна ваша позиция, тем более, что со многим я согласен (хотя и не со всем, но со значительной частью). В любом случае, считаю, что дискуссия была полезной и благоприятно повлияет на мировоззрение как мое, так и всех тех, кто был вынужден все это читать :)

    >>> Синие писолки и линолеум вместо брызговиков вещь крайне полезная...

    Знаю... Правильно подобранные пысалки повышают мощность двигателя на 10 л.с.

    >>> Общие утверждения редко бывают истинными, если их применять ко всем без исключения частным случаям ;-)

    Вот-вот... И я об этом...



    № 408   24-02-2007 13:30 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 404« (Бел Амор)

    Синие писолки и линолеум вместо брызговиков вещь крайне полезная...
    Автомобильный фольклор

    ___________________________
    Про фантазию я, кажется, уже говорил... Несколько раз порывался отправить ответ, но после фильтрации нецензурщины оставались одни предлоги. Дело не в фантазии, просто насмотрелся я на такие произведения.
     Cep


    № 407   24-02-2007 13:18 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 400« (Бел Амор)
    ___________________________
    >>> Если отвлечься от конкретного чекбокса, то в общем случае с таким утверждением я не согласен.
    Общие утверждения редко бывают истинными, если их применять ко всем без исключения частным случаям ;-)

    >>> вопрос: какие косяки во внешнем виде и поведении сможет заметить ваш острый глаз и какие потенциальные проблемы могут возникнуть впоследствии?
    Автор все вылизал, так что комар носа не подточит. Но поставили программу на другой компьютер, а там шрифт немного другой. И... бабах! ... текст уже опутсился на пару пикселов ниже. А потом поставили на другую ОС, где радиобуттон организован совсем по-другому. И тут наше сочетание стандартного компонента (который является надстройкой надо объектом ОС) и нестандартного текста к нему превращается в полную кашу.

    Скорость обработки -- это вообще отдельная песня. Слепили мы что-то нестанартное из трех различных компонентов. При перерисовке компоненты будут перерисовываться по очереди, реагируя на WM_PAINT, в то время как единый компонент будет перерисовываться сразу целиком.
     Geo


    № 406   24-02-2007 04:45 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 405« (Антон Григорьев)
    ___________________________
    >>> Сам эту процедуру не видел, но из вашего описания получается следующие косяки:

    Виноват... Не очень ясно объяснил. Вы немного не так поняли.
    Итак, у обычной радиогруппы присутствует:
    1. Рамка
    2. Надпись на рамке (это и есть TRadioGroup.Caption)
    3. Несколько радиокнопок с надписями (задаются через TRadioGroup.Items)

    Задача: не изменяя ничего внутри рамки, сделать надпись вверху слева на рамке жирной.
    Проблема в том, что шрифт задается один на всех и отдельно установить Bold для TRadioGroup.Caption не получится. Поэтому мы на место этой надписи просто сажаем новую TLabel и для нее и задаем нужный шрифт.
    Ни с какими событиями это не связано, это чисто внешнее украшательство. В сухом остатке, если убрать все лишнее (там есть еще несколько нюансов, не имеющих отношения к делу в данном случае), то все это безобразие выглядит примерно так:

    procedure BoldCaption(RadioGroup: TRadioGroup);
    begin
      with TLabel.Create(RadioGroup) do
      begin
        Parent := RadioGroup;
        Top := 0;
        Left := 8;
        AutoSize := True;
        Caption := RadioGroup.Caption;
        Font.Style := [fsBold];
        RadioGroup.Caption := '';    // на случай, если захотим выравнивать метку
      end;
    end;


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

    Приведу пример реального использования (изменены фамилии и убрано 4 строки):

    constructor TSomeForm.Create;
    begin
      inherited Create(Application);
      ...
      SomeDoc := TSomeDoc.Create;
      ...
      ...
      PageControl.ActivePage := tsCommon;
      ...
      {Внешний вид}
      WindowState := wsMaximized;
      BoldCaption(rgSome1);
      BoldCaption(rgSome2);
      BoldCaption(rgSome3);
      BoldCaption(rgSome4);
      pnlSome.BevelOuter := bvNone;
    end;

    destructor TSomeForm.Destroy;
    begin
      SomeDoc.Free;
      inherited Destroy;
    end;


    Все ясно, четко и понятно (замечу, что форма очень навороченная). Ошибиться или запутаться можно, но это надо очень постараться.


    № 405   23-02-2007 23:52 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 400« (Бел Амор)
    ___________________________

    Если отвлечься от конкретного чекбокса, то в общем случае с таким утверждением я не согласен. В качестве примера приведу поцедуру BoldCaption из того-же модуля FormUtil, которая создает метку, сажает ее на RadioGroup в нужное место, делает ее Bold, копирует себе Caption радиогруппы и обнуляет ее. Получается радиогруппа с жирным заголовком. Внимание, вопрос: какие косяки во внешнем виде и поведении сможет заметить ваш острый глаз и какие потенциальные проблемы могут возникнуть впоследствии? При условии, что эта процедура вызывается один раз в конструкторе формы и не планируется устанавливать Enabled = False, а также менять Caption.

    Сам эту процедуру не видел, но из вашего описания получается следующие косяки:

    1. У нормальной радиокнопки, когда она в фокусе, название обводится пунктирным прямоугольником, чего у вашей метки нет.

    2. У нормальной радиокнопки для выбора можно щёлкать мышью не только по кружку, но и по тексту.

    И если второй пункт реализуется относительно просто с помощью TLabel.OnClick, то первый требует переписывания TLabel. Так не проще ли сразу переписать тот компонент, который нужен?

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


    № 404   23-02-2007 15:41 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 403« (Cepгей Poщин)
    ___________________________

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

    Ну, судя по написанному вами далее, фантазия у вас развита неплохо, так что не скромничайте... А в качестве примера: неужели никогда не возникало желания, чтобы какой-нибудь хорошо акцентированный TDBEdit что-то отображал, но при этом был не только ReadOnly, но еще и не мог принимать фокус? И при этом не был блеклым? Что, писать наследника? Ужоз... Ж8D

    Где в описании написано, что её нужно вызывать только в конструкторе и не более одного раза?

    Сэр... Вы зануда...

    Предлагаю вполне реальный сценарий:
    1.В конструкторе есть некий участок кода, который занимается инициализацией каких-то данных, среди него завалялся вызов этой процедуры.
    2.Потом его решили вызывать не только при создании формы, но и после отображения формы из скрытого состояния.
    3.Потом его решили вызывать при нажатии на кнопочку Refresh, чтобы отображать изменения в БД.
    4.Потом обленились и решили вызывать по таймеру каждые 30 мин.
    5.Потом на круглом столе появляются копросы типа: "как бы мне cделать так, чтобы в полночь/в обед/во время перекура программа сама себя закрывала, а потом откывала?"


    (задумчиво) Про фантазию я, кажется, уже говорил...
    Сэр... Мои аплодисменты...


    № 403   23-02-2007 14:48 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 401« (Бел Амор)
    ___________________________
    Я с трудом представляю себе неоходимость перебирать разномастные компоненты, лежащие на конкретной форме А я с трудом представляю зачем нужно делать запрещенный компонент без внешних проявлений, но это так, к слову...
    т.к. процедура вызывается один раз в конструкторе формы Где в описании написано, что её нужно вызывать только в конструкторе и не более одного раза? Ладно, допустим когда в приложении одна форма и одна такая процедура (пусть две) можно по быстрому посмотреть на её код, прочитать описание, проанализировать, но если их переваливает за сотню, такой стиль программирования крайне осложнит любые попытки что-либо изменить в проекте. Особено если над ним предварительно уже поработало несколько поколений, каждое из которых плодило свои наборы подобных вспомогательных процедур.
    Он споткнулся, упал, поднялся, опять упал и так поднимался и падал Вы на льду ни когда не стояли? Предлагаю вполне реальный сценарий:
    1.В конструкторе есть некий участок кода, который занимается инициализацией каких-то данных, среди него завалялся вызов этой процедуры.
    2.Потом его решили вызывать не только при создании формы, но и после отображения формы из скрытого состояния.
    3.Потом его решили вызывать при нажатии на кнопочку Refresh, чтобы отображать изменения в БД.
    4.Потом обленились и решили вызывать по таймеру каждые 30 мин.
    5.Потом на круглом столе появляются копросы типа: "как бы мне cделать так, чтобы в полночь/в обед/во время перекура программа сама себя закрывала, а потом откывала?"
    Сэр... Признайтесь... Ведь вы немножко преувеличили? :) Если на эту программу посмотрит профессионал, то он скажет "лучше всё взять да переписать!", а "студень" и месяц может провозиться.

    Короче, по моему, заменять свойства такими процедурами — плохо, а методы допустимо. Например: нет большой разницы procedure SaveCheckboxToIni и procedure TCheckboxEx.SaveToIni.

    P. S. В общем правильно делаете, что ни кому не даёте смотреть свои исходники ;o)
     Cep


    № 402   23-02-2007 13:57 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 401« (Бел Амор)
    ___________________________

    >>> А как это повлияет на последовательность перехода по tab?
    Никак. Панель имеет тот-же TabOrder, что имел раньше пересаженный на нее компонент, а внутри панели действует свой порядок обхода, но там один компонент, а сама панель фокус не принимает (смотрим код), как и вся стопка из панелей, если вдруг она появится.


    Прошу извинить, проглотил пару фраз.
    Панель запрещена, поэтому находящийся на ней компонент фокуса не принимает. Но в качестве перестаховки панель имеет тот-же TabOrder, что раньше имел находящийся теперь на ней компонент. И если вдруг кто-то доберется до этой панели и поставит ей Enabled = True, то порядок обхода по Tab останется таким-же, каким он был до вызова процедуры.


    № 401   23-02-2007 13:21 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 394« (Cepгей Poщин)
    ___________________________

    В-четвертых: допустим некто в будущем захочет перебрать все контролы на форме, после DisableCtrl это будет сделать гораздо сложнее.

    Руки оборвать этому "некту"...

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

    Сэр... Признайтесь... Ведь вы немножко преувеличили? :)
    Кроме того, я уже говорил, что это совершенно реальный кусок кода. И комментарии - тоже реальны. Так что нет необходимости даже читать код.

    В результате тревиальная конструкция
    For i := 0 to ControlCount - 1 do
    ...
    на написание которой уходит секунд 15 превратится в сложную задачу.


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

    Потом, что будет если DisableCtrl вызвать несколько раз (по ошибке)?

    Стопка будет. Из панелей. Без каких-либо проявлений во внешнем виде и поведении.
    Но это скорее из области фантастики, т.к. процедура вызывается один раз в конструкторе формы и описанная вами ситуация скорее напоминает анекдот "он споткнулся, упал, и так семь раз подряд".

    А если это происходит где-то в цыкле?

    Хорошо: "Он споткнулся, упал, поднялся, опять упал и так поднимался и падал, пока его не схватили за руки, за ноги и за голову пять  человек, после чего он отбился чудом и убежал..."

    А как это повлияет на последовательность перехода по tab?

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


    № 400   23-02-2007 13:18 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 393« (Geo)
    ___________________________

    >>>>>> Часть участников обсуждения считает, что при недостатке функционала стандартного компонента следует строго писать наследника, в котором этот самый функционал и добавляется.
    >>>Не знаю, кто так считает. Но только не я ;-)

    Блин, почудится-же иногда... Пора налаживать режим сна и питания...

    Я восстал против другого. Типа, у CheckBox'а убираем Caption, рядом кладем TStaticText и т.д. По-моему, создавать видимость компонента с нестандартными свойствами путем слепления в кучу нескольких стандартных компонент -- это не есть гут.

    Тут скорее соглашусь. В данном конкретном случае наблюдается некоторый перебор...

    Во-первых, обработка  такого "составного компонента" ухудшается (скорость проприсовки, реакция на события и т.п.), во-вторых, зачастую остаеются мелкие "косячки", которые лично мне сильно режут глаз, в-третьих, проблемы могут возникнуть при переходе на другую тему (компьютер, версию ОС).

    А тут скорее не соглашусь. Если отвлечься от конкретного чекбокса, то в общем случае с таким утверждением я не согласен. В качестве примера приведу поцедуру BoldCaption из того-же модуля FormUtil, которая создает метку, сажает ее на RadioGroup в нужное место, делает ее Bold, копирует себе Caption радиогруппы и обнуляет ее. Получается радиогруппа с жирным заголовком. Внимание, вопрос: какие косяки во внешнем виде и поведении сможет заметить ваш острый глаз и какие потенциальные проблемы могут возникнуть впоследствии? При условии, что эта процедура вызывается один раз в конструкторе формы и не планируется устанавливать Enabled = False, а также менять Caption.
    Да, в этом случае просто напрашивается обычный нормальный наследник, помещенный в палитру. Но...
    Допустим, есть старый проект, в котором мы хотим во всех радиогруппах сделать жирный заголовок. Внимание, вопрос номер два: что проще и безопаснее сделать:
    1. Удалить старую радиогруппу, вставить новую радиогруппу, восстановить имя, Caption, Items, размеры, положение, события... Я ничего не забыл? А таких групп -много...
    2. В конструкторе формы добавить по одной строчке на каждую радиогруппу. Если что и забыл - максимум - заголовок останется обычным.
    Так что наследника радиогруппы, конечно, желательно написать и использовать во вновь создаваемых формах, а в старых - лучше все-таки использовать старую добрую BoldCaption. И каких-либо потенциальных проблем здесь я не вижу.

    Так что такой прием я признаю только для одного случая: когда нужно срочно заткнуть дыру, обнаруженную за 5 минут до демонстрации программы Заказчику ;-)

    Соглашусь на 30% и то только в отношении конкретного чекбокса :)


    № 399   21-02-2007 03:13 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 398« (Cepгей Poщин)
    ___________________________

    Ответ на »сообщение 397« (panda)
    ___________________________
    но не проходит
    for Control in Controls do
      if (Control is TCheckBox) then Memo1.Lines.Add(Control.Name);
    т.к. Controls не коллекция и не список а свойство типа TControl.
    А fControls недоступно.



    Зато, если Controls относится к форме, можно дописать что вроде:

    TForm1 = class(TForm)
      ...
    public
      function GetEnumerator: TControlEnumerator;
    end;


    и тогда можно будет так:

    for Control in self do
      if (Control is TCheckBox) then Memo1.Lines.Add(Control.Name);


    не так выразительно, конечно, но...



    № 398   20-02-2007 08:19 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 397« (panda)
    ___________________________
    Что характерно в дельфе проходит:

    for S In List do
      if S <> '' then Memo1.Lines.Add(S);


    но не проходит

    for Control in Controls do
      if (Control is TCheckBox) then Memo1.Lines.Add(Control.Name);


    т.к. Controls не коллекция и не список а свойство типа TControl.
    А fControls недоступно.

     Cep


    № 397   20-02-2007 06:51 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 396« (Cepгей Poщин)
    ___________________________

    Там был пример конструировании списков с фильтрацией.
    Задача: получить все четные числа.
    Решение, например, на Python:

    def getEvenNumbers(l):
      return [x for x in l if x % 2 == 0]


    Конструировать список объектов и фильтровать его по значению свойства Enabled (или еще какого) ничуть не сложнее.

    Но это уже проблема Delphi Language, а не подхода к решению.


    № 396   20-02-2007 05:54 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 395« (panda)
    ___________________________
    Там ссылка на статью, а у меня нет доступа. Может своими словами как-то...
     Cep


    № 395   20-02-2007 05:42 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 394« (Cepгей Poщин)
    ___________________________

    В результате тревиальная конструкция
    For i := 0 to ControlCount - 1 do
    ... на написание которой уходит секунд 15 превратится в сложную задачу.


    Честно говоря, плохая конструкция ;-)
    См., например, »сообщение 1878 в теме №366 на БП«


    № 394   20-02-2007 04:39 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 393« (Geo)
    ___________________________
    В-четвертых: допустим некто в будущем захочет перебрать все контролы на форме, после DisableCtrl это будет сделать гораздо сложнее. В большом проекте неделя будет затрачена только на поиски и определение смысла этой самой процедуры. В результате тревиальная конструкция

    For i := 0 to ControlCount - 1 do
    ...

    на написание которой уходит секунд 15 превратится в сложную задачу.
    Потом, что будет если DisableCtrl вызвать несколько раз (по ошибке)? А если это происходит где-то в цыкле? А как это повлияет на последовательность перехода по tab?
     Cep


    № 393   20-02-2007 02:38 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 391« (Бел Амор)
    ___________________________
    >>> Часть участников обсуждения считает, что при недостатке функционала стандартного компонента следует строго писать наследника, в котором этот самый функционал и добавляется.
    Не знаю, кто так считает. Но только не я ;-)

    Я восстал против другого. Типа, у CheckBox'а убираем Caption, рядом кладем TStaticText и т.д. По-моему, создавать видимость компонента с нестандартными свойствами путем слепления в кучу нескольких стандартных компонент -- это не есть гут. Во-первых, обработка  такого "составного компонента" ухудшается (скорость проприсовки, реакция на события и т.п.), во-вторых, зачастую остаеются мелкие "косячки", которые лично мне сильно режут глаз, в-третьих, проблемы могут возникнуть при переходе на другую тему (компьютер, версию ОС).

    Так что такой прием я признаю только для одного случая: когда нужно срочно заткнуть дыру, обнаруженную за 5 минут до демонстрации программы Заказчику ;-)
     Geo


    № 392   19-02-2007 23:11 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 391« (Бел Амор)
    ___________________________

    1. Писать наследника.
    2. Делать дополнительную обработку в форме "по месту".
    3. Писать отдельнолежащую процедуру.

    4. Писать class helper.

    Только ради одной этой фичи можно переходить на D2006 (TD). ИМХО, разумеется.


    № 391   19-02-2007 15:58 Ответить на это сообщение Ответить на это сообщение с цитированием
    Поддержу усилиия уважаемого Geo по "поднятию темы".
    При обсуждении вопроса »вопрос КС №49421« дикуссия плавно перетекла на обсуждение темы, более подходящей для этой ветки.
    Попробую кратко сформулировать суть вопроса.
    Часть участников обсуждения считает, что при недостатке функционала стандартного компонента следует строго писать наследника, в котором этот самый функционал и добавляется. Мол, "на то оно и ООП". Я считаю, что к решению этой задачи следует подходить более сбалансированно и кроме вышеуказанного метода вполне допустимы еще два. Итак, с одной стороны: жестко писать наследника, с другой - сбалансированное применение трех методов:

    1. Писать наследника.
    2. Делать дополнительную обработку в форме "по месту".
    3. Писать отдельнолежащую процедуру.

    Когда применять:

    1. Нормальный универсальный вариант. Общий случай.
    2. Если нужно добавить что-то, что требеутся только в одном единственном месте на весь проект и все сводится к паре обработчиков по паре строк. В качестве примера можно привести »вопрос КС №49421«
    3. Если эта процедура позволяет реализовать что-то очень просто и очень универсально.

    В качестве примера для пункта 3 приведу реальный кусок из моего модуля FormUtil
    (сразу оговорюсь, что работаю с D6 и, возможно, в D2006 процедура HideScroll неактуальна):

    //----------------------------------------------------------------------
    // Назначение: Скрывает полосы прокрутки у TDBCtrlGrid
    // Способ: Создает на месте CtrlGrid панель  с размерами,
    // меньшими на размер полос прокрутки и пересаживает
    // на нее CtrlGrid (назначает Parent для CtrlGrid)

    procedure HideScroll(CtrlGrid: TDBCtrlGrid);
    var
      Panel: TPanel;
    begin
      Panel := TPanel.Create(CtrlGrid.Owner);
      Panel.Parent := CtrlGrid.Parent;
      Panel.Top := CtrlGrid.Top;
      Panel.Left := CtrlGrid.Left;
      Panel.Height := CtrlGrid.RowCount * CtrlGrid.PanelHeight;
      Panel.Width := CtrlGrid.ColCount * CtrlGrid.PanelWidth;
      Panel.TabOrder := CtrlGrid.TabOrder;
      CtrlGrid.Parent := Panel;
      CtrlGrid.Top := 0;
      CtrlGrid.Left := 0;
      Panel.TabStop := False;
    end;

    //----------------------------------------------------------------------
    // Назначение: Делает указанный элемент запрещенным, но исключает внешние
    // проявления, присущие прямому назначению Enabled=False
    // Способ: Создает на месте элемента панель  с такими-же размерами,
    // пересаживает на нее указанный элемент и запрещает панель

    procedure DisableCtrl(Ctrl: TWinControl);
    var
      Panel: TPanel;
    begin
      Panel := TPanel.Create(Ctrl.Owner);
      Panel.Parent := Ctrl.Parent;
      Panel.Top := Ctrl.Top;
      Panel.Left := Ctrl.Left;
      Panel.Height := Ctrl.Height;
      Panel.Width := Ctrl.Width;
      Panel.TabOrder := Ctrl.TabOrder;
      Ctrl.Parent := Panel;
      Ctrl.Top := 0;
      Ctrl.Left := 0;
      Panel.Enabled := False;
    end;


    Если для HideScroll вполне применим и способ 1, т.е. создать наследника TDBCtrlGrid, то процедура DisableCtrl - гораздо более универсальный подход, т.к. сразу охватывает всех наследников TWinControl.

    P.S. (задумчиво...) Переписать чтоли через with... (зевая...) можно будет убрать var...
    P.P.S. ;)


    № 390   23-01-2007 03:20 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 389« (Cepгей Poщин)
    ___________________________

    Если отстреливать всех, кто игнорирует все предупреждения компилятора, то рикуешь остаться один со всем их немалым программным наследием, except end; и {$WARNINGS OFF}.
    Ну... можно, например, найти работу, где разработанные программы в принципе не тестируются (чтобы не огорчаться). Но оно Вам надо? Если развитие культуры программирования не поддерживается (а даже наоборот) - это не повод снижать и свою культуру.

    P. S. Будь на то моя воля, я бы предупреждение Return value of function ... might be undefined сделал бы ошибкой.
    Ну так а я о чем толкую? ;-)
    Если приходится рецезировать код, в котором стоит {$WARNINGS OFF} (или при компиляции выдаются предупреждения), я просто сразу отпинываю его обратно. Разумеется, автор кода может пойти к своему начальнику, моему начальнику и т.д. (вплоть до директора). Но почему-то так не делает :-)



    № 389   23-01-2007 01:34 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 388« (panda)
    ___________________________
    У меня выработалась привычка по меньшей мере с подозрением относиться к предупреждениям и подсказкам компилятора А у меня выработалась привычка дуть на холодную воду... Думаю не самя вредная.
    Если отстреливать всех, кто игнорирует все предупреждения компилятора, то рикуешь остаться один со всем их немалым программным наследием, except end; и {$WARNINGS OFF}.
    Кстати по быстродействию разница близка к ошибке измерения.
    P. S. Будь на то моя воля, я бы предупреждение Return value of function ... might be undefined сделал бы ошибкой.
     Cep


    № 388   23-01-2007 00:11 Ответить на это сообщение Ответить на это сообщение с цитированием
    Ответ на »сообщение 384« (Max Belugin) и »сообщение 385« (Cepгей Poщин)
    ___________________________

    Понимаете ли в чем дело. У меня выработалась привычка по меньшей мере с подозрением относиться к предупреждениям и подсказкам компилятора (и отстреливать - на работе - всех, кто пытается их игнорировать) ;-)
    Исключения конечно, есть, но они могут распространяться на 1-2 строки и учитывать не все предупреждения, а только некоторые (например, Unsafe code).
    Поэтому возможностей Delphi в этом плане мне хватает за глаза и за уши.


    <<<... | 487—438 | 437—388 | 387—338 | ...>>>
    Всего сообщений в теме: 737; страниц: 15; текущая страница: 7


    Добавить свое сообщение

    Отслеживать это обсуждение

    Дополнительная навигация:
    Количество сообщений на странице

    Порядок сортировки сообщений
    Новое сообщение вверху списка (сетевая хронология)
    Первое сообщение вверху списка (обычная хронология)

    Перейти на конкретную страницу по номеру
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования