August 11, 2020, 15:35:34

Neuigkeiten:

Ist euer Problem gelöst, dann bitte den Knopf "Thema gelöst" drücken!


Runtime - Kontextmenü --> Textfilter implementieren

Begonnen von mipa_acc, Januar 24, 2012, 11:47:21

⏪ vorheriges - nächstes ⏩

mipa_acc

Hallo Community!

in der Runtimeversion von Access 2010 ist - wie in allen anderen Versionen auch - das Kontektmenü in Formularen Sparmaßnahmen zum Opfer gefallen. Was ich aber unglaublich praktisch finde, ist der Textbasierte Filter. Gibt es eine Möglichkeit, ohne großen Aufwand diesen Filter auch in der Runtime Version von Access verfügbar zu machen? Ich bin jetzt nicht wirklich DER Vba Programmierer, von dem her tu ich mich da relativ schwer.
Habt ihr da evtl. ein paar Tipps oder nützliche Links für mich?

In der Forensuche habe ich mit den Suchwürtern "Runtime, Textfilter, Filter" nicht wirklich viel gefunden. Entweder suche ich falsch oder das Thema wurde noch nicht besprochen.
Unter http://www.access-im-unternehmen.de/index.php?id=300&BeitragID=749#anker-23-anchor habe ich schon eine Anleitung gefunden, welche ich auch erfolgreich in mein Projekt eingebunden habe, allerdings fehlen mir die Kenntnisse, die Filtermöglichkeiten auf einen Textfilter zu erweitern.

Vielen Dank im Voraus!

Gruß

Peace Ð

Dezember 04, 2013, 15:47:21 #1 Letzte Bearbeitung: Dezember 04, 2013, 15:51:41 von Peace Ð
also die Lösung unter dem von Dir geposteten Link funktioniert bei mir, wichtig ist nur, dass dort, wo was von Klassenmodulen die Rede ist, auch von Dir Klassenmodule mit dem gegebenen Inhalt erstellt werden ;) Klassenmodule sind KEINE normalen Module! Das wusste ich bspw. nicht, was dann bei mir zu Fehlern geführt hat^^


Mein aktuelles Problem bezieht sich auf das Filtern von Kombinationsfeldern, daher denke ich, dass dieser Thread recht gut passt, weshalb ich keinen neuen erstellt habe...

Filtern an sich ist bereits kein Problem, klappt sowohl mit mehreren Datums-Angaben, als auch mit Text, nur bei Kombinationsfeldern wird nicht nach dem eingegebenen Text gefiltert, sondern nach der Spaltennummer, der Zugrundeliegenden Tabelle...
Sprich ich habe eine Personaldatenbank mit einer Tabelle namens tblAbteilungen und möchte im Formular ein Kombinationsfeld mit den möglichen Abteilungen haben. So weit so gut, wenn ich die Formularansicht öffne, kann ich auch die jeweilige Abteilung auswählen. Wenn es aber ans Filtern geht, muss ich beispielsweise nach "0*" suchen, damit mir alle Datensätze mit der Abteilung "Geschäftsführung" angezeigt werden... Weiterhin würde mich interessieren, warum das Filtern allgemein via VBA NUR in der Runtime funktioniert und nicht in Access selbst.

Wo liegt da nun der Knackpunkt im Code? Ich habe bereits versucht, die gebundene Spalte von 0 auf 1 zu setzen, allerdings hat das einfach nur die Einträge verschoben^^


Der Code ist verdammt lang und ich habe das unwichtige teilweise schon rausgelöscht :X Leider gibts hier im Forum kein Spoiler-Tag^^

Option Compare Database
Option Explicit

Private WithEvents m_Form As Form
Private cbr As CommandBar
Private colOrderBy As Collection
Private colFilter As Collection
Private colCommandbarButtons As Collection
Private WithEvents m_Filterform As Form
Private WithEvents m_FilterformDate As Form
Private WithEvents m_FilterformDateBetween As Form
Private WithEvents m_Filterbox As TextBox
Private WithEvents m_FilterboxDate As TextBox
Private WithEvents m_FilterboxDateFrom As TextBox
Private WithEvents m_FilterboxDateTo As TextBox
Private m_FilterSource As String
Private strCurrentFilter As String
Private strCurrentFilterDate As String
Private strCurrentFilterDateFrom As String
Private strCurrentFilterDateTo As String
Private m_Action As String

