Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!

Mobiles Hauptmenü

Checkboxen (Kontrollkästchen) auf Änderung überwachen

Begonnen von noah, Januar 10, 2017, 13:32:59

⏪ vorheriges - nächstes ⏩

noah

Hallo, ich habe in einem Formular etwa 20 Checkboxen, bei dessen Änderung direkt ein Code ausgeführt werden soll, und zwar für alle Checkboxen derselbe. Dies kann ich ja erreichen, indem ich für jede Checkbox ein 'Click'-Ereignis festlege - macht 20 mal '..._Click()'.
Da das Ereignis für alle Checkboxen dasselbe ist würde ich das gerne so zusammenfassen, so dass ich nur noch ein 'Click'-Ereignis abfangen muss, was das Makro mit dem weiteren Code aufruft. In Excel hatte ich das mit einem Klassenmodul gelöst, was ich aber in Access bisher nicht hinbekommen habe. Auch die Suche im Internet hat bisher nur Ergebnisse gebracht, die in Excel, aber nicht in Access funktionieren. Hat da jemand einen Tip für mich?

Xoar

#1
Hi,
es reicht also wenn der Code ein einziges mal ausgelöst wird?

Ein Modul erstellen, oder im Klassenmodul

Public Sub CodeAnweisung ()
     MsgBox "Hier steht der Code der ausgeführt wird."
End Sub

Jetzt musst beim click () Ereignis jedes Steuerelementes einmal die Sub aufrufen.

Btn1_click ()
    Call CodeAnweisung
End Sub


Jetzt wird bei jedem Click Ereignis der Code ausgeführt, dieser ist zudem nur 1x vorhanden und kann so gepflegt werden.

Oder meinst Du das anders?

Man kann auch mit einer Schleife alle Steuerelemente durchlaufen und jeweils ein Ereignis auslösen

Dazu müssten alle CheckBoxen unter Tag die gleiche Zusatzbezeichnung bekommen. Z.B. Klick. damit dann nur diese durchlaufen werden.

noah

So wie Du es beschreibst habe ich es ja zur Zeit - ein SUB, wo die auszuführende Aktion drin steht und ca. 20 SUB's, die diese Aktion starten sollen. Ich finde es sehr unübersichtlich. Außerdem kann es gut sein, dass da noch das ein odere Andere Kontrollkästchen hinzukommt, und so muss ich dann ja alles anpassen - Datenbank, Formular UND die Auswertung.
Die Namen aller Checkboxen beginnen mit 'Q_', im Makro, das gestartet wird werden alle in einer Schleife durchlaufen und je nach Zustand (aktiviert/deaktiviert) wird eine Aktion ausgeführt.

Kurz nochmal zur Erläuterung:

In der Datenbank sind ca. 20 Spalten für Qualifikationen (Ja/Nein). Für jede Spalte gibt es eine Checkbox im Formular, mit dem die Datensätze bearbeitet werden.

In einem anderen Formular wird mir eine Liste aller Datensätze (ca. 2050) angezeigt,  die sich beliebig filtern lässt (Standort, Abteilung, Geschlecht, etc...). Und eben auch nach Qualifikationen soll gefiltert werden. Und da ist halt mein Problem - die Liste soll direkt nachdem ich irgendein Kästchen der Qualifikationen an- oder abwähle direkt neu geladen werden. Und es sollen mehrere Qualifikationen wählbar sein, daher fällt eine Optionsgruppe (mit der es dann ja ganz einfach wäre) flach.
Um den Code schlanker zu halten möchte ich es halt in der Art 'SUB irgendeinKontrollkästchen_Click() ... ' haben. Da es in excel möglich ist kann ich mir durchaus vorstellen, dass es auch in Access machbar ist - nur eben anders.

Weiter kann es  auch sein, dass da noch Qualifikationen hinzukommen (oder wegfallen), also ist mein Ziel, die Checkboxen in den Formularen anhand der Spalten in der Tabelle (fangen alle mit 'Q_' an) dynamisch erstellen zu lassen. Und spätestens dann müssen die Checkboxen ja 'dynamisch' überwacht werden. Aber eins nach dem anderen...


DF6GL

Hallo,

das Ganze basiert auf falschem Ansatz...

