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?
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.
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...
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.
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.
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...
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
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):
ID | Qualifikation | Kuerzel |
... | ... | ... |
10 | Gefahrgutschein | ADR |
11 | Wechselladerschein | WLF |
... | ... | ... |
Tabelle tblPersQualifikationen (wie im oberen Link beschrieben ein Datensatz pro MA pro Qualifikation):
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 FunctionUnd 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.
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.