Przejdź do treści
School IT / Przestrzeń do nauki

Kolory i pędzle

W XAML wpisujesz po prostu Background="Red". W C# taki zapis się nie skompiluje — bo kolor tła to nie tekst, tylko pędzel. Poznasz zapis kolorów nazwą i kodem szesnastkowym, gotowe pędzle z klasy Brushes, kolory składane z czerwieni, zieleni i niebieskiego oraz gradient w kodzie. Zadania egzaminacyjne bardzo często wymagają zmiany koloru po kliknięciu — po tej lekcji zrobisz to bez szukania w internecie.

C# XAML Brushes SolidColorBrush Color.FromRgb #RRGGBB 90 min
CEL LEKCJI

Czego się dziś nauczysz

  • Zapiszesz kolor w XAML nazwą oraz w postaci #RRGGBB i #AARRGGBB.
  • Odróżnisz kolor (Color) od pędzla (Brush).
  • Zmienisz kolor tekstu i tła z kodu za pomocą Brushes.
  • Złożysz własny kolor z trzech składowych przez Color.FromRgb i SolidColorBrush.
  • Sprawdzisz w kodzie, jaki kolor ma kontrolka.
  • Utworzysz gradient w C#.
TEORIA

Kolor to nie tekst

błąd — program się nie skompiluje
Komunikat.Foreground = "Red";   // ✗ CS0029: Cannot implicitly convert type 'string' to 'Brush'

Właściwości Foreground i Background mają typ Brush — pędzel, czyli „czym malować”. Pędzel może malować jednym kolorem, gradientem albo nawet obrazkiem. XAML zamienia tekst "Red" na pędzel sam; w C# musisz podać gotowy obiekt pędzla.

PojęcieTyp w C#Co to jest
kolorColorsama wartość: ile czerwieni, zieleni, niebieskiego i przezroczystości
pędzel jednolitySolidColorBrushmaluje jednym kolorem
pędzel z gradientemLinearGradientBrushmaluje przejściem kolorów (lekcja 02)
gotowe pędzleBrushes.Red, Brushes.Gold…jednolite pędzle dla wszystkich nazwanych kolorów

Wszystkie te klasy są w przestrzeni nazw System.Windows.Media. Dopisz na górze pliku using System.Windows.Media;.

TEORIA

Kolory w XAML

ZapisPrzykładZnaczenie
nazwaTomato, SteelBlueponad 140 nazwanych kolorów; edytor je podpowiada
#RRGGBB#FF8000czerwony FF (255), zielony 80 (128), niebieski 00 — pomarańczowy
#AARRGGBB#80FF8000pierwsza para to alfa — nieprzezroczystość: FF pełna, 80 połowa, 00 niewidoczny
TransparentBackground="Transparent"całkowicie przezroczysty
#FF8000
#80FF8000 na białym
SteelBlue
Tomato
#00FF00

kod szesnastkowy: każda para cyfr to liczba 0–255

Jak czytać kod szesnastkowy

Cyfry szesnastkowe to 0–9 i A–F (A = 10 … F = 15). Para FF to 15 · 16 + 15 = 255, 80 to 8 · 16 = 128. W C# liczbę w tym zapisie wypiszesz formatem X2: $"{255:X2}" daje FF.

TEORIA

Gotowe pędzle: Brushes

Dla każdego nazwanego koloru klasa Brushes ma gotowy pędzel. To najprostszy sposób zmiany koloru z kodu:

MainWindow.xaml.cs
// na górze pliku: using System.Windows.Media;

Komunikat.Foreground = Brushes.Red;       // kolor tekstu napisu
Komunikat.Background = Brushes.LightYellow;
Background = Brushes.WhiteSmoke;          // tło okna (bez nazwy przed kropką)
Start.Background = Brushes.LightGreen;    // tło przycisku

Pędzel można też przepisać z jednej kontrolki na drugą: Background = przycisk.Background; ustawi tło okna na takie samo, jakie ma kliknięty przycisk.

TEORIA

Kolor z liczb: Color.FromRgb

Gdy kolor wynika z obliczeń (np. temperatura, wynik testu), składasz go z trzech liczb 0–255 i tworzysz z niego pędzel:

MainWindow.xaml.cs
Color pomaranczowy = Color.FromRgb(255, 128, 0);            // R, G, B
Komunikat.Background = new SolidColorBrush(pomaranczowy);

