C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Как получить данные не из активной записи, или значение поля как hint к DBGrid
AVC
Отправлено: 26.08.2004, 15:18


Ветеран

Группа: Модератор
Сообщений: 1583



Давно назревала необходимость (для меня), да и на форумах несколько раз видел подобные вопросы. Вот решил поизучать проблему и предлагаю чесному (ударение на о) народу свое решение.

Предполагалось что при работе с DBGrid где то присутствует буфер, в котором хранятся отображаемые записи. Была идея добраться до этого буфера. Исследование исходников показало, что да такой буфер есть и получить буфер нужной строки не представляет проблемы, но (облом) каждый наследник TDadaSet (TBDEDataSet, TADODataSet, TYOracleDataSet и т.д) хранит в нем информацию так как это ему удобно. Конечно, в каждом конкретном случае можно написать свои или воспользоваться функциями разработчика компонента для извлечения и преобразования данных поля из буфера. Но зачем если я работаю, например, с ADO мне нужны вызовы DBI. Это конечно можно решить условной компиляцией но это не красиво и требует доработки под каждый новый компонент. Поэтому для обеспечения универсальности было принято решение — а пусть DataSet сам этим занимается, тем более что есть прецеденты (DBGrid). Т.е. блокируются контролы, делается бросок к нужной записи, сохраняется значение поля, бросок обратно.
Таким образом следует признать, что Данные не из активной записи получить можно, но крайне сложно. Намного проще получать из текущей записи.

После получения ответа на первый вопрос, организация использования значения поля любой видимой записи в качестве hint’а для наследника TCustomDBGrid было просто развлекушкой.

Итак результат.
Предлагаемые функции должны (очень надеюсь) работать с любыми наследниками TDataSet и TCustomDBGrid
Прототипы функций (GUM_Etr.h)
CODE

// Привязывается к DBGrid'у для показа Hint'а из строки над которой в данный момент находится курсор мыша
extern PACKAGE void __fastcall DBGrid_UnderMouse_FieldAsHint
(TDBGrid *grd
,const AnsiString &pFieldName = ""
);

// Возвращает Field над которым в сетке в данный момент завис курсор мыша
extern PACKAGE TField* __fastcall DBGrid_UnderMouse_ColumnFiled (TDBGrid *grd);

// Возвращает значение поля над которым в сетке в данный момент завис курсор мыша
extern PACKAGE Variant __fastcall DBGrid_UnderMouse_FieldValue
(TDBGrid *grd
,const AnsiString& pFieldName = ""
,bool AsString = false
);

* Для Hint поле должно быть приводимо к типу string

Использование: подключить к проекту GrdUndM.cpp (желательно в резидентную часть) в нужные формы включить
#include “GUM_Etr.h”

Простой пример использования Hint
В запросе
Select …, (Account || chr(10) || FIO || chr(10) || Address) as Abon_InfoHint From …
В конструкторе формы DBGrid_UnderMouse_FieldAsHint(Grd_Main, “Abon_InfoHint”)

Результат
user posted image

Буду признателен за любые замечания и предложения.
файлы можно взять здесь
Для получения последней версии переходите к последним постам.

Отредактировано AVC — 28/12/2005, 10:15

User Attached Image Скачать файл
GUMBCC.ARJ


Gedeon
Отправлено: 26.08.2004, 17:11


Ветеран

Группа: Модератор
Сообщений: 1742



О, инфа полезная, протестить времени пока нету, но в том, что работает я не сомневаюсь, будет время возьмем на вооружение.
Kate
Отправлено: 08.09.2004, 13:31


Ученик-кочегар

Группа: Участник
Сообщений: 9



Вещь действительно должна получиться полезная.
Вот только я попробовала, и у меня не получилось (наверное сказывается недостаток опыта).

Итак, у меня CB6. Я создала абсолютно новый проект, добавила к нему GrdUndM.cpp (что значит "в резидентную часть" извините, не знаю sad.gif ). Пробую откомпилить, и на все места, где встречается ESTRorNULL выдает ошибку
E2354 Two operands must evaluate to the same type
т.е., как я понимаю, проблема в строке
(AsString? Variant(AnsiString("")) : Null)
но я обычно пишу попроще и не совсем понимаю, что бы это значило.

