Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

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


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

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

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

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

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

 
   
С Л С

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

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

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

Квинтана

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

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

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

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

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  13:57[Войти] | [Зарегистрироваться]
Ответ на вопрос № 83910

26-02-2025 12:26
На форме лежит компонент TDBDateTimeEditEh, у которого есть такая особенность: дату можно увеличивать и уменьшать на единичку стрелками вверх-вниз, но TDBDateTimeEditEh.Value изменится только после того, как будет выполнено обновление (например, при переходе фокуса на другой компонент). А ещё на форме есть TBitBtn, у которого свойство Default равно true. И вот тут получается маленькая неприятность...

Допустим, мы стрелками сменили значение даты, но не перешли ни на какой другой компонент, а нажали Enter. Соответственно, начал выполняться обработчик TBitBtn.OnClick, но TDBDateTimeEditEh.Value осталось старым, а не заменилось на значение, изменённое стрелками. Вот как бы мне при это аккуратно обновить значение даты на новое до того, как начнёт выполняться обработчик нажатия на кнопу? Что-то я совсем запутался в том, какие сообщения в какой последовательности будут в этом случае обрабатываться. Теоретический, всегда можно приделать костыль, типа, перехватывать нажатие клавиш для формы, и если нажат Enter, то выполнять TDBDateTimeEditEh.UpdateData, но хотелось бы как-то... э-э-э... поэстетичнее.

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


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

09-03-2025 07:57 | Сообщение от автора вопроса
Это всё здорово и, наверное, даже правильно. Но у меня речь шла немного о другом. Есть готовый скриптовый движок, который сейчас переделан на другой версии Delphi (и некоторых других библиотеках). И у него выявлена такая вот проблема. Добавлять в движок новый компонент и переделывать все скрипты никто не будет.

Пока не нашёл ничего лучше, чем вставить вот такой костыль

procedure TMyBaseForm.CMDialogKey(var Message: TCMDialogKey);
begin
  if GetKeyState(VK_MENU) >= 0 then
    with Message do
      case CharCode of
        VK_RETURN:
          begin
            if FActiveControl <> nil and (FActiveControl is TDBDateTimeEditEh) then
            begin
              TDBDateTimeEditEh(FActiveControl).UpdateData;
            end;
            Exit;
          end;
      end;
  inherited;
end;


06-03-2025 07:20
>>>Через DataSet не поучится: компонент может просто использоваться для указания даты, но не быть связанным ни с каким DataSet-ом.
  Ну это уже заморочки EhLib.
  Ведь специально отдельно сделали "обычные компоненты" и на их основе "data-aware компоненты".
  Первые хранят данные, либо в классе VCL, либо в недрах ComCtl32.dll. Они предназначены для отображение данных. Что видим, то и храним. Поэтому и нет никаких промежуточных слоёв данных. А вторые - в "источниках данных". При изменении в них данных, вызывается целый каскад событий. Начиная от "обычного компонента", через DataLink, DataSource, DataSet к "источнику данных".
  Простота первых - позволяет обращаться непосредственно к отображаемым данным. Более того, данные в них мгновенны. Т.е. это то что мы видим. Например, при нажатии клавиши или при получении строки TEdit.Text, в предке TControl, отправляется сообщение в недра ComCtl32.dll.
  А со вторыми всё сложнее. Во-первых, они так же, как и первые, обращаются к отображаемым данным. Но поскольку акцент делается на "источнике данных", то доступ к "отображаемым данным" скрывают в недрах класса. Во-вторых, поскольку механизм передачи данных в "источник данных" бывает достаточно сложен и медлителен, то данные передаются порциями. Например, при завершении редактирования элемента управления (как частный случай потеря фокуса DbEdit). Поэтому поведение этих компонент отличается от "обычных". В-третьих, редактирование содержимого "data-aware компонента" приводит к изменению состояния "источника данных" (изменение, вставка и т.д.). Поэтому их, в отличии от "обычных компонент", нельзя рассматривать обособлено, а только как цепочку компонент (Edit->DbEdit->DataSoutse->...). И данные в них не мгновенны, а протяжённые во времени. Т.е. проходят несколько этапов (и при этом, ещё и хранятся в разных местах, для разных этапов).
 
  Поэтому можно сказать:
  - При внешней схожести, "обычные компоненты" и "data-aware компоненты" различны, и по предназначению, и по поведению, и по методике использования;
  - Если не нужен "источник данных", то рекомендуется использовать "обычные компоненты";
  - EhLib попыталась сделать компонент два в одном. Если подключён DataSource, то это "data-aware компонент", а если нет - "обычный компонент". И даже добавила свойство Value, которое работает, и в том, и в другом случае. Но его поведение, она оставила характерным для "data-aware компонентов". Поэтому, из-за этого, при использовании его как "обычный компонент" и свойства Value, возникает желание, либо доработать сам компонент (до поведения "обычного"), либо изменить стандартное поведение "data-aware компонентов" VCL.
 
  Наверно, можно работать с "data-aware компонентом" как с "обычным". Вопрос только зачем?
  Например, так можно получить или установить отображаемое текстовое значение TDBDateTimeEditEh или TDbEdit (до потери ими фокуса) с помощью аналогов методов TControl.GetText и TControl.SetText:


// Получить текст DBDateTimeEditEh1.Value: Memo1.Lines.Add(Control_GetText(DBDateTimeEditEh1))
// Получить текст DbEdit.Text:            Memo1.Lines.Add(Control_GetText(DbEdit1))
function Control_GetText(aControl :TControl) :string;
  function Control_GetTextLen: Integer;
  begin
    Result := aControl.Perform(WM_GETTEXTLENGTH, 0, 0);
  end;

  function Control_GetTextBuf(aBuffer: PChar; aBufSize: Integer): Integer;
  begin
    Result := aControl.Perform(WM_GETTEXT, aBufSize, Longint(aBuffer));
  end;

  var
    wLen: Integer;
begin
  wLen := Control_GetTextLen;
  SetString(Result, PChar(nil), wLen);
  if wLen <> 0
    then Control_GetTextBuf(Pointer(Result), wLen + 1);
end;


06-03-2025 06:41 | Комментарий к предыдущим ответам
>>>Не совсем понимаю суть вопроса.
  У вас есть "некий конструктор форм с ограниченным набором компонентов".
  Очевидно, в этот "набор компонент" не ходит TDBDateTimeEditEh.
  Но в этот "набор компонент" наверняка входит TDbEdit. TDbEdit и TDBDateTimeEditEh достаточно похожи и даже имеют общего предка TCustomMaskEdit. Да и механизм работы с данными у них схож (data-aware). Кроме того, и TDbEdit, и TDBDateTimeEditEh, в случае с BitBtn.Default, ведут себя одинаково (данные передаются после потели фокуса или по DataSet.Post).
  Поскольку TDbEdit проще и входит в "набор компонент" "конструктора форм", я и предлагал на его основе проследить механизм работы, для указанного вами случая. А затем, по аналогии, применить его для TDBDateTimeEditEh.
 
  Ведь насколько я понял, вы же хотите не переделывать "некий конструктор форм", а только использовать его возможности.

>>>несколько раз жмём стрелку вверх, увеличивая дату
  Можно ещё, для этого, колёсико мышки покрутить.

05-03-2025 13:53 | Сообщение от автора вопроса
Не совсем понимаю суть вопроса.

Есть некая базовая форма — потомок TForm. Почти пустая, но с некоторым количеством дополнительных возможностей (в детали вдаваться не хочется). Есть текст DFM, который заполняет эту форму компонентами с заданными свойствами. Этот DFM формируется в специальном билдере и содержит только предопределённый набор компонент. Кроме того, имеется ещё компонент Скриптер, которые содержит текст скрипта (а-ля Delphi) и умеет его выполнять. Скрипт работает с компонентами, размещёнными на форме, то есть обращения к компонентам, их методам и свойствам внутри скрипта переводятся движком а обращения к компонентам на форме. Специальной функцией эта форма создаётся и запускается (модально или не модально)

