Łączenie obiektów

0

Witajcie,

Jestem w trakcie pisania pewnego programu i na chwilę obecną nie mam dobrego pomysłu na rozwiązanie pewnej sytuacji, więc liczę na wasze pomysły.

Sytuacja wygląda tak:

Mam swój komponent, który dziedziczy po TPanel. Komponent ten ma właściwość aKratka: array of array of TKratka (też dziedziczy po TPanel). Jest to zrobione w ten sposób aby uzyskać podany efekt:

13421898955128c2c00b747.png

Następnie po wciśnięciu odpowiedniego klawisza można zmienić typ pola (małego kwadratu) - co wizualnie skutkuje zmianą koloru (każdy typ ma inny kolor)

10109432095128c32d8e3c8.png

W sytuacji gdy mamy dwa obiekty obok siebie tego samego typu to chciałbym je połączyć w jedną całość (tak jak scalanie komórek w excelu) i o ile pomyślałem sobie, że ukryję jeden obiekt a drugi normalnie rozszerzę, o tyle wymiękłem przy zrobieniu czegoś takiego:

16857295535128c413dd10b.png

Macie pomysł jak coś takiego uzyskać łącząc obiekty?

Pozdrawiam i czekam na odpowiedzi

0

takie rzeczy to się robi na np. drawgrid a nie prawie 40 panelami! Bardziej pro było by zamiast grida po prostu to namalować - wcale nie jest to takie trudne

1

Racja, TPanel nie służy do takich rzeczy. Najłatwiej utwórz nowy komponent TCustomControl i w metodzie OnPaint rysuj sobie dowolne figury, dowolnymi kolorami na canvasie.

0

Ech ... czy ja piszę po Chińsku? Mam swój komponent, który DZIEDZICZY po TPanel. To co widzicie to tylko ułamek funkcjonalności i każdy obiekt z osobna ma swoje metody. Drawgrid służy jak zauważyliście do rysowania, a w mojej aplikacji zupełnie nie o to chodzi. Obiekty są tworzone dynamicznie i nie muszą mieć struktury kwadratu dlatego są to oddzielne obiekty. Ergo potwierdziłeś moje przypuszczenia, że bez rysowania po canvasie się nie obejdzie.

Dzięki mimo wszytko

0

Dobrze zrozumieliśmy co napisałeś. Twój komponent mimo, że dziedziczy po TPanel to ma też w sobie dynamiczną tablicę kilkudziesięciu TPaneli (TKratki). Raczej to niezbyt efektywne, ale jeżeli zależy Ci to tak zostawić, to musisz zmodyfikować TKratke aby rysowała tylko wybrane krawędzie.

0

a myślisz, że tdrawgrid (albo tstringgrid) to jest panel i na nim np. 1000 innych paneli, które też każdy obiekt z osobna ma swoje metody?? To co stworzyłeś to jest po prostu koszmar. Przy siatce 100x100 masz 10 000 (dziesięć tysięcy!) paneli plus jeden, każdy zajmuje zasoby, a jako iż panele dziedziczą po TWinControl zajumją tych zasobów znacznie więcej bo każdy ma uchwyt i własne okno (nie tform w rozumieniu VCL). To jest po prostu masakra i tego się tak nie robi!

0

Sądzę, że możesz zastosować pewien trik, który wizualnie spowoduje oczekiwany efekt.

Dla wszystkich kratek zastosuj domyślnie:

BevelInner := bvRaised;
BevelKind := bkNone;
BevelOuter := bvLowered;
BorderStyle := bsNone;

Natomiast dla kratek, które są w kolorze ustaw:

BevelInner := bkNone;
BevelOuter := bkNone;

by potem przywrócić domyślne wartości.

Efekt, który uzyskałem

user image

0

ergo i opi efekt taki jak mniej więcej opisaliście udało mi się uzyskać już wcześniej ale dla przykładu każdy kratka ma popup'a w zależności od tego co na danej kratce jest to popup jest budowany dynamicznie w oparciu o dane z danej kratki. W przypadku ukrycia krawędzi w zależności od tego w którym miejscu user kliknie na danym obszarze pokazuje mu się inne menu (to jeszcze idzie obejść) ale są jeszcze inne metody, których się obejść nie da. Dlatego zależy mi na tym aby to był jeden duży obiekt (bo np napis <<caption>> musi iść przez 3 kratki). A co do ciebie abrakadaber to znam specyfikę draw i string grida i nie musisz mnie uczyć podstaw projektowania bo znam się na tym dobrze, specyfika programu, której nie znasz wymaga takiego, a nie innego rozwiązania więc zostaw swoje wywody na dział newbie jeżeli nie umiesz rozwiązać mojego problemu.

