Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Точное позиционирование в DBGrid [Win95/98]


Страницы:   1 2 3

msguns ©   (2005-05-19 17:03:00) 

Суть проблемы в том, чтобы после изменения записи в таблице и переоткрытия отображающего ее нередактируемогоНД не просто найти эту запись и сделать ее активной, а добиться того, чтобы она отображалась в том же самом месте грида.
Понимаю, что надо поиграться с предком грида, имеющем соотв.св-ва (Row), но это требует массу времени, которого, как всегда, не хватает.
Возможно, у кого-то есть хорошие (не громоздкие) решения, которыми не жаль поделиться. Сделайте одолжение - буду весьма признателен.


Alex_S   (2005-05-22 14:01:00) [1]

Этот вопрос здесь уже обсуждался (например, в начале января 2005 г. Msguns тогда много отдыхал, числа до 15, как водится в Украине, поэтому и пропустил). Кто-то был недоволен предлагаемым решением, но я его использую. Так что, если это кого-то ещё интересует, то пожалуйста. (С тех пор еще немного подчистил)
Суть задачи следующая. Например, DBGrid показывает записи нередактируемого набора TQuery, запись изменяется через TTable, надо вернуть её в DBGrid так, чтобы она попала в ту же строку после перечитки TQuery.
Предлагаемое решение.
Для удобного вида можно в DBGrid1.Options включить dgRowSelect, чтобы ведялалсь вся строка.
Здесь важно определить, в какой строке (начиная с номера 1) из видимого списка DBGrid находилась редактируемая запись. Для этого предлагается следующая процедура обработки события DBGrid1.OnDrawColumnCell:

        { --- Текущая строка в DBGrid1 ---- }

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
 DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
 if gdSelected in State then
   NRow:=(Rect.Top div 21);
{ при перерисовке ячеек DBGrid для выделенной ячейки определяем номер строки NReg - глобальная переменная типа integer;
 21 - высота строки. У себя проверьте эту величину.
 Для того, чтобы затем случайно она не изменилась в других    экранных режимах для формы Form1 задайте свойство Scaled:=false }
end;


А теперь воспользуемся вычисленным номером NRow при перечитке TQuery:
При этом указатель сначала стоит на редактируемой записи (которая вносится в набор данных  - Table1.Post)


procedure TForm1.RereadQuery(Sender: TObject);
var k,k0,n: integer;
begin
k:=Query1.Fields.Fields[0].AsInteger;
n:=(DBGrid1.Height div 21) div 2; { номер средней строки в DBgrid1 }
if Query1.RecordCount<n then n:=NRow; { Если записей мало }
DBGrid1.DataSource.DataSet.DisableControls;
Query1.Close; Query1.Open;
Query1.Locate('Code',k,[]);
Query1.MoveBy(n-NRow); { обращаемся к средней строке DBGrid'а }
k0:=Query1.Fields.Fields[0].AsInteger; { запоминаем значение Code этой записи -
  в задаче использовался набор данных с первым полем Code типа Autoinc }
Query1.Locate('Code',k0,[]); { устанавливаем указатель на среднюю в DBGrid запись }
Query1.MoveBy(NRow-n); { теперь DBGrid двигаться не будет, устанавливаем указатель на измененную запись }
DBGrid1.DataSource.DataSet.EnableControls; { оживляем DBGrid1 }
DBGrid1.SetFocus; { и передаем ей фокус, если надо }
end;

Здесь я также учёл, что в результате редактирования записи она может оказаться уже на новом месте в наборе данных - по условиям сортировки и проч.
Поле Code здесь уникальное, поэтому запись все равно будет однозначно определена. Если кому-то покажется, что где-то
действия Locate и MoveBy лишние, то попробуйте сократить - мне кажется, они несколько по-разному работают с DBGrid.

PS. Не говорю, что решение единственно верное, но ничего лучшего для поставленной цели я пока не придумал. Сделаете лучше, флаг вам в руки. Стрелять пианиста не надо, он играет, как умеет.

С уважением, Alex_S


Bronco   (2005-05-21 13:02:00) [2]


> mr.IL ©   (21.05.05 11:09) [40]

Тогда нафига нужна локальная таблица, напрямую можно и серверную редактировать. Тот же самый Post и никакого смещения.
Речь то идет о другом: автору после редактирования нужно полностью обновить набор данных, т.е. close-open. Он строго придерживается сей идеологии и отходить от нее не хочет.


mr.IL   (2005-05-21 11:09:00) [3]

Локальную таблицу отдаем на редактирование гридом. Когда грид редактирует связанный с ним ДС напрямую, он не смещается после поста.


Bronco   (2005-05-21 10:30:00) [4]


> mr.IL ©   (21.05.05 08:16) [38]


> Решаем поставленную в теме задачу.

Поясни, каким образом твой вариант избавит msguns-а от смещения картинки в гриде?


mr.IL   (2005-05-21 08:16:00) [5]

Между прочим, если скидывать запрос в локальную таблицу, решаем 2 проблемы. 1.Уменьшаем трафик. 2.Решаем поставленную в теме задачу.


P.N.P.   (2005-05-20 21:26:00) [6]

>msguns ©
Пора бы смириться - без своего наследника никак.
Да в принципе и с наследником не так просто будет.
ИМХО конечно :)