Собственно, поэтому я и не могу что-либо добавить в обработчик TBitBtn.OnClick, потому что форма изначально пустая: на ней нет ни TBitBtn, ни метода OnClick. Всё это появится только после загрузки DFM и скрипта.  хотелось бы сделать сразу на пустой форме, чтобы не пришлось что-то анализировать и добавлять после загрузки компонент.

Если же про саму проблему, то TDbEdit не подходит, так как не совсем подходит: он не позволяет вводить данные если не подключен к DataSet-у. А с TDBDateTimeEditEh это выглядит примерно так:

type
  TForm1 = class(TForm)
    DBDateTimeEditEh1: TDBDateTimeEditEh;
    BitBtn1: TBitBtn;
    procedure BitBtn1Click(Sender: TObject);
  end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  ShowMessage(DBDateTimeEditEh1.Value);
end;


Здесь BitBtn1.Default = true. Компонент DBDateTimeEditEh1 к данным не подключен, но значение менять можно. А ещё, если содержит фокус, то значение даты можно увеличивать и уменьшать на единицу стрелочками вверх-вниз, но свойство Value от это не изменяется, меняется только текст компонента. Например, запускаем эту форму, выставляем сегодняшнюю дату, а потом, не уводя фокус, несколько раз жмём стрелку вверх, увеличивая дату. А пото, опят-таки не уводя фокус, жмём Enter. Управление передаётся на обработчик события OnClick, но вызванное окно показывает не изменённую дату, так как фокус с DBDateTimeEditEh1 не ушёл, поэтому значение Value не обновилось.

03-03-2025 10:33 | Вопрос к автору: запрос дополнительной информации
>>>...не поучится. В данном случае работает некий конструктор форм с ограниченным набором компонентов ...
Допустим, что вместо TDBDateTimeEditEh используется простой TDbEdit. Как производится его (DbEdit1) обработка в аналогичном случае?

02-03-2025 12:26 | Сообщение от автора вопроса
Через DataSet не поучится: компонент может просто использоваться для указания даты, но не быть связанным ни с каким DataSet-ом.
TBitBtn.obClick тоже не совсем подходит. Поясняю... В данном случае работает некий конструктор форм с ограниченным набором компонентов и скриптовой обработкой. Я же занимаюсь системным программированием данного конструктора. Событие OnClick задействовано для прикладного уровня.

Вертится мысль подвесить обработчик на что-нибудь вроде CM_DIALOGKEY, где и обрабатывать VK_RETURN, но хотелось бы света на педмет того, какое сообщение лучше всего использовать (я в них всегда плавал), и как лучше заставить компонент актуализироваться (TDBDateTimeEditEh.UpdateData или что-то более универсальное, вроде TForm(FActiveControl.Parent).SelectNext

27-02-2025 11:18
>>>Вот как бы мне при этом аккуратно обновить значение даты на новое ...
Другой способ, в обработчике BitBtn.obClick, перед проверкой значения Value, можно переключить фокус на кнопку со свойством Default:

  if not BitBtn1.Focused
    then BitBtn1.SetFocus;


27-02-2025 10:38
>>>Компонент TDBDateTimeEditEh, у которого есть такая особенность: дату можно увеличивать и уменьшать на единичку стрелками вверх-вниз, но TDBDateTimeEditEh.Value изменится только после того, как будет выполнено обновление (например, при переходе фокуса на другой компонент).
  Изменение значения только после потери фокуса, это стандартное поведение data-aware компонентов.
 
>>>Допустим, мы стрелками сменили значение даты, но не перешли ни на какой другой компонент, а нажали Enter. ... Вот как бы мне при этом аккуратно обновить значение даты на новое ...
  Можно, перед проверкой значения, сохранить данные связанного DataSet'а. Например, в обработчике BitBtn.obClick, перед проверкой значения Value, вставьте:

  with MyDataSet do
    if Active and (State in [dsEdit, dsInsert])
      then Post; //или диалог с подтверждением Post, Cancel или Abort


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

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Вода мокрая или сухая?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: 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» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

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