Модераторы: Poseidon, Snowy, bems, MetalFan

Поиск:

Закрытая темаСоздание новой темы Создание опроса
> Создание компонента, StringGrid+CheckBox 
:(
    Опции темы
Slawanix
  Дата 7.1.2005, 16:03 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



Подскажите пожалуста, как это можно сделать: интегрировать в StringGrid компонент CheckBox, так чтобы в каждой строчке таблицы был чекбох, и его можно было проверять на булевую. Чтобы для каждой строчки таблицы чекбокс мог иметь уникальное значение. А в заголовке таблицы был главный бокс, который мог управлять состоянием всех отстальных боксов. smile
--------------------
моск кипит    
PM MAIL WWW   Вверх
Fedor
Дата 7.1.2005, 16:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Днепрянин
****


Профиль
Группа: Участник
Сообщений: 2090
Регистрация: 8.2.2003
Где: Великий

Репутация: нет
Всего: 32



Цитата
90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Вот:
Цитата
Некоторое время тому назад такой вопрос уже ставился: возможно ли поместить элемент управления, например, CheckBox или ComboBox внутрь компонента ...Grid. Я сегодня помозговал и нашел неплохую, на мой взгляд, технологию. Это работает! Вот решение для тех, кто этим интересуется:


При создании компонента (в обработчике OnCreate), создайте его объекты Objects[C,R], например TCheckBox.Create(Self). Имейте в виду, что вы должны присвоить ячейкам Cells[C,R] какие-либо значения прежде, чем чем вы сможете иметь доступ к Objects[C,R]. Установите у вновь созданного компонента свойство Visible в FALSE, а свойство parent в SELF. Осуществите другую необходимую инициализацию. Имейте в виду, что вы должны внести необходимые модули в список uses, если создаете тип компонента, которого нигде кроме как на форме нет.

Создайте процедуру, берущую координаты колонки/строки и правильно позиционирующую соотвествующий объект в пределах прямоугольника ячейки, например:


procedure TForm1.FixObjPosn(vCol, vRow: LongInt);
{Размещаем содержимое компонента в области прямоугольника ячейки}
var
  R: TRect;
begin
  R := StringGrid1.CellRect(vCol, vRow);
  if StringGrid1.Objects[vCol, vRow] is TControl then
    with TControl(StringGrid1.Objects[vCol, vRow]) do
      if R.Right = R.Left then {прямоугольник ячейки невидим}
        Visible := False
      else
      begin
        InflateRect(R, -1, -1);
        OffsetRect(R, StringGrid1.Left + 1, StringGrid1.Top + 1);
        BoundsRect := R;
        Visible := True;
      end;
end;




смещение позиции необходимо, поскольку CellRect расчитывается относительно верхнего левого угла строки сетки, и родителем компонента является форма).


В обработчике события сетки OnSelectCell проверьте, располагается ли элемент Objects в текущей колонке Col и строке Row TControl - если так, установите его свойство visible в FALSE. Теперь вызовите процедуру установления координат из шага 2 для *НОВЫХ* Col и Row, передавая их из параметров обработчика события в параметры функции.

В обработчике OnTopLeftChanged просто вызовите FixObjPosn

В обработчике события OnDrawCell во-первых, если ячейка выбрана, EXIT. Если элемент ячейки Objects не TControl, также EXIT. В противном случае вам нужно создать код, обеспечивающий отрисовку "фасада" каждого типа элемента управления, которого вы разместили в сетке.

Обратите внимание на то, что если вы делаете что-либо с элементом управления, на который влияют ДРУГИЕ элементы управления (например, изменение статуса какой-либо радиокнопки из группы, или операции enable/disable), вы должны вызвать метод сетки Refresh.

Опс! Это звучит немного запутанно, но это работает. Успехов!



--------------------
Мы - Днепряне. Мы всех сильней.
PM ICQ   Вверх
Slawanix
Дата 7.1.2005, 16:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



Fedor, спасибо, надеюсь это есть в старой версии DRKB, пошел смотреть. smile
--------------------
моск кипит    
PM MAIL WWW   Вверх
Slawanix
Дата 7.1.2005, 16:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



