Ms Access средство перемещения списка с множественным выбором

У меня есть два списка (lfmVocabulary и lfmVocabularyAssign). Они оба не привязаны к форме, и у меня возникают проблемы с достижением определенных аспектов дизайна кода.

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

Пытаясь добиться этого, я поместил код в модуль следующим образом.

Option Compare Database

Public Sub MoveListBoxItems(lfmVocabularyAssign As ListBox, _
lfmVocabulary As ListBox)

Dim intListX As Integer

For intListX = lfmVocabulary.ListCount = -1 To 0
    If lfmVocabulary.Selected(intListX) Then
     lfmVocabularyAssign.AddItem lfmVocabulary.List(intListX)
     lfmVocabulary.RemoveItem intListX
    End If
Next
End Sub

В форме у меня есть следующий код:

Option Explicit

Dim db As Database
Dim rs As Recordset


Private Sub cmdAdd_Click()

MoveListBoxItems lfmVocabulary, lfmVocabularyAssign

End Sub


Private Sub cmdSelectAll1_Click()

    Dim n As Integer

    With Me.lfmVocabulary
        For n = 0 To .ListCount - 1
            .Selected(n) = True
        Next n
    End With

End Sub

Private Sub Form_Load()

    Set db = CurrentDb
    Set rs = db.OpenRecordset("qryVocabularyDefinitions")

    Me.lfmVocabulary.RowSource = ""
    Do Until rs.EOF
        Me.lfmVocabulary.AddItem rs!Vocabulary
        rs.MoveNext
    Loop

End Sub

Я новичок в Access и кодировании в целом, и я просматривал Интернет в поисках решения.

Я бы предложил тысячу благодарностей всем, кто может мне помочь: D


person Jason Mosier    schedule 08.07.2017    source источник


Ответы (2)


В формах MS Access (в отличие от пользовательских форм Excel) вы можете напрямую назначить запрос для ListBox.RowSource без необходимости повторения набора записей:

Me.lfmVocabulary.RowSource = "qryVocabularyDefinitions"
Me.lfmVocabulary.RowSourceType = "Table/Query"
Me.lfmVocabulary.Requery

И чтобы обновить значения, передайте динамический запрос, используя выбранные элементы предыдущего списка:

Dim in_clause As String: in_clause = ""
Dim strSQL As String, i As Integer

' ITERATE TO BUILD COMMA-SEPARATED LIST FOR SQL IN() CLAUSE
With Me.lfmVocabulary
    For n = 0 To .ListCount - 1
       If .Selected(n) = True Then
           in_clause = in_clause & .ItemData(n) & ", "
       End If
    Next n
End With

' REMOVE LAST COMMA AND SPACE
in_clause = Left(in_clause, Len(in_clause)-2)

strSQL = "SELECT * FROM qryVocabularyDefinitions" _
           & " WHERE ID IN (" & in_clause & ")"

Me.lfmVocabularyAssign.RowSource = strSQL
Me.lfmVocabularyAssign.RowSourceType = "Table/Query"
Me.lfmVocabularyAssign.Requery
person Parfait    schedule 09.07.2017
comment
Parfait, Куда мне вставить этот код? В модуле или в событии «Загрузить форму»? Кроме того, у меня сложилось впечатление, что списки для описанной цели должны быть установлены в списке значений, а не в таблице/запросе. Я ошибаюсь в этом? - person Jason Mosier; 09.07.2017
comment
Первый блок кода может перейти к событию OnLoad, а затем к событию кнопки OnClick для обновления списка Назначить. Вы, как разработчик, можете настроить его по мере необходимости. Список значений — это один из вариантов, но он кажется излишним, если данные получены из таблицы/запроса. - person Parfait; 09.07.2017
comment
Parfait, Ок, пробую этот код в скопированном рекреации. Первый список заполняется нормально, но когда я пробую событие OnClick, возникает следующая ошибка: Ошибка компиляции: метод или элемент данных не найден. И выделяет .List в вашей структуре кода. - person Jason Mosier; 09.07.2017
comment
См. редактирование с помощью .itemData согласно документам< /а>. - person Parfait; 10.07.2017
comment
Спасибо, Парфе. Кажется, я на правильном пути. Теперь, однако, я получаю окно сообщения Введите значение параметра some_column. Мне это никогда не кажется легким и прямолинейным :D Я пока не могу выразить свою признательность за вашу помощь. - person Jason Mosier; 10.07.2017
comment
Не уверен, что эта информация имеет значение, но в qryVocabularyDefinitions у меня есть 4 столбца. Первый - это идентификатор, а второй - фактическое словарное слово, которое я хочу визуализировать. Я хотел бы, чтобы оба значения были сохранены для справки, но визуально представлено только слово Vocabulary. Это абсолютно верно в первом поле списка, играющем со свойством Column, но я не вижу, чтобы что-то переносилось во второй список. - person Jason Mosier; 10.07.2017
comment
Кроме того, если я ввожу 1 или 2 в поле «Введите параметр», я получаю все элементы списка из первого списка, а не те, которые я выбрал. - person Jason Mosier; 10.07.2017
comment
Ха-ха... ты действительно покинул some_column? Вы должны были заменить это связанным столбцом списка. Поскольку вы никогда не показывали содержимое запроса или списка, я не был уверен, но в качестве вашего реле используйте ID. И убедитесь, что оба списка имеют одинаковую структуру дизайна (т. е. свойства столбца, связанные). - person Parfait; 10.07.2017
comment
лол, у меня действительно нет опыта кодирования: D Не могли бы вы отразить изменения кода в отредактированной версии кода выше :) - person Jason Mosier; 10.07.2017
comment
Я чувствовал, что я был так близко. Как заменить это связанным столбцом списка (я предполагаю, что вы имеете в виду связанный столбец 1-го списка, lfmVocabulary). Кроме того, я смог получить данные из qryVocabularyDefinitions в первом списке (lfmVocabulary), назначив их источнику строк. Но для второго списка (lfmVocabularyAssign) у меня нет значений в источнике строки или источнике управления. - person Jason Mosier; 10.07.2017
comment
ТЫ СДЕЛАЛ ЭТО! Вы не представляете, как это меня радует! - person Jason Mosier; 10.07.2017
comment
Ха-ха... рад помочь! Чтобы сделать аналог, в SQL-запросе измените IN на NOT IN. - person Parfait; 10.07.2017
comment
Интересное явление. Я заменил и изменил код (с помощью Me.lfmVocabularyAssign), чтобы он работал во втором списке. Но функция cmdRemove_Click() перемещает только выбранное назад и переносит все остальное из первого списка во второй. - person Jason Mosier; 10.07.2017
comment
Не совсем понимаю. Это то, что вы хотите? Пожалуйста, разместите эту функцию в своем коде. - person Parfait; 10.07.2017
comment
Я отредактировал свой комментарий выше, чтобы отразить ситуацию и код - person Jason Mosier; 10.07.2017
comment
Я откатил ваши изменения. Я не хотел, чтобы вы перезаписывали свой исходный пост, а просто добавили к нему функцию cmdRemove(), так как будущие читатели будут сбиты с толку опубликованными здесь ответами. Но если подумать сейчас, вам может понадобиться задать новый вопрос и сослаться на этот. Нажмите отредактировано ## минут назад, чтобы получить содержание предлагаемого вами изменения для нового вопроса, скопировав зачеркнутый текст. - person Parfait; 10.07.2017

