TColorsGrid - komponent do wyboru koloru z zadanej palety

2

W projekcie, nad którym pracuję już bodaj szósty miesiąc, potrzebuję użyć dedykowanego komponentu, który pozwoli użytkownikowi wybrać kolor z zadanej palety; A że interfejs programu będzie zupełnie kastomowy - piszę kolejny komponent praktycznie od podstaw, dlatego że musi pasować do całości i posiadać dedykowaną funkcjonalność;

Niestety Lazarus póki co nie wspiera dynamicznie łączonych paczek (packages), dlatego dla każdego nowego komponentu piszę aplikację testową, w której PaintBox "udaje" ten właściwy komponent;

Oczywiście wszystko nie jest zaprogramowane w tym testowym programie, bo to raczej nie ma sensu; Ma on pozwolić na szybkie sprawdzenie czy wszystkie algorytmy działają prawidłowo i wykluczyć tracenie czasu na rekompilowanie środowiska; W każdym razie komponent będzie bardzo podobny do tego (albo i identyczny - zastanawiam się jeszcze), który widać na poniższym zrzucie:

TColorsGrid.png

To co widać po lewej jego stronie to lista kafelek z kolorami (przewinięta w prawo do końca), a ta duża kafelka po prawej to podgląd koloru na trochę większej przestrzeni; Na nim będzie malowana jeszcze maska, czyli grafika PNG z półprzezroczystą fakturą, a na jej dolnej części (na jaśniejszym pasku) będzie kod koloru (specyficzny dla danej palety, nie RGB); Ramki rysowanej linią przerywaną nie będzie w ogóle - służy jedynie do testów;

Natomiast tytuł okna ustalany jest na podstawie indeksu aktywnego koloru; Jeżeli kliknie się w daną małą kafelkę, poprzednio aktywna zostanie odznaczona, nowa zostanie zaznaczona i przemalowana zostanie kafla poglądowa (ta duża); Jeśli kliknie się w puste pole, na którym nie znajduje się mała kafelka, lub w pole podglądu - tytuł okna zmieni się na odpowiedni tekst (że pod kursorem nie ma kafelka z kolorem do wyboru);

Funkcji kryjących się pod przyciskami raczej nie trzeba tłumaczyć - służą do przewijania listy kolorów;


Co sądzicie o takim komponencie? Wygląda ciekawie, czy może zbyt nudno/ubogo?

W razie czego do posta dorzucam źródła dla Lazarusa i plik wykonywalny - można się pobawić; Do kompilacji nie potrzeba żadnych dodatkowych modułów czy paczek; Kod nie jest zbytnio skomplikowany - trochę macierzy i rekordów, trochę malowania i nieco podstawowej arytmetyki; Jeżeli komuś przyda się kod, to niech korzysta bez ograniczeń.

PS: Plik wykonywalny został przemielony przez strip.exe i upx.exe.
PS1: skan pliku wykonywalnego na VirusTotal

0

w sumie nie pisałam nigdy takiego modułu czy programu do generowania kolorów, ale może ten program podsunie pomysły :
http://paletton.com/#uid=1000u0kllllaFw0g0qFqFg0w0aF

0

@kasiaKasia - to nie ma być program do generowania kolorów, tylko komponent, a że sprawdzenie wprowadzonych zmian podczas pisania komponentu kosztuje zbyt wiele czasu (rekompilacja Lazarusa trwa kilka minut, więc straciłbym ze dwie godziny łącznie na sprawdzenie wszystkiego), szybciej i wygodniej napisać sobie aplikację testową, a jak wszystko będzie w niej działać to wystarczy przenieść kod i gotowe; A jak wiadomo komponenty mają służyć do przedstawiania danych, a nie do ich generowania;

Ostatnimi czasy piszę sporo komponentów i mogę czasem jakiś przydatny kod wrzucić, a że można by przy okazji coś podyskutować, to ten dział jest raczej najbardziej odpowiedni;

PS: W kodzie w jednej metodzie są hardkodowane indeksy do obliczeń - zapomniałem ich pozamieniać przy dodawaniu nowych funkcji.

0

żle zrozumiałam treść , pomyślałam że chcesz napisać komponent do generowania kolorów
kilka pytań / uwag :

  1. Dlaczego zmienne np.: *AColor * - poprzedzasz literką "A" . Choć to nie zmienia faktu , że zmienne nazywasz bardzo ładnie , ja nawet tak nie umiem.
  2. Prev - to wstecz , a u ciebie działa tak że przesówa kwadracik w prawą stronę . Chyba na odwrót powinno dzialac *Next * z Prev
  3. Cześć kodu, gdzie masz wywałanie procedur i funkcji , ja bym umieściła w innym pliku. Kod stał by się bardziej czytelny.