0

Zadam pytanie może inaczej, co myślicie o metodzie polygon do takiego zastosowania?

1

A co do ciebie abrakadaber to znam specyfikę draw i string grida i nie musisz mnie uczyć podstaw projektowania bo znam się na tym dobrze,

ROTFL, dawno nie słyszałem tak zacnego dowcipu. Po tym co wymodziłeś właśnie widać jak dobrze się na tym znasz...

specyfika programu, której nie znasz wymaga takiego, a nie innego rozwiązania więc zostaw swoje wywody na dział newbie jeżeli nie umiesz rozwiązać mojego problemu.
A więc to "specyfika programu" wymaga od ciebie robienia idiotycznych rzeczy? Powiem więcej wymaga od ciebie robienia akurat w taki sposób, który nie pozwala w 100% rozwiązać problemu?? Ciekawą masz tą specyfikę... Ja tam osobiście uważam, że po wstępnej analizie stwierdziłeś, że tak będzie po prostu prościej a najwyżej później się zobaczy co cię najwidoczniej przerosło...

A co do rozwiązania to jak sobie wyobrażasz skleić kilka paneli w jeden? Możesz zamiast tamtych wstawić jeden odpowiednio przycięty ale będzie to równoznaczne z ręcznym sprawdzaniem czy ktoś kliknął w obcięty obszar czy nie.

No i nadal twierdzę, że masz do d**y projekt a teraz jedyne co ci zostało to robienie łat i obejść no ale przecież "znasz się na tym dobrze" więc powodzenia...

0

W sumie to nie wiem do czego ma to całe służyć, a najważniejsze aby działało. Przyszło mi na myśl, że możesz jeszcze taki powiększony panel prostokątny wysłać "na tyły". Panel.SendToBack spowoduje, że zostanie zakryty przez pozostałe kwadraciki i wyjdzie ten klocek tetrisa.
To co piszesz o popupie to nie jest żaden problem, w zdarzeniu OnMouseDown wyliczasz nad którą kratką nastąpiło kliknięcie, edytujesz popup, a potem go wyświetlasz: Popup1.popup(x,y);

woolfik napisał(a):

ale są jeszcze inne metody, których się obejść nie da

Jeżeli na panelu się da, to inaczej też się musi dać zrobić.

Pytasz o polygon, ale nie wiem w jakim kontekście. Ja bym jako TKratke utworzył własną klasę z parametrami figury, np. współrzędne wierzchołków, albo TRect, albo punkt i długości itp. Na tej podstawie można spokojnie rysować w komponencie głównym.

0

Polygon chciałęm zastosować do rysowania po canvasie kształtu jaki mi pasuje ale się nie sprawdził. Technicznie to chcę uzyskać taki efekt:

184323125512bb65b1e5f6.png

oraz taki

2094446046512bb7dc45928.png

0
woolfik napisał(a)

Polygon chciałęm zastosować do rysowania po canvasie kształtu jaki mi pasuje ale się nie sprawdził.

Polygon byłby bardzo dobrym rozwiązaniem, jednak jeśli każda kratka jest osobnym komponentem to nie możesz od razu rysować po kilku kratkach wykorzystując Canvas tylko jednego; Jeśli posłuchałbyś wcześniejszych rad i zastosował jedną kontrolkę (np. dziedziczącą z klasy TCustomControl) to miałbyś tylko jedną kanwę, a więc mógłbyś rysować po całej kontrolce i mając do dyspozycji tylko jedną kanwę mógłbyś skorzystać z metody Polygon;

Natomiast nie rozumiem na jakiej zasadzie masz rysowane napisy na tych klockach - nie opisałeś kiedy, jak i po co je rysujesz, oraz do czego służy ta pomarańczowa ramka.

0

Dobra już nie ważne poradziłem sobie w ten sposób, że jeżeli łączymy np kratkę A1 z A2 to A2 zwalniam i rozszerzam A1 natomiast w momencie gdy obecne A1 łączę z B1 to B1 zwalniam i rozszerzam A1. Niestety w tym momencie kratka B2 jest przykryta panelem A1 (bo to kwadrat) ale na szczęście jest coś takiego jak CreateRectRgn który robi dokładnie to czego potrzebowałem czyli wycinam miejsce gdzie znajduje się kratka B2 dzięki czemu mam dowolny kształt zachowując jedne obiekt. Odniosę się jeszcze do kwestii optymalizacyjnych. Maksymalny rozmiar całej siatki to będzie 50x50 więc naprawdę przy dzisiejszych komputerach taka ilość obiektów nie będzie nawet odczuwalna. Niestety nie mogę wam opisać całości funkcjonalności dlatego temat do zamknięcia ;).