Прошу простить за ламерство smile.gif
AVC
Отправлено: 08.09.2004, 14:05


Ветеран

Группа: Модератор
Сообщений: 1583



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

ESTRorNULL используется просто для сокращения записи. Проверяется значение bool'евой переменной AsString и возвращается либо пустая строка, либо Null.
Попробуйте в ней изменить Null на Variant().AsType(varNull)
AVC
Отправлено: 08.09.2004, 15:58


Ветеран

Группа: Модератор
Сообщений: 1583



Да действительно 6-ая стройка не понимает глобальной переменной Null
Для исправления этой ошибки тем, кто уже скачал тексты нужно
в файле GrdUndM.h заменить строку
#define ESTRorNULL (AsString? Variant(AnsiString("")) : Null)
заменить на
#define ESTRorNULL (AsString? Variant(AnsiString("")) : Variant().AsType(varNull))

или взять исправленный вариант здесь.

Работоспособность проверена для 5 и 6. На 3-ке работать не будет из за изменения Borland'ом способа доступа к полям в DataSet. С 4-кой не работал.

User Attached Image Скачать файл
GUM.ARJ


Kate
Отправлено: 09.09.2004, 09:23


Ученик-кочегар

Группа: Участник
Сообщений: 9



Спасибо. Теперь все работает. biggrin.gif
Еще заметила такую особенность: У Grid'а при ShowHint == false не срабатывает обработчик OnMouseMove, а при ShowHint == true — срабатывает. Но мне-то он не нужен, так, случайно заметила.
AVC
Отправлено: 09.09.2004, 10:17


Ветеран

Группа: Модератор
Сообщений: 1583



О спасибо. Мы с вами все таки доведем эту функцию до совершенства smile.gif
Исправить в файле GrdUndM.cpp
строки начиная с 357
TDBGrid *grd = dynamic_cast(Sender);
if (!grd || !grd->ShowHint) return;

TGUM_GridList_Item *gumi = Find(grd);
if (!gumi) return;

на
TDBGrid *grd = dynamic_cast(Sender);
if (!grd) return;

TGUM_GridList_Item *gumi = Find(grd);
if (!gumi || !grd->ShowHint)
{ if (gumi->OldMouseMove) gumi->OldMouseMove(grd, Shift, X, Y); // Родной MouseMove
return;
}

Очередной вариант здесь (v3)


User Attached Image Скачать файл
GUM.ARJ


Gedeon
Отправлено: 09.09.2004, 10:58


Ветеран

Группа: Модератор
Сообщений: 1742



Пусть меня простит AVC, так как обычным TDBGrid давно не пользуюсь переделал только что Ваше творение под TDBGridEh простой заменой TDBGrid на TDBGridEh biggrin.gif .
Тут такая мысль появилась — завернуть это все в визуальный компонент, чтобы и на несколько гридов на одной форме лепить можно было бы.

P.S. Последнее изменение в файл не внесено

P.P.S.
не
CODE
TDBGrid *grd = dynamic_cast(Sender);

а
CODE
TDBGrid *grd = dynamic_cast<TDBGrid*>(Sender);


Отредактировано Gedeon — 09/09/2004, 12:09

User Attached Image Скачать файл
EhLibGum.zip


AVC
Отправлено: 09.09.2004, 11:11


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

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

Раскажите гениалогию TDBGridEh. На самом деле мне важно наследие от TCustomDBGrid. Судя по тому, что у вас все получилось у TDBGrid и TDBGridEh общие предки.

QUOTE

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

Вызывайте DBGrid_UnderMouse_FieldAsHint с теми сетками, которые вам нужны. Естественно, что число сеток на форме нигде не лимитировано. Визуальный компонент для вызова одной единственной функции? хмм... жирновато будет. biggrin.gif
AVC
Отправлено: 09.09.2004, 11:17


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