Color polprzezroczysty = Color.FromArgb(128, 255, 128, 0);  // A, R, G, B
Komunikat.Background = new SolidColorBrush(polprzezroczysty);

Składowe mają typ byte

Color.FromRgb przyjmuje liczby typu byte (0–255). Gdy masz zmienne int, rzutuj je: Color.FromRgb((byte)r, (byte)g, (byte)b) — ale najpierw sprawdź, że mieszczą się w zakresie. Rzutowanie 300 na byte nie zgłosi błędu, tylko da 44 (300 − 256).

TEORIA

Porównywanie kolorów

Często trzeba sprawdzić „czy pole jest już czerwone”. Pędzle z Brushes to zawsze te same obiekty, więc porównanie działa:

MainWindow.xaml.cs
if (Pole.Background == Brushes.Red)        // ✓ działa, gdy kolor ustawiono przez Brushes.Red
{
    Pole.Background = Brushes.Green;
}

Ale dwa nowe pędzle tego samego koloru to dwa różne obiekty — porównanie da false. Wtedy porównuj kolory, a nie pędzle — albo, co zwykle jest prostsze, trzymaj stan w polu klasy (np. bool zaznaczone), a kolor traktuj tylko jako jego obraz.

TEORIA

Gradient w kodzie

Gradient z lekcji 02 utworzysz też w C# — przyda się, gdy kolory mają zależeć od danych:

MainWindow.xaml.cs
// pionowy gradient: z góry (kolor 1) na dół (kolor 2)
Background = new LinearGradientBrush(Colors.LightSkyBlue, Colors.White, 90);

Trzeci parametr to kąt w stopniach: 0 — od lewej do prawej, 90 — z góry na dół. Zwróć uwagę: tu potrzebne są kolory (Colors.LightSkyBlue, typ Color), a nie pędzle (Brushes).

PRZYKŁAD

Mieszalnik kolorów RGB

Program składa kolor z trzech składowych. Przyciski − i + zmieniają czerwony, zielony i niebieski o 32. Podgląd pokazuje kolor i jego kod szesnastkowy, a napis w podglądzie sam zmienia się na biały, gdy tło jest ciemne. Wszystkie sześć przycisków obsługuje jedna metoda — co zmienić, mówi jej Tag.

Mieszalnik kolorów–✕
Twój kolor
#E08040
Czerwony
−
224
+
Zielony
−
128
+
Niebieski
−
64
+
Szary (start)

po trzech kliknięciach „+” przy czerwonym i dwóch „−” przy niebieskim

MainWindow.xaml — pełny plik
<Window x:Class="Lekcja06.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Mieszalnik kolorów" Height="420" Width="380"
        ResizeMode="CanMinimize"
        WindowStartupLocation="CenterScreen">

    <StackPanel Margin="15">
        <!-- Podgląd: tło i kolor tekstu ustawia kod -->
        <TextBlock x:Name="Podglad" Text="Twój kolor" Height="110"
                   FontSize="22" FontWeight="Bold"
                   TextAlignment="Center" Padding="0,38,0,0"/>

        <TextBlock x:Name="Kod" FontSize="20" FontFamily="Consolas"
                   TextAlignment="Center" Margin="0,10,0,12"/>

        <!-- Trzy wiersze: nazwa składowej, przyciski −/+ i wartość.
             Tag mówi metodzie, którą składową i w którą stronę zmienić. -->
        <StackPanel Orientation="Horizontal" Margin="0,0,0,6">
            <TextBlock Text="Czerwony" Width="90" Foreground="DarkRed" FontWeight="Bold" VerticalAlignment="Center"/>
            <Button Content="−" Width="40" Tag="R-" Click="Zmien_Click"/>
            <TextBlock x:Name="WartoscR" Width="50" TextAlignment="Center" VerticalAlignment="Center"/>
            <Button Content="+" Width="40" Tag="R+" Click="Zmien_Click"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,6">
            <TextBlock Text="Zielony" Width="90" Foreground="DarkGreen" FontWeight="Bold" VerticalAlignment="Center"/>
            <Button Content="−" Width="40" Tag="G-" Click="Zmien_Click"/>
            <TextBlock x:Name="WartoscG" Width="50" TextAlignment="Center" VerticalAlignment="Center"/>
            <Button Content="+" Width="40" Tag="G+" Click="Zmien_Click"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Margin="0,0,0,12">
            <TextBlock Text="Niebieski" Width="90" Foreground="DarkBlue" FontWeight="Bold" VerticalAlignment="Center"/>
            <Button Content="−" Width="40" Tag="B-" Click="Zmien_Click"/>
            <TextBlock x:Name="WartoscB" Width="50" TextAlignment="Center" VerticalAlignment="Center"/>
            <Button Content="+" Width="40" Tag="B+" Click="Zmien_Click"/>
        </StackPanel>

        <Button Content="Szary (start)" Width="120" HorizontalAlignment="Left" Click="Reset_Click"/>
    </StackPanel>