0
woolfik napisał(a)

Dobra już nie ważne poradziłem sobie w ten sposób, że jeżeli łączymy np kratkę A1 z A2 to A2 zwalniam i rozszerzam A1 natomiast w momencie gdy obecne A1 łączę z B1 to B1 zwalniam i rozszerzam A1.

Jeśli wolisz zapychać pamięć i męczyć się z dynamicznie tworzonymi kontrolkami to rób tak, jak uważasz, jednak gdybyś tworzył "wirtualne" kratki, które nie są osobnymi kontrolkami to całość była by mało skomplikowana, rysowanie odbywałoby się o wiele szybciej i przede wszystkim prościej, a zajętość pamięci była by nieporównywalnie mniejsza;

woolfik napisał(a)

Niestety w tym momencie kratka B2 jest przykryta panelem A1 (bo to kwadrat) ale na szczęście jest coś takiego jak CreateRectRgn który robi dokładnie to czego potrzebowałem czyli wycinam miejsce gdzie znajduje się kratka B2 dzięki czemu mam dowolny kształt zachowując jedne obiekt.

Jeśli już chcesz pozostać przy swoim rozwiązaniu to oprogramuj to tak, by nie trzeba było zbytnio kombinować (poczytaj o rególe KISS) - a teraz musisz kombinować; Na dodatek w Twojej metodzie przy zwalnianiu dynamicznie stworzonych kontrolek łatwo o wycieki pamięci - ciekaw jestem, jak będzie się program zachowywać po modyfikowaniu kontrolek przez 15 minut; Oczywiście można to bezbłędnie zaprogramować, jednak jest przy tym więcej roboty, niż przy jednej kontrolce własnoręcznie przemalowywanej;

woolfik napisał(a)

Odniosę się jeszcze do kwestii optymalizacyjnych. Maksymalny rozmiar całej siatki to będzie 50x50 więc naprawdę przy dzisiejszych komputerach taka ilość obiektów nie będzie nawet odczuwalna.

Nie ucz się tak - oszczędzaj pamięć w miarę możliwości, a tworzenie maksymalnie 2500 kontrolek zamiast jednej to nie jest oszczędność, a zwykłe marnowanie pamięci i mocy obliczeniowej; Z chęcią przetestuję Twój program na moim 10-letnim laptopie :]

0

Pociągnę jeszcze odrobinę temat bo moje rozwiązanie nie jest w 100% tym co chciałem uzyskać. Czyli sugerujecie trzymać całą strukturę jako ... no właśnie TShape czy może TCustomControl? Czyli tworzymy jeden obiekt następnie w pamięci trzymam array z poszczególnymi kratkami i całość rysuję na canvasie? Jeżeli tak to mam od razu parę pytań.

  1. Każda kratka musi mieć popup menu czyli jak rozumiem oprogramowujemy onMousDown czytamy parametry x i y, sprawdzamy która kratka jest na tych współrzędnych i odpowiednio budujemy popup (to samo onKeyPress) - dobrze rozumiem?
  2. W obecnej postaci po onClick Kratka dostaje "obwódkę", która wskazuje na zaznaczony element. W przypadku waszego rozwiązania musiałbym mieć zmienną globalną i na canvasie odpowiednio rysować obwódkę tak?
  3. Mając osobne obiekty robię DrawText i mam tekst na całej szerokości/wysokości obiektu. W przypadku pojedynczego obiektu jak zrobić drawtext dla np polygona?
  4. Mając obiekty dziedziczące po TPanel z automatu mam bevel i border, w przypadku użycia jednego obiektu musiałbym to ręcznie oprogramowywać prawda?
  5. Ten pomarańczowy kwadracik, który widać na ostatnim screenie to podział danego obiektu na mniejsze, dzięki temu tekst mogę pisać jakby w dwóch obiektach. Jeżeli to będzie jeden obiekt całościowy to ... wracamy do punktu 3.

Pozdrawiam i z niecierpliwością czekam na odpowiedź,

0

Czyli sugerujecie trzymać całą strukturę jako ... no właśnie TShape czy może TCustomControl?

Osobiście wolałbym TCustomControl, bo oprogramować można własną kontrolkę od podstaw, zawierającą tylko potrzebne pola/metody; Roboty jest trochę więcej, ale warto - wszelką obsługę, rysowanie i zachowanie implementujesz sam;

Czyli tworzymy jeden obiekt następnie w pamięci trzymam array z poszczególnymi kratkami i całość rysuję na canvasie?

