Berechtigungsformular mit TreeView, ListView und CheckBox oder ganz anders?



  • 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->Col
    

    liefern 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*> pCheckBox
    
    std::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ügen
    

    Wie 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 aussehen

    if(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.


Anmelden zum Antworten