![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Точное позиционирование в DBGrid [Win95/98]
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 запрос опять лопатить кучу таблиц, нагружать сеть и прочее.