CYFROWY BARON • PROGRAMOWANIE • Zobacz wątek - DropDownStyle dla ComboBox
Strona 1 z 1

DropDownStyle dla ComboBox

Nowy postNapisane: sobota, 2 kwietnia 2011, 23:47
przez Slynx
Piszę poprawiony komponent ComboBox z możliwością dodawania obrazków dla każdego elementu (16x16) i natrafiłem na pewien problem, a raczej pytanie.
Tak wygląda efekt, który chcę osiągnąć:

Obrazek

A tak który mam:
Obrazek

Problem w tym, że nie wiem jak to zrobić, tj. nie wiem co jest w DrawMode.Normal kontrolowanym przez system.
Może ktoś się orientuje co trzeba dodać by w osiągnąć ten efekt ? Jak opcja, właściwość jest ustawiana ? Bo source Code do komponentów NET raczej nie udostępniają, żebym sobie podejrzał ;)
--
Powinienem tam pokazać jakiś obrazek żeby było widać, że działa, ale już mniejsza o to ;p

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 00:45
przez Corvis
Nic nie kumam !!

W Builderze, żeby tak zrobić wystarczy zrobić Style -> csDropDownList

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 10:12
przez Cyfrowy Baron
Ja również nie rozumiem. :roll: Czy chodzi o sam wygląd komponentu? :oops:

Slynx napisał(a):Piszę poprawiony komponent ComboBox z możliwością dodawania obrazków dla każdego elementu (16x16)


Może chodzi o możliwość wstawiania grafiki do komponentu typu TComboBox?! Jeżeli tak to należy posłużyć się zdarzeniem OnDrawItem oraz ustawić właściwość Style komponentu na csOwnerDrawFixed.

Z wykorzystaniem komponentu TImageList do przechowywania ikon ładowanych do ComboBox1. By ikony wyglądały na liście ładnie i bez tła należy w ImageList1 ustawić właściwość ColorDepth na cd32Bit. Jeżeli komponent nie posiada takiej właściwości to trzeba pokombinować, ale o tym nie będzie teraz.

KOD cpp:     UKRYJ  
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
  ComboBox1->ItemHeight = ImageList1->Height + 2; /* dopasowanie wysokości elementów listy do wysokości ikon */
}
void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index,
        TRect &Rect, TOwnerDrawState State)
{
 TCanvas *tCanvas = ComboBox1->Canvas;
 String cText = ComboBox1->Items->Strings[Index];

 /* zmienna x pomaga w wyśrodkowaniu tekstu w pionie względem ikony */
 int x = ( ComboBox1->ItemHeight - tCanvas->TextHeight(cText) ) / 2 - 1;

 /* zmienna Index określa numer elementu listy, tutaj dodatkowo określa
    numer ikony pobieranej z ImageList1 */

 ImageList1->Draw(tCanvas, Rect.Left + 1, Rect.Top + 1, Index, true);

 tCanvas->TextOut( Rect.Left + ImageList1->Width + 2, Rect.Top + x, cText );
}


uzyskamy taki efekt:

combo1.png


Ja użyłem w ImageList1 grafiki o wymiarach 20x20, a nie 16x16 bo akurat takie miałem pod ręką.

Lepszy efekt uzyskasz jednak nieco rozbudowując ten kod:

KOD cpp:     UKRYJ  
void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index,
        TRect &Rect, TOwnerDrawState State)
{
 TCanvas *tCanvas = ComboBox1->Canvas;
 String cText = ComboBox1->Items->Strings[Index];

 int x = ( ComboBox1->ItemHeight - tCanvas->TextHeight(cText) ) / 2 - 1;

 if(State.Contains(odSelected))
 {
  tCanvas->Brush->Color = clYellow;
  tCanvas->Font->Color = clRed;
 }
 else
 {
  tCanvas->Brush->Color = ComboBox1->Color;
  tCanvas->Font->Color = ComboBox1->Font->Color;
 }

 tCanvas->FillRect(Rect);

 ImageList1->Draw(tCanvas, Rect.Left + 1, Rect.Top + 1, Index, true);

 TRect cRect = Rect;
 cRect.Left  = Rect.Left  + ImageList1->Width + 2;
 cRect.Right = Rect.Right - 1;
 cRect.Top   = Rect.Top + x;

 DrawText( tCanvas->Handle, cText.c_str(), -1, &cRect,
           DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOCLIP );

 if(State.Contains(odFocused))
 {
  tCanvas->DrawFocusRect(Rect);
 }
}


Otrzymasz taki efekt:

combo2.png