Вы допустили несколько мелких ошибок и не учли некоторые сложности, вот правильный код:

Public Sub MoveListBoxItems(lstDestination As ListBox, lstSource As ListBox)
    Dim intListX As Integer
    Dim selectedItems As Collection
    Set selectedItems = New Collection
    For intListX = 0 To lstSource.ListCount - 1 'Start with 0, then iterate through the whole list
        If lstSource.Selected(intListX) Then
            lstDestination.AddItem lstSource.ItemData(intListX) 'Add items first

        End If
    Next intListX 'Increment intListX by 1
    Do While intListX >= 0
        If lstSource.Selected(intListX) Then
            selectedItems.Add intListX 'Add the items to be removed to a collection, in reverse order
        End If
        intListX = intListX - 1
    Loop
    Dim iterator As Variant
    For Each iterator In selectedItems
        lstSource.RemoveItem iterator 'And then remove them
    Next iterator
End Sub

Сложности включают следующее: удаление элемента из списка отменяет выбор всех элементов, поэтому вам следует сохранить выбранные элементы в коллекции. Кроме того, вам нужно удалить элементы в обратном порядке, так как удаление одного изменяет индекс (число) для каждого с более высоким индексом.

person Erik A    schedule 08.07.2017
comment
Эрик фон Асмут, я вставил ваш код в свой модуль, но у меня возникли проблемы с его вызовом с помощью командной кнопки cmdAdd. Каждый раз, когда я пытался запустить следующую процедуру Public Sub cmdAdd_Click() Call MoveListBoxItems(lstDestination, lstSource) End Sub Это дает мне ошибку компиляции Ожидаемая переменная или процедура, а не модуль - person Jason Mosier; 09.07.2017
comment
Обратите внимание: я изменил имена своих объектов, чтобы они соответствовали вашей кодировке. - person Jason Mosier; 09.07.2017
comment
Код, который вы используете для вызова MoveListBoxItems в своем вопросе, по-прежнему действителен. Менять имена в форме не обязательно, но не помешает. Вы поместили MoveListBoxItems в свой модуль формы? Есть ли в вашей базе данных модуль с именем MoveListBoxItems? - person Erik A; 09.07.2017
comment
В VBA есть модуль, поэтому я предполагаю, что вы имеете в виду модуль базы данных. Я думаю, это нормально, а не модуль класса. Что касается модуля формы, я не уверен. У меня есть код в форме, который ссылается на модуль базы данных, но не более того, что я опубликовал. Я также изменил форму подписки на общедоступную, если это имеет значение. Но как только я запускаю код, у него такая же ошибка с желтым выделением в общедоступной подпрограмме cmdAdd_click(). - person Jason Mosier; 09.07.2017
comment
Можете ли вы просто вернуться к Private Sub cmdAdd_Click() MoveListBoxItems lfmVocabulary, lfmVocabularyAssign End Sub. Это то, что я использовал для тестирования. Ваша ошибка, скорее всего, в некоторых изменениях, которые вы сделали. - person Erik A; 09.07.2017
comment
Я вернулся, как вы сказали, но ошибка все еще возникает. :( - person Jason Mosier; 09.07.2017
comment
Решение @Parfait более простое. Я проверил свой код и уверен, что он работает, не могу точно сказать, что вы делаете неправильно. - person Erik A; 09.07.2017