Berechtigungsformular mit TreeView, ListView und CheckBox oder ganz anders?
-
Hallo Community,
habe mal wieder ein Problem und bräuchte einen Lösungsansatz.
Ich möchte eine Tabelle erzeugen, die ungefähr so aussieht:
--------------------------------------------------------------------------
| Aufgabe____________|__Level0___|___Level1__|___Level2__| bis Level9
-------------------------------------------------------------------
| Benutzer anlegen___|____0______|____0______|____1______|
| Benutzer ansehen___|____0______|____1______|____1______|
| Benutzer löschen___|____0______|____0______|____1______|
------------------------------------------------------------------
| Dateien anlegen____|____1______|____1______|____1______|
| Dateien ansehen____|____1______|____1______|____1______|
| Dateienlöschen____|____0______|____0______|____1______|
-------------------------------------------------------------------Anstelle der 0 bzw. 1 in den Levelfeldern sollen dort CheckBoxen drin sein,
die mir die Daten in ein array[6][9] als true oder false Werte sichern soll.Den Aufruf der Aufgaben habe ich mir vorgestellt wie in einem TreeView:
+ Alle Berechtigungen
|-------Benutzer
|-------Dateien
|-------...Je nachdem was ich in diesem TreeView auswähle sollen mir die Aufgaben z.B. von Benutzer oder Dateien oder eben Alle Berechtigungen angezeigt werden und ich möchte über Checkboxen den Level setzten / rücksetzen können.
Diesen Level werde ich mir dann aus dem array holen und der jeweilen Button, Formular ... als "Tag" zuweisen.
Die Zuweisung ist kein Problem, aber wie bekomme ich eine Ordentliche Tabelle mit Checkboxen hin.
Ich habe es mit einem ListView versucht. Habe dort auch die Überschriften und Aufgaben drin.
ListView1->Items->Clear(); // ListView leeren ListView1->Items->Add(); // Item hinzufügen ListView1->Items->Item[0]->Caption ="Benutzer anlegen"; // Überschrift ListView1->Items->Item[0]->SubItems->Add("1"); //<-- Hier Checkbox Problem ListView1->Items->Item[0]->SubItems->Add("2"); //<-- Hier Checkbox Problem ListView1->GridLines = true; // Gitternetz einIch habe probiert Checkboxen dynamisch zu erzeugen, die werden aber immer in der linken oberen Ecke der ListView Komponente erstellt und ich kann sie nicht den einzelnen Feldern zuordnen, sondern als Parent nur ListView1 auswählen.
Wenn ich sie fest positioniere (wie mach ich das?) habe ich hinterher das Problem, das sie bei einer Auswahl von "Alle Berechtigungen" alle übereinander habe.
TCheckBox *NewCheckBox = new TCheckBox(ListView1->Items->Item[0]); NewCheckBox->Name = "CB10_0"; NewCheckBox->Parent = ListView1;Außerdem weiß ich nicht wie es sich verhählt, wenn ich da mehrere 100 Checkboxen dynamisch aufrufe. Die Level gehen von (0 bis 9) und ich habe sehr viele verschiedene Aufgaben die ich einzeln sezten oder sperren möchte.
Vielleicht hat mir auch jemand eine ganz andere Lösung um eine Art Berechtigungsformular zu erstellen. Und ich tue mir nur unnötig schwer mit meinem Ansatz.
Wäre für jeden Tip dankbar.
Viele Grüße.
-
Die ListView-Komponente unterstützt schon Checkboxes von sich aus, du mußt es nur aktivieren (aber nicht zu früh freuen):
ListView->Checkboxes = true;Nun werden neben jeder ZEILE Checkboxen angezeigt, aber NICHT für jede Spalte.
(mit ViewStyle=vsList oder =vsReport).
Du müßtest dann für jede Spalte eine eigene ListView-Komponente erzeugen. Nachteil wäre v.a. dann, wenn eine Scrollbar angezeigt werden soll...Eine andere Möglichkeit wäre, du benutzt die Komponente TDrawGrid und zeichnest selber die zwei Zustände der Checkbox (je Grid-Eintrag) mittels Canvas.
Mit den Ereignissen OnMouseDown, OnMouseUp etc. kannst du dann das Anklicken der Checkbox simulieren.Oder aber du besorgst dir eine externe Komponente mit eingebauten Inplace-Editoren:
unter http://sunsite.informatik.rwth-aachen.de/delphi/ gibt es eine Menge Komponenten für Delphi und C++ Builder.Schau mal unter "BC++B X.0 / Grids / XStringgrid" nach - diese scheint für dich am geeignetesten zu sein (X == deine BCB-Version).
-
Das Zauberwort sollte 'Inplace-Editor' lauten.
Schau mal hier: http://www.bytesandmore.de/rad/cpp/snipp/sc02038.php
Es werden zwar andere Komponenten verwendet, aber das Prinzip ist das Gleiche.
-
@Th:
ListView->Checkboxes =true;hatte ich schon entdeckt und ausprobiert, aber das war leider nicht das was ich brauche.
Eine eigene ListView Komponente neben jeder Spalte fällt auch weg, da es so viele Aufgaben werden, dass ich auf jeden Fall einen Scrollbalken brauche.
Komponente TDrawGrid zeichnen und die zwei Zustände der Checkbox (je Grid-Eintrag) mittels Canvas ist echt sehr umständlich, da ich ja die Komponente positionieren muß und ich je nachdem welcher Oberbegriff ausgewählt wird die Auswahl entweder Komplett oder nur zur Aufgabe gehörend anzeigen möchte.
Ich probiere mal ob ich die CheckBoxen reinbekomme.
@Joe_M.
Die Sache mit den Inplace-Editor scheint mir auch nicht schlecht zu sein. Nur funktioniert bei mir der Quelltext von der angegebenen Seite nicht. Um mir das in Natura mal anzusehen.Ich bekomme immer die Meldung FormMain->StringGrid1 Besitzt keine entsprechende Komponente. Soll die Deklaration entfernt werden.
Wenn ich auf dem Formular ein StringGrid platziere, dann wird mir aber nichts angezeigt.
-
Bei einem StringGrid heißen die zwei Eigenschaften zum Setzen der max. Spalten und Zeilen:
StringGrid->ColCount = 11; StringGrid->RowCount = 42;Nun hast du ein Gitter der Größe 42 * 11 und kannst mit StringGrid->Cells[x][y] auf die einzelnen Inhalte zugreifen (ich habe mir die Komponente XStringGrid nicht genau angeschaut, nehme aber an daß sie von TStringGrid geerbt ist).
Funktioniert denn das Demo-Programm zu der Komponente bei dir? Dann kannst du dort ja in den Sourcen nachschauen.
-
Habe mittlerweile, die eigenschaft ColCount gefunden. Danke nochmal, bin irgendwie davon ausgegangen, dass ich damit die Anzahl der Spalten zähle.
Mach mich mal dran die CheckBoxen einzupflegen. Mal schauen wie das hinhaut.
PS: Das Demo hat bei mir irgendwie nicht richtig funktioniert.
Viele Grüße aus dem Schwabenländle.
-
Also, ich habe immer noch ein Problem.
Ich habe nun die XStringGrid Komponente drin, aber Checkboxen bekomme ich da keine raus. Habe aber mit ihr einfach meine Checkbox positioniert. Und das ganze mit Inline Funktionen gelöst.
Problem:
Entweder habe ich nur eine Checkbox beim Start des Formulars eingeblendet und zwar in der Zelle, die den Fokus hat oder ich klicke so wie im unterem Beispiel jedes Feld an. Dann wird in jedem Feld eine CheckBox erstellt.Gibt es aber irgendwie ein Ereignis, dass ich bei TreeView oder StringGrid auswählen kann, dass ich automatisch in jeder Zelle eine Checkbox anzeigen kann?
Habe versucht die XStringGrid1->Col und XStringGrid1->Row wie in einem Array durchzuzählen und dort jeweils mit
PlaceCheckBox(pCheckBox);eine CheckBox zu setzen, aber irgendwie funktioniert das nicht.
Hat mir jemand noch mal einen Tip?
void __fastcall TFormBerechtigungen::PlaceCheckBox(TCheckBox *pCheckBox1) { // Maße eines Gitterfensters bestimmen TRect Rect = XStringGrid1->CellRect(XStringGrid1->Col,XStringGrid1->Row); // CheckBox den obersten Punkt des XStringGrid zuweisen pCheckBox1->Top = XStringGrid1->Top; // CheckBox den linken Punkt des XStringGrid zuweisen pCheckBox1->Left = XStringGrid1->Left; // CheckBox Top Position zuweisen pCheckBox1->Top = pCheckBox1->Top + Rect.Top + XStringGrid1->GridLineWidth +1; // CheckBox Left Position zuweisen pCheckBox1->Left = pCheckBox1->Left + Rect.Left + XStringGrid1->GridLineWidth +14; // CheckBox Höhe zuweisen pCheckBox1->Height = (Rect.Bottom - Rect.Top) - 1; // CheckBox Breite zuweisen pCheckBox1->Width = (Rect.Right - Rect.Left) - 17; // CheckBox sichtbar machen pCheckBox1->Visible = true; // CheckBox Focus zuweisen pCheckBox1->SetFocus(); }void __fastcall TFormBerechtigungen::XStringGrid1Click(TObject *Sender) { pCheckBox = new TCheckBox(GroupBox1); pCheckBox->Parent = GroupBox1; pCheckBox->Color = clWindow; pCheckBox->Alignment = taRightJustify; pCheckBox->Visible = false; pCheckBox->OnClick = CheckBoxClick; PlaceCheckBox(pCheckBox); }
-
Es macht vielleicht Sinn, statt der GroupBox das StringGrid als Parent der CheckBox anzugeben.
-
Habe ich abgeändert, aber das Problem bleibt das selbe. Bekomme nur in der ersten Zelle den Button automatisch angezeigt und bei den anderen muß ich reinklicken.
-
Ich hab jetzt zwar nicht die XStringGrid Komponente aber du kannst das doch auch ganz einfach über ein entsprechendes Array bzw besser noch mit entsprechendem vector von 'TCheckBox' machen.
Du erzeugst dynamisch zur Laufzeit soviel neue Instanzen von TCheckBox wie du in deinem Grid benötigst.
Die positionierst du dann 'über' dem Grid.
Am besten natürlich wenn du da gleich von StringGrid ableitest.
-
Also ich komm hier von einem zum Anderem. Ich habe es nun geschaft, dynamisch so viele CheckBoxen zu erstellen wie ich benötige. Diese habe ich auch der XStringGrid Komponente zugeordnet. Die CheckBoxen sind auch in den entsprechenden Feldern positioniert.
Aber irgendwie mache ich noch etwas falsch beim Zuweisen.
Ich kann jetzt zwar die Buttons betätigen und das OnClick Ereignis wird ausgelöst, aber ich bekomme in der OnClick Funktion keine Informationen mehr darüber in welcher Zeile oder Spalte des StringGrids ich mich befinde.
Aufrufe wie
XStringGrid->Colliefern immer nur eine Eins zurück.
Das komische ist, ich kann darin noch nicht mal abfragen, ob eine Checkbox checked ist. Die Überprüfung wirkt sich in keinster Weise aus.
Ich habe mir die Faq zu dynamisch erzeugte Komponenten durchgelesen...
http://www.c-plusplus.net/forum/viewtopic-var-t-is-39206.html
...da ich vermute, dass mein Fehler in den mit new erzeugten CheckBoxen liegt. Das was ich da gefunden habe, kann ich bei mir so nicht anwenden, da ich keine const int Variable nehmen kann. Ich weiß ja erst beim Aufruf im TreeView wie viele Checkboxen ich brauche.
void __fastcall TFormBerechtigungen::PlaceCheckBox(int Row, int Col) { for(int Zeile =1; Zeile<Row; Zeile++) { for(int Spalte =1; Spalte<Col; Spalte++) { pCheckBox = new TCheckBox(pXStringGrid); pCheckBox->Parent = pXStringGrid; pCheckBox->Color = clWindow; pCheckBox->Alignment = taRightJustify; // Maße eines Gitterfensters bestimmen TRect Rect = pXStringGrid->CellRect(pXStringGrid->Col,pXStringGrid->Row); // CheckBox den obersten Punkt des XStringGrid zuweisen pCheckBox->Top = pXStringGrid->Top; // CheckBox den linken Ounkt des XStringGrid zuweisen pCheckBox->Left = pXStringGrid->Left; // CheckBox obere Position zuordnen pCheckBox->Top = pCheckBox->Top // pXStringGrid->Top beibehalten + (Rect.Top * Zeile) // Position von Erster Zelle * Anzahl Zeilen + pXStringGrid->GridLineWidth +1 // Gitter Linie addieren - pXStringGrid->Top; // Positionsverschiebung pXStringGrid->Top abziehen // Position der Zellen ermitteln TRect Rect1 = pXStringGrid->CellRect(Spalte-1,Zeile-1); // CheckBox linke Position zuordnen pCheckBox->Left = pCheckBox->Left // pXStringGrid->Left beibehalten + Rect1.Right // Position Rechts Zelle + pXStringGrid->GridLineWidth +1 // Gitter Linie addieren - pXStringGrid->Left // Positionsverschiebung pXStringGrid->Left abziehen + 12; // Positionierung in der Mitte // CheckBox Höhe zuweisen pCheckBox->Height = (Rect.Bottom - Rect.Top) - 2; // CheckBox Breite zuweisen pCheckBox->Width = (Rect.Right - Rect.Left) - 17; // CheckBox anzeigen pCheckBox->Visible = true; // CheckBox Funktion zuweisen pCheckBox->OnClick = CheckBoxClick; } } }Also, wenn mir nun einfach jemand sagen kann. Schau mal was du da machst, so ruft das doch kein Mensch auf, dann wäre das echt super.
-
Schau mal was du da machst, so ruft das doch kein Mensch auf...

Ja, so ist das auch nichts. Du erzeugst dynamisch jede Menge neue CheckBoxen.
Nur musst du ja irgendwie auch darauf zugreifen können.
Dann machst du dir ein Array oder besser noch einen vector ungefähr so:TCheckBox *checkboxen[9][6];Dann erzeugst du deine Checkboxen
for (int y=0;y<6;y++) { for(int x=0;x<9;x++) { checkboxen[x][y]=new TCheckBox(Form1); checkboxen[x][y]->Parent ... ... } }
-
Ok, meinen Fehler verstehe ich nun. Nur weiß ich immer noch nicht wie ich ihn genau behebe.
TCheckBox *checkboxen[9][6];Das hier geht bei mir nicht, da auch hier die Angabe des Arrays fest definiert sein muß. Wenn ich hier sowas versuche
TCheckBox *checkboxen[Row][Col];bekomme ich eine Fehlermeldung, dass die Ausdrücke Konstant sein müssen.
Mit einem vector habe ich bis jetzt noch nicht gearbeitet. Habe mich aber ein wenig eingelesen. Dabei würde so etwas gehen.
std::vector<TCheckBox*> pCheckBoxstd::vector<TCheckBox*> pCheckBox[];Aber das hier geht nicht.
std::vector<TCheckBox*> pCheckBox[][];So kann ich aber auch meine CheckBoxen nicht mit
checkboxen[x][y]=new TCheckBox(Form1);initialisieren. Es sei denn ich löse es so:
checkboxen[x]=new TCheckBox(Form1);und zähle alle erzeugten vector Komponenten. Aber wird das so gehandhabt?
Wie muß ich eigentlich von einem vector den Speicher wieder freigeben. Habe gelesen, dass er nicht wieder freigegeben wird, wenn das Parent Form gelöscht wird?
-
Dir fehlen ja wirklich noch grundlegende C++ Kenntnisse, und dann willst du eine GUI programmieren.
Ein paar Tips gebe ich dir, aber beschäftige dich erstmal mit einem kleineren Projekt, dann ist der Frustfaktor auch nicht so groß!
1. Du solltest dir ersteinmal die Hilfe zu den Komponenten ansehen, um die Eigenschaften, Methoden und Ereignisse zu verstehen (die BCB6-Hilfe ist dafür besser geeignet als die beim TurboExplorer).
Für ein StringGrid gibt es das Ereignis OnSelectCell (statt das allgemeingültige OnClick)2. Ein std::vector<> kapselt ein dynamisches Array, d.h. du brauchst keine Größe (wie bei den Arrays) angeben:
#include <vector> std::vector<TCheckBox*> pCheckBoxes; // Deklaration des vectors (als privates Form-Member) TCheckBox *pCheckBox = new TCheckBox(0); pCheckBox->Parent = this; ... // weitere Eigenschaften pCheckBoxes->push_back(pCheckBox); // neues Element hinzufügenWie kommt es, daß du noch nicht die Standard-Datentypen der C++ Library kennst (diese werden in jedem C++ Buch / Tutorial und auch hier im Forum erklärt)?
-
Th schrieb:
Dir fehlen ja wirklich noch grundlegende C++ Kenntnisse, und dann willst du eine GUI programmieren.
Ein paar Tips gebe ich dir, aber beschäftige dich erstmal mit einem kleineren Projekt, dann ist der Frustfaktor auch nicht so groß!
Bis jetzt hatte ich nur mit reinem C zu tun. Ich brauche das ganze für das Technikerprojekt. Da komm ich aber mit reinem C nicht so weit, da eine GUI gefordert ist. Der Borland Builder ist die Entwicklungsumgebung, die sie bereits haben und in der das Projekt realisiert werden soll.
Ich habe mir nun ein paar Bücher gekauft von Richard Kaiser und Helmut Erlenkötter und lese mich gerade feste ein. Die Hilfe von Borland Builder nutze ich so gut es geht und ich lese auch viel hier im Forum.
Für ein StringGrid gibt es das Ereignis OnSelectCell (statt das allgemeingültige OnClick)
Das Ereignis habe ich gesehen und ausprobiert. Für mich ist aber die ausgewählte Zelle erstmal nicht von Bedeutung. Ich benutze die StringGrid Komponente um einmal die Anzahl der Checkboxen zu ermitteln und um meine Checkboxen in tabellarischer Form zu den Aufgaben und Level zu positionieren.
Ich möchte wissen ob zu einer bestimmten Aufgabe die CheckBox gesetzt oder nicht gesetzt ist. Diesen Zustand speicher ich mir dann in einem zweidimensionalem Array ab.
So kann ich aus dem CheckBox Zustand und der Tag Variable der Aufgabe vergleichen ob diese auf true oder false ist und erlaube oder verbiete dem jeweiligem User die Benutzung der Aufgabe.So kann ich mir einen Zugriffslevel für jede Aufgabe zusammenbauen.
Ungefähr in dieser Art:
if(Aufgabe.Tag != CheckBoxZustand[x][y]) { // Tue irgendwas } else { // Fehler ausgeben Application->MessageBoxA("Keine Berechtigung","Achtung",MB_OK): }2. Ein std::vector<> kapselt ein dynamisches Array, d.h. du brauchst keine Größe (wie bei den Arrays) angeben
Ok, das wußte ich nicht. Dachte ich könnte da auch sowas wie ein zweidimensionales Array anlegen um dann über die Zellen den jeweiligen CheckBox Zustand abfragen. Würde es erleichtern beim Abspeichern.
Stricke mein Programm mal um. Danke für die Hilfe.
-
Ok, das wußte ich nicht. Dachte ich könnte da auch sowas wie ein zweidimensionales Array anlegen ...
Das kannst du ja auch. Nur mit dem Vorteil das es dynamisch ist.
Und die Abfrage würde dann so aussehenif(CheckBoxZustand[x][y]->Checked) { // Tue irgendwas } else { // Fehler ausgeben Application->MessageBoxA("Keine Berechtigung","Achtung",MB_OK): }
-
Habe mir das Tutorial "Aufbau der STL - Container" durchgelesen und das mit dem vector ausprobiert. Bekomme es aber irgendwie nicht hin auf meine CheckBoxen zuzugreifen.
Sie werden zwar erzeugt und in den vector geschoben, aber den Zustand konnte ich nicht abfragen.
Habe das dann mal mit einfachen integer Werten probiert, dann kann ich die auch wieder auslesen.Habe aber mittlerweile eine andere Lösung für mein Problem.
DynamicArray<TCheckBox*>CheckBox; // CheckBox Container anlegen ... void __fastcall TFormBerechtigungen::PlaceCheckBox(int Row, int Col) { int Anzahl = Row * Col; // Anzahl benötigter CheckBoxen ermitteln CheckBox.Length = Anzahl; // Array auf diese Länge setzten for (int i = 0; i < CheckBox.Length; i++) { CheckBox[i] = new TCheckBox(pXStringGrid); // Neue CheckBoxen erstellen } int i=0; // Bei CheckBox Null beginnen for(int Zeile =1; Zeile<Row; Zeile++) { for(int Spalte =1; Spalte<Col; Spalte++) { CheckBox[i]->Parent = pXStringGrid; CheckBox[i]->Color = clWindow; CheckBox[i]->Alignment = taRightJustify; ... // CheckBox Funktion zuweisen CheckBox[i]->OnClick = CheckBoxClick; i++; // nächste CheckBox } } }Das Array ist zwar nicht Zweidimensional und es ist bestimmt nicht die schönste Lösung, aber zumindest funktioniert es.
Falls mir jemand noch zum Verständnis am Beispiel von Th erklären kann wie ich die CheckBox hole und ihren Zustand erfrage wäre das super.