To wszystko kod dla środowiska C++Builder. Mnie nie pytaj jak go dostosować do potrzeb VC++, gdyż nie wiem.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 15:41
przez Slynx
Wydawało mi się, że dość wyraźnie się wyraziłem. Piszę, że... piszę własną wersję komponentu, tak by można było dodać obrazki dla każdego elementu, bo standardowo NIE można. Więc jeśli piszę samemu to oczywiście, że DrawMode = csOwnerDrawFixed.
Wyrażnie powiedziałem, że gdy komponent rysowany jest przez System (DrawMode = Normal) to uzyskuje efekt jak na pierwszym obrazku. Natomiast gdy chcę ręcznie pokierować rysowaniem (czyli obsłużyć OnDraw) ustawiając DrawMOde = csOwnerDrawFixed (choć w .NET jest to chyba OwnerDrawFixed) uzyskuje efekt jak na drugim obrazku. A pytanie brzmiało - Czego mi brakuje w obsłudze rysowania by uzyskać efekt jak na pierwszym obrazku.

Czegoś po prostu nie ustawiłem, czegoś co jest ustawione przy DrawMode = Normal. Nie wiem, jak jaśniej to przedstawić.

To co napisałeś Cyfrowy Baronie jest właśnie tym co już mam. Teraz chodzi mi o to, by dodać taki wygląd jak na pierwszym (wstawionym przeze mnie) obrazku.
Chyba widać różnicę ? (Poszarzałe tło pierwszego elementu - i to nie jest jednolity kolor)

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 20:12
przez Cyfrowy Baron
Slynx napisał(a):Wyrażnie powiedziałem, że gdy komponent rysowany jest przez System (DrawMode = Normal) to uzyskuje efekt jak na pierwszym obrazku. Natomiast gdy chcę ręcznie pokierować rysowaniem (czyli obsłużyć OnDraw) ustawiając DrawMOde = csOwnerDrawFixed


W C++Builder nie ma właściwość DrawMode, a csOwnerDrawFixed znajduje się we właściwości Style. Zmiana właściwości Style nie zmienia wyglądu tegoż obiektu. Spróbuj z wartością csOwnerDrawVariable, która również pozwala rysować w tym komponencie.
To tyle jeżeli chodzi o podobieństwa w C++Builder i VC++. Tutaj może pomóc tylko osoba używająca środowiska VC++.

Slynx napisał(a):A pytanie brzmiało - Czego mi brakuje w obsłudze rysowania by uzyskać efekt jak na pierwszym obrazku.

Niczego nie brakuje, wygląda raczej na to, że u Ciebie ustawienie stylu csOwnerDrawFixed wyłącza style Windows XP/Vista\7. Nie pamiętam już jak to było we wcześniejszych wersjach środowiska C++Builder, ale tam przy zmianie stylu na ręczne rysowanie też się chyba wyłączał styl Windows XP. Sytuacja zmieniła się dopiero w nowszych wersjach środowiska, gdy zmieniły się również biblioteki, wcześniej nie dało się nic z tym zrobić, oczywiście poza napisaniem komponentu od podstaw. Jeżeli masz taką możliwość, to sprawdź, czy w VC++ 2010 też występuje ten problem.
Slynx napisał(a):Chyba widać różnicę ? (Poszarzałe tło pierwszego elementu - i to nie jest jednolity kolor)


To gradient i takie efekt dla wybranego elementu dałoby się uzyskać ryzując zamiast pojedynczego koloru - gradient. Problemem pozostaje jednak sam przycisk rozwijania listy, gdyż akurat na nim rysować się nie da. Trudno jednak mi coś doradzić, gdyż w C++Builder ten komponent korzysta z API i tam jest zdefiniowany, natomiast w przypadku platformy .NET korzysta z .NET Framework i chyba tam właśnie jest zdefiniowany jego wygląd.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 21:29
przez Cyfrowy Baron
Kod na efekt z gradientem:

Plik nagłówkowy np. Unit1.h
KOD cpp:     UKRYJ  
private:
        Graphics::TBitmap *cBmp;