CODE

не
TDBGrid *grd = dynamic_cast(Sender);
а
CODE  
TDBGrid *grd = dynamic_cast<TDBGrid*>(Sender);

biggrin.gif Нет мне прощения. Поленился взять код в тэги и поэтому TBDGrib* корова языком слизала.
Gedeon
Отправлено: 09.09.2004, 14:18


Ветеран

Группа: Модератор
Сообщений: 1742



QUOTE (AVC @ 09/09/2004, 12:13)
Раскажите гениалогию TDBGridEh. На самом деле мне важно наследие от TCustomDBGrid. Судя по тому, что у вас все получилось у TDBGrid и TDBGridEh общие предки.



TObject->TPersistent->TComponent->TControl->TWinControl->TCustomControl->TCustomGrid->TCustomDBGridEh

Как видите общий предок TCustomGrid

Вот похоже от него надо плясать, проверяя наличие некоторых методов.

QUOTE

Вызывайте DBGrid_UnderMouse_FieldAsHint с теми сетками, которые вам нужны. Естественно, что число сеток на форме нигде не лимитировано. Визуальный компонент для вызова одной единственной функции? хмм... жирновато будет. biggrin.gif


Да это-то понятно я имел ввиду один контрол в котором можно было бы назначать несколько сеток (по типу Fields в гриде) с указанием поля подсказки для каждого, но возможно Вы правы и это лишний труд. Я думаю такой компонент был бы интересен тем же разработчикам EhLib, а самому конечно проще руками 1 функцию написать biggrin.gif
AVC
Отправлено: 09.09.2004, 14:47


Ветеран

Группа: Модератор
Сообщений: 1583



TCustomGrid меня не устраивает. Нужен хотя бы TCustomDBGrid. Придется сделать либо через define либо две функции. Склоняюсь ко второму варианту.

На счет компонента — конечно можно сделать. Но например у меня форма когда стартует еще не знает с каким (какими) запросами она будет работать. Она их зачитыает с сервера. Что уж говорить об имени поля для Hint которое то же хранится на сервере в описании запроса.
AVC
Отправлено: 09.09.2004, 17:34


Ветеран

Группа: Модератор
Сообщений: 1583



v4. Теперь работает с TDBGrid и TDBGridEh.
На одной форме могут быть как простые DBGrid так и DBGridEh одновременно.
Для тех, кто не любит читать начало краткое содержание предыдущих серий
CODE

...
Привязывается к DBGrid'у для показа Hint'а из строки над которой
в данный момент находится курсор мыша.
  void DBGrid_UnderMouse_FieldAsHint
    (TDBGrid           *grd
    , const AnsiString &pFieldName = ""
    );

  void DBGridEh_UnderMouse_FieldAsHint
    (TDBGridEh         *grd
    , const AnsiString &pFieldName = ""
    );
  если pFieldName пусто, то опрашивается поле под мышом
   иначе значение этого поля с именем в pFieldName

  Показывает Hint если DataSet открыт и непуст и значение ShowHint
  сетки равно true
  Для показа Hint'а использует параметры Application
  Многократный вызов с одним и те же значением DBGid не является ошибкой
  — используются параметры последнего вызова

  Вызывается для каждой сетки, к которой нужен такой Hint.
...

Использование:

1. Включить в проект (желательно не в динамическую библиотеку) модуль
  GrdUndM.cpp или GrdUndME.cpp для EhLib

2. В тех модулях, где необходимо использовать функции добавить
  #include "GUM_Etr.h" или #include "GUM_EtrE.h"

3. Для начала показа нint'а вызвать DBGrid_UnderMouse_FieldAsHint там,
  где вам это удобно (например в конструкторе формы)

Пример:
На форме DataSet, DataSource, Query правильно связанные друг с другом
и кнопка
в обработчике события нажатия кнопки:
if (QryPdx->Active) QryPdx->Active = false;

