CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - TListView gpogubienie zmiana koloru w komórkach
Strona 1 z 1

TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: poniedziałek, 13 grudnia 2010, 17:28
przez Darek_C++
Czy można ustawić wygląd czcionki / tekstu w poszczególnych komórkach w komponencie TListView np:.
KOD cpp:     UKRYJ  
TListItem * ElementListy = ListView1->Items->Add();
ElementListy->Caption = "Pierwszy";

ElementListy->SubItems->Add("---");

ElementListy->SubItems->Add("Kolor czerwony pogrubiona czcionka");

ElementListy->SubItems->Add("Kolor zielony normalna czcionka");
Jeśli tak to jak to zrobić ?



W zasadzie to chodzi o zmianę koloru już wyplecionych komórek w zależności od statusu. Akcja wykonywana w wątku:

KOD cpp:     UKRYJ  
if(ststusOK)
{
        ListView1->Items->Item[this->nrNaListViev]->SubItems->Strings[1] = "Prawidłowy"; // Kolor zielony
}
else
{
        ListView1->Items->Item[this->nrNaListViev]->SubItems->Strings[1] = "Błędny";  // Kolor czerwony
}
Mam kod który w zdarzeniu OnCustomDrawSubItem podczas wypełniania komórek ustawia kolor ich tekstu:

KOD cpp:     UKRYJ  
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
          TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
        if(SubItem == 3)
        {
                randomize();
                if( RandomRange(1, 10) >= 5)
                {
                        Sender->Canvas->Font->Color = clRed;
                }
                else
                {
                        Sender->Canvas->Font->Color = clGreen;
                }
        }
}


Ale mi chodzi o zmianę koloru w komórkach już wypełnionych :(

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: poniedziałek, 13 grudnia 2010, 19:40
przez Cyfrowy Baron
Trzeba posłużyć się zdarzeniem OnCustomDrawSubItem dla SubItem a dla kolumny pierwszej OnCustomDrawItem. W przykładzie posłużę się jednak SubItem. Poza tym do określania kolorów posłużę się tablicą asocjacyjną, by nie tworzyć pętli w połączeniu z dwiema tablicami do określenia wielu kolorów:
W pliku nagłówkowym dodajemy nagłówek #include <map> a w sekcji private deklarujemy tablicę:

KOD cpp:     UKRYJ  
#include <map>

private:
        std:: map<AnsiString, TColor>  tabColor;


Resztę robimy w pliku źródłowym. Tablicę trzeba wypełnić kolorami a w zdarzeniu OnCustomDrawSubItem trzeba te kolory przypisać poszczególnym SubItem w zależności od tego jaki wpis zawierają. Tobie chodziło o stany prawda-fałsz, ja jednak nieco to rozwinąłem, byś przedstawić to szerzej.
KOD cpp:     UKRYJ  
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 tabColor["Czerwony"] = clRed;
 tabColor["Niebieski"] = clBlue;
 tabColor["Zielony"] = clGreen;
 tabColor["Żółty"] = clYellow;
 tabColor["Brązowy"] = clMaroon;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
        TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
 AnsiString aColor = Item->SubItems->Strings[ SubItem - 1];

 if(tabColor.find( aColor ) != tabColor.end())
 {
   ListView1->Canvas->Font->Color = tabColor[aColor];
 }
 else
 {
   ListView1->Canvas->Font->Color = clBlack;
 }
}
//---------------------------------------------------------------------------


Dla Twoich potrzeb, będzie to oczywiście prostsze i nie potrzebna jest żadna tablica:

tego kodu nie testowałem, pisałem z pamięci, więc może zawierać błędy.
KOD cpp:     UKRYJ  
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
        TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
 AnsiString boolValue = Item->SubItems->Strings[ SubItem - 1];

 if(boolValue == "Prawidłowy")
 {
   ListView1->Canvas->Font->Color = clGreen;
 }
 else if(boolValue == "Błędny")
 {
   ListView1->Canvas->Font->Color = clRed;
 }
 else
 {
     ListView1->Canvas->Font->Color = clBlack;
 }
}

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: poniedziałek, 13 grudnia 2010, 20:14
przez Darek_C++
OK, ale TListViev ma już wczytane dane np listę adresów www. Wyjściowo jest wypełniony np:
[Adres] [ Status]
http://www.adres1.pl - Status nie sprawdzony
http://www.adres2.pl - Status nie sprawdzony
http://www.adres3.pl - Status nie sprawdzony
http://www.adres3.pl - Status nie sprawdzony