Plik źródłowy np. Unit1.cpp
KOD cpp:     UKRYJ  
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
 ComboBox1->ItemHeight = ImageList1->Height + 2;

 cBmp = new Graphics::TBitmap;
 cBmp->Width = ComboBox1->Width;
 cBmp->Height = ComboBox1->Height;

 int l = 0;

 for(int g = 0; g <= cBmp->Height; g++)
 {
   l += 3;
   TColor kolor = RGB(255 - l, 255 - l, 255 - l);

   cBmp->Canvas->Pen->Color = kolor;
   cBmp->Canvas->MoveTo(0, g);
   cBmp->Canvas->LineTo(cBmp->Width, g);
 }
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBox1DrawItem(TWinControl *Control, int Index,
        TRect &Rect, TOwnerDrawState State)
{
 TCanvas *tCanvas = ComboBox1->Canvas;
 String cText = ComboBox1->Items->Strings[Index];

 int x = ( ComboBox1->ItemHeight - tCanvas->TextHeight(cText) ) / 2 - 1;

 tCanvas->Brush->Style = bsSolid;

 if(State.Contains(odSelected))
 {
  tCanvas->Brush->Color = clYellow;
  tCanvas->Font->Color = clRed;
 }
 else
 {
  tCanvas->Brush->Color = ComboBox1->Color;
  tCanvas->Font->Color = ComboBox1->Font->Color;
 }

 if(State.Contains(odComboBoxEdit))
 {
  tCanvas->Brush->Bitmap = cBmp;
  tCanvas->Font->Color = clBlack;
 }

 tCanvas->FillRect(Rect);

 ImageList1->Draw(tCanvas, Rect.Left + 1, Rect.Top + 1, Index, true);

 TRect cRect = Rect;
 cRect.Left  = Rect.Left  + ImageList1->Width + 5;
 cRect.Right = Rect.Right - 1;
 cRect.Top   = Rect.Top + x;

 tCanvas->Brush->Style = bsClear;
 DrawText( tCanvas->Handle, cText.c_str(), -1, &cRect,
           DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS | DT_NOCLIP );

 if(State.Contains(odFocused))
 {
  tCanvas->DrawFocusRect(Rect);
 }
}


A tak to wygląda:

combobox.png


Mój się nieco różni od tego, który Ty przedstawiłeś, ale ja korzystam z Windows XP i ze stylem tego systemu tak to właśnie wygląda.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: niedziela, 3 kwietnia 2011, 21:47
przez Slynx
Ok, dzięki za informację. Z tego co wiem to komponenty do wersji 2008 Visuala są w wersji 2.0, dla Visuala 2010 wszystkie są w wersji 4.0, więc może tam znajduje się różnica.
Aktualnie pobieram wersję 2008 Proffesional Edition, która ma znacznie rozszerzone możliwości (np. pliki zasobów, ktorych nie ma w wersji EE), więc możliwe, że i w tej kwestii coś się zmieni (albo po prostu możliwość aktualizacji komponentów). Poczekamy, zobaczymy.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: poniedziałek, 4 kwietnia 2011, 09:13
przez Cyfrowy Baron
Slynx napisał(a):Aktualnie pobieram wersję 2008 Proffesional Edition, która ma znacznie rozszerzone możliwości (np. pliki zasobów, ktorych nie ma w wersji EE)


To niczego nie zmieni, biblioteki będą w tej samej wersji nie do końca zgodnej z Windows XP. W przypadku C++Builder 6 problem występował zarówno w wersji Personal, Enterprise jak i Professional, więc przypuszczam, że w przypadku VC++ 2008 będzie podobnie. Musiałbyś użyć wersji 2010, gdyż tylko ta będzie w pełni zgodna z Windows 7.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: poniedziałek, 4 kwietnia 2011, 12:25
przez Slynx
No niestety w wersji 2010 nie pracuję ze względu na brak Intellisense, więc musi się bez tego jakoś obejść.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: poniedziałek, 4 kwietnia 2011, 13:17
przez Cyfrowy Baron
Wcześniej czy później i tak będziesz musiał się przesiąść na nowsze wersje środowiska, szczególnie jeżeli chcesz tworzyć aplikacje zgodne z Windows 7. Z tego coś się orientuję to Intelisense w Visual Studio 2010 nie działa tylko dla języka C++/CLI. Czytałem gdzieś, że jest taki program Visual Assist X 10.6, który to zmienia, nie jest to jednak program darmowy, a licencja jednostanowiskowa kosztuje $99, a do celów edukacyjnych, czyli bez zastosowania komercyjnego kosztuje już tylko $49.

Re: DropDownStyle dla ComboBox

Nowy postNapisane: poniedziałek, 4 kwietnia 2011, 15:39
przez Slynx
O tym wszystkim wiem. Szukałem na ten temat. Intellisense ma być dostępny w kolejnej wersji. W końcu wyrazili swoje oficjalne stanowisko i powiedzieli, że za dużo już pracy w to włożyli by teraz z tego rezygnować. Póki wszystko działa ( a przynajmniej częściowo, bo projekt się rozrasta i Visual zaczyna coraz bardziej spowalniać :/) będę się trzymał 2008, potem pewnie przeskoczę na najnowszą wersję jeśli żaden update nie wyjdzie do 2010.

Musiałbym po prostu język zmienić, a to jednak trochę... pracochłonne. I zaraz bym tu forum zasypał nowymi problemami związanymi z tą zmianą :/ Na razie jedyne co mogę zrobić to czekać.
Poza tym, no wiesz... wersja trial wersją trial. Może i 30 dni, ale te 30 dni to już od jakichś 6-7 miesięcy mam... ale jeśli tego oprogramowania nie sprzedaje ani nic, to zwyczajnie mam to gdzieś. Jak to będzie bardziej komercyjnie to wtedy się zaopatrzę w normalny soft.