Консультация № 187705
05.01.2014, 18:06
109.34 руб.
0 10 1
Здравствуйте! У меня возникли сложности с таким вопросом: В процессе создания программы использую DBGrid. Для удобства пользования решил сделать сортировку в отображаемой таблице. Отыскал интересный вариант сортировки. Ссылка на описание сортировки.
Код:
procedure TForm1.DBGrid1TitleClick(Column: TColumn);
{$J+}
const PreviousColumnIndex : integer = -1;
{$J-}
begin
if DBGrid1.DataSource.DataSet is TCustomADODataSet then
with TCustomADODataSet(DBGrid1.DataSource.DataSet) do
begin
try
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style :=
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style - [fsBold];
except
end;

Column.title.Font.Style :=
Column.title.Font.Style + [fsBold];
PreviousColumnIndex := Column.Index;

if (Pos(Column.Field.FieldName, Sort) = 1)
and (Pos(' DESC', Sort)= 0) then
Sort := Column.Field.FieldName + ' DESC'
else
Sort := Column.Field.FieldName + ' ASC';
end;
end;


У меня несколько вопросов.
1- Если возможно объясните как пошагово код работает. Ибо не просто заниматся копипастом, а еще и разобратся.
2- Сортировка работает, но при следующем пуске программы отображение в DBGrid1 опять идет по id базы данных.
Как сделать чтобы отображалось по последней сортировке (настройки программы сохраняются в ini файл при закрытии программы WriteParams).
Получается что при пуске программы читается по чем сортировка в DBGrid1?
Вот понаписал!

Обсуждение

давно
Старший Модератор
31795
6196
06.01.2014, 15:26
общий
Адресаты:
1)Самой сортировки в коде нет, она спрятана в методе SORT. В данном коде только формирование данных для "SQL-запроса" в метод SORT и работа со стилем имени колонки.
Если уже вибиралось поле сортировки раньше, стиль отображения заголовка колонки сбрасывается:
Код:
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style :=. . .

Устанавливается новый стиль отображения заголовка колонки и новая текущая колонка сортировки:
Код:
Column.title.Font.Style :=. . .
PreviousColumnIndex:=. . .

Данные для запроса "имя колонки и убывание/возрастание:"
Код:
Sort:=. . .


2)
Цитата: Владимир
Получается что при пуске программы читается по чем сортировка в DBGrid1

Да. Если индексное поле базы не совопадает с последним использованным полем сортировки, нужно будет проводить принудительную сортировку по нужному полю.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
352040
133
06.01.2014, 16:42
общий
Адресаты:
По первому вопросу понятно. Спасибо, разъяснили.
По второму вопросу. У меня в базе несколько таблиц. Основная таблица "S1" в ней поле "ID" с типом данных "счетчик". Все таблицы связаны с этим полем. И сортировка DBGrid1 у меня получается идет по "ID". Исходя из Вашего ответа мне нужно сохранить последнее использованное поле сортировки, и при запуске приложения из сохраненных настроек взять последнее поле и принудительно отсортировать.
Исходя из всего изложенного, что мне сохранять в ini файл с настройками?
Об авторе:
Пользуюсь Delphi Enterprise Version7.
давно
Старший Модератор
31795
6196
06.01.2014, 16:51
общий
06.01.2014, 16:51
Адресаты:
Что Вас больше устраивает. К примеру: PreviousColumnIndex или FieldName
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
352040
133
06.01.2014, 17:36
общий
Адресаты:
Это касаемо DBGrid1 сохранение? Потому как когда пишу код, после DBGrid1 ставлю точку, и нет PreviousColumnIndex ни FieldName
Так у меня происходит запись, чтение ширины колонки DBGrid1.
Код:

IniFile.WriteInteger('-----0-DBGrid1-----','2-0',DBGrid1.Columns.Items[0].Width);

DBGrid1.Columns.Items[0].Width:=IniFile.ReadInteger('-----0-DBGrid1-----','2-0',DBGrid1.Columns.Items[0].Width);
А как сюда прикрутить PreviousColumnIndex?
Об авторе:
Пользуюсь Delphi Enterprise Version7.
давно
Старший Модератор
31795
6196
08.01.2014, 13:39
общий
Адресаты:
Цитата: Владимир
Потому как когда пишу код, после DBGrid1 ставлю точку, и нет ...

Просто, Вы не там смотрите эти записи. В коде используется следующий оператор:
О п е р а т о р w i t h

Оператор with используется для сокращения записи при обращении к полям записей или к свойствам и методам объекта. В этих случаях применение with позволяет избежать повторных ссылок на объект в последующих операторах. Оператор with может записываться следующим образом:
with <объект> do <оператор>;
В операторе,следующем за ключевым словом do, можно для полей, свойств и методов объекта, указанного как <объект>, не включать ссылки на этот объект. При этом каждый идентификатор в операторе, который совпадает с именем поля, свойства, метода объекта, трактуется как относящийся к этому объекту и к нему неявно добавляется ссылка на этот объект.


Т.е. искать нужно после DBGrid1.DataSource.DataSet...
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
08.01.2014, 14:10
общий
Адресаты:
в теории, сохранить данные о последней сортировке в ini-файл реально, как и потом их считать в переменную. я таким образом сохраняю имя последнего пользователя, запускающего программу. а потом после первого открытия формы или при активации запустить процедуру сортировки с данными из ini-файла.
Неизвестный
10.01.2014, 19:25
общий
Адресаты:
По вопросу сохранения данных о сортировке в ini-файл.

Лучше работать с глобальной переменной, доступ к которой можно получить из любого места программы. А начальную инициализацию этой переменной производить при первом запуске программы и первоначальных установках.

Объявляем глобальную переменную, в которой хранится номер столбца предыдущей сортировки
PreviousColumnIndex : integer = -1;

Пусть данные последней сортировки сохраняются в ini-файл командой
IniFile.WriteInteger('-----0-DBGrid1-----','Index', PreviousColumnIndex);
При этом в переменной PreviousColumnIndex уже хранится какое-либо неотрицательное значение ( т.е. индекс уже выбран )

После первой прорисовки формы необходимо запустить код

if DBGrid1.DataSource.DataSet is TCustomADODataSet then
//На самом деле, эта проверка необязательна. Если есть 100% уверенности,
//что в источниках данных используется только ADO подключение, то можно
//убрать проверку. Но ошибкой наличие проверки не будет.

//Можно добавить оператор
// with TCustomADODataSet(DBGrid1.DataSource.DataSet) do
//чтобы в дальнейшем работать с методами и свойствами объекта
// DBGrid1.DataSource.DataSet
//но это немного запутает описание программы, поэтому пишем полные имена

begin

//Здесь можно добавить отмену выделения заголовков всех столбцов таблицы, но лучше это
//настроить при разработке, чтобы изначально ни один заголовок не был выделен.

//Заносим в переменную номер столбца сортировки из ini-файла
PreviousColumnIndex := IniFile.ReadInteger('-----0-DBGrid1-----','Index', PreviousColumnIndex);

//Выделяем заголовок столбца новой сортировки
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style:=
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style + [fsBold];

//Запускаем сортировку, взяв имя поля из таблицы
TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort :=
DBGrid1.Columns[PreviousColumnIndex].FieldName + ' ASC';

end;

А дальше сортировка настраивается в процедуре при нажатии на заголовок столбца как в примере. Главное не забыть сохранить в ini-файл значение номера столбца сортировки. Можно еще и направление сортировки сохранить – ASC или DESC.
давно
Посетитель
352040
133
11.01.2014, 18:09
общий
Благодарю за подсказку, буду пробовать реализовать в своем проекте. На данный момент вынужден отложить работу, в командировку уезжаю.
Об авторе:
Пользуюсь Delphi Enterprise Version7.
Неизвестный
11.01.2014, 23:00
общий
Адресаты:
К сожалению, до закрытия вопроса осталось чуть больше суток. Поэтому завтра днем составлю ответ из сообщений мини-форума, если ув. Зенченко Константин Николаевич не сформирует.
Неизвестный
12.01.2014, 13:55
общий
это ответ
Здравствуйте, Владимир!

Начну с ответа на второй вопрос.

Объявляем глобальную переменную, в которой хранится номер столбца предыдущей сортировки
PreviousColumnIndex : integer = -1;

Пусть данные последней сортировки сохраняются в ini-файл командой
IniFile.WriteInteger('-----0-DBGrid1-----','Index', PreviousColumnIndex);
При этом в переменной PreviousColumnIndex уже хранится какое-либо неотрицательное значение ( т.е. индекс уже выбран )

В случае первого добавления кода в программу в ini-файле такого значения не будет, поэтому может выскочить ошибка. Чтобы этого избежать нужно изменить начальное значение переменной
PreviousColumnIndex : integer = 0;
Тогда если значения нет, то будет задана сортировка по первому столбцу по возрастанию. В дальнейшем после сохранения значения в файле будет работать нормально.

После первой прорисовки формы необходимо запустить код

if DBGrid1.DataSource.DataSet is TCustomADODataSet then
//На самом деле, эта проверка необязательна. Если есть 100% уверенности,
//что в источниках данных используется только ADO подключение, то можно
//убрать проверку. Но ошибкой наличие проверки не будет.

begin

//Здесь можно добавить отмену выделения заголовков всех столбцов таблицы, но лучше это
//настроить при разработке, чтобы изначально ни один заголовок не был выделен.

//Заносим в переменную номер столбца сортировки из ini-файла
PreviousColumnIndex := IniFile.ReadInteger('-----0-DBGrid1-----','Index', PreviousColumnIndex);
//Возможно, при первом запуске нужно будет заредактировать эту строку, т.к. в ini-файле еще нет такого параметра и может выскочить ошибка.

//Выделяем заголовок столбца новой сортировки
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style:=
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style + [fsBold];

//Запускаем сортировку по возрастанию, взяв имя поля из таблицы
TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort :=
DBGrid1.Columns[PreviousColumnIndex].FieldName + ' ASC';

end;


Далее работает обработка события нажатия на заголовок столбца таблицы ( это ответ на первый вопрос ) .

procedure TForm1.DBGrid1TitleClick(Column: TColumn);
//Входным параметром является стобец таблицы
begin
//Проверяем, что источник данных является источником ADO
if DBGrid1.DataSource.DataSet is TCustomADODataSet then
//Не будем использовать оператор With для сокращения записей чтобы было видно, где какой объект задействован
begin
//Т.к. в переменной может храниться неверное значение, или она еще не определена, то делаем обработку возможной ошибки
try
//Отменяем выделение заголовка столбца предыдущей сортировки
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style :=
DBGrid1.Columns[PreviousColumnIndex].title.Font.Style - [fsBold];
except
//Если возникла ошибка, ничего не делаем и выполняем последующие операторы
end;
//Устанавливаем выделение заголовка нажатого стобца
Column.title.Font.Style := Column.title.Font.Style + [fsBold];
//Заносим в переменную выделенный столбец, чтобы знать, какому заголовку потом отменять выделение
PreviousColumnIndex := Column.Index;
//Здесь двойная проверка. В первой проверяется, является ли текущая сортировка уже по выбранному столбцу и в случае верного результата проверяется наличие в сортировке ключевого слова DESC ( по убыванию ) .
if (Pos(Column.Field.FieldName, TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort) = 1)
and (Pos(' DESC', TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort)= 0) then
//Если сортировка уже по текущему столбцу и не по убыванию, то устанавливаем
TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort := Column.Field.FieldName + ' DESC'
else
//Во всех остальных случаях устанавливаем сортировку по выбранному столбцу по возрастанию
TCustomADODataSet(DBGrid1.DataSource.DataSet).Sort := Column.Field.FieldName + ' ASC';
end;
end;

Кажется все.

С уважением.
Форма ответа