Bronco   (2005-05-20 19:21:00) [7]


> mr.IL ©   (20.05.05 17:48) [35]


> Может я немного не в тему

В тему. Но не в эту :-)


mr.IL   (2005-05-20 17:48:00) [8]

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


Bronco   (2005-05-20 17:05:00) [9]

> msguns ©

Конечно смотри сам, но я все-таки опять про идеологию...
Одно дело, когда юзер по собственному желанию нажал кнопку "Refresh" - тут требуется полное обновление НД, хочешь ты или нет.
Другое дело, когда юзер (или твоя программа) апдейтит одну запись в таблице и тебе ее просто надо обновить на экране.
Вот в этом случае (ИМХО) только ее и желательно обновлять. При этом (опять же ИМХО) совершенно не обязательно видеть изменения конкурентов, на то у юзера есть кнопка "Refresh"
Хотя это только мое мнение, не претендующее на истину.


Polevi   (2005-05-20 16:05:00) [10]

>msguns ©   (20.05.05 15:31) [32]
ok


msguns   (2005-05-20 15:31:00) [11]

>Polevi ©   (20.05.05 15:05) [31]
>мне жаль тебя, ты сам не понимаешь что творишь

В жалости не нуждаюсь, побереги ее. Что творю, как это ни странно, вполне понимаю.

>тебе люди дело советуют а ты огрызаешься

Вот это "дело" :

>Polevi ©   (19.05.05 18:52) [9]
>close open в топку
>Polevi ©   (20.05.05 09:36) [11]
>чушь какаято, имхо

 ?
Спасибо, кушайте сами.
В такой форме советуют не советуют, а стебаются.

Я не утверждаю, что технология  перечитки супер, но именно о ней я читал у Вострикова с Ковязиным, а также с многочисленных форумов, и не только по интербэйз. Возможно, переоткрытие требуется не всегда и можно фетчить только измененные записи (правда непонятно, что делать с изменениями конкурентов), но я такой не пользуюсь. Возможно, зря.
Но все же такая форма ответов, ИМХО, говорит только о том, что человек не столько желает помочь, сколько себя показать, не так ли. Собственную крутость.
Выглядит это особенно коряво, когда "советы" не по сути, а около. Это неважно, что не в тему. Главное, что всем видна крутизна. Вместо вопроса по гриду мы сведем все дело к порочности Open-Close НД, в гриде отображаемом.
Что, от этого процент холестерина в крови понижается ? Или адреналинчик прибывает ?

Спасибо за внимание, однако в будущем просьба не утруждаться. Обойдемся как-нибудь без.


Polevi   (2005-05-20 15:05:00) [12]

>msguns ©   (20.05.05 13:22) [29]
мне жаль тебя, ты сам не понимаешь что творишь
тебе люди дело советуют а ты огрызаешься

>Цепочка может быть достаточно длинной.
>Поэтому приходится переоткрывать ВСЕ открытые на форме НД. Или большинство из них

бедные пользователи, несчастный сервер
их ждет очередной монстр


evvcom   (2005-05-20 14:54:00) [13]