В ответе, которы дал Fedor, показан способ интеграции в run-time, а можно создать и затем инсталлировать собственный компонент, отвечающий этим требованиям, чтобы все свойства были доступны в инспекторе в дизайне (разработке приложения)? smile .
Заранее благодарен, Slawanix.
--------------------
моск кипит    
PM MAIL WWW   Вверх
dm9
Дата 7.1.2005, 17:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дмитрий Копытин
****


Профиль
Группа: Vingrad developer
Сообщений: 3876
Регистрация: 22.7.2002
Где: Москва

Репутация: 6
Всего: 137



Цитата(Slawanix @ 7.1.2005, 16:03)
Подскажите пожалуста, как это можно сделать: интегрировать в StringGrid компонент CheckBox


Вот так:
http://forum.vingrad.ru/index.php?showtopi...ndpost&p=292858
PM MAIL ICQ   Вверх
Slawanix
Дата 7.1.2005, 21:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



dm9, ты меня приятно удивил smile smile , найти бы такую штучку, да еще чтобы и бесплатная была, эхх smile . Спасибо, однако, между нами говоря, самому это сделать более приятно, ...осмыслить и сделать.
--------------------
моск кипит    
PM MAIL WWW   Вверх
dm9
Дата 7.1.2005, 21:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Дмитрий Копытин
****


Профиль
Группа: Vingrad developer
Сообщений: 3876
Регистрация: 22.7.2002
Где: Москва

Репутация: 6
Всего: 137



Это не сложно, однако очень долго. Зачем изобретать велосипед, если есть уже готовое?

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

Это сообщение отредактировал(а) dm9 - 7.1.2005, 21:20
PM MAIL ICQ   Вверх
Akella
Дата 8.1.2005, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 36
Всего: 329



есть такой пример с DBGrid

Код

procedure DrawGridCheckBox(Canvas: TCanvas; Rect: TRect; Checked: boolean);
var
 DrawFlags: Integer;
begin
 Canvas.TextRect(Rect, Rect.Left + 1, Rect.Top + 1, ' ');
 DrawFrameControl(Canvas.Handle, Rect, DFC_BUTTON, DFCS_BUTTONPUSH or DFCS_ADJUSTRECT);
 DrawFlags := DFCS_BUTTONCHECK or DFCS_ADJUSTRECT;// DFCS_BUTTONCHECK
 if Checked then
   DrawFlags := DrawFlags or DFCS_CHECKED;
 DrawFrameControl(Canvas.Handle, Rect, DFC_BUTTON, DrawFlags);
end;

На событие OnDrawColumnCell вешаем вызов процедуры DrawGridCheckBox():

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
 DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
 if Column.FieldName = 'WEIGHT' then // Модифицируйте под себя
   if Column.Field.AsInteger > 10 then
     DrawGridCheckBox(DBGrid1.Canvas, Rect, true)
   else
     DrawGridCheckBox(DBGrid1.Canvas, Rect, false)
end;