Statt alle Qualifikationen mit Ja/nein-Feldern in einem DS ("horizontal") darzustellen,  sollten in einer zusätzlichen  n-verknüpften Tabelle die zutreffenden Qualifikationen eines Bewerbers (?)  "vertikal" , also ein Ds für eine Qualifikation, gespeichert werden.  (-->Normalisierung).


Dann entfällt die ganze Trickserei mit dieser VBA-Vergewaltigung.

MzKlMu

Hallo,
als Unterstützung für Franz:
Ja/Nein Felder zur Auswahl von Attributen/Eigenschaften sind für eine Datenbank völlig ungeeignet.
Siehe hierzu:
http://allenbrowne.com/casu-23.html

Dann braucht es auch keinen VBA Code, keinen Buchstaben.
Gruß Klaus

noah

Dass das mit den Qualifikationen unglücklich gelöst ist, ist mir bewusst. Ich habe das ganze mal vor einiger Zeit als Excel-Tabelle übernommen, um parallel zu unserer Personalabteilung eine eigene Personalübersicht zu haben. Und in Excel ist das halt ein Tabellenblatt mit entsprechend vielen Spalten. Diese habe ich jetzt per Makro in Access importiert, allerdings (der Einfachheit halber) nahezu in derselben Tabellenform, wie die Daten vorlagen. Ich versuche jetzt mal die Tabellen mit den Mitarbeitern und den Funktionen zu trennen, die Tabellen dafür habe ich gerade erstellt. mal gucken wie weit ich komme....
Wenn ich Hilfe brauche melde ich mich...

markusxy

Vielleicht noch eine einfache Möglichkeit für das Event Problem.

Private Function Btn_click ()
    'Hier ist dein toller Code.
     if activecontrol = True then....
End Sub

Statt jetzt für jedes Control eine Event Prozedur anzulegen, kannst du im Eigenschaftsblatt des jeweiligen Controls beim gewünschten Event die Funktion hinterlegen. z.B. Nach Aktualisierung "=Btn_click ()" eintragen (ohne Hochkomma).

Die Funktion muss direkt im Formular Modul stehen.

Bezüglich dem Design gebe ich den anderen grundsätzlich recht.
Allerdings kann es sein, dass es für denjenigen der die Daten eingibt, wichtig sein kann so eine Übersicht zu haben. Die Programmierer geben die Daten ja nicht ein und denken nur daran, wie sie es am leichtesten haben. Für Auswertungen nimmt man dann eine Kreuztabelle, damit man die Daten wieder horizontal hat. ;D

Jedes der beiden Modelle hat Vorteile (es gibt auch noch weitere Möglichkeiten), dass übersehen die meisten und konzentrieren sich nur auf die "Nachteile".

LG Markus

noah

Sooo...da bin ich wieder. War doch etwas Arbeit, die Tabellen umzubauen und entsprechend wieder aus der Excel-Datei mit Daten zu befüllen.

@markus888: Genau so hatte ich es ja, eine Prozedur, in der der auszuführende Code steht und für jedes Kontrollkästechen ein onClick-Event a'la run Btn_Click()... Hat trotzdem einen unübersichtlichen Code ergeben, da ich ja für jedes Kontrollkästchen ein Sub a'la Kontrollkäsctchen_x_Click anlegen musste. Da man aber in der Entwurfsansicht alle Kontrollkästchen markieren und dann als Klick-Ereignis das Makro angeben kann sieht der Code jetzt etwas übersichtlicher aus.

Nun aber zu meiner nächsten Frage:
Ich habe die Tabellen wie in dem Link beschrieben aufgebaut. Angefangen mit der Tabelle tblPersonal, in der die Personaldaten (Name, Vorname, PK,....) stehen. In jedem Datensatz steht auch eine individuell für jeden Mitarbeiter   erstellte eindeutige ID. Diese ID findet sich in allen Tabellen wieder, um die Datensätze einwandfrei zuzuordnen.
Weiter habe ich Tabellen mit den Dienststellen, Abteilungen, Statusämtern, etc.
Und eben auch eine Tabelle mit Qualifikationen.
Ausgegeben werden die Datensätze in eine Listbox im Formular wie folgt:


Set QD = CurrentDb().CreateQueryDef("Wachliste") 'für Abfrage
     QD.SQL = "SELECT DISTINCTROW NMN.GUID, " & _
                           "ADST.Leitzeichen AS Wache, " & _
                           (...) & _
                           "IIF(NOT NMN.DSTNEU = 0, BEM.BEMERKUNG & '(AB ' & NMN.DSTNEUAB & ' ' & NDST.Leitzeichen & '/' & NABT.Leitzeichen & ')', BEM.BEMERKUNG) AS Bemerkung " & _
                            FROM (((((((((((tblPersonal NMN LEFT JOIN tblPersDienststellen PDST ON NMN.GUID=PDST.GUID)" & _
                           "LEFT JOIN ADMTBL_Dienststellen ADST ON ADST.ID=PDST.DSTID) " & _
                           "LEFT JOIN ADMTBL_Dienststellen NDST ON NDST.ID=NMN.DSTNEU) " & _
                           "LEFT JOIN tblPersAbteilungen PABT ON NMN.GUID=PABT.GUID)" & _
                           "LEFT JOIN ADMTBL_Abteilungen AABT ON AABT.ID=PABT.ABTID) " & _
                           "LEFT JOIN ADMTBL_Abteilungen NABT ON NABT.ID=NMN.ABTNEU) " & _
                           "LEFT JOIN tblPersBemerkungen BEM ON BEM.GUID=NMN.GUID) " & _
                           "LEFT JOIN tblPersStellenfaktor PSF ON PSF.GUID=NMN.GUID) " & _
                           "LEFT JOIN tblPersStatusaemter PSTA ON PSTA.GUID=NMN.GUID) " & _
                           "LEFT JOIN tblPersQualifikationen PQUAL ON PQUAL.GUID=NMN.GUID) " & _
                           "LEFT JOIN ADMTBL_Qualifikationen AQUAL ON AQUAL.ID=PQUAL.QUALID) " & _
                           "LEFT JOIN ADMTBL_Statusaemter ASTA ON ASTA.ID=PSTA.STAID "
                            " WHERE " & _
                            Personalliste_Filter_Dienststellen & _
                            Personalliste_Filter_Abteilungen & _
                            Personalliste_Filter_Statusamt & _
                            Personalliste_Filter_Geschlecht & _
                            Personalliste_Filter_Qualifikationen & _
                            Personalliste_Sortierung
     Set QD = Nothing
     DoCmd.Requery

Hat 'ne gute Nachtschicht gedauert, den SQL-String zu schreiben... :o

Die Ergebnisse sollen gefiltert werden können, indem man links in den Auswahlboxen (siehe Bild im Anhang...) eine oder mehrere  Dienststellen, Abteilungen etc. auswählt. Dies geschieht, indem in den jeweiligen Functions (Personalliste_Filter_...) anhand der selektierten Auswahlen die Filter aufgebaut werden. (z.B. WHERE (ADST.Leitzeichen='F11' OR ADST.Leitzeichen='F12')). Wenn nichts ausgewählt ist gibt die Function jeweils einen leeren String zurück. So auch im Filter Qualifikationen. Der funktioniert, wenn ich die angewählten Qualifikationen mit 'ODER' verknüpfe. Dann werden mir alle Einträge aufgelistet, auf die irgendeine der gewählten Qualifikationen zutrifft. Wenn ich das aber per UND verknüpfen möchte wird mir gar nichts mehr angezeigt, was ja vermutlich daran liegt, dass jetzt in der Tabelle 'tblPersQualifikationen' nach Einträgen gesucht wird, die in der Spalte QualID die ID's ALLER gewählten Qualifikationen enthält. Wie also kann ich den Filter so aufbauen, dass mir bei einer Verknüpfung per 'UND' die Datensätze angezeigt werden, auf die alle Filter zutreffen?

Ich hänge hier noch die Codeschnipsel an, mit denen der Filter für die Qualifikationen aufgebaut wird.

Tabelle ADMTBL_Qualifikationen (darin sind alle möglichen Qualifikationen eingetragen):






IDQualifikationKuerzel
.........
10GefahrgutscheinADR
11WechselladerscheinWLF
.........

Tabelle tblPersQualifikationen (wie im oberen Link beschrieben ein Datensatz pro MA pro Qualifikation):



IDMAIDQUALID
.........

Private Function Personalliste_Filter_Qualifikationen()
    Dim CTL As Control, CTLVAL As Control
   
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Set db = CurrentDb
   
    Dim UNDODER As String
   
    Select Case Me.OptGrp_UND_ODER_Qualifikatinen
        Case Is = 2
            UNDODER = "OR"
        Case Else
            UNDODER = "AND"
    End Select
   
    Personalliste_Filter_Qualifikationen = "AND ("
   
    For Each CTL In Me.Controls
            Select Case CTL.ControlType
                Case acCheckBox
                    If CTL.Name Like "Q_*" Then
                        Set CTLVAL = Me.Controls(CTL.Name)
                            If CTLVAL = -1 Then
                                Set rst = db.OpenRecordset("SELECT [ID] FROM ADMTBL_Qualifikationen WHERE [Kuerzel] = '" & CTL.Name & "'")
                                    Personalliste_Filter_Qualifikationen = Personalliste_Filter_Qualifikationen & _
                                                                             " " & UNDODER & " AQUAL.ID=" & rst(0)
                                    rst.Close
                            End If
                        Set CTLVAL = Nothing
                    End If
                Case Else
            End Select
    Next CTL
   
    Personalliste_Filter_Qualifikationen = Replace(Replace(Replace(Personalliste_Filter_Qualifikationen, "( AND", "("), "( OR", "(") & ")", "AND ()", "")
   
End Function


Und ein weiteres Problem habe ich auch noch. Die in der Listbox aufgelisteten Datensätze möchte ich zählen, bzw. aus der Spalte VK Summen bilden. Der SQL-String dazu sieht folgnedermaßen aus:

Set rs = db.OpenRecordset("SELECT DISTINCTROW count(NMN.ID) AS cntGESAMT, sum(PSF.FAKTOR) AS sumVK, " & _
                                "count(IIF(NMN.GES='M',1,Null)) AS sumMGES, " & _
                                "count(IIF(NMN.GES='W',1,Null)) AS sumWGES, " & _
                                "count(IIF(NOT ASTA.StatusamtKurz='BiR',1,Null)) AS sumBEAGES, " & _
                                "count(IIF(ASTA.StatusamtKurz='BiR',1,Null)) AS sumBIRGES, " & _
                                "count(IIF(NOT ASTA.StatusamtKurz = 'BiR' AND NMN.GES='M',1,Null)) AS sumMBEA, " & _
                                "count(IIF(NOT ASTA.StatusamtKurz = 'BiR' AND NMN.GES='W',1,Null)) AS sumWBEA, " & _
                                "count(IIF(ASTA.StatusamtKurz = 'BiR' AND NMN.GES='M',1,Null)) AS sumMBIR, " & _
                                "count(IIF(ASTA.StatusamtKurz = 'BiR' AND NMN.GES='W',1,Null)) AS sumWBIR, " & _
                                "sum(IIF(NOT ASTA.StatusamtKurz = 'BiR',PSF.FAKTOR,Null)) AS VKBea, " & _
                                "sum(IIF(ASTA.StatusamtKurz = 'BiR',PSF.FAKTOR,Null)) AS VKBir " & _
                                "FROM ... " & _
                                "WHERE...;"


'FROM ...' und 'WHERE ...' ist jeweils derselbe String, der auch bereits oben steht. Die gezählten bzw. errechneten Werte werden mir pro Datensatz mehrmals gezählt, vermutlich sooft wie die jeweilige 'ID' in der Tabelle tblPersQualifikationen vorhanden ist. Wie kann ich die Datensätze so zählen, dass sie nur sooft, wie sie auch tatsächlich in der Tabelle Personal vorhanden sind zählen?
   
Ich hoffe, dass das so einigermaßen verständlich ist und mir jemand einen Lösungsansatz geben kann.
 

noah

Soooo....ich hab's hinbekommen.
Für alle, die an der Lösung interessiert sind:

Dass die Namen in der Personalliste doppelt angezeigt werden verhindere ich ja mit "SELECT DISTINCTROW...". Das funktioniert so aber nicht mit count(). Da muss der Code dann lauten: "SELECT count(*) FROM (SELECT DISTINCTROW...)"...

Und nun werden mir nur die tatsächlich auch angezeigten Datensätze gezählt.