Dokładnie tak, tworzysz prywatne pole jako dynamiczna dwuwymiarowa macierz rekordowa i dorabiasz jej metody do modyfikacji elementów, ustalasz do niej dostęp itd. i wykorzystujesz ją podczas rysowania;

  1. Każda kratka musi mieć popup menu czyli jak rozumiem oprogramowujemy onMousDown czytamy parametry x i y, sprawdzamy która kratka jest na tych współrzędnych i odpowiednio budujemy popup (to samo onKeyPress) - dobrze rozumiem?

Tworzysz jedną właściwość PopupMenu z tylko jednym menu kontekstowym, przechwytujesz komunikat naciśnięcia odpowiedniego przycisku myszy i pokazujesz (lub nie) je, przy czym możesz wcześniej modyfikować elementy tego menu, jeśli dla różnych kratek mają być różne; Według współrzędnych obliczasz która to kratka i jakie pozycje mają być w menu, ewentualnie pokazujesz/ukrywasz lub blokujesz/odblokowujesz odpowiednie dla danej kratki;

Jednak należy zwrócić uwagę, że klasa TCustomControl nie posiada żadnych zdarzeń, a ilość właściwości jest ograniczona do niezbędnego minimum; Nawet fokusa nie ma, więc trzeba go dorobić, by móc przechwytywać wciskane klawisze; Musisz sam oprogramować fokusa oraz dodać interesujące Cię zdarzenia;

  1. W obecnej postaci po onClick Kratka dostaje "obwódkę", która wskazuje na zaznaczony element. W przypadku waszego rozwiązania musiałbym mieć zmienną globalną i na canvasie odpowiednio rysować obwódkę tak?

Nie - żadnych zmiennych globalnych; Wcześniej napisałem Ci, że dynamiczna macierz, która będzie przechowywać dane dla każdej kratki jest macierzą rekordową, stąd każdy element tablicy jest strukturą, w której zawarte są informacje o każdej kratce (takie jak wspomniana obwódka, kolor, tekst itd.); W ten sposób unikniesz zbędnych kombinacji;

  1. Mając osobne obiekty robię DrawText i mam tekst na całej szerokości/wysokości obiektu. W przypadku pojedynczego obiektu jak zrobić drawtext dla np polygona?

Jeśli dobrze rozumiem, to podczas rysowania wyliczasz pozycję danej kratki i według tych współrzędnych rysujesz obwódkę tylko i wyłącznie danej kratki - nie musisz zawsze przerysowywać całego komponentu (bo po co?); Dzięki temu, że masz jedną kontrolkę i wirtualną kratkę możesz narysować kilka kratek w jednej procedurze rysującej, przez co nie będzie zamętu z odwoływaniem się do innych obiektów-kratek; Po kliknięciu na kratkę możesz łatwo przerysować kilka kratek - wystarczy odczytać ich położenie i prostą arytmetyką obliczyć figurę, jaką trzeba narysować - tak samo dla wszelkich napisów;

  1. Mając obiekty dziedziczące po TPanel z automatu mam bevel i border, w przypadku użycia jednego obiektu musiałbym to ręcznie oprogramowywać prawda?

Owszem, bo tak jak wspomniałem wcześniej - klasa TCustomControl posiada jedynie niezbędne właściwości; Możesz dorobić sobie takie właściwości, a styl rysowania ramki implementujesz w procedurze rysującej kontrolkę; Wystarczy do tego zwykły typ wyliczeniowy lub zbiór - zależy ile wartości może przyjmować ta obwódka;

  1. Ten pomarańczowy kwadracik, który widać na ostatnim screenie to podział danego obiektu na mniejsze, dzięki temu tekst mogę pisać jakby w dwóch obiektach. Jeżeli to będzie jeden obiekt całościowy to ... wracamy do punktu 3.

Jeśli zrobisz macierz, która będzie przechowywać struktury zawierające informacje o danej kratce, to możesz w tej strukturze zawrzeć informacje na temat podziału jednej kratki na mniejsze części, lub grupy kratek na mniejsze części; Niestety nie wiem na jakiej zasadzie mają być dzielone te kratki, więc ciężko na to pytanie odpowiedzieć; Pamiętaj, że wykorzystując macierz z informacjami o kratkach możesz obliczyć położenie tej ramki i styl uzupełniania kratek; Każda struktura kratki może zawierać tablicę, w której uwzględnisz podział na mniejsze części - te informacje należy uwzględnić podczas rysowania kontrolki; Jeśli dobrze przemyślisz tą strukturę, to wystarczy jedynie w odpowiednim miejscu narysować ramkę i tekst, a w strukturach zawrzesz o nich informacje.

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