Для скрытия текста в ячейках с CheckBox`ом от отображения значения при вводе с клавиатуры определи реакцию на событие OnColumnEnter:

procedure TfrmMain.DBGrid1ColEnter(Sender: TObject);
begin
 with TDBGrid(Sender) do
   if SelectedField.FieldName = 'Weight' then // Модифицируйте под себя
     Options := Options - [dgEditing]
   else
     Options := Options + [dgEditing]
end;


Добавлено @ 10:42

в чудесной базе, под названием DRKB, есть целая статья smile
Код

Данный совет и сопутствующий код показывает как просто поместить любой компонент в
ячейку сетки данных. Компонент в данном контексте может означать любой видимый элемент
управления - от простого combobox до сложного диалогового окна. Методы, описанные ниже,
применимы практически к любому визуальному компоненту. Если Вы можете поместить его на
форму, то, вероятно, сможете поместить и в ячейку DBGrid.

Здесь нет новых идей, фактически основная технология работы заключается в имитации-
трансплантации внешних компонентов в DBGrid. Идея в том, чтобы получить контроль над
табличной сеткой. Практически DBGrid состоит из набора компонентов TDBEdit. Вводя данные в
ячейку, вы работаете непосредственно с TDBEdit. Остальные без фокуса ячейки в данный
момент реально являются статичной картинкой. В данном совете Вы узнаете как поместить в
сфокусированную ячейку другой, отличный от TDBEdit, визуальный компонент.

КОМПОНЕНТ #1 - TDBLOOKUPCOMBO
Вам нужна форма с компонентом DBGrid на ней. Создайте новый проект и поместите на
основную форму DBGrid.

Далее поместите на форму TTable, установите псевдоним (Alias) в DBDEMOS, TableName в
GRIDDATA.DB и присвойте свойству Active значение True. Поместите DataSource и сошлитесь в
свойстве DataSet на Table1. Вернитесь к DBGrid и укажите в свойстве DataSource компонент
DataSource1. Данные из GRIDDATA.DB должные появиться в табличной сетке...

Первый элемент, который мы собираемся поместить в DBGrid - TDBLookupCombo, т.к. нам нужна
вторая таблица для поиска. Поместите второй TTable на форму. Установите псевдоним (Alias) в
DBDEMOS, TableName в CUSTOMER.DB и присвойте свойству Active значение True. Поместите
второй DataSource и сошлитесь в свойстве DataSet на Table2.

Теперь нужно поместить компонент TDBLookupCombo из палитры Data Controls на любое место
формы - это не имеет никакого значения, т.к. он обычно будет невидим или будет нами
имплантирован в табличную сетку. Установите свойства компонента LookuoCombo следующим
образом:

DataSource      DataSource1
DataField       CustNo
LookupSource    DataSource2
LookupField     CustNo
LookupDisplay   CustNo  {Вы можете изменить это на Company позже,
                        но сейчас пусть это будет CustNo)

Пока мы только настроили компоненты. Теперь давайте создадим некоторый код.

Первое, что Вам необходимо - сделать так, чтобы DBLookupCombo, который Вы поместили на
форму, во время запуска приложения оставался невидимым. Для этого выберите Form1 в
инспекторе объектов, перейдите на закладку Events (события) и дважды щелкните на событии
onCreate. Delphi немедленно сгенерит и отобразит скелет кода будущего обработчика события
onCreate:

procedure TForm1.FormCreate(Sender: TObject);
begin

end;

Присвойте свойству Visible значение False в LookupCombo следующим образом:

procedure TForm1.FormCreate(Sender: TObject);
begin
 DBLookupCombo1.Visible := False;
end;

Наверняка многим стало интересно, почему я не воспользовался инспектором объектов для
изменения свойств компонента. Действительно, можно было бы и так. Лично я таким способом
инициализирую компоненты, чьи свойства могут изменяться во время работы приложения. Я
изменил статическое свойство, которое не отображается во время проектирования (если
воспользоваться инспектором объктов). Я думаю это делает код легче для понимания.

Теперь нам необходимо "прикрутить" компонент к нашей табличной сетке. Наша задача -
автоматически отобразить DBLookupCombo в ячейке во время получения ею фокуса (или
перемещении курсора). Для этого необходимо написать код для обработчиков двух событий:
OnDrawDataCell и OnColExit. Первым делом обработаем событие OnDrawDataCell. Дважды
щелкните на строчке OnDrawDataCell в инспекторе объектов и введите следующий код:

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
 Field: TField; State: TGridDrawState);
begin
 if (gdFocused in State) then
 begin
   if (Field.FieldName = DBLookupCombo1.DataField) then
   begin
     DBLookupCombo1.Left := Rect.Left + DBGrid1.Left;
     DBLookupCombo1.Top := Rect.Top + DBGrid1.top;
     DBLookupCombo1.Width := Rect.Right - Rect.Left;
     { DBLookupCombo1.Height := Rect.Bottom - Rect.Top; }
     DBLookupCombo1.Visible := True;
   end;
 end;
end;


Причины чрезмерного использования конструкций begin/end скоро станут понятны.
В коде "говорится", что если параметр State имеет значение gdFocused, то данная ячейка
имеет фокус (в любой момент времени только одна ячейка в табличной сетке может иметь
фокус). Далее: если это выделенная ячейка и ячейка имеет тоже имя поля как и поле данных
DBLookupCombo, DBLookupCombo необходимо поместить над этой ячейкой и сделать его
видимым. Обратите внимание на определение позиции DBLookupCombo: она определяется
относительно формы, а не ячейки. Так, например, положение левой стороны LookupCombo
должно учитывать положение сетки (DBGrid1.Left) плюс положение соответствующей ячейки
относительно сетки (Rect.Left).

Также обратите внимание на то, что определение высоты LookupCombo в коде
закомментарено. Причина в том, что LookupCombo имеет минимальную высоту. Вы просто не
сможете сделать ее меньше. Минимальная высота LookupCombo больше высоты ячейки. Если Вы
раскомментарили строку, касающуюся высоты LookupCombo, Ваш код изменит размер
компонента и Delphi немедленно его перерисует. Это вызовет неприятное моргание
компонента. Бороться с этим невозможно. Позвольте, чтобы LookupCombo был немного больше,
чем ячейка. Это выглядит немного странным, но это работает.


Теперь ради шутки запустите программу. Заработала? Сразу после запуска переместите курсор
на одну из ячеек табличной сетки. Вы ожидали чего-то большего? Да! Мы только в середине
пути. Теперь нам нужно спрятать LookupCombo при покидании курсором колонки. Напишем
обработчик события onColExit. Это должно выглядеть примерно так:


procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
 If DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
   DBLookupCombo1.Visible := false;
end;


Код использует свойство TDBGrids SelectedField для ассоциации имени поля ячейки (FieldName) с
нашим LookupCombo. Код "говорит": "Если ячейка была в колонке с DBLookupCombo (имя поля
ячейки совпадает с именем поля DBLookupCombo), его необходимо сделать невидимым".

Теперь снова запустите приложение. Чувствуете эффект?

Теперь вроде бы все правильно, но мы забыли об одной вещи. Попробуйте ввести новое
значение в одно из LookupCombo. Проблема в том, что нажатие клавиши обрабатывает DBGrid,
а не LookupCombo. Чтобы исправить это, нам нужно написать для табличной сетки обработчик
события onKeyPress. Это должно выглядеть примерно так:

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
 if (key <> chr(9)) then
 begin
   if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
   begin
     DBLookupCombo1.SetFocus;
     SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
   end;
 end;
end;


В данном коде "говорится": если нажатая клавиша не является клавишей Tab (Chr(9)) и текущее
поле в табличной сетке LookupCombo, тогда установите фокус на LookupCombo и передайте
сообщение с кодом нажатой клавиши LookupCombo. Здесь я воспользовался WIN API функцией.
Вам не нужно знать как это работает, достаточно того, что это просто работает.

Небольшое пояснение я все же дам. Для того, чтобы функция Window SendMessage послала
сообщение "куда надо", ей в качестве параметра необходим дескриптор ("адрес") нужного
компонента. Используйте свойство компонента Handle. Затем нужно сообщить компоненту что
мы от него хотим. В нашем случае это Windows-сообщение WM_CHAR, извещающее
LookupCombo о том, что ему посылается символ. Наконец, мы передаем ему сам символ нажатой
клавиши - word(Key). Word(key) - приведение к типу word параметра Key события нажатия
клавиши. Все достаточно просто, правда? Все, что Вам действительно необходимо сделать -
заменить имя DBLookupCombo1 нашего вымышленного компонента на имя реального
компонента, который будет участвовать в "модернизации" табличной сетки. Более подробную
информацию о функции SendMessage Вы можете почерпнуть из электронной справки,
поставляемой вместе с Delphi.

Запустите снова Ваше приложение и попробуйте что-нибудь ввести. Это работает!
Экспериментируя, Вы увидите что с помощью клавиши Tab Вы можете перейти из режима
редактирования в режим перемещения курсора и наоборот.

Теперь перейдите к инспектору объектов и измнените у компонента DBLookupCombo свойство
LookupDIsplay на Company. Снова запустите. Это то, что Вы ожидали?

КОМПОНЕНТ #2 - TDBCOMBO

Здесь я не собираюсь обсуждать технологию имплантации DBCombo, так как она практически
не отличается от той, что была показана выше. Все написанное в пункте #1 имеет силу и здесь.
Вот пошагово разработанный код для вашего компонента.

procedure TForm1.FormCreate(Sender: TObject);
begin
 DBLookupCombo1.Visible := False;
 DBComboBox1.Visible := False;
end;

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
 Field: TField; State: TGridDrawState);
begin
 if (gdFocused in State) then
 begin
   if (Field.FieldName = DBLookupCombo1.DataField) then
   begin
     DBLookupCombo1.Left := Rect.Left + DBGrid1.Left;
     DBLookupCombo1.Top := Rect.Top + DBGrid1.top;
     DBLookupCombo1.Width := Rect.Right - Rect.Left;
     DBLookupCombo1.Visible := True;
   end
   else if (Field.FieldName = DBComboBox1.DataField) then
   begin
     DBComboBox1.Left := Rect.Left + DBGrid1.Left;
     DBComboBox1.Top := Rect.Top + DBGrid1.top;
     DBComboBox1.Width := Rect.Right - Rect.Left;
     DBComboBox1.Visible := True;
   end
 end;
end;

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
 if DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
   DBLookupCombo1.Visible := false
 else if DBGrid1.SelectedField.FieldName = DBComboBox1.DataField then
   DBComboBox1.Visible := false;
end;

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
 if (key <> chr(9)) then
 begin
   if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
   begin
     DBLookupCombo1.SetFocus;
     SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
   end
   else if (DBGrid1.SelectedField.FieldName = DBComboBox1.DataField) then
   begin
     DBComboBox1.SetFocus;
     SendMessage(DBComboBox1.Handle, WM_Char, word(Key), 0);
   end;
 end;
end;

КОМПОНЕНТ #3 - TDBCHECKBOX
Технология работы с компонентом DBCheckBox более интересна. В этом случае нам необходимо
дать понять пользователю о наличие компонента DBCheckBox в ячейках без фокуса. Вы можете
вставлять статическое изображение компонента или динамически изменять изображение в
зависимости от логического состояния элемента управления. Я выбрал второе. Я создал два BMP-
файла - включенный (TRUE.BMP) и выключенный (FALSE.BMP) DBCheckBox. Поместите два
компонента TImage на форму, присвойте им имена ImageTrue и ImageFalse и назначьте
соответствующие BMP-файлы в свойстве Picture. Да, чуть не забыл: Вам также необходимо
поместить на форму два компонента DBCheckbox. Установите набор данных обоих компонентов
в DataSource1 и присвойстве свойству Color значение clWindow. Для начала создадим для формы
обработчик события onCreate:

procedure TForm1.FormCreate(Sender: TObject);
begin
 DBLookupCombo1.Visible := False;
 DBCheckBox1.Visible := False;
 DBComboBox1.Visible := False;
 ImageTrue.Visible := False;
 ImageFalse.Visible := False;
end;

Теперь нам нужен обработчик события onDrawDataCell чтобы делать что-то с ячейками, не
имеющими фокуса. Здесь подойдет следующий код:

procedure TForm1.DBGrid1DrawDataCell(Sender: TObject; const Rect: TRect;
 Field: TField; State: TGridDrawState);
begin
 if (gdFocused in State) then
 begin
   if (Field.FieldName = DBLookupCombo1.DataField) then
   begin
     // ...СМОТРИ ВЫШЕ
   end
   else if (Field.FieldName = DBCheckBox1.DataField) then
   begin
     DBCheckBox1.Left := Rect.Left + DBGrid1.Left + 1;
     DBCheckBox1.Top := Rect.Top + DBGrid1.top + 1;
     DBCheckBox1.Width := Rect.Right - Rect.Left { - 1};
     DBCheckBox1.Height := Rect.Bottom - Rect.Top { - 1};
     DBCheckBox1.Visible := True;
   end
   else if (Field.FieldName = DBComboBox1.DataField) then
   begin
     // ...СМОТРИ ВЫШЕ
   end
 end
 else {в этом месте помещаем статическое изображение компонента}
 begin
   if (Field.FieldName = DBCheckBox1.DataField) then
   begin
     if TableGridDataCheckBox.AsBoolean then
       DBGrid1.Canvas.Draw(Rect.Left, Rect.Top, ImageTrue.Picture.Bitmap)
     else
       DBGrid1.Canvas.Draw(Rect.Left, Rect.Top, ImageFalse.Picture.Bitmap)
   end
 end;
end;

Самое интересное место - последний участок кода. Он выполняется в случае, когда состояние
не равно gdFocused и сам CheckBox находится в колонке. В нем осуществляется проверка
данных поля: если они равны True, то выводится рисунок TRUE.BMP, в противном случае -
FALSE.BMP. Предварительно я создал два изображения, представляющие собой "слепок" двух
логических состояния компонента, теперь будет очень трудно обнаружить отсутствие
компонента в ячейках с фокусом и без оного. Теперь напишем обработчик события onColExit:

procedure TForm1.DBGrid1ColExit(Sender: TObject);
begin
 If DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField then
   DBLookupCombo1.Visible := false
 else
 If DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField then
   DBCheckBox1.Visible := false
 else
 If DBGrid1.SelectedField.FieldName = DBComboBox1.DataField then
   DBComboBox1.Visible := false;
end;


Организуйте обработку события onKeyPress как показано ниже:

procedure TForm1.DBGrid1KeyPress(Sender: TObject; var Key: Char);
begin
 if (key <> chr(9)) then
 begin
   if (DBGrid1.SelectedField.FieldName = DBLookupCombo1.DataField) then
   begin
     DBLookupCombo1.SetFocus;
     SendMessage(DBLookupCombo1.Handle, WM_Char, word(Key), 0);
   end
   else if (DBGrid1.SelectedField.FieldName = DBCheckBox1.DataField) then
   begin
     DBCheckBox1.SetFocus;
     SendMessage(DBCheckBox1.Handle, WM_Char, word(Key), 0);
   end
   else if (DBGrid1.SelectedField.FieldName = DBComboBox1.DataField) then
   begin
     DBComboBox1.SetFocus;
     SendMessage(DBComboBox1.Handle, WM_Char, word(Key), 0);
   end;
 end;
end;

 
Наконец, последняя хитрость. Для удобства пользователя заголовку компонента нужно
присвоить текущее логическое значение. С самого начала у меня была идея поручить это
обработчику события onChange, но проблема в том, что событие может возникнуть
неединожды. Итак, я должен снова воспользоваться функцией Windows API и послать
компоненту соответствующее значение: "SendMessage(DBCheckBox1.Handle, BM_GetCheck, 0,
0)", которая возвращает 0 в случае если компонент невключен и любое другое число в
противном случае.

procedure TForm1.DBCheckBox1Click(Sender: TObject);
begin
 if SendMessage(DBCheckBox1.Handle, BM_GetCheck, 0, 0) = 0 then
   DBCheckBox1.Caption := ' ' + 'Ложь'
 else
   DBCheckBox1.Caption := ' ' + 'Истина'
end;

Это все. Надеюсь, Вы узнали для себя что-то новое. Я пробовал данную технологию с
диалоговыми окнами. Делается достаточно просто и великолепно работает. Радует простота
реализации. Вам даже не нужно знать как это работает, единственное, что Вам придется -
заменить в тексте кода имена вымышленных компонентов на те, которые Вы реально хотите
отображать в табличной сетке.

Ревизия
Вышеприведенный код оказался несвободным от недостатков - после первой публикации совета
дотошные программисты таки обнаружили две значительные недоработки. Первая проблема -
если компонент имеет фокус, то для перемещения на следующую ячейку необходимо
двукратное нажатие клавиши Tab. Вторая проблема возникает при добавлении новой записи.


Проблема # 1 - Необходимость двойного нажатия клавиши Tab.

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

Для начала в форме, содержащей табличную сетку, опишем логическую переменную
WasInFloater следующим образом:

type

TForm1 = class(TForm)
...
...
private
{ Private declarations }
WasInFloater : Boolean;
...
...
end;


Затем для компонента LookupCombo напишем обработчик события onEnter, где присвоим
переменной WasInFloater значение True. Это позволит нам понять где в данный момент
находится фокус.

procedure TForm1.DBLookupCombo1Enter(Sender: TObject);
begin
 WasInFloater := True;
end;

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


procedure TForm1.DBGrid1KeyUp(Sender: TObject; var Key: Word;
 Shift: TShiftState);
begin
 if (Key in [VK_TAB]) and WasInFloater then
 begin
   SendMessage(DBGrid1.Handle, WM_KeyDown, Key, 0);
   WasInFloater := False;
 end;
end;

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

Проблема #2 - Новая запись исчезает, когда компонент получает фокус.

Вторая проблема - в случае, когда вы нажимаете в навигаторе кнопку "добавить", запись
добавляется, но, когда Вы после щелкаете на одном из компонентов, имплантированных в
табличную сетку, новая запись таинственным образом исчезает. Причина этого - странный флаг
dgCancelOnExit в опциях DBGrid, который имеет значение True по умолчанию. Установите это в
False и вышеназванная проблема исчезает.

По-моему, Borland неправильно поступил, назначив такое значение по умолчанию, флаг должен
иметь значение False. Я все время сталкиваюсь с данной проблемой, да и не только я, судя по
новостным конференциям. Данная опция действует в случае потери компонентом фокуса и
отменяет последние результаты редактирования. Во всяком случае во всех моих проектах я
первым делом сбрасываю данный флаг.


Это сообщение отредактировал(а) dsergey - 8.1.2005, 10:50
PM MAIL   Вверх
Alex
Дата 8.1.2005, 10:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Или здесь:
DBGrid - http://vingrad.ru/VF-DLP-000362
StringGrid - http://vingrad.ru/VF-DLP-000361


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Akella
Дата 8.1.2005, 11:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Творец
****


Профиль
Группа: Модератор
Сообщений: 18485
Регистрация: 14.5.2003
Где: Корусант

Репутация: 36
Всего: 329



Цитата
Насчёт бесплатного - кажется, у этой штуки открытые исходники.

мне кажется ты погорячился smile
PM MAIL   Вверх
Slawanix
Дата 9.1.2005, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



Ребята, спасибо огромное за советы. А я, в свою очередь в факе нашел статейку как раз по моей теме с чекбоксами. Проверил работает, надо теперь под себя затачивать smile . Пожелайте мне удачи, и я к вам присоединюсь smile .
Вот та самая статья из фака http://vingrad.ru/VF-DLP-000359
--------------------
моск кипит    
PM MAIL WWW   Вверх
Slawanix
Дата 9.1.2005, 23:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



При использовании примера из фака http://vingrad.ru/VF-DLP-000359 у меня возникли проблемки.
для создания тех самых чекбоксов в той самой стринггрид использую эти процедуры:

Код

Procedure clean_previus_buffer(Grid:TstringGrid);
var
NewCheckBox: TCheckBox;
i: Integer;
begin
for i := 1 to Grid.RowCount do
 begin
  NewCheckBox := (Grid.Objects[5,i] as TCheckBox);
  if NewCheckBox <> nil then
   begin
    NewCheckBox.Visible := false;
    Grid.Objects[5,i] := nil;
   end;
  end;
end;

//процедура добавления чекбоксов в тблицу.
procedure AddCheckBoxes(Grid:TstringGrid);
var
i: Integer;
NewCheckBox: TCheckBox;
begin
clean_previus_buffer(Grid); // очищаем неиспользуемые ячейки в таблице...
for i := 1 to Grid.RowCount do
 begin
  NewCheckBox := TCheckBox.Create(Application);
  NewCheckBox.Width := 0;
  NewCheckBox.Visible := false;
  NewCheckBox.Caption := 'OK';
  NewCheckBox.Color := clWindow;
  NewCheckBox.Tag := i;
  //Связываем предыдущее событие OnClick  
  // с существующим TCheckBox  
TCheckBox
  NewCheckBox.OnClick := Form1.CheckBox1.OnClick;
  NewCheckBox.Parent := Form1;
  Grid.Objects[5,i] := NewCheckBox;
 end;
 set_checkbox_alignment(Grid); // расположение ячеек в таблице...
end;

Procedure set_checkbox_alignment(Grid:TstringGrid);
var
NewCheckBox: TCheckBox;
Rect: TRect;
i: Integer;
begin
for i := 1 to Grid.RowCount do
 begin
 NewCheckBox := (Grid.Objects[5,i] as TCheckBox);
 if NewCheckBox <> nil then
  begin
   Rect := Grid.CellRect(5,i); // получаем размер ячейки для тблицы
   NewCheckBox.Left := Grid.Left + Rect.Left+2;
   NewCheckBox.Top := Grid.Top + Rect.Top+2;
   NewCheckBox.Width := Rect.Right - Rect.Left;
   NewCheckBox.Height := Rect.Bottom - Rect.Top;
   NewCheckBox.Visible := True;
  end;
 end;
end;

procedure TForm1.sgSourseDrawCell(Sender: TObject; ACol, ARow: Integer;
 Rect: TRect; State: TGridDrawState);
begin
if not (gdFixed in State) then set_checkbox_alignment(sgSourse);
end;

procedure TForm1.SgTargetDrawCell(Sender: TObject; ACol, ARow: Integer;
 Rect: TRect; State: TGridDrawState);
begin
if not (gdFixed in State) then set_checkbox_alignment(sgTarget);
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
 ShowMessage('There it is!!!');
end;


Вызов AddCheckBoxes(Form1.sgSourse);
то есть, добавление ячеек происходит после отображения инфы в остальных ячейках всей таблицы.

Что я изменил относительно текста фака:
1) StringGrid расположил не на панели, а на форме (на той же где и чекбокс);
2) функция AddCheckBoxes вызывается в потоке API (вот так);
Код
h1:=CreateThread(nil,1024,@ScannerBoss,nil,0,th1);


боксы появляются,но вот Проблеммы:
1)отрисовка боксов есть только на видимых пользователю строках, то есть, которые видны без прокрутки
2) при закрытии программы выскакивает бага с текстом:
проект вызвал исключение класса EOSError c сообщением SystemError. Code: 1400 'Недопустимый дескриптор окна'

а без вызова AddCheckBoxes прога работет намана.
--------------------
моск кипит    
PM MAIL WWW   Вверх
Alex
Дата 10.1.2005, 00:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Slawanix, этот пример 100% рабочий было дело сам его использовал, правдо не в потоке. Пример рабочий, но имеет один недостаток при большом колличестве CheckBox (более 10) начинает все страшно тормозить в плане перерисовки.


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Slawanix
Дата 10.1.2005, 00:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 177
Регистрация: 29.7.2004
Где: г. Великие Луки

Репутация: нет
Всего: 1



Цитата
при большом колличестве CheckBox (более 10) начинает все страшно тормозить в плане перерисовки.

Alex, похоже я с этим как раз и столкнулся. А можно его как-то оптимизировать, или надо будет по-другому изворачиаться. Дело в том, что количество может быть практически неограничено.
--------------------
моск кипит    
PM MAIL WWW   Вверх
Alex
Дата 10.1.2005, 00:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 4147
Регистрация: 25.3.2002
Где: Москва

Репутация: 80
Всего: 162



Slawanix, я особо разбираться не стал т.к. мне нужно было еще некоторые нестандартные вещи сделать, и воспользовался TMS GridPack


--------------------
Написать можно все - главное четко представлять, что ты хочешь получить в конце. 
PM Skype   Вверх
Закрытая темаСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0986 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.