Public Sub SetOrderBy(strAction As String)
   Dim strOrderBy As String
   Dim var As Variant
   Dim lngFieldtype As Long
   m_Action = strAction
   m_FilterSource = Screen.ActiveControl.ControlSource
   Select Case m_Action
       Case "AddSortAsc", "AddSortDesc", "DropSort", "DropAllSort"
           Select Case m_Action
               Case "AddSortAsc"
                   On Error Resume Next
                   colOrderBy.Remove m_FilterSource
                   On Error GoTo 0
                   colOrderBy.Add m_FilterSource & " ASC", m_FilterSource
               Case "AddSortDesc"
                   On Error Resume Next
                   colOrderBy.Remove m_FilterSource
                   On Error GoTo 0
                   colOrderBy.Add m_FilterSource & " DESC", m_FilterSource
               Case "DropSort"
                   On Error Resume Next
                   colOrderBy.Remove m_FilterSource
                   On Error GoTo 0
               Case "DropAllSort"
                   Set colOrderBy = New Collection
                   m_Form.OrderBy = ""
           End Select
           strOrderBy = ""
           For Each var In colOrderBy
               strOrderBy = strOrderBy & ", " & var
           Next var
           strOrderBy = Mid(strOrderBy, 3)
           m_Form.OrderBy = strOrderBy
           m_Form.OrderByOn = True
       Case "AddFilter", "DropFilter", "DropAllFilter"
           Select Case m_Action
               Case "AddFilter"
                   lngFieldtype = GetFieldType(m_FilterSource)
                   Select Case lngFieldtype
                       'Zahlentypen
                       Case dbBigInt, dbByte, dbCurrency, dbDecimal, dbDouble, dbFloat, dbInteger, dbLong, dbNumeric, dbSingle
                       'Text
                       Case dbChar, dbText, dbMemo, dbGUID
                           DoCmd.OpenForm "frmFilter"
                           On Error Resume Next
                           strCurrentFilter = ""
                           strCurrentFilter = Split(colFilter.Item(m_FilterSource), "|")(0)
                         
                           On Error GoTo 0
                           Set m_Filterform = Forms!frmFilter
                           Set m_Filterbox = Nothing
                           Set m_Filterbox = Forms!frmFilter!txtFilter
                           If Len(strCurrentFilter) > 0 Then
                               m_Filterbox.Text = strCurrentFilter
                           Else
                               m_Filterbox.Text = "*"
                           End If
                           m_Filterbox.AfterUpdate = "[Event Procedure]"
                           m_Filterbox.OnChange = "[Event Procedure]"
                       'Datum
                       Case dbDate, dbTime, dbTimeStamp
                       'Boolean
                       Case dbBoolean
                       Case Else
                   End Select
               Case "DropFilter"
                   m_FilterSource = Screen.ActiveControl.ControlSource
                   On Error Resume Next
                   colFilter.Remove m_FilterSource
                   On Error GoTo 0
                   SetFilter
               Case "DropAllFilter"
                   Set colFilter = New Collection
                   SetFilter
           End Select
       Case "AddFilterDateEqual", "AddFilterDateLarger", "AddFilterDateLargerEqual", "AddFilterDateSmaller", "AddFilterDateSmallerEqual"
           DoCmd.OpenForm "frmFilterDate"
           Set m_FilterformDate = Forms!frmFilterDate
           m_FilterformDate.OnClose = "[Event Procedure]"
           On Error Resume Next
           strCurrentFilterDate = ""
           strCurrentFilterDate = Split(colFilter.Item(m_FilterSource), "|")(1)
           On Error GoTo 0
           Set m_FilterformDate = Forms!frmFilterDate
           Set m_FilterboxDate = Nothing
           Set m_FilterboxDate = Forms!frmFilterDate!txtFilterDate
           Select Case m_Action
               Case "AddFilterDateEqual"
                   m_FilterformDate.lbl.Caption = "Ist gleich:"
               Case "AddFilterDateLarger"
                   m_FilterformDate.lbl.Caption = "Ist größer:"
               Case "AddFilterDateLargerEqual"
                   m_FilterformDate.lbl.Caption = "Größer gleich:"
               Case "AddFilterDateSmaller"
                   m_FilterformDate.lbl.Caption = "Ist kleiner:"
               Case "AddFilterDateSmallerEqual"
                   m_FilterformDate.lbl.Caption = "Kleiner gleich:"
           End Select
           m_FilterboxDate.SetFocus
           If Len(strCurrentFilterDate) > 0 Then
               m_FilterboxDate.Text = strCurrentFilterDate
           Else
               m_FilterboxDate.Text = ""
           End If
           m_FilterboxDate.AfterUpdate = "[Event Procedure]"
       Case "AddFilterDateBetween"
           DoCmd.OpenForm "frmFilterDateBetween"
           On Error Resume Next
           strCurrentFilterDateFrom = ""
           strCurrentFilterDateFrom = Split(colFilter.Item(m_FilterSource), "|")(1)
           strCurrentFilterDateTo = ""
           strCurrentFilterDateTo = Split(colFilter.Item(m_FilterSource), "|")(2)
           On Error GoTo 0
           Set m_FilterformDate = Forms!frmFilterDateBetween
           Set m_FilterboxDateFrom = Nothing
           Set m_FilterboxDateFrom = Forms!frmFilterDateBetween!txtFilterDateFrom
           m_FilterboxDateFrom.SetFocus
           If Len(strCurrentFilterDateFrom) > 0 Then
               m_FilterboxDateFrom.Text = strCurrentFilterDateFrom
           Else
               m_FilterboxDateFrom.Text = ""
           End If
           Set m_FilterboxDateTo = Nothing
           Set m_FilterboxDateTo = Forms!frmFilterDateBetween!txtFilterDateTo
           m_FilterboxDateTo.SetFocus
           If Len(strCurrentFilterDateTo) > 0 Then
               m_FilterboxDateTo.Text = strCurrentFilterDateTo
           Else
               m_FilterboxDateTo.Text = ""
           End If
           m_FilterboxDateFrom.AfterUpdate = "[Event Procedure]"
           m_FilterboxDateFrom.OnLostFocus = "[Event Procedure]"
           m_FilterboxDateTo.AfterUpdate = "[Event Procedure]"
           m_FilterboxDateTo.OnLostFocus = "[Event Procedure]"
           m_FilterboxDateFrom.SetFocus
   End Select