type
  TMainForm = class(TForm)
    pbColorsGrid: TPaintBox;
    btnPreviousPage: TButton;
    btnPreviousColumn: TButton;
    btnNextColumn: TButton;
    btnNextPage: TButton;
    procedure FormCreate(Sender: TObject);
    procedure pbColorsGridPaint(Sender: TObject);
    procedure pbColorsGridMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure btnPreviousPageClick(Sender: TObject);
    procedure btnPreviousColumnClick(Sender: TObject);
    procedure btnNextColumnClick(Sender: TObject);
    procedure btnNextPageClick(Sender: TObject);
  private
    FPalette: TColorsGridPaletteArr;
    FAbsoluteDimensions: TColorsGridDimensions;
    FVisibleDimensions: TColorsGridDimensions;
    FVisibleColumnsRange: TColorsGridColumnsRange;
    FColorIndex: Int32;
  private
    function CalcSingleColorGridRect(AIndex: Int32): TRect;
    function CalcPreviewColorGridRect(): TRect;
  private
    function ColorIndexAtPoint(APoint: TPoint): Int32;
  private
    procedure DrawSingleColorGrid(ABox: TPaintBox; AIndex: Int32; ARect: TRect; AActive: Boolean);
    procedure DrawPreviewColorGrid(ABox: TPaintBox; AIndex: Int32; ARect: TRect);
  public
    procedure ShowNextColorsColumn();
    procedure ShowPreviousColorsColumn();
    procedure ShowNextColorsPage();
    procedure ShowPreviousColorsPage();
  end;
0
  1. Zgodnie ze stosowaną konwencją nazewnictwa, prefiks A oznacza Argument; Tak samo jak prefiks T oznacza Type, P oznacza Pointer czy I jako Interface; Recz gustu, podobnie jak użyta notacja węgierska; Dzięki temu, że stosuję się do jednej konwencji, kod jest czytelny i zrozumiały;
  2. Poklikaj jeszcze trochę a dowiesz się, dlaczego aktywny kwadracik ucieka w prawo dla Pervious i w lewo dla Next :]
  3. Owszem, można by podzielić tę klasę, jednak jest to tylko aplikacja testowa, nad którą nie mogę ślęczeć zbyt długo - sprawdzam algorytmy i jak wszystko działa dobrze, to przenoszę je do odpowiedniego modułu paczki komponentów, opakowując w klasy i robiąc wszystko już na gotowo.
0

Ad. 1. Dzieki :) :) :) zawsze mi się o tych notacjach zapomina
Ad. 2. :)
Ad. 3. :)

0

Mały update:

  • dodałem kilka nowych zabezpieczeń, bo poprzedni kod miał jedną lukę,
  • dodałem informacje o wyświetlonych na ekranie kolorach, a raczej o zakresach,
  • dodałem obsługę deaktywowania interfejsu dla metody Paint;
    To tajemnicze deaktywowanie interfejsu to nic innego jak malowanie zawartości komponentu jedynie w odcieniach szarości; Wszystkie komponenty posiadają taką funkcję; Końcowy efekt ma być taki, że przy deaktywowaniu formularza (np. wywołując inny metodą ShowModal), cała jego zawartość - łącznie z obramowaniem - zostanie wyszarzona;

Ten efekt będzie można wykorzystać też w innym celu, np. deaktywując wszystkie komponenty oprócz jednego, aby wskazać użytkownikowi co ma kliknąć (inaczej pisząc - jeden kolorowy przycisk na szarym formularzu przykuje jego uwagę); Co do zastosowania tego to jeszcze się zastanawiam;

Źródła i plik wykonywalny w załączniku; Teraz zabieram się za przenoszenie kodu do właściwej klasy komponentu.

3