QryPdx->DatabaseName = "BCDEMOS";
QryPdx->SQL->Text = "Select t.*, (t.Name + ' (' + t.Capital + ')') as Hint From country.db t";
DBGrid_UnderMouse_FieldAsHint (Grd_Main, "Hint");
или DBGridEh_UnderMouse_FieldAsHint (Grd_Main, "Hint");

QryPdx->Active = true;


(Gedeon в вашем архиве вы мне выложили мои же тексты — это ошибка?)

Исходные тексты здесь

User Attached Image Скачать файл
GUM.ARJ


Gedeon
Отправлено: 09.09.2004, 18:12


Ветеран

Группа: Модератор
Сообщений: 1742



QUOTE (AVC @ 09/09/2004, 18:36)
(Gedeon в вашем архиве вы мне выложили мои же тексты — это ошибка?)

biggrin.gif позор мне, не то заархивировал. biggrin.gif
AVC
Отправлено: 10.09.2004, 08:08


Ветеран

Группа: Модератор
Сообщений: 1583



Gedeon, если вас не затруднит, проверьте, пожалуйста, работоспособность v4 на EhLib.
Я ей не пользуюсь поэтому работать пришлось почти "в темную"
Gedeon
Отправлено: 10.09.2004, 18:49


Ветеран

Группа: Модератор
Сообщений: 1742



Млин целый день с инетом какая-то хрень не мог никуда попасть, но он как бы есть, не мог работать biggrin.gif .

С EhLib все прекрасно работает.

2AVC большое спасибо за данный топик, узнал много нового, да и вещь очень полезная получилась.

2Всем Очень рекомендую использовать.
Michael99
Отправлено: 21.12.2006, 05:47


Ученик-кочегар

Группа: Участник
Сообщений: 7



Использую DBGridEh и при использовании напоролся на 2 проблемы.
1. И самая главная — У таблицы есть нижняя колонка, т.е. свойство FooterRowCount=1. Если количество отображаемых записей в таблице например 20-30% и курсор мыши двигать под данными — активная запись переходит на одну вверх с каждым движением.
2. У меня стоит свойство UseMultiTitle=true, при движении мыши над данными Title и FooterRow — мигает.
olegenty
Отправлено: 21.12.2006, 07:46


Ветеран

Группа: Модератор
Сообщений: 2412



версия EhLib какая?
Michael99
Отправлено: 25.12.2006, 06:10


Ученик-кочегар

Группа: Участник
Сообщений: 7



Версия EhLib 3.6
olegenty
Отправлено: 25.12.2006, 08:08


Ветеран

Группа: Модератор
Сообщений: 2412



так вот, вполне вероятно, что в версии 4.1/4.2b этих проблем нет.
эксперимент поставить времени нет, сам пользуюсь 4.2b и проблем не знаю.
Michael99
Отправлено: 25.12.2006, 09:17


Ученик-кочегар

Группа: Участник
Сообщений: 7



Я в Inete нашел только 3.6 халявную версию, поэтому рад и ей. Я полагал, может в коде Gum'a кто-нибудь из знатоков подскажет — что подправить. Может и другим пригодится исправленная версия.
AVC
Отправлено: 25.12.2006, 18:13


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

1. И самая главная — У таблицы есть нижняя колонка, т.е. свойство FooterRowCount=1. Если количество отображаемых записей в таблице например 20-30% и курсор мыши двигать под данными — активная запись переходит на одну вверх с каждым движением.

Теперь работает правильно с FooterRowCount> 0.
Заменить соответствующие файлы из прилагаемого архива.

User Attached Image Скачать файл
grdundme.rar


AVC
Отправлено: 26.01.2007, 11:46


Ветеран

Группа: Модератор
Сообщений: 1583



Новое обновление по замечаниям от Gedeon, связанных с фильтрами DBgridEh

Касается только тех, кто использует DBgridEh и её STFilter
(для остальных ни чего не изменилось)

Эта версия больше адаптирована для EhLib v4. Для компиляции c v4 нужно снять комментарий со строки
//#define EhLibV_4
в файле Gum_EtrE.h строка 15


User Attached Image Скачать файл
gum.rar



Вернуться в Работа с базами данных в C++Builder