W wątku pobieram kod HTML danej strony i w zależności od wyniku operacji tekst w komórce powinien zmienić status na np "Jest" kolor zielony "Nie ma" kolor czerwony .
Innymi słowy jak zmienić kolor tekstu np dla kolumny [Nagłówek 4] -> tekst "czerwony" który jest koloru czerwonego w kodzie jest to:
ListView1->Items->Item[2]->SubItems->Strings[2] = "Czerwony";

Czyli zmienić kolory dla już istniejących danych w komórkach ?

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: poniedziałek, 13 grudnia 2010, 20:38
przez Cyfrowy Baron
No przecież testowy program zmienia kolor tekstu już znajdującego się w tabeli. Zdarzenie OnCustomDrawSubItem działa dynamicznie, reaguje na zmianę zawartości komórek. Podałem Tobie gotowe rozwiązanie. Numer kolumny określa zmienna SubItem, więc jeżeli to ma być kolumna 4, to wystarczy dodać warunek if(SubItem == 3) a potem w tym warunku kolejne sprawdzające zawartość wierszy. Zdarzenie sprawdza zawartość każdego wiersza.
Nie rozumiem z czym masz jeszcze problem. :roll:

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: poniedziałek, 13 grudnia 2010, 20:42
przez Darek_C++
Zaraz to przetestuje na działającym programie...
Niestety, ale nie działa zgodnie z oczekiwaniem :(
Użycie w kodzie wątku [nieistotne fragmenty pominąłem]:
KOD cpp:     UKRYJ  
void __fastcall WatekSprawdz::Execute()
{
        Synchronize(&PobierzStart);
        this->WykonajZadanieGet();
        Synchronize(&PobierzStop);
}
void __fastcall WatekSprawdz::MyListView1CustomDrawSubItem(TCustomListView *Sender,
                TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
        if(Item->Index == this->nrNaListViev)
        {
                if(SubItem == 2)
                {
                        if(this->kodOdpInt == 200)
                        {
                           Sender->Canvas->Font->Color = clGreen ;
                        }
                        else
                        {
                           Sender->Canvas->Font->Color = clRed;
                        }
                }
        }
}

void __fastcall WatekSprawdz::PobierzStop()
{
        this->End = GetTickCount();

        String czasZadania =  FloatToStr((this->End - this->Start) / 1000) + " s.";
        ListView1->Items->Item[this->nrNaListViev]->SubItems->Strings[0] = (String) this->kodOdpInt;
        ListView1->Items->Item[this->nrNaListViev]->SubItems->Strings[2] = czasZadania;
        this->ListView1->OnCustomDrawSubItem = MyListView1CustomDrawSubItem;
}
 

Wątki wywołuje w timerze wiec nieraz działa kilka jednocześnie.
Na początku się kolorują, ale jak przesunę suwakiem TListView zmieniają się na czarne :(

W polu klasy wątka nrNaListViev jest nr lini z ListView z jakiej został pobrany adres do sprawdzenia.

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: niedziela, 19 grudnia 2010, 01:19
przez Darek_C++
Jakiego innego działającego sposobu nie ma na to kolorowanie w TListViev ?

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: niedziela, 19 grudnia 2010, 11:38
przez Cyfrowy Baron
Człowieku! To nigdy nie będzie Tobie działać, bo Ty nie rozumiesz zasady działania zdarzeń OnDraw, a tutaj OnCustomDraw. To jest wewnętrzne zdarzenie obiektu ListView i wszystkie warunki odnoszące się do zawartości ListView muszą być uzależnione od tego obiektu lub argumentów zdarzenia. To oznacza, że ten warunek if(this->kodOdpInt == 200) nie ma racji bytu w tym zdarzeniu, gdyż wogóle nie jest w żadne sposób związany z obiektem ListView. Zwóć uwagę na ten fragment użytego przez Ciebie kodu if(Item->Index == this->nrNaListViev) lub tego if(SubItem == 2). Warunki są uzależnione od argumentów zdarzenia, więc są prawidłowe działają.
Kod: Zaznacz cały
                        if(this->kodOdpInt == 200)
                        {
                           Sender->Canvas->Font->Color = clGreen ;
                        }
                        else
                        {
                           Sen


To oznacza tyle, że jeżeli kodOdpInt ma wartość 200 to wszystkie teksty w SubItem2 będą zielone w przeciwnym razie będą czerwone.



Mój kod:

KOD cpp:     UKRYJ  
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
        TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
 AnsiString aColor = Item->SubItems->Strings[ SubItem - 1];

 if(tabColor.find( aColor ) != tabColor.end())
 {
   ListView1->Canvas->Font->Color = tabColor[aColor];
 }
 else
 {
   ListView1->Canvas->Font->Color = clBlack;
 }
}


bez tablicy asocjacyjnej można by go zapisać tak:

KOD cpp:     UKRYJ  
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
        TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
 if(Item->SubItems->Strings[ SubItem - 1] == "czerwony")
 {
   ListView1->Canvas->Font->Color = clRed;
 }
 else
 {
   ListView1->Canvas->Font->Color = clGreen;
 }
}


Widzisz, że warunek jest uzależniony od argumentów zdarzenia.



W Twoim przypadku by kod zadział i kolor całej kolumny kolumny SubItem zmienił kolor po zmianie wartości zmiennej kodOdpInt, musisz wymusić przerysowanie obiektu. Jest to konieczne, gdyż uzależniasz zmianę zawartości obiektu ListView od zmiennej w żaden sposób z tym obiektem nie związanej.
KOD cpp:     UKRYJ  
  this->kodOdpInt = 100;
  ListView1->Repaint();


Kolor zostanie zmieniony nie tylko w kolumnie SubItem, ale również we wszystkich po niej następujących. Jeżeli chcesz ograniczyć warunek tylko do jednej kolumny SubItem to musisz wprowadzić kontr-warunek określający kolor domyślny:

KOD cpp:     UKRYJ  
 if(SubItem == 2)
 {
  if(this->kodOdpInt == 200)
  {
   Sender->Canvas->Font->Color = clGreen ;
  }
  else
  {
   Sender->Canvas->Font->Color = clRed;
  }
 }
 else Sender->Canvas->Font->Color = clBlack;


Przemyśl zasadę działania tego zdarzenia bo kombinując po swojemu do niczego nie dojdziesz.

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: niedziela, 19 grudnia 2010, 12:25
przez Darek_C++
Problem jest taki, że podany przez Ciebie kod:
Kod: Zaznacz cały
void __fastcall TForm1::ListView1CustomDrawSubItem(TCustomListView *Sender,
        TListItem *Item, int SubItem, TCustomDrawState State, bool &DefaultDraw)
{
if(Item->SubItems->Strings[ SubItem - 1] == "czerwony")
{
   ListView1->Canvas->Font->Color = clRed;
}
else
{
   ListView1->Canvas->Font->Color = clGreen;
}
}
Uruchamiany w wielu wątkach powoduje, że przez jakiś czas cele są kolorowane prawidłowo, a po pewnym czasie wszystkie teksty robią się czarne.
Sprawdź samemu...

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: niedziela, 19 grudnia 2010, 13:24
przez Cyfrowy Baron
Sprawdź samemu...


Sprawdziłem. To o czym piszesz jest niemożliwe. Opisana przez Ciebie sytuacja może się zdarzyć tylko wtedy, gdy warunki nie zostaną spełnione lub gdy gdy ListView nie zostanie podpięty pod zdarzenie. Nie jest możliwe by kod najpierw działał, by za chwilę zupełnie bez powodu przestać działać.
Problemem nie jest samo zdarzenie i kod w nim się znajdujący lecz wątki. Podczas wykonywania kodu w wątkach, coś gdzieś się gubi, co jest o tyle prawdopodobne, że podpinasz zdarzenie dynamicznie (Sender->...). Przejrzyj dokładnie kod i sprawdź kiedy i w którym wątku obiekt ListView gubi zdarzenie.

Re: TListView gpogubienie zmiana koloru w komórkach

Nowy postNapisane: niedziela, 19 grudnia 2010, 14:28
przez Darek_C++
CB Super : 8-)
Masz rację, że działa tylko nie tak jak ja pierwotnie dałem w wątku, ale dla zdarzenia głównym oknie tam gdzie jest ListViev.

Jeszcze raz dziękuję.