End Sub


Public Property Set Form(frm As Form)
   Dim ctl As Control
   Dim strControlSource As String
   Dim db As Dao.Database
   Dim rst As Dao.Recordset
   Dim fld As Dao.Field
   Set m_Form = frm
   m_Form.OnClose = "[Event Procedure]"
   Set colOrderBy = New Collection
   Set colFilter = New Collection
   Set colCommandbarButtons = New Collection
   Set db = CurrentDb
   Set rst = m_Form.RecordsetClone
   Set rst = db.OpenRecordset(m_Form.RecordSource, dbOpenDynaset)
   For Each ctl In m_Form.Controls
       strControlSource = ""
       On Error Resume Next
       strControlSource = ctl.ControlSource
       On Error GoTo 0
       If Len(strControlSource) > 0 Then
           'Datentyp des Feldes herausfinden
           Set fld = rst.Fields(strControlSource)
           Select Case fld.Type
               'Zahlentypen
               Case dbBigInt, dbByte, dbCurrency, dbDecimal, dbDouble, dbFloat, dbInteger, dbLong, dbNumeric, dbSingle
                   CreateSortBar "Aufsteigend sortieren", "Absteigend sortieren", "cbrNumber"
                   CreateFilterBarNumber
                   ctl.ShortcutMenuBar = "cbrNumber"
               'Text
               Case dbChar, dbText, dbMemo, dbGUID
                   CreateSortBar "Von A bis Z sortieren", "Von Z bis A sortieren", "cbrText"
                   CreateFilterBarText
                   ctl.ShortcutMenuBar = "cbrText"
               'Datum
               Case dbDate, dbTime, dbTimeStamp
                   CreateSortBar "Von früheren zu späteren Daten sortieren", "Von späteren zu früheren Daten sortieren", "cbrDate"
                   CreateFilterBarDate
                   ctl.ShortcutMenuBar = "cbrDate"
               'Boolean
               Case dbBoolean
                   CreateSortBar "Von Ja nach Nein sortieren", "Von Nein nach Ja sortieren", "cbrBoolean"
                   CreateFilterBarBoolean
                   ctl.ShortcutMenuBar = "cbrBoolean"
               Case Else
               End Select
       End If
   Next ctl
End Property



Private Sub m_Filterbox_Change()
   Dim strControlSource As String
   On Error Resume Next
   colFilter.Remove m_FilterSource
   On Error GoTo 0
   colFilter.Add m_FilterSource & " LIKE '" & m_Filterbox.Text & "'|" & m_Filterbox.Text, m_FilterSource
   SetFilter
End Sub