> Но только в том случае, если редактирование в гриде.

Не обязательно. Я сейчас делаю проект Delphi/Oracle. Таблиц море, доступ только через хранимки чтение отдельно, запись отдельно. Отображение в гриде, запись через дополнительную форму и DB-компоненты (иногда даже через обычные ComboBox и прочее). Если мне надо пересчитать итог в главном наборе после изменения подчиненного, то хранимка на Update в out параметре может вернуть нужный итог, после чего его можно заменить в главном наборе без переоткрытия и даже искусственно запретить в этом случае вызов хранимки на Update главного набора.
Сделать можно как угодно, было бы желание. И говорить, что это возможно, а это невозможно, не надо.
Но пользоваться твоим компонентом, работающим так, как ты спрашиваешь, я бы не стал. Накладно очень переоткрывать НД на каждом апдейте. Все имхо.


msguns   (2005-05-20 13:22:00) [14]

>evvcom ©   (20.05.05 13:03) [27]
>Но я не понимаю, что тебе не нравится в моих советах.

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

Но вот по поводу рефреша..

Ситуация:
Одна транзакция читает данные с сервера, которые отображаются на клиенте (в том числе в гридах) комплексно. Например: сложный документ с несколькими дочерними таблицами и кучей подсчитанных итогов. Юзер вносит изменение в дочернюю таблицу и надо не просто увидеть изменение в ней, но и пересчитать итоги, отразить изменение в мастер-таблице (например, сумму по фактуре) и т.д. Цепочка может быть достаточно длинной. Поэтому приходится переоткрывать ВСЕ открытые на форме НД. Или большинство из них. Причем изменение в доч.таблице выполняется в другой транзакции, вот почему простой рефреш не "увидит" изменений, т.к. лишь извлекает записи из буфера текущего НД, а он и не менялся однако !

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


evvcom   (2005-05-20 13:11:00) [15]


> "читаем в одной транзакции - пишем в другой".
> Правда, к гриду опять же это никакого отношения не имеет.

Вот именно. Грид читает в одной. Далее спрашивает у DataSet редактируемый ли он? Если нет, то не заставишь грид редактировать, если да, то гриду пофиг в действительности вставится запись или нет в транзакции на запись. Он ее отобразит и будет думать, что вставилась. Причем если сделать CancelUpdates, грид должен из своих строк также удалить эти записи. И все это работает (во всяком случае в DevExpress). Могут быть какие-то глюки, но это уже другое, это уже ошибки компонента.


evvcom   (2005-05-20 13:03:00) [16]


> >А чтобы привести в порядок последовательность, добавляешь
> кнопку refresh
>
> Сам пробовал ? Прежде чем советовать ?

Именно так и делаю. Отлично работает.


> Гриду уьтрамариново, редактируемый или нередактируемый датасет
> он малюет

> >и юзер сам решит, когда ему приводить набор в порядок
>
> Ага, деваха добавила запись и фиг увидела ее в решетке,
> добавила другую - тот же отлуп.

Какой он малюет естественно уьтрамариново, но при операциях "редактирования в гриде" грид ведет себя уже не уьтрамариново. И деваха, добавляя запись, нормально видит ее в решетке. Если решетка DB, то автоматом, если не DB, то извини, если ты ей шыш нарисуешь, то его она и увидит.

Может ты не хочешь понять, о чем тебе твердят, либо не можешь толком сформулировать причины не желания использовать более простых и надежных способов. Но я не понимаю, что тебе не нравится в моих советах.


msguns   (2005-05-20 12:56:00) [17]

За эту фразу:

Поэтому я пошел не в магазин (БД), а в рем.мастерскую (Общая), откуда меня послали к умникам вроде Polevi

прошу прощения,- не сдержался.
терпеть не могу хамства, а еще больше - себя хамящего.


msguns   (2005-05-20 12:51:00) [18]

>evvcom ©   (20.05.05 12:17) [23]
>Может я чего не понимаю в твоих терминах, но если набор не редактируемый, то он не редактируемый!

Дело не в терминах и вообще не в наборах данных, а в гриде!
Гриду уьтрамариново, редактируемый или нередактируемый датасет он малюет. Что касается всяких UpdateObject, UpdateSQL, Insert/Delete/UpdateSQL и т.д., - то все это разные примочки разных механизмов доступа, позволяющих редактирование собственно в гриде. Но где я спрашивал о том, КАК МОЖНО РЕДАКТИРОВАТЬ В ГРИДЕ ? ГДЕ ???
Вместо того, чтобы пообсуждать проблему ремонта старого телевизора мне упорно советуют купить новый. У меня уже есть новый ! Даже несколько !
Но мне хочется разобраться со старым
Поэтому я пошел не в магазин (БД), а в рем.мастерскую (Общая), откуда меня послали к умникам вроде Polevi

>А чтобы привести в порядок последовательность, добавляешь кнопку refresh

Сам пробовал ? Прежде чем советовать ?

>и юзер сам решит, когда ему приводить набор в порядок

Ага, деваха добавила запись и фиг увидела ее в решетке, добавила другую - тот же отлуп. А потом вспомнила "Ага ! Мне ж надо рефреш нажать" *Что, кстати, ни к чему другому не приведет, поэтому-то нужно переоткрытие.
Во избежание дальнейшего топтания на одном месте уточняю, что речь идет о технологиях типа "читаем в одной транзакции - пишем в другой".
Правда, к гриду опять же это никакого отношения не имеет.

>ЮЮ ©   (20.05.05 12:18) [24]
>Это не придирки а непонимание :)
Как раз для редактирования и удаления нет ничего проще, чем сделать редактируемым DataSet, тогда что пользователь сделал в гриде, то и получил, а на сервер пойдет один UPDATE или DELETE.

Нет, не годится. Читай выше о транзакциях.

>Если уж переоткрытие так мило, говорят, отключение DataSource у грида (или DataSeta у DataSource) спасает грид от ухода с места.

не спасает.

>Еще вариант: перед открытием запомнить первую, последнюю и текущую записи в гриде (ч/з DataLink) и позиционироваться сначала в последнюю, затем в первую и наконец, в последнюю очередь, в текущую, что должно, по идее установить в DataLink теже записи, что и перед переоткрытием

Вариант Johnmen`а, присланный мне, построен похоже (другого я и не знаю). За идею спасибо. Еще покручу его в котелке ;)


ЮЮ   (2005-05-20 12:18:00) [19]

Это не придирки а непонимание :)
Как раз для редактирования и удаления нет ничего проще, чем сделать редактируемым DataSet, тогда что пользователь сделал в гриде, то и получил, а на сервер пойдет один UPDATE или DELETE.

Если уж переоткрытие так мило, говорят, отключение DataSource у грида (или DataSeta у DataSource) спасает грид от ухода с места.

Еще вариант: перед открытием запомнить первую, последнюю и текущую записи в гриде (ч/з DataLink) и позиционироваться сначала в последнюю, затем в первую и наконец, в последнюю очередь, в текущую, что должно, по идее установить в DataLink теже записи, что и перед переоткрытием


evvcom   (2005-05-20 12:17:00) [20]


> msguns ©   (20.05.05 11:05) [14]
> >evvcom ©   (20.05.05 09:48) [12]
>
> НД не редактируемый !
> Если же я сделаю его редактируемым, то
> 1. способы делания нередактируемого НД редактируемым у разных
> "движков" разные

Может я чего не понимаю в твоих терминах, но если набор не редактируемый, то он не редактируемый! Если к TQuery или TStoredProc, которые по сути являются не редактируемыми, прицепляешь UpdateObject, то они уже редактируемы. И способы зависят не от движка БД, а от реализации компонента (класса). И грид воспринимает эти DataSet-ы как редактируемые. И Open/Close делать, я все же не вижу смысла.

> 2. запись после вставки в грид и Apply окажется внизу, т.е.
> не будет следовать заданной для всего рекордсета последовательностью.

И не надо. См ЮЮ ©   (20.05.05 11:52) [19]. А чтобы привести в порядок последовательность, добавляешь кнопку refresh и используешь TBookmark, и юзер сам решит, когда ему приводить набор в порядок. Выигрыш от этого хотя бы даже в том, что не будет после каждой вставки/апдейта SQL запрос опять лопатить кучу таблиц, нагружать сеть и прочее.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо