powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Hint для строки DBGrid
24 сообщений из 24, страница 1 из 1
Hint для строки DBGrid
    #39539109
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нужно при наведении на строку DBGrid показать хинтом содержимое поля этой строки. Вопрос, как достать это содержимое без бегания по датасету? Или хотя бы, без изменения позиции скролла?

Сейчас делаю вот так
Код: pascal
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.
procedure TForm1.HintTimer(ASender: TObject);
var
  LDS: TDataSet;
  LCurRow: Integer;
  LGridCoord: TGridCoord;
  LFldStatus: TField;
  LHint: string;
begin
  FHintTimer.Enabled := False;
  LDS := DataSet;
  if LDS <> nil then
    LFldStatus := LDS.FindField(CfnOutStatusStr)
  else
    LFldStatus := nil;
  LGridCoord := DBGrid1.MouseCoord(FMousePos.X, FMousePos.Y);
  if
    (LFldStatus = nil) or (LFldStatus.IsNull) or
    (LGridCoord.X <= 0) or (LGridCoord.Y <= 0)
  then
    Exit;
  LDS.DisableControls;
  try
    LCurRow := LDS.RecNo;
    LDS.RecNo := LGridCoord.Y;
    try
      LHint := LFldStatus.AsString;
    finally
      LDS.RecNo := LCurRow;
    end;
  finally
    LDS.EnableControls;
  end;
  DBGrid1.Hint := LHint;
  Application.ActivateHint(DBGrid1.ClientToScreen(FMousePos));
end;

но переприсваивание RecNo при определенных положениях приводит к прокручиванию записей.

С уважением, Vasilisk
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539113
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_при определенных положенияхЕсли не ошибаюсь, то это происходит когда я пытаюсь спозиционироваться на запись, которая идет до текущей
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539118
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
А датасет какой ?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539119
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну и от грида тоже зависит, наверное.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539120
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов РустамА датасет какой ?TIBDataSet
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539121
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов РустамНу и от грида тоже зависит,Стандартный TDBGrid
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539126
Freedoom
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
_Vasilisk_, см rxDbGrid . Хотя эта версия для Lazarus, можно посмотреть реализацию и прикрутить к dbGrid Delphi
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539134
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_> TIBDataSet TDBGrid

Тогда вроде бы никак или без доп.телодвижений никак.
Первый не позволяет "без бегания по датасету", а второй
не хранит значения ячеек. Если достаточно без изменения
позиции скролла - ну, попробуй вместо RecNo букмарки
использовать и/или текущее смещение от верха грида.

Может, задачу можно пересмотреть (тем паче, если
хинты нужны только для ID, а не всех ячеек) ?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539169
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов Рустамиспользовать и/или текущее смещение от верха грида.TopRow protected свойство. Если до него добраться через THackDBGrid, то оно всегда равно 1
Гаджимурадов РустамМожет, задачу можно пересмотретьИсходная задача такая: в гриде отрисовываются записи разным цветом. Цвет записи зависит от значения поля STATUS. Хотелось выводить хинтом расшифровку этого статуса
Гаджимурадов РустамПервый не позволяет "без бегания по датасету",Есть шальная идея, запоминать значения при перерисовке

Вот казалось бы, зачем гриду дергаться? При перемещении по записям вызван DisableControls. После EnableControls ничего не меняется.

Попробую еще не вызывать DisableControls/EnableControls. Может получится более адекватная работа
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539194
Ghost Writer
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_,

вот настоящий THackDBGrid
держать список статусов:
цвет=имя статуса
в зависимости от DBGrid1.Canvas.Pixels[FMousePos.X, FMousePos.Y] брать статус из списка
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539205
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_> Исходная задача такая: в гриде отрисовываются записи разным цветом.
_Vasilisk_> Цвет записи зависит от значения поля STATUS. Хотелось выводить
_Vasilisk_> хинтом расшифровку этого статуса

Так это же сильно всё упрощает. При отрисовке наращивай
статус в каком-нибудь списке, а перед хинтом вытаскивай.
Некошерно, конечно, но дешево и сердито. :)

> Вот казалось бы, зачем гриду дергаться?

Подозреваю, что именно из-за изменения смещения.

> Попробую еще не вызывать DisableControls/EnableControls.

Будет ещё хуже.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539347
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Freedoom_Vasilisk_, см rxDbGrid . Хотя эта версия для Lazarus, можно посмотреть реализацию и прикрутить к dbGrid Delphi
тогда уж лучше посмотреть исподники EhGrid. Там эта фишка уже лет 10, как реализована
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539354
Freedoom
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Доктогда уж лучше посмотреть исподники EhGrid. Там эта фишка уже лет 10, как реализована
_Vasilisk_ Стандартный TDBGrid
rxDbGid, в отличие от ExGrid, наследник TDbGrid. Либо мы говорим о разных EhGrid.
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539409
Freedoom
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
_Vasilisk_

Код: pascal
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.
  TRxDBGridDataHintShowEvent = procedure(Sender: TObject; CursorPos: TPoint;
      Cell: TGridCoord; Column: TRxColumn; var HintStr: string;
      var Processed: boolean) of object;

FOnDataHintShow:TRxDBGridDataHintShowEvent;

procedure TRxDBGrid.CMHintShow(var Message: TLMessage);
var
  Cell: TGridCoord;
  tCol: TRxColumn;
  HintStr_: string;
  Processed: boolean;
  rec: integer;
  CellRect_: TRect;
begin
  if Assigned(TCMHintShow(Message).HintInfo) then
  begin
    with TCMHintShow(Message).HintInfo^ do
    begin
      Cell := MouseCoord(CursorPos.X, CursorPos.Y);
      tCol := TRxColumn(ColumnFromGridColumn(Cell.X));
      if (Cell.Y = 0) and (Cell.X >= Ord(dgIndicator in Options)) then
      begin
        if Assigned(tCol) and (TRxColumnTitle(tCol.Title).Hint <> '') and
          (TRxColumnTitle(tCol.Title).FShowHint) then
          HintStr := TRxColumnTitle(tCol.Title).Hint;
      end
      else
      if Cell.X >= Ord(dgIndicator in Options) then
      begin
        CellRect_ := CellRect(Cell.X, Cell.Y);
        if (CellRect_.Bottom > CursorPos.Y) and (CellRect_.Right > CursorPos.X) then
          if Assigned(FOnDataHintShow) then
          begin
            rec := DataLink.ActiveRecord;
            try
              DataLink.ActiveRecord := Cell.y - 1;
              HintStr_ := tCol.Field.DisplayText;
            finally
              DataLink.ActiveRecord := rec;
            end;
            Processed := False;
            FOnDataHintShow(Self, CursorPos, Cell, tCol, HintStr_, Processed);
            if Processed then
              HintStr := HintStr_;
          end;
      end;
    end;
  end;
  inherited CMHintShow(Message);
end;



Если лень писать (регистрировать) новый компонент, и DbGrid один, то можно прямо в модуле с формой сделать свой TDbGrid = Class(Vcl.DBGrids.TDBGrid)
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539449
Фотография Док
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
FreedoomrxDbGid, в отличие от ExGrid, наследник TDbGrid. Либо мы говорим о разных EhGrid.
нет, ты прав. Тогда в контексте вопроса твой отсыл корректнее
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539606
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Freedoom,

За код огромное спасибо
Freedoom
Код: pascal
1.
 DataLink.ActiveRecord := rec;

не приводит к дерганию грида. Пока сделал так
Код: pascal
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.
procedure TForm1.HintTimer(ASender: TObject);
var
  LDS: TDataSet;
  LCurRow: Integer;
  LGridCoord: TGridCoord;
  LFldStatus: TField;
  LHint: string;
begin
  FHintTimer.Enabled := False;
  LDS := DataSet;
  if LDS <> nil then
    LFldStatus := LDS.FindField(CfnOutStatusStr)
  else
    LFldStatus := nil;
  LGridCoord := DBGrid1.MouseCoord(FMousePos.X, FMousePos.Y);
  if
    (LFldStatus = nil) or (LFldStatus.IsNull) or
    (LGridCoord.X <= 0) or (LGridCoord.Y <= 0)
  then
    Exit;
  LCurRow := THackDBGrid(DBGrid1).DataLink.ActiveRecord;
  THackDBGrid(DBGrid1).DataLink.ActiveRecord := LGridCoord.Y - 1;
  try
    LHint := LFldStatus.AsString;
  finally
    THackDBGrid(DBGrid1).DataLink.ActiveRecord := LCurRow;
  end;
//  OutputDebugString(PChar(LHint));
  DBGrid1.Hint := LHint;
  Application.ActivateHint(DBGrid1.ClientToScreen(FMousePos));
end;

ничего не дергается. Но очень часто хинт не отображается. Причем если я расскомментирую OutputDebugString то все работает как часы.

Еще пошаманю немного. Если не взлетит, то буду писать наследника
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539647
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Freedoom
Код: pascal
1.
procedure TRxDBGrid.CMHintShow(var Message: TLMessage);

Одна засада - сообщение приходит только один раз, когда мышь заходит на грид. Чтобы посмотреть еще раз, нужно вывести мышь за пределы грида и завести обратно. Как-то можно это вылечить?
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539671
Freedoom
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
_Vasilisk_, посмотри чему равен Message.Result после inherited CMHintShow(Message). Попробуй добавить Message.Result := 0;
По поводу библиотеки RX лучше общаться напрямую с её автором ( http://www.freepascal.ru/forum/viewforum.php?f=18).
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539739
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Итак. Большое спасибо Freedoom, у меня все заработало.

Теперь для общественности:

Ответ на самый первый мой вопрос "Как избежать скроллинга грида". Ответ - не трогать датасет для изменения текущей записи. Данные о нужной записи, нужно получать через DataLink.ActiveRecord (нумерация с 0). При этом DisableControls/EnableControls не нужны.

По хинтам. Как все работает. TControl на любое сообщение WM_MOUSEMOVE вызывает
Код: pascal
1.
Application.HintMouseMessage(Self, Message);

и уже этот метод управляет хинтами.

Для начала он вытягивает контрол, для которого нужно показать хинт
Код: pascal
1.
NewHintControl := GetHintControl(FindDragTarget(Control.ClientToScreen(SmallPointToPoint(MouseMsg.Pos)), True));

если контрол не был получен, или для него не нужно показывать хинт, то все прячем и уходим
Код: pascal
1.
2.
  if (NewHintControl = nil) or not NewHintControl.ShowHint then
    CancelHint

А вот если нашли, то выполняется хитрая проверка
Код: pascal
1.
2.
if (NewHintControl <> FHintControl) or
  (not FHintCursorRect.Contains(Control.ClientToScreen(SmallPointToPoint(MouseMsg.Pos)))) then

т.е. либо у нас новый контрол, для которого мы еще не показывали хинт, или наша мышиная точка выходит за пределы прямоугольника для которого уже был показан хинт. Если условие выполнилось, то следующим шагом определяем задержку, когда нужно будет показать хинт. Задержка определяется полями FHintShortPause и FHintPause (напоминаю, мы находимся в TApplication) и текущей активностью хинта
Код: pascal
1.
2.
3.
4.
WasHintActive := FHintActive;
if WasHintActive then
  Pause := FHintShortPause else
  Pause := FHintPause;

после этого мы спрашиваем у контрола, а согласен ли он с текущим положением дел
Код: pascal
1.
NewHintControl.Perform(CM_HINTSHOWPAUSE, Ord(WasHintActive), Winapi.Windows.LPARAM(@Pause));

после этого, если Pause = 0 запускаем процедуру показа хинта, или запускаем таймер, который запустит эту процедуру

В процедуре показа хинта производятся всякие проверки, типа а не уехало ли окно и т.д. а потом заполняется структура THintInfo. Эта структура полностью управляет отображением хинта. Из интересного мне приведу пару полей
Код: pascal
1.
2.
3.
4.
5.
HintInfo.HintControl := FHintControl; // Для кого отображаем
HintInfo.HintPos := CursorPos;  // экранные координаты мыши
HintInfo.CursorRect := FHintControl.BoundsRect;  // тот самый "прямоугольник хинта". По умолчанию - весь контрол
HintInfo.CursorPos := FHintControl.ScreenToClient(CursorPos);  // координаты мыши в СО контрола
HintInfo.HintStr := GetShortHint(GetHint(FHintControl));  // Сама строка

а дальше есть два шанса изменить эту структуру:

1. Обработать контролом сообщение CM_HINTSHOW
Код: pascal
1.
CanShow := FHintControl.Perform(CM_HINTSHOW, 0, Winapi.Windows.LPARAM(@HintInfo)) = 0;


2. Пошаманить с глобальным обработчиком Application.OnShowHint
Код: pascal
1.
2.
if CanShow and Assigned(FOnShowHint) then
  FOnShowHint(HintInfo.HintStr, CanShow, HintInfo);

после этого, после проверки
Код: pascal
1.
2.
FHintActive := CanShow and (FHintControl <> nil);
if FHintActive and (HintInfo.HintStr <> '') then

мы обновляем "прямоугольник хинта"
Код: pascal
1.
2.
3.
4.
5.
with HintInfo do
begin
  FHintCursorRect.TopLeft := FHintControl.ClientToScreen(CursorRect.TopLeft);
  FHintCursorRect.BottomRight := FHintControl.ClientToScreen(CursorRect.BottomRight);
end;

и показываем сам хинт.

Теперь о модификации. Было принято решение модифицировать в обработчике сообщения CM_HINTSHOW
Код: pascal
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.
procedure TDBGrid.CMHintShow(var AMsg: TCMHintShow);
var
  LInfo: PHintInfo;
  LCell: TGridCoord;
  LRec: Integer;
begin
  if Assigned(FOnGetHint) then begin
    AMsg.Result := 1;
    LInfo := AMsg.HintInfo;
    LCell := MouseCoord(LInfo^.CursorPos.X, LInfo^.CursorPos.Y);
    if (LCell.X > 0) and (LCell.Y > 0) then begin
      LRec := DataLink.ActiveRecord;
      try
        // Перемещаемся на нужную запись
        DataLink.ActiveRecord := LCell.Y - 1;
        // Получаем нужный хинт
        FOnGetHint(Self, LInfo^.HintStr);
      finally
        DataLink.ActiveRecord := LRec;
      end;
      // Устанавливаем "прямоугольник хинта" на текущую строку
      LInfo^.CursorRect := CellRect(LCell.X, LCell.Y);
      LInfo^.CursorRect.Left := 0;
      LInfo^.CursorRect.Right := Width;
      AMsg.Result := 0;
    end;
  end;
  inherited;
end;


Код: pascal
1.
2.
FOnGetHint: TOnGetHint;
TOnGetHint = procedure(ASender: TObject; var AStr: string) of object;


А чтобы при перемещении по строкам хинт появлялся с задержкой, был добавлен такой обработчик
Код: pascal
1.
2.
3.
4.
5.
6.
procedure TDBGrid.CMHintShowPause(var AMsg: TCMHintShowPause);
begin
  inherited;
  if AMsg.WasActive <> 0 then
    AMsg.Pause^ := Application.HintPause;
end;
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539847
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Спасибо за подробный How-To. Все бы так. :)