Private Sub SetFilter()
   Dim strFilter As String
   Dim var As Variant
   For Each var In colFilter
       strFilter = strFilter & " AND " & Split(var, "|")(0)
   Next var
   strFilter = Mid(strFilter, 6)
   m_Form.Filter = strFilter
   m_Form.FilterOn = True
End Sub

DF6GL

Hallo,


nur bezgl (zu dem "Kanonen-Spatzen"-Code kein Kommentar..): 

ZitatWenn es aber ans Filtern geht, muss ich beispielsweise nach "0*" suchen, damit mir alle Datensätze mit der Abteilung "Geschäftsführung" angezeigt werden...


ist unklar, was und wie gefiltert wird/werden soll.


Die "Geschäftsführung" muss in tblAbteilungen ein durch einen Primärschlüssel eindeutig definierbarer Datensatz sein.

Wenn z. B. alle Mitarbeiter gefiltert werden sollen, die einer bestimmten Abteilung ("Geschäftsführung") zugeordnet sind, dann braucht es da keinen "Sternchen-Vergleich", der eh nur bei Text(-Werten) sinnvoll ist und der Primärschlüssel(wert) aus tblAbteilungen muss in tblMitarbeiter in einem Fremdschlüsselfeld abgelegt sein.

Peace Ð

Dezember 05, 2013, 08:05:33 #3 Letzte Bearbeitung: Dezember 05, 2013, 08:19:27 von Peace Ð
Zitat von: DF6GL am Dezember 04, 2013, 16:49:20Die "Geschäftsführung" muss in tblAbteilungen ein durch einen Primärschlüssel eindeutig definierbarer Datensatz sein.

Wenn z. B. alle Mitarbeiter gefiltert werden sollen, die einer bestimmten Abteilung ("Geschäftsführung") zugeordnet sind, dann braucht es da keinen "Sternchen-Vergleich", der eh nur bei Text(-Werten) sinnvoll ist und der Primärschlüssel(wert) aus tblAbteilungen muss in tblMitarbeiter in einem Fremdschlüsselfeld abgelegt sein.


Morgen,

ich habe bereits die AbteilungsID als Primärschlüssel in der Abteilungs-Tabelle gesetzt und auch eine 1:n-Beziehung zur Mitarbeiter-Tabelle zwischen AbteilungsID und AbteilungsID gesetzt.
Den Sternchen-Vergleich mache ich auch einfach nur so aus Prinzip... Abgesehen davon ist das Kombinationsfeld, das gefiltert werden soll, sowieso vom Typ Text.
Dennoch bleibt die Frage, was ich abändern muss, damit beim Filtern des Kombi-Feldes auch Buchstaben anerkannt werden und nicht NUR Zahlen, obwohl es ja mit Text gefüllt ist.

Grüße

DF6GL

Hallo,

nun, ich versteh immer noch nicht die "Filter"-Vorstellung.


"Den Sternchen-Vergleich mache ich auch einfach nur so aus Prinzip... "   ??

"Prinzipiell" müssen die Datentypen berücksichtigt werden... und die ID (Zahl, Long) ist nun mal kein TEXT.

Vielleicht meinst Du auch, das Kombi-Listenfeld  mittels Eingabe eines oder mehrerer Zeichen in das Kombi-Textfeld einzuschränken. (bei Spalte0 == ID, Spalte1 == Abteilungsname, gebundene Spalte ==1 )

Das geht standardmäßig so nicht, wenngleich sich auch der Cursor jeweils auf den  ersten passend gefundenen Eintrag positioniert.

Möglicherweise ist mit etwas VBA und den "Tasten"-Ereignissen eine solche Einschränkung der Listenfeld-Einträge zu erreichen, wobei sich DAO und ADODB etwas unterschiedlich verhalten.

Eine andere Möglichkeit wäre , das(die) Kombifeld(liste) mit einem ungebundenen Suchfeld vorzufiltern, ähnlich der Methode der  "abhängigen Kombifelder".

Sub txtAbtName_Afterupdate() 
Me!cmbAbteilung.Rowsource =" Select Abt_ID, Abt_Name from tbl_Abteilung Where Abt_Name Like '" & Me!txtAbtName & "*'"
End Sub




Peace Ð

Dezember 05, 2013, 13:03:49 #5 Letzte Bearbeitung: Dezember 05, 2013, 15:16:08 von Peace Ð
haha, ok, ich erklär am besten wohl nochmal die genauen Umstände, damit Du nichtmehr auf dem Schlauch stehst :D