Komponent został właśnie ukończony; Dodane zostały poniższe funkcje:

  1. animowane przewijanie listy dla metod ShowPreviousColorsPage i ShowNextColorsPage;
  2. obsługa prawego przycisku myszy:
  3. pierwsze kliknięcie pokazuje hint z kodem koloru i krótką informacją,
  4. drugie kliknięcie (gdy hint jest widoczny) zamyka okno podpowiedzi,
  5. kliknięcie w kwadrat podglądu też aktywuje podpowiedź (i analogicznie - drugie kliknięcie ukrywa okienko),
  6. okienko podpowiedzi samo znika po upływie zadanej ilości milisekund (w aplikacji testowej po 5000ms),
  7. po zjechaniu kursorem z aktywnego kwadracika koloru (lub kwadratu podglądu) hint znika;
  8. obsługa rolki myszy:
  9. przewijanie kółka "do siebie" przewija listę w prawo, a "od siebie" w lewo (tak samo jak w systemie);
  10. nowe zdarzenia:
  11. OnColorChanged - wywoływane po zmianie koloru (zaznaczeniu innego niż aktywny),
  12. OnViewChanged - wywoływane po zmianie widoku (przy przewijaniu listy);
    Do przedstawienia końcowego efektu machnąłem niedużą aplikację testową - spakowany plik wykonywalny w załączniku:

clrsgrid.png

Program testowy posiada też inne komponenty - formatowalne etykiety (TFormatLabel), checkboxy (TCheckButton, które używają formatowalnych etykiet), tło formularza (TWindowBackground), mały przycisk do zamykania formularza (TSmallButton) oraz okienko podpowiedzi, które także jest komponentem (TTipWindow), dlatego zawsze pokazuje się wewnątrz formularza-rodzica;

Komponenty klasy TCheckButton po pierwsze przytulają po jednym TFormatLabel, aby móc formatować tekst tych przycisków (pogrubiać co potrzeba, dodać linki itd); Dodatkową funkcją tych przycisków jest możliwość pracy jako standardowe TCheckBox lub jako TRadioButton - wystarczy zmienić wartość właściwości Mode z cbmkCheck na cbmkRadio;

Jeśli chodzi o własną implementację okna podpowiedzi, to powodów jest kilka - przede wszystkim własne rysowanie, a także dużo większa możliwość manipulowania takim oknem; Własnego rysowania tłumaczyć nie trzeba, ale o co chodzi z tym manipulowaniem - pomijając możliwość nadawania z osobna tytułu i informacji, obsługuje także zawijanie tekstu, a także możliwość ustalenia czasów oczekiwania na pokazanie się okienka i jego ukrycia; Dodatkowo, podpowiedź można wywoływać na żądanie (a nie jak standardowo - po upływie określonego czasu); Inna przydatna rzecz to możliwość poruszania kursorem i nieukrywanie podpowiedzi - poruszanie kursorem w obrębie komponentu nie schowa okienka; Każdy komponent obsługujący podpowiedź potrafi schować okienko po kliknięciu PPM - wygodna rzecz;

Jeszcze jedna rzecz - blokowanie i odblokowywanie interfejsu; Wyszarzenie (to nie ustawienie Enabled na False) lub pokolorowanie całej zawartości okna to nic innego jak pętelka po komponentach formularza i zmiana właściwości InterfaceActive, co zmienia wartość pola klasy komponentu i wywołuje metodę Invalidate - nic więcej; To posłuży do wyszarzania nieaktywnych formularzy w momencie otwierania innego okna metodą ShowModal, a także do deaktywowania niektórych komponentów według potrzeby; Ta druga funkcja jest zaimplementowana w aplikacji testowej - po odznaczeniu checkbuttona enable interface deaktywowane zostają wszystkie komponenty oprócz samego buttona i jego etykiety; Zaznaczenie koloruje wszystkie komponenty;

To w sumie tyle nowości jeśli o komponent chodzi (w razie czego dopiszę coś do listy, jeśli o czymś zapomniałem); Ważna rzecz - formularza nie da się przesuwać po ekranie i to nie jest bug, a fjuczer; W docelowej aplikacji będzie to użyte do IMHO genialnego efektu, ale póki co szczegółów nie zdradzę - na to przyjdzie jeszcze czas :]

Ważne: załącznik przeskanowałem na VirusTotal i jakieś mało znane AV pokazują malware; Program nie jest zainfekowany - po prostu korzysta z własnych zasobów do obsługi kastomowych fontów i został spakowany za pomocą UPX, stąd zapewne panika;

Jeśli ktoś jest zainteresowany to może pobawić się testowym programem i ewentualnie ocenić moje dzieło; W razie jakichkolwiek pytań - pytajcie śmiało; Czekam więc na odzew.

1 użytkowników online, w tym zalogowanych: 0, gości: 1