_Vasilisk_> // Перемещаемся на нужную запись
> DataLink.ActiveRecord := LCell.Y - 1;

И что, запись не перемещается?
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539867
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов РустамИ что, запись не перемещается?Ну грид не дергается. А из датасета данные достаются из нужной строки
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39539869
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
_Vasilisk_> Ну грид не дергается.

Без DisableControls это странно. Проверь на высоком гриде
и с большой разницей между текущей записью и хинтуемой.
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39540499
Фотография _Vasilisk_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Гаджимурадов РустамБез DisableControls это странноТам нечему дергаться
Код: pascal
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.
procedure TDataLink.SetActiveRecord(Value: Integer);
begin
  if DataSource.State <> dsSetKey then
    DataSource.DataSet.FActiveRecord := Value + FFirstRecord;
end;

function TIBCustomDataSet.InternalGetFieldData(Field: TField; Buffer: Pointer): Boolean;
var
  Buff: TRecordBuffer;
  .........
begin
  Buff := GetActiveBuf;
  .........
end;

function TIBCustomDataSet.GetActiveBuf: TRecordBuffer;
begin
  case State of
    dsBrowse:
      if IsEmpty then
        result := nil
      else
        result := ActiveBuffer;
  ..........
end;

function TDataSet.ActiveBuffer: TRecordBuffer;
begin
  Result := FBuffers[FActiveRecord];
end;

Как видишь, никакого перемещения. Меняется только указатель на текущий буфер
...
Рейтинг: 0 / 0
Hint для строки DBGrid
    #39540789
Гаджимурадов Рустам
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Да, я забыл про if DataSource.State <> dsSetKey then
Posted via ActualForum NNTP Server 1.5
...
Рейтинг: 0 / 0
24 сообщений из 24, страница 1 из 1
Форумы / Delphi [игнор отключен] [закрыт для гостей] / Hint для строки DBGrid
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]