Ich erstelle gerade eine Mitarbeiterdatenbank, auf die später alle Mitarbeiter via Access Runtime zugreifen sollen. Da die Runtime, aber kein Kontextmenü beherrscht, habe ich diesen langen Quellcode, den ich gepostet hab, im Netz gefunden, um ein Kontextmenü für die Runtime zu erstellen. Das Kontextmenü enthält Filter- und Sortiermöglichkeiten, die bereits auf den Feldtyp (Text, Zahl, Ja/Nein,...) abgestimmt sind (sprich: Datumsfelder enthalten "von früherem Datum nach späterem sortieren" usw.). Da das Kombi-Feld ein Text-Feld ist, ist im Kontextmenü der Eintrag "Filtern nach..." vorhanden, wird dieser angeklickt, öffnet sich ein kleines Filter-Formular mit einem Textfeld, was bereits ein Sternchen enthält. Wird in das Textfeld des Filterformulars etwas eingetragen, bewirkt die OnChange-Prozedur des Feldes, dass alle Datensätze sofort gefiltert werden. Ich weiß grad nicht, wie ich es besser erklären soll^^

Ich hab zu Testzwecken einfach mal 3 Datensätze angelegt, 2 davon habe ich der Abteilung IT zugeordnet, einen der Geschäftsführung.
Ich möchte nun in das Textfeld-des Filterformulars "IT" eingeben und dann auch bitte die 2 Datensätze angezeigt bekommen, die der IT-Abteilung zugeordnet sind. Stattdessen werde ich aber zu einem neuen Datensatz geleitet. Gebe ich in das Textfeld des Filterformulars aber die ID der Abteilung in der Abteilungs-Tabelle ein, klappt das Filtern wunderbar, jedoch wäre das etwas unkomfortabel für den späteren Gebrauch der restlichen Mitarbeiter in der Runtime.

Ich dachte daran, dass es daran liegen könnte, dass der AutoWert der Abteilungs-Tabelle eben eine Zahl ist und kein Textfeld. Das Ändern auf Text hat aber nicht geholfen, ich konnte immernoch nur via Zahl filtern.


Ich hoffe, dass diese Erklärung weiterhilft und ich hoffe auch, dass Du weiterhin gewillt bist, dich meiner anzunehmen :) Allerdings kann ich auch verstehen, wenn nicht ;D

Grüße!

DF6GL

Hallo,

es liegt nicht an meiner Hilfe-Bereitschaft...

und vermutlich stehst Du auf dem Schlauch   ;) ;) ;D
Zitat
Ich hab zu Testzwecken einfach mal 3 Datensätze angelegt, 2 davon habe ich der Abteilung IT zugeordnet, einen der Geschäftsführung.
Ich möchte nun in das Textfeld-des Filterformulars "IT" eingeben und dann auch bitte die 2 Datensätze angezeigt bekommen, die der IT-Abteilung zugeordnet sind.



Tabellenmäßig sieht das so aus:


tblMitarbeiter:

MAID  (PK, Autowert)
MA_AbtID  (Zahl, Long)
MA_Name
....
....


MAID         MA_AbtID           MA_Name
1               1               Maier
2               1               Müller
3               2               Schulze
4               1               Mustermann
5               2               Musterfrau



tblAbteilungen

AbtID (Pk, Autowert)
Abt_Bezeichnung (Text)
....
....

AbtID          Abt_Bezeichnung
1                 Geschäftsführung
2                    IT



Um nun die richtigen "Zahlen" (Fremdschlüsselwerte) filtern zu können, müssen die erst mal aus der 1-Tabelle (tblAbteilungen) anhand der Abt-Bezeichnung bestimmt  und dann zur Filterung hergenommen werden

Beispielhaft:

strKrit = " MA_ABtID in (Select AbtID from tblAbteilung Where Abt_Name like '" & Me!Suchfeld & "*')"


strSQL= " Select * from tblMitarbeiter " & " Where " & strSQL


Wie (entspr. der akt. Such-Situation) und wo (vermutlich als neues Collection-Element)   Du nun diesen Where-Condition (Filter-String) in Deinen Code einbaust, überlass ich jetzt Dir...

Peace Ð

Super, vielen vielen Dank! Ich habe zwar keine Ahnung, was ich gemacht hab, aber nach vielem Herumspielen mit den Datenherkünften usw. des Kombinationsfeldes, funktioniert es jetzt einwandfrei ;D ;D

Wie gesagt, trotzdem vielen Dank für den Aufwand! :)