</Window>
MainWindow.xaml.cs — pełny plik
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace Lekcja06;

public partial class MainWindow : Window
{
    private const int Krok = 32;

    // Składowe koloru: 0 (brak) … 255 (pełna)
    private int r = 128;
    private int g = 128;
    private int b = 128;

    public MainWindow()
    {
        InitializeComponent();
        PokazKolor();
    }

    private void Zmien_Click(object sender, RoutedEventArgs e)
    {
        Button przycisk = (Button)sender;
        string polecenie = $"{przycisk.Tag}";          // np. "R+" albo "B-"

        int zmiana = Krok;
        if (polecenie[1] == '-')
        {
            zmiana = -Krok;
        }

        if (polecenie[0] == 'R')
        {
            r = Ogranicz(r + zmiana);
        }
        else if (polecenie[0] == 'G')
        {
            g = Ogranicz(g + zmiana);
        }
        else
        {
            b = Ogranicz(b + zmiana);
        }

        PokazKolor();
    }

    private void Reset_Click(object sender, RoutedEventArgs e)
    {
        r = 128;
        g = 128;
        b = 128;
        PokazKolor();
    }

    // Pilnuje zakresu 0–255
    private int Ogranicz(int wartosc)
    {
        if (wartosc < 0)
        {
            return 0;
        }
        if (wartosc > 255)
        {
            return 255;
        }
        return wartosc;
    }

    private void PokazKolor()
    {
        Color kolor = Color.FromRgb((byte)r, (byte)g, (byte)b);
        Podglad.Background = new SolidColorBrush(kolor);

        // Na jasnym tle czarny napis, na ciemnym — biały
        double jasnosc = 0.299 * r + 0.587 * g + 0.114 * b;
        if (jasnosc > 128)
        {
            Podglad.Foreground = Brushes.Black;
        }
        else
        {
            Podglad.Foreground = Brushes.White;
        }

        WartoscR.Text = r.ToString();
        WartoscG.Text = g.ToString();
        WartoscB.Text = b.ToString();
        Kod.Text = $"#{r:X2}{g:X2}{b:X2}";
    }
}

Co dzieje się po kolei

  • Składowe koloru są w polach r, g, b typu int, startują od 128 — to szary. Konstruktor od razu woła PokazKolor(), żeby podgląd i liczby były wypełnione.
  • Każdy z sześciu przycisków ma w Tag dwuznakowe polecenie, np. R+ albo B-. Pierwszy znak mówi, którą składową zmienić, drugi — w którą stronę.
  • $"{przycisk.Tag}" zamienia Tag na tekst, a polecenie[0] i polecenie[1] to pojedyncze znaki (char) — dlatego porównujemy je z 'R' i '-' w apostrofach.
  • Ogranicz pilnuje zakresu 0–255. Od 128 w górę kolejne wartości to 160, 192, 224 i 255 (256 zostało przycięte).
  • W PokazKolor wartości int są rzutowane na byte — bezpiecznie, bo zakres pilnuje Ogranicz. Z koloru powstaje nowy SolidColorBrush.
  • Jasność liczymy wzorem, który uwzględnia, że oko najmocniej reaguje na zieleń. Na jasnym tle napis jest czarny (Brushes.Black), na ciemnym — biały.
  • {r:X2} zapisuje liczbę szesnastkowo na dwóch znakach: 224 → E0, 64 → 40.

Sprawdź trzy rzeczy

  1. Ustaw wszystkie składowe na 0, a potem na 255. Kod pokaże #000000 i #FFFFFF, a napis w podglądzie zmieni kolor.
  2. Usuń wywołanie Ogranicz przy czerwonym i klikaj „+”. Po przekroczeniu 255 kolor nagle zrobi się ciemny — rzutowanie na byte „przekręca” liczbę.
  3. Zmień jeden Tag na "X+". Przycisk zacznie zmieniać niebieski — trafi do ostatniego else. W komentarzu zaproponuj, jak się przed tym zabezpieczyć.
ELEMENTY WBUDOWANE

Zestawienie elementów

ElementZnaczenieUwagi
BrushpędzelTyp właściwości Foreground i Background.
Brushes.Redgotowy pędzel jednolityDla każdego nazwanego koloru. Zawsze ten sam obiekt.
Colorwartość koloruSkładowe A, R, G, B typu byte.
Colors.Redgotowy kolorTyp Color, nie pędzel.
Color.FromRgb(r, g, b)kolor z trzech liczbKażda 0–255.
Color.FromArgb(a, r, g, b)kolor z przezroczystościąa = 255 — pełny, 0 — niewidoczny.
new SolidColorBrush(kolor)pędzel z koloruKażde new to nowy obiekt.
new LinearGradientBrush(k1, k2, kąt)gradient w kodzieKąt 0 — poziomo, 90 — pionowo.
#RRGGBB, #AARRGGBBkod koloru w XAMLPary cyfr szesnastkowych.
{liczba:X2}liczba szesnastkowoDwa znaki, wielkie litery.
(byte)liczbarzutowanie na 0–255Bez sprawdzenia zakresu „przekręca” wartość.
CZĘSTE BŁĘDY

Zanim utkniesz

ZapisProblem
Napis.Foreground = "Red";CS0029 — w C# potrzebny pędzel: Brushes.Red.
Napis.Foreground = Colors.Red;CS0029 — Colors daje kolor, a właściwość wymaga pędzla. Użyj Brushes.Red albo new SolidColorBrush(Colors.Red).
brak using System.Windows.Media;CS0103: The name 'Brushes’ does not exist in the current context.
Color.FromRgb(r, g, b) ze zmiennymi intCS1503 — potrzebne rzutowanie na byte.
(byte)r, gdy r wynosi 300Wynik 44 bez żadnego błędu — sprawdzaj zakres przed rzutowaniem.
Pole.Background == new SolidColorBrush(Colors.Red)Zawsze false — dwa różne obiekty pędzla.
Background="#FF80"Za mało cyfr. Kod ma 3, 6 albo 8 cyfr: #F80, #FF8800, #FFFF8800.
alfa na końcu: #FF800080 zamiast #80FF8000W WPF przezroczystość jest pierwszą parą, nie ostatnią (inaczej niż w CSS).
ZADANIA

Zadania

Każde zadanie wykonaj w nowym projekcie Aplikacja WPF. Wskazówkę otwórz dopiero wtedy, gdy utkniesz.

ZAD 1Sygnalizator na przejściu★☆☆

Okno ma duży napis (rozmiar 40, wyśrodkowany, z wewnętrznym odstępem 20) i trzy przyciski: Czerwone, Żółte, Zielone. Każdy ustawia tło napisu na odpowiedni kolor i tekst: „STÓJ”, „UWAGA”, „IDŹ”. Na żółtym tle tekst ma być czarny, na pozostałych — biały. Wszystkie trzy przyciski obsługuje jedna metoda.

Sygnalizator–□✕
IDŹ
Czerwone
Żółte
Zielone
pokaż wskazówkę
  • Przyciski rozpoznasz porównaniem sender z ich nazwami.
  • Najpierw ustaw kolor tekstu na biały dla wszystkich, a w gałęzi „żółte” zmień go na czarny.
ZAD 2Paleta szkolnych kolorów★☆☆

Szkoła ma kolory identyfikacji: #1F3A93, #F2C14E, #2E8B57, #C0392B, #7F8C8D. Zrób rząd pięciu przycisków, których tło ma te kolory (ustawione w XAML), a napisem jest kod koloru. Kliknięcie przycisku ustawia na ten sam kolor tło okna i wypisuje „Wybrano: #F2C14E”. Jedna metoda dla wszystkich, bez żadnego if.

pokaż wskazówkę
  • Pędzel możesz przepisać wprost: tło okna = tło klikniętego przycisku.
  • Kod koloru jest już w Content przycisku.
ZAD 3Termometr słowny★★☆

Okno pokazuje temperaturę, np. „12 °C — chłodno”, i przyciski −5, −1, +1, +5. Zakres od −20 do 40 °C. Kolor napisu zależy od temperatury: poniżej 0 — niebieski („mróz”), 0–15 — zielony („chłodno”), 16–25 — pomarańczowy („przyjemnie”), powyżej 25 — czerwony („upał”). Wszystkie cztery przyciski obsługuje jedna metoda, a wartość zmiany jest w Tag. W komentarzu wypisz temperatury, którymi sprawdziłeś granice przedziałów.

pokaż wskazówkę
  • Tag może zawierać liczbę ujemną, np. "-5" — int.Parse sobie z nią poradzi.
  • Kolor i opis wybierz w jednej metodzie odświeżającej łańcuchem if / else if.
ZAD 4Lampka z regulacją jasności★★☆

Okno ma ciemne tło (#202020) i duży napis-„lampkę” (np. 200 × 200, tekst „💡” albo „LAMPA”). Przyciski Ciemniej i Jaśniej zmieniają przezroczystość żółtego tła lampki w 5 krokach: 0 %, 25 %, 50 %, 75 %, 100 %. Napis „Jasność: 50%” pokazuje stan, a przyciski na granicach zakresu stają się nieaktywne. Kolor buduj przez Color.FromArgb.

pokaż wskazówkę
  • Trzymaj w polu numer poziomu 0–4, a alfę licz z niego: poziom · 255 / 4.
  • Pamiętaj o rzutowaniu na byte.
ZAD 5Niebo o różnych porach dnia★★☆

Okno ma pionowy gradient tła i przyciski Świt, Południe, Zachód, Noc. Każdy ustawia w kodzie inny gradient (np. świt: Pink → LightSkyBlue, noc: MidnightBlue → Black) oraz kolor napisu z nazwą pory dnia tak, żeby był czytelny. Przy starcie okno ustawia porę na podstawie aktualnej godziny.

pokaż wskazówkę
  • Gradient w kodzie: new LinearGradientBrush(kolor1, kolor2, 90) z kolorami z Colors.
  • Napisz metodę z parametrem (np. numerem pory), którą wywołasz z przycisków i z konstruktora.
ZAD 6Gra „Trafiony kolor”★★★

Okno pokazuje obok siebie dwa duże pola: cel (kolor ustalony w kodzie, np. 153, 204, 51) i Twój kolor. Gracz ustawia swój kolor przyciskami −/+ dla R, G i B (krok 51, więc możliwe wartości to 0, 51, 102, 153, 204, 255). Przycisk Sprawdź liczy odległość: suma różnic składowych (wartości bezwzględne) i wypisuje „Gorąco!” (0), „Ciepło” (do 102), „Letnio” (do 255) albo „Zimno” oraz liczbę prób. Po trafieniu wypisz „Trafione w 7 próbach!” i zablokuj przyciski. Przycisk Nowa gra ustawia inny cel (z tablicy kilku przygotowanych kolorów, po kolei) i zeruje próby.

pokaż wskazówkę
  • Wartość bezwzględną daje Math.Abs.
  • Kolory celów trzymaj w trzech tablicach (R, G, B) i polu z numerem aktualnego celu.
  • Wszystkie przyciski −/+ możesz włożyć do jednego panelu i blokować go w całości.
PODSUMOWANIE

Co trzeba zapamiętać

  • Foreground i Background mają typ Brush — w C# podajesz pędzel, nie tekst.
  • Brushes.Nazwa — gotowy pędzel; Colors.Nazwa — sam kolor.
  • Własny kolor: new SolidColorBrush(Color.FromRgb(r, g, b)), z przezroczystością — Color.FromArgb.
  • W XAML: nazwa, #RRGGBB albo #AARRGGBB (alfa na początku).
  • Pędzle z Brushes można porównywać; nowe pędzle — nie. Stan najlepiej trzymać w polu klasy.
  • Gradient w kodzie: new LinearGradientBrush(kolor1, kolor2, kąt).

Dokumentacja: Microsoft Learn — klasa Brushes, SolidColorBrush.

Postęp zapisuje się w tej przeglądarce.