Flackerndes StringGrid



  • Hallo.

    Ich zeichne alle Zellen von dem StringGrid selbst über TStringGrid1DrawCell(). Mit Zellen sind ale nicht weiss.
    Für die Eingabe verwende ich nicht InplaceEdit, sondern lege ein eigenes angepasstes Edit direkt in die Zelle (quasi darüber). Wenn ich RETURN in diesem Edit betättige, dann springt es zur darunterliegenden Zelle weiter.

    Hier fängt dann das Problem an. Ich sehe dann in der Zelle, in der das Edit vorher lag, plötzlich ein sehr kurzes weises aufblinken/flackern. Um so schneller ich RETURN drücke, um so auffälliger wird das Ganze. Sieht sehr unschön aus.

    Ich habe schon DoubleBuffer = true probiert, das hat aber nichts bewirkt. Auch das StringGrid in ein Panel legen nicht. Ich habe auch in TStringGrid1DrawCell das Canvas über Lock() und Unlock() gesetzt. Half auch nichts.

    Hat jemand eventuell einen Tipp für mich?



  • flackus schrieb:

    Für die Eingabe verwende ich nicht InplaceEdit, sondern lege ein eigenes angepasstes Edit direkt in die Zelle (quasi darüber). Wenn ich RETURN in diesem Edit betättige, dann springt es zur darunterliegenden Zelle weiter.

    Code?



  • Wäre toll wenn einer drüberschauen würde und eventuell den Fehler erkennt.
    Ich habe den Code mal aufs nötigste gestutzt, damit er übersichtlich ist.

    Zwei Dinge sind auf der Form. Ein StringGrid und eine unsichtbares Edit.
    InplaceEditEx ist ein angepasstes TEdit.
    StringGrid hat alle Options auf FALSE, die ersten 4 sind TRUE, für das Linienzeichnen. ColCount = 7 und RowCount = 5

    Ich setze StringGrid->Color = clRed (habe alle Farben mal extrem gewählt) und genau diese Farbe(rot) hat auch das "flackern" dann.

    Arbeitsweise: Ich klicke mit Maus in das StringGrid, dadurch wird TeStringGrid1Click() aufgerufen und das Edit an seine Position gesetzt und sichtbar gemacht. Edit ist dann fokusiert und zur Eingabe bereit. Ich kann nun mit Return oder ArrowUp und ArrowDown das Edit in dem StringGrid in der Spalte Zellenweise weiterspringen.

    Das flackern ist nicht konstant da, man muss schon paar mal drücken um das zu sehen. Mal ist es mehr, mal ist es weniger da.

    class TForm1 : public TForm
    {
    __published:	// Von der IDE verwaltete Komponenten
        TTeStringGrid *TeStringGrid1;
        TMyEdit *InplaceEditEx;
        void __fastcall TeStringGrid1DrawCell(TObject *Sender, int ACol,
              int ARow, TRect &Rect, TGridDrawState State);
        void __fastcall InplaceEditExKeyUp(TObject *Sender, WORD &Key,
              TShiftState Shift);
        void __fastcall TeStringGrid1Click(TObject *Sender);
    private:	// Anwender-Deklarationen
    
        void __fastcall PlaceInplaceEdit();
    
    public:		// Anwender-Deklarationen
        __fastcall TForm1(TComponent* Owner);
    };
    
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::TeStringGrid1DrawCell(TObject *Sender, int ACol,
          int ARow, TRect &Rect, TGridDrawState State)
    {
        TeStringGrid1->Canvas->Lock();
    
        if ((ARow>0) && (ACol>=2) && (ACol<=4))
        {
            TeStringGrid1->Canvas->Brush->Color = 0x00FFAABF;
            TeStringGrid1->Canvas->Font->Color = clBlack;
        }
    
        TeStringGrid1->Canvas->FillRect(Rect);
    
        InflateRect(&Rect, -5, 0);
        TeStringGrid1->Canvas->Font->Style = TFontStyles();
        DrawText(TeStringGrid1->Canvas->Handle, TeStringGrid1->Cells[ACol][ARow].c_str(),
        -1, &Rect, DT_SINGLELINE | DT_VCENTER | DT_RIGHT);
    
        TeStringGrid1->Canvas->Unlock();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::PlaceInplaceEdit()
    {
        TRect Rect = TeStringGrid1->CellRect(TeStringGrid1->Col,TeStringGrid1->Row);
        InplaceEditEx->SetBounds(TeStringGrid1->Left + Rect.Left+3,
                                TeStringGrid1->Top + Rect.Top+5,
                                (Rect.Right - Rect.Left)-6,
                                (Rect.Bottom - Rect.Top)-3);
        InplaceEditEx->Text = TeStringGrid1->Cells[TeStringGrid1->Col][TeStringGrid1->Row];
        InplaceEditEx->Visible = true;
        InplaceEditEx->SetFocus();
        InplaceEditEx->SelectAll();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::InplaceEditExKeyUp(TObject *Sender, WORD &Key,
          TShiftState Shift)
    {
        if ((Key==VK_RETURN) ||
            (Key==VK_DOWN))
        {
            Key = 0;
            if (TeStringGrid1->Row < TeStringGrid1->RowCount - 1)
            {
                TeStringGrid1->Row++;
            }
            else
            {
                TeStringGrid1->Row = 1;
            }
            PlaceInplaceEdit();
        }
        else if (Key==VK_UP)
        {
            if (TeStringGrid1->Row > 1)
            {
                TeStringGrid1->Row--;
            }
            else
            {
                TeStringGrid1->Row = TeStringGrid1->RowCount - 1;
            }
            PlaceInplaceEdit();
        }
        else if (Key==VK_TAB)
        {
            Key=0;
        }
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::TeStringGrid1Click(TObject *Sender)
    {
        if ((TeStringGrid1->Row>0) &&
            (TeStringGrid1->Col>=2) && (TeStringGrid1->Col<=4))
        {
            PlaceInplaceEdit();
        }
        else
        {
            InplaceEditEx->Visible = false;
        }
    }
    //---------------------------------------------------------------------------
    


  • Sorry für Doppelpost, will nur hinzufügen das nicht das Edit daran schuld ist!
    Ich kann den Spass auch mit einem Stink normalen Button betreiben.
    P.S. Hier einfach Leertaste drücken, das wie ein Mausklick auf den Button.

    //---------------------------------------------------------------------------
    void __fastcall TForm1::PlaceInplaceEdit()
    {
        TRect Rect = TeStringGrid1->CellRect(TeStringGrid1->Col,TeStringGrid1->Row);
        Button1->SetBounds(TeStringGrid1->Left + Rect.Left+3,
                                TeStringGrid1->Top + Rect.Top+5,
                                (Rect.Right - Rect.Left)-6,
                                (Rect.Bottom - Rect.Top)-3);
        Button1->Visible = true;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
        if (TeStringGrid1->Row < TeStringGrid1->RowCount - 1)
        {
            TeStringGrid1->Row++;
        }
        else
        {
            TeStringGrid1->Row = 1;
        }
        PlaceInplaceEdit();
    }
    //---------------------------------------------------------------------------
    


  • Da du ja die Tabellenzelle selber zeichnest:

    Ev. könntest du prüfen, ob das Editcontrol in dieser Zelle aktiv ist, und wenn ja, lässt du das neuzeichnen einfach weg.
    Ist nur so eine Idee.
    😉



  • Das hat mit dem Edit wie gesagt nix zu tun und er muss die vorherige Zelle ja neuzeichnen, damit diese ohne das Edit angezeigt wird.

    anderes Beispiel:

    Ich änder in einer Zelle den Wert, dadurch ändern sich bei mir in allen Zellen dieser Zeile die Werte ebenfalls und zack sehe ich nach dem Enter in alle Zellen dieser Zeile es kurz weiss aufblitzen. Echt unschön.

    Quasi fehlt ein DoubleBuffered, aber dieses bewirkt ja nichts.



  • Ich habe eben mal bissle weiter rumgespielt/rumprobiert
    (was macht man nicht so in seiner Freizeit alles^^)

    Das Problem scheint in PlaceInplaceEdit() zu liegen.

    TRect Rect = TeStringGrid1->CellRect(TeStringGrid1->Col,TeStringGrid1->Row);
        InplaceEditEx->SetBounds(TeStringGrid1->Left + Rect.Left+3,
                                TeStringGrid1->Top + Rect.Top+5,
                                (Rect.Right - Rect.Left)-6,
                                (Rect.Bottom - Rect.Top)-3);
    

    Wenn ich dort die Zeilen für das InplaceEditEx->SetBounds(..) auskommentiere, sprich das Edit, Button oder was auch immer für eine Komponente nicht mehr direkt in die Zelle darstellen will, dann flackert nix mehr. Ich kann die beliebige Komponente auch auf das StringGrid mittig beliebeig ablegen ohne das was flackert.

    Erlich gesagt verstehe ich das nicht. Vor allem verstehe ich nicht wieso die ganze Zeile aufflackert, wenn doch das SetBounds nur die Komponente auf eine Zelle pflanzt.



  • Entwickelt sich hier zum Selbstgespräch 😉
    Habe eben noch was entscheidendes rausgefunden.

    Es scheint am neuzeichnen der Komponente auf StringGrid zu liegen. Wenn ich das Zellzeichnen komplett rausnehme, dann ändere ich in der festpositionierten Edit die Werte und zeichne StringGrid flackerlos.

    Bewege ich jedoch das Edit (oder eine andere Komponenet) über SetBounds oder allein über Edit->Top, dann flackert StringGrid die Zeile, welche veränderungen enthält. Auch ein Edit->Visible = false reicht bereits, um das StringGrid zum flackern zu bringen, ohne das Edit zu bewegen nur Visible kurz setzen.

    Hat jemand dafür eine Erklärung, evuentuell Lösung? Ich verstehe es erlich gesagt nicht.



  • Benutze einfach eine interne Variable, so daß du das Neuzeichnen selber verhinderst.

    bool bDraw = true; // am besten als Member oder static
    
    DrawCell(...)
    {
      if(!bDraw) return;
    
      ...
    }
    
    PlaceInplaceEdit()
    {
      bDraw = false;
    
      ... (SetBounds etc.)
    
      Application->ProcessMessages(); // wichtig!!!
    
      bDraw = true;
    }
    


  • Danke. Habs gleich mal ausprobiert. Das setzen von bDraw allein bringt leider nichts. Wenn ich ProcessMessages() mit reinsetze, nach dem SetBounds, dann zeichnet er die zu befüllenden Zellen garnicht mehr, sie werden weiss. Lass ich ProcessMessages() drin und entferne die return-Abfrage in DrawCell, dann zeichnet er wieder die betroffenen Zellen, aber diese flackern weiterhin. Hol mich der Kuckuck, das StringGrid ist mir langsam zu blöd. Wahrscheinlich hatte noch keiner das Problem, da alle es auf "weiss" belassen und dadurch das flackern nicht wirklich sehen.



  • Hi,

    ich habe das selbe Problem mit dem Flackern. Bei mir stürzt das Programm dadurch sogar gelegentlich beim Zeichnen ab.

    Hatte aber noch nicht die Zeit dem Fehler nachzugehen. Werde das aber auf jeden Fall in den nächsten paar Wochen tun.

    Deshalb verfolge ich die Diskusion hier aufmerksam.

    MfG



  • Hast du denn StringGrid->DefaultDrawing auf false gesetzt?
    Denn sonst zeichnet das StringGrid selber erst die Zellen, bevor es die OnDrawCell-Methode anspringt.

    Du mußt zwar evtl. das Focus-Rechteck selber zeichnen, aber das ist ja kein Problem: s. Canvas->DrawFocusRect.



  • DefaultDrawing stand auf true, aber auch ein ändern auf false macht keinerlei sichtbaren Unterschied.


Anmelden zum Antworten