Поиск в Grid'е

Программирование на Visual Basic, главный форум. Обсуждение тем программирования на VB 1—6.
Даже если вы плохо разбираетесь в VB и программировании вообще — тут вам помогут. В разумных пределах, конечно.
Правила форума
Темы, в которых будет сначала написано «что нужно сделать», а затем просьба «помогите», будут закрыты.
Читайте требования к создаваемым темам.
skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Поиск в Grid'е

Сообщение skiperski » 24.08.2005 (Ср) 16:30

Вопрос в следующем: как рационально организовать поиск в гриде?

Как я себе это вижу: есть грид, при нём несколько текстовых полей. В гриде таблица, например, клиентов. Нужно быстро найти чела по его ФИО. В текстовое поле раз начинают водить фамилию, а курсор в гриде подтягивается к ближайшей по значению записи. Ежели таковая в списке отсутствует, то указатель остаётся на ближайшей по значению записи, если однофамильцев много, то в текстовое поле нумбер два начинаюит вводить имя, грид работает по прежнему алгоритму. Далее, если много тёзок, поиск по отчеству или адресу.

Как всю эту лабуду реализовать? Где-то тут был пример с комбобоксом, а как реализовать поиск в определённой колонке грида? Может есть другие, более простые решения? Каким гридом в данном случае лучше пользоваться (название и имя библиотеки, пожалуйста)? Данных не много, около 1000, может чуть больше-меньше. Рекордсет может быть не связан с гридом. Редактирование, добавление, удаление будут реализованы в отдельных формах, потому грид может быть статичным. Вроде бы всё. Да, ещё, мне привычнее работать с ADO, но это не критично, т.к., как это неоднократно показал alibek, DAO имеет свои неоспоримые преимущества и, в конце концов, можно использовать оба.

Для тех кто не знает или забыл объясняю: до недавнего времени я работал практически только с веб интерфейсом, потому и не знаком со стандартными элементами в ВБ. Экспериментировать со всеми имеющимися гридами не хочется - времени жалко. Т.к. подобные задачи выполнял практически каждый программист БД, то наверняка существуют уже сложившиеся стандарты дефакто. И чтобы не изобретать велосипед в очередной раз, прошу осветить этот вопрос.

Сравнительные хар-ки и пространные рассуждения с перечислением достоинств и недостатков одних элементов перед другими категорически приветсвуются.

Konst_One
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
Аватара пользователя
 
Сообщения: 3041
Зарегистрирован: 09.04.2004 (Пт) 13:47
Откуда: Химки

Сообщение Konst_One » 24.08.2005 (Ср) 16:34

обычно поиск я отдаю на откуп серверу посредством запросов SQL с соответствущим фильтром WHERE

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.08.2005 (Ср) 16:40

Нет, это должен быть не фильтр, а именно поиск. Т.е. пользователь видит всегда все записи, а по гриду перемещается курсор. Данных, как уже ометил, немного. И ни каких дополнительных кликов типа кнопки "Поиск" и пр.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 24.08.2005 (Ср) 16:47

Я делал так.
Есть комбо, дублирующий содержимое колонки, причём при заполнении ItemData ставится равным чему-то типа ID.

В твоём случае пойдёт заполнить комбо дубликатами имён, а в качестве ItemData использовать номер ряда датагрида. При наборе, дополнить автозаполнение комбо командой datagrid.row = combo.itemdata(combo.listindex).
В зависимости от способа реализации автозаполнения, может потребоваться дополнительная процедура (есть :) ) для узнавания реального ListIndex, т.к. в этом случае он часто бывает -1.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 24.08.2005 (Ср) 17:14

Эх, убегаю, времени ответить нет :)
Но я однажды делал что-то похожее. Правда это было давно и сейчас я бы сделал совсем не так.
У меня был список (правда записей в нем было куда меньше, около сотни).
При любыъ изменениях в блоке поиска/фильтра запускалась процедура, результатом работы которой был массив целых чисел; элемент массива соответствовал номеру строки в гриде, в массив включались только те строки, которые соответствовали фильтру.
После этого строки, соответствующие массиву, подсвечивались, а грид прокручивался, чтобы отображать первую строку массива.
Правда у меня не совсем грид был, а листбокс, но это не принципиально.
Если до завтра терпит, то попробую код выложить :)
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.08.2005 (Ср) 17:18

alibek писал(а):Эх, убегаю, времени ответить нет :)

Ну, успел же уже :)

alibek писал(а):Если до завтра терпит, то попробую код выложить :)

Спасибо, терпит и дольше. Можно пока без кода - только теорию. Я только прикидываю как это будет реализовано. С выделением нескольких строк - хорошая идея.

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

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.08.2005 (Ср) 17:23

GSerg писал(а):Есть комбо, дублирующий содержимое колонки

Тогда нет смысла ещё и грид таскать. Можно все данные в комбо или лист слить, а хоцца красиво. И потом как искать по двум полям? В первом комбо фамилии, во втором - имена, но какие? если все, то много повторов, если только уникальные, то они никак не связаны с фамилией. Или при вводе фамилии фильтровать имена? Как идея - принято, с реализацией пока не ясно. Спасибо.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 24.08.2005 (Ср) 17:36

skiperski писал(а):Тогда нет смысла ещё и грид таскать.

Есть смысл грид таскать. Комбо не для отображения, а для поиска, потому что в нём уже этот механизм реализован. Можно даже сделать текстбокс, а искать в невидимом комбо.

skiperski писал(а):И потом как искать по двум полям?

А действительно, как? :)
Если юзер может сначала по одному искать, потом по другому - то в любом случае непонятно: то ли при переходе к поиску по новому полю делать совсем новый поиск, то ли "искать в найденном" (c) Яndex.
Если решить этот вопрос на концептуальном уровне, станет легче думать дальше :)
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

lord0n
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 845
Зарегистрирован: 30.06.2005 (Чт) 9:55
Откуда: Moskow

Сообщение lord0n » 24.08.2005 (Ср) 18:08

1. а что мешает собрать ФИО в одну колонку?
тогда можно будет реализовать поиск через комбо
2. если записей не много можно реализовать через цикл,
но ИХМО - это некрасиво :(
Теория - это когда что-то не работает и известно почему.
Практика - это когда что-то работает, но неизвестно почему.
Нам удалось совместить теорию с практикой, теперь ничего не работает и неизвестно почему.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.08.2005 (Ср) 18:08

GSerg писал(а):А действительно, как? :)

Пример:
Код: Выделить всё
Id Фамилия     Имя
1   А           А
2   А           Б
3   Б           А
4   Б           Б
5   В           Б
6   В           А

Во-первых, сами по себе данные в двух комбо будут смотреться по меньшей мере странно. Во-вторых, как должен быть отсортирован второй? В-третьих, при поиске в первом, например Б, получим Id=3, затем ищем во втором, тоже Б, и получаем Id=2. Хотя надо проверить.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 24.08.2005 (Ср) 18:09

lord0n писал(а):1. а что мешает собрать ФИО в одну колонку?
тогда можно будет реализовать поиск через комбо

Так, видимо, и сделаю. Проще всего. Но может будут другие приемлемые варианты.

lord0n
Постоялец
Постоялец
Аватара пользователя
 
Сообщения: 845
Зарегистрирован: 30.06.2005 (Чт) 9:55
Откуда: Moskow

Сообщение lord0n » 24.08.2005 (Ср) 18:12

ещё одна идея пришла
сделать клон таблицы, и искать запросом в клоне, приэтом при изменении в текстбоксе подсвечивать найденную в данный момент строку
Теория - это когда что-то не работает и известно почему.
Практика - это когда что-то работает, но неизвестно почему.
Нам удалось совместить теорию с практикой, теперь ничего не работает и неизвестно почему.

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 25.08.2005 (Чт) 1:48

skiperski писал(а):Во-первых, сами по себе данные в двух комбо будут смотреться по меньшей мере странно.

Сделай два текстовых поля и невидимые комбо.
Комбо используется только потому, что в нём уже реализованы CB_FINDSTRING, CB_SELECTSTRING и CB_FINDSTRINGEXACT.

skiperski писал(а):Во-вторых, как должен быть отсортирован второй? В-третьих, при поиске в первом, например Б, получим Id=3, затем ищем во втором, тоже Б, и получаем Id=2. Хотя надо проверить.

Я же уже коснулся этого вопроса :)
Это вопрос дизайна и концепции. Как решить - начинать новый поиск при переходе к другому полю ввода или продолжать текущий?
Опять же, и то и другое делается в комбо легко, потому что для CB_FINDSTRING можно указать, с какой позиции искать.
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 25.08.2005 (Чт) 8:40

Вах... Что то все мудрите.

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

Код: Выделить всё
Private Sub txFind_Change()
    Dim s As String, ss As String, i As Integer, b As Boolean
    Dim r As ADODB.Recordset, jc As GridEX20.JSColumn
   
    s = Trim$(txFind.Text)
    If s = "*" Then s =vbNullString

    Screen.MousePointer = vbHourglass
    Set r = Grid.ADORecordset
    If Len(s) Then
        If Left$(s, 1) <> "*" Then s = "*" & s
        If Right$(s, 1) <> "*" Then s = s & "*"
        s = Replace(s, "'", "''"): ss = vbNullString
        For Each jc In Grid.Columns
            If jc.Visible Then
                If Len(ss) Then ss = ss & " OR "
                ss = ss & "[" & jc.DataField & "] LIKE '" & s & "'"
            End If
        Next jc
        r.Filter = ss
    Else
        r.Filter = 0
    End If
   
    Grid.HoldFields
    Set Grid.ADORecordset = r
   
    b = Grid.ItemCount
    For i = 1 To TB.Buttons.Count
        ' Кнопки Edit & Delete на Toolbar-e
        TB.Buttons(i).Enabled = b
    Next i
    Grid.Enabled = b
    Screen.MousePointer = vbDefault
End Sub


И только. Это для случая когда кол-во записей в таблице/вьюшке относительно небольшое и выборка может осуществляться установкой фильтра на Recordset. Если же записей много, то подставляем условие во WHERE запроса (а-ля SELECT TOP 100 * FROM ... WHERE ...).

Чуть доработав данную функцию (есть, но искать влом) можно сделать ее универсальной и правильно формировать условие для полей разного типа текст/число/дата. То бишь можно сделать форму поиска универсальной, у которой меняется только Layout Grid-a и Recordset.

А вы какие-то невидимые поля, комбо... Не влом мучиться?
Вложения
Bank.rar
(11.41 Кб) Скачиваний: 89
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 25.08.2005 (Чт) 8:48

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

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 25.08.2005 (Чт) 9:14

GSerg писал(а):Внимательно читаем вопрос.
Нужен не фильтр.


Если я что-то ищу то мне удобней именно фильтр. Иначе найденное значение может находиться в разных строках разбросанных по всему Grid-у. Придется кучу раз жать кнопку продолжить.

Но опять-же все реализуется элементарно. Форма при этом может выглядеть а-ля приложенный рисунок. При нажатии на кнопку Далее просто сравниваем поля Grid-a в нужном направлении с введеным значением.
Вложения
Find.rar
(12.15 Кб) Скачиваний: 88
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

GSerg
Шаман
Шаман
 
Сообщения: 14286
Зарегистрирован: 14.12.2002 (Сб) 5:25
Откуда: Магадан

Сообщение GSerg » 25.08.2005 (Чт) 9:42

Читаем вопрос ещё внимательнее.

Это должен быть не фильтр (независимо от того, удобен ли он тебе), и не должно быть дополнительных кнопок типа "Далее".
Как только вы переберёте все варианты решения и не найдёте нужного, тут же обнаружится решение, простое и очевидное для всех, кроме вас

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.08.2005 (Чт) 10:00

Вот.
Я сам удивился, но на паре сотен записей работает на удивление быстро.
"Что "гав!", я и сама офигела" :)

З.Ы. Данный пример рассчитан на то, что счетчик в нем идет строго по порядку. Если где-нибудь в писании есть команда типа LB_FINDITEMDATA, то я его с радостью переделаю на универсальный вид :)

З.З.Ы. Как ни странно, но даже замена
Код: Выделить всё
I = rs!ID - 1
на
Код: Выделить всё
  For I = lstNames.ListCount - 1 To 0 Step -1
    If r!ID = lstNames.ItemData(I) Then Exit For
  Next I
не слишком затормозила процесс. Правда все это проверялось на 270 записях, как оно поведет себя при тысяче записей, надо проверить.
Вложения
autosearch.zip
Пример автопоиска.
(16.56 Кб) Скачиваний: 103
Lasciate ogni speranza, voi ch'entrate.

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 25.08.2005 (Чт) 12:16

alibek писал(а):Я сам удивился, но на паре сотен записей работает на удивление быстро.


Я бы все-же предпочел не делать запросы на каждую букву, а искать уже в заполненом ListBox-е - чтобы зря сетку не грузить...

Свой вариантик с фильтром по твоей базе прилагаю (можно сравнить удобство) поиска...
Вложения
autosearch.rar
(370.2 Кб) Скачиваний: 103
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 25.08.2005 (Чт) 12:21

Огромное спасибо всем! Завтра срочно убываю на несколько днёв, сегодня сборы. По возвращении всем подробно отвечу.

ПыСы to alibek: Посмотрел как работает - нравится. Код ещё не смотрел.

До скорого!

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.08.2005 (Чт) 12:35

Andrey Fedorov писал(а):Я бы все-же предпочел не делать запросы на каждую букву, а искать уже в заполненом ListBox-е - чтобы зря сетку не грузить...

В целом, да, согласен.
Но в этом конкретном случае в листбоксе поля слиты в одно, их не выделить.
Чтобы не грузить запросами сервер, можно на клиентском рекордсете фильтры делать (клон-фильтр-клон-фильтр).
Lasciate ogni speranza, voi ch'entrate.

Andrey Fedorov
Член-корреспондент академии VBStreets
Член-корреспондент академии VBStreets
 
Сообщения: 3287
Зарегистрирован: 21.05.2004 (Пт) 9:28
Откуда: Москва

Сообщение Andrey Fedorov » 25.08.2005 (Чт) 12:48

alibek писал(а):Но в этом конкретном случае в листбоксе поля слиты в одно, их не выделить.


В массив их. И в нем искать. А индекс массива = индексу ListBox-a.

alibek писал(а):Чтобы не грузить запросами сервер, можно на клиентском рекордсете фильтры делать (клон-фильтр-клон-фильтр).


В принципе у меня примерно так и сделано, только без клонов...
Фиг Вам! - Сказал Чебурашка, обгладывая Крокодила Гену...

alibek
Большой Человек
Большой Человек
 
Сообщения: 14205
Зарегистрирован: 19.04.2002 (Пт) 11:40
Откуда: Russia

Сообщение alibek » 25.08.2005 (Чт) 12:58

А я вначале в массив и грузил :)
Только потом переделал -- зачем мудрить с оптимизацией поиска, когда он встроен в ADO? Поэтому оставил рекордсет.

А что касается клонов, это я стормозил чего-то :) Перепутал с Find, в котором можно указывать только одно поле.
Конечно же можно без клонов.
Lasciate ogni speranza, voi ch'entrate.

skiperski
Идеолог
Идеолог
Аватара пользователя
 
Сообщения: 1386
Зарегистрирован: 25.06.2002 (Вт) 15:52

Сообщение skiperski » 09.09.2005 (Пт) 1:19

Спасибо всем!

Визуально больше всего понравился код от alibek'а. Буду дорабатывать. Спасибо. Также спасибо Andrey Fedorov.



Есть ещё вопрос или опрос по поводу реализации интерфейса пользователя. Открыл новую тему.


Вернуться в Visual Basic 1–6

Кто сейчас на конференции

Сейчас этот форум просматривают: Yandex-бот и гости: 12

    TopList