Obsługa modułu z poziomu innego modułu

Obsługa modułu z poziomu innego modułu
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

Witam,
Po dłuższej przerwie od korzystania z Lazarusa i zabawy w programowanie zdecydowałem się powrócić. Staram się wszystko robić dokładniej i rozsądniej, tak żeby mój kod był przejrzysty, bo często miałem z tym problemy. Niestety okazuje się, że moje chęci spowodowały dodatkowy problem, z którym sobie nie mogę poradzić. Całość podzieliłem na osobne moduły. Problem pojawia się jeśli jednym modułem chcę oddziaływać na drugi. W skrócie są dwa moduły. Pierwszy tworzy pusty TPanel po lewej stronie formy, drugi tworzy TButton po prawej stronie. Oba te komponenty są tworzone dynamicznie. Chciałbym osiągnąć by po naciśnięciu przycisku, Panel zmieniał kolor.

Nie potrafię znaleźć rozwiązania. Jedyne co mi przychodzi do głowy to odniesienie się do rodzica przycisku. Z tego co widzę istnieje coś takiego jak ComponentIndex. Nie wiem czy jest to to czego szukam, ale zakładam że każdy komponent musi być jakoś identyfikowane. Kwestia tylko jak się odnieść do tego konkretnego. Bo pewnie łatwiejsze będzie to gdy takie komponenty będę miał stworzone dwa, ale co jeśli będzie ich 100?

Udało mi się osiągnąć coś takiego

Kopiuj
unit Main;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls, MyPanel, MyButton;

type

  TForm2 = class(TForm)

    procedure FormCreate(Sender: TObject);
  private
  public

  end;

var
  Form2: TForm2;

implementation

{$R *.lfm}


procedure TForm2.FormCreate(Sender: TObject);
var
  Panel: TMyPanel;
  Button: TMyButton;
begin
  Panel := TMyPanel.CreateIt(Form2);
  Button := TMyButton.CreateIt(Form2);

  Panel.Show;
  Button.Show;
end;

end.

Kopiuj
unit MyPanel;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, ExtCtrls, Forms, Windows, Graphics, Controls;

type
  TMyPanel = class(ExtCtrls.TPanel)
    public
      constructor CreateIt(AOwner: TComponent);
      procedure Paint; override;
    end;

implementation

constructor TMyPanel.CreateIt(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Hide;
  Parent := AOwner as TWinControl;
  Left := 0;
  Top := 0;
  Width := 100;
  Height := 100;
end;

procedure TMyPanel.Paint;
var
  Rec :TRect;
begin
  with Canvas do
  begin
    Brush.Color := clBlack;
    Brush.Style := bsSolid;
    Pen.Style := psClear;
    with Rec do
    begin
      Left := 0;
      Top := 0;
      Right := Self.Width + 1;
      Bottom := Self.Height + 1;
    end;
    Rectangle(Rec);
  end;
end;

end.


Kopiuj
unit MyButton;

{$mode delphi}{$H+}

interface

uses
  Classes, SysUtils, ExtCtrls, Forms, Windows, Graphics, Controls, Dialogs;

type
  TMyButton = class(ExtCtrls.TPanel)
    public
      procedure ButtonClick(Sender: TObject);
      constructor CreateIt(AOwner: TComponent);
      procedure Paint; override;
    end;

implementation

procedure TMyButton.ButtonClick(Sender: TObject);
begin
  Showmessage('zmiana koloru panel');
  (Sender as TWinControl).Parent.Components[0].Destroy;
end;

constructor TMyButton.CreateIt(AOwner: TComponent);
begin
  inherited Create(AOwner);
  Hide;
  Parent := AOwner as TWinControl;
  Left := 110;
  Top := 0;
  Width := 1000;
  Height := 100;
  onClick := ButtonClick;
end;

procedure TMyButton.Paint;
var
  Rec :TRect;
begin
  with Canvas do
  begin
    Brush.Color := clGreen;
    Brush.Style := bsSolid;
    Pen.Style := psClear;
    with Rec do
    begin
      Left := 0;
      Top := 0;
      Right := Self.Width + 1;
      Bottom := Self.Height + 1;
    end;
    Rectangle(Rec);
  end;
end;

end.


I faktycznie udaje się usunąć ten Panel który chce, natomiast nie potrafię się odnieść do jego właściwości Color. Druga kwestia to jest to co pisałem powyżej, Jeśli będzie tych komponentów chociażby 10, to już nie wystarczy wpisać 0 i wiedzieć że zadziała.

edytowany 1x, ostatnio: cerrato
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
1

Przechowaj referencje tych dynamicznie tworzonych komponentów w jakichś zmiennych (np. polach klasy formy), a nie będziesz ich musiał później szukać.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Poznań
  • Postów:8775
1

Pytanie, czy chcesz to zrobić porządnie, czy żeby po prostu działało?

Moim zdaniem (są różne podejścia, ale ja się staram trzymać takiego w swojej "twórczości" ;) ) poszczególne moduły nie powinny za bardzo wiedzieć o swoim istnieniu. Zamiast tego staram się stworzyć jakiś centralny kontroler, czyli jakiś obiekt, który zarządza interakcjami między poszczególnymi elementami składowymi. W Twoim przypadku (aczkolwiek nie jest to do końca idealne, ale na początek może być) takim kontrolerem może być klasa TForm2, która odpowiada za utworzenie okienka, na którym Twoje działania maja się odbywać.

I teraz samo działanie się sprowadza do tego, że moduł/kod odpowiedzialny za obsługę wciśnięcia przycisku totalnie nie ma pojęcia o pozostałych modułach. Jego w ogóle nie obchodzi, co będzie się działo po wciśnięciu przycisku. Jedyne co ten kod robi, to przekazuje do kontrolera informację o tym, że przycisk został wciśnięty. Czyli tworzysz w klasie TForm2 procedurę o jakiejś nazwie i jedynie przekazujesz do modułu z przyciskiem, że w chwili wciśnięcia, ma on poinformować kontroler/główną klasę o takim zdarzeniu. A potem kod przycisku idzie spać i się niczym nie interesuje ;)


edytowany 2x, ostatnio: cerrato
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0

@lucasp17: a tak w ogóle to co Ty wyprawiasz? Kombinujesz jak koń pod górę, zamiast zrobić to porządnie.

Designera użyj i ustaw komponenty w odpowiedni sposób, zamiast cudować z dynamicznym tworzeniem komponentów. Natomiast swoje kontrolki wrzuć do swojego pakietu, a ten doinstaluj w IDE, tak aby dało się je wykorzystać w designerze.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0
furious programming napisał(a):

@lucasp17: a tak w ogóle to co Ty wyprawiasz? Kombinujesz jak koń pod górę, zamiast zrobić to porządnie.

Designera użyj i ustaw komponenty w odpowiedni sposób, zamiast cudować z dynamicznym tworzeniem komponentów. Natomiast swoje kontrolki wrzuć do swojego pakietu, a ten doinstaluj w IDE, tak aby dało się je wykorzystać w designerze.

Ja wiem, że wiele rzeczy cały czas robię nie do końca tak jak należy. Ale w tym przypadku jest to tylko skrócony kod, po to żeby było najłatwiej rozwiązać ten problem, o który mi chodzi i żebym zrozumiał co jest co. To dla mnie najlepszy sposób nauki na małych przykładach gdzie widzą jasno co za co odpowiada. Nie ukrywam, że nie jestem programistą, a to moje pisania to tylko luźna przygoda, która zaspokaja moje potrzeby.

cerrato napisał(a):

Pytanie, czy chcesz to zrobić porządnie, czy żeby po prostu działało?

Moim zdaniem (są różne podejścia, ale ja się staram trzymać takiego w swojej "twórczości" ;) ) poszczególne moduły nie powinny za bardzo wiedzieć o swoim istnieniu. Zamiast tego staram się stworzyć jakiś centralny kontroler, czyli jakiś obiekt, który zarządza interakcjami między poszczególnymi elementami składowymi. W Twoim przypadku (aczkolwiek nie jest to do końca idealne, ale na początek może być) takim kontrolerem może być klasa TForm2, która odpowiada za utworzenie okienka, na którym Twoje działania maja się odbywać.

I teraz samo działanie się sprowadza do tego, że moduł/kod odpowiedzialny za obsługę wciśnięcia przycisku totalnie nie ma pojęcia o pozostałych modułach. Jego w ogóle nie obchodzi, co będzie się działo po wciśnięciu przycisku. Jedyne co ten kod robi, to przekazuje do kontrolera informację o tym, że przycisk został wciśnięty. Czyli tworzysz w klasie TForm2 procedurę o jakiejś nazwie i jedynie przekazujesz do modułu z przyciskiem, że w chwili wciśnięcia, ma on poinformować kontroler/główną klasę o takim zdarzeniu. A potem kod przycisku idzie spać i się niczym nie interesuje ;)

To jest chyba dokładnie to co sam miałem na myśli. Przykład powyżej jest tylko skrótem tego wszystkiego. W obu moich modułach dzieje się dużo więcej. Ale właśnie chciałbym aby interakcja pomiędzy nimi odbywała się zupełnie gdzieś indziej.

Tylko nie wiem właśnie jak tą informacje przekazać. Mógłbyś zaproponować jakieś rozwiązanie na tym konkretnym przykładzie?

Żeby to było bardziej skomplikowane.. jeśli 2 moduł by tworzył dwa przyciski, jeden miałby zmieniać kolor np na niebieski, a drugi na żółty. Ale chciałbym by pod oba była podpięta ta sama procedura, która najpierw musi sprawdzić który przycisk został wciśnięty, a później wiedzieć do którego komponentu musi się odnieść.

edytowany 2x, ostatnio: cerrato
cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:około 9 godzin
  • Lokalizacja:Poznań
  • Postów:8775
4

dwa przyciski, jeden miałby zmieniać kolor np na niebieski, a drugi na żółty. Ale chciałbym by pod oba była podpięta ta sama procedura, która najpierw musi sprawdzić który przycisk został wciśnięty, a później wiedzieć do którego komponentu musi się odnieść

No to robisz coś w stylu

Kopiuj
procedure TForm2.ChangeColor(NewColorL TColor);

a następnie dla przycisku pierwszego dajesz w obsłudze wciśnięcia coś w stylu

Kopiuj
procedure Button1Click(Sender: TObject);
begin
   Form2.ChangeColor(clBlue);
end;  

a dla drugiego

Kopiuj
procedure Button2Click(Sender: TObject);
begin
   Form2.ChangeColor(clYellow);
end;  

Zauważ, żę tak naprawdę "kontrolera" nie obchodzi, który przycisk został wciśnięty. On jedynie dostaje informację, że ma wykonać określoną czynność. Tak samo jak przycisku - wcale nie interesuje, co konkretnie ma się wydarzyć. On jedynie przekazuje dalej informację, że coś ma zostać wykonane (w tym przypadku - że jakiś kolor ma być zmieniony na żółty), ale nie ma pojęcia ani co za element ma być pokolorowany, ani tym bardziej w jaki sposób ma to się stać.


edytowany 1x, ostatnio: cerrato
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

Zauważ, żę tak naprawdę "kontrolera" nie obchodzi, który przycisk został wciśnięty. On jedynie dostaje informację, że ma wykonać określoną czynność. Tak samo jak przycisku - wcale nie interesuje, co konkretnie ma się wydarzyć. On jedynie przekazuje dalej informację, że coś ma zostać wykonane (w tym przypadku - że jakiś kolor ma być zmieniony na żółty), ale nie ma pojęcia ani co za element ma być pokolorowany, ani tym bardziej w jaki sposób ma to się stać.

Przy czym to już nie do końca jest to co bym chciał, bo właśnie chciałbym jedną procedurę, która by obsługiwała wszystkie przyciski. Więc ona musiałaby rozróżniać, który przycisk został wciśnięty rzeczywiście

A druga kwestia Form2.ChangeColor(clYellow); tego nie mogę wstawić do innego modułu, bo on nie widzi Form2. Chyba, że do się to jakoś banalnie obejść, ewentualnie coś źle rozumiem.

edytowany 1x, ostatnio: cerrato
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:minuta
  • Lokalizacja:Gorlice
3

Może być jedna procedura do obsług OnClick wszystkich przycisków a o, który przycisk chodzi wskaże parametr Sender czyli np. tak:
Można nadać przyciskom odpowiednie wartości właściwości Tag (w tym wypadku 1 i 2). Preferuję rozpoznawanie elementu po Tag niż np. po Name ale można by i po Name tylko kod byłby inny.
i to samo zrobić na kilka sposobów (oczywiście nie podaję wszystkich możliwych):
1)

Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
const
  COLORS: array [1..2] of TColor = (clBlue, clYellow);
var
  Button: TButton absolute Sender;
begin
  Unit2.ChangeColor(COLORS[Button.Tag]);
end;
Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
const
  COLORS: array [1..2] of TColor = (clBlue, clYellow);
begin
  Unit2.ChangeColor(COLORS[(Sender as TButton).Tag]);
end;
Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
begin
  if (Sender as TButton).Tag = 1 then //przy większej liczbie buttonów zamiast drabinki if elseif lepiej zastosować case
    Unit2.ChangeColor(clBlue)
  else
    Unit2.ChangeColor(clYellow)
end;

Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

Czyli dochodzimy do tego, że i tak wszystkim komponentom muszę nadać atrybut identyfikujący, prawda?

Miang
  • Rejestracja:prawie 7 lat
  • Ostatnio:4 minuty
  • Postów:1661
1

Może by się dało jakoś wykorzystać TAction.OnUpdate ?


dzisiaj programiści uwielbiają przepisywać kod z jednego języka do drugiego, tylko po to by z projektem nadal stać w miejscu ale na nowej technologii
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0
lucasp17 napisał(a):

Czyli dochodzimy do tego, że i tak wszystkim komponentom muszę nadać atrybut identyfikujący, prawda?

Niekoniecznie. Jeśli dane zdarzenie podepniesz pod wszystkie przyciski to referencję danego (np. klikniętego) przycisku otrzymasz w parametrze Sender, o którym wspomniał już @kAzek. Nie upraszczaj problemu, a po prostu napisz co docelowo chcesz zaimplementować – dobierze się odpowiednie rozwiązanie.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

W skrócie to jest właśnie to co napisałem. Załóżmy że mam kilka przycisków w module A. Każdy z nich ma wykonywać inne operacje, ale załóżmy że ma zmieniać Panel na inny kolor.

Być może moje podejście jest niewłaściwe i dla każdego przycisku powinno się tworzyć osobną procedurę OnClick, natomiast przyciski tworzę dynamicznie w tablicy i stworzenie jednej procedury daje mi gwarancję, że tylko ją będę musiał modyfikować.

Po kliknięciu przycisku jest Sender, to fakt. Ale tak czy siak procedura musi rozróżnić, czy Sender to jest przycisk 1 czy przycisk 2. Porównać je może poprzez Tag. Czyli tak czy siak jakoś muszą być identyfikowane. Nie korzystałem z Tag, nie czytałem jeszcze o tym, zrobię to, ale zakładać że jest to właściwość, którą trzeba nadać przyciskom, by później je rozróżnić.

edytowany 1x, ostatnio: flowCRANE
KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:minuta
  • Lokalizacja:Gorlice
1

Właśnie dlatego chcemy abyś przedstawił konkretny problem to na tej podstawie dobierze się rozwiązanie. Twoje założenie ze zmianą koloru to banalny przykład a nie problem ustaw każdemu przyciskowi właściwość Tag na konkretny kolor (chyba wygodniej to w kodzie) i po kliknięciu odczytujesz z tej właściwości kolor żadne cuda...

Kopiuj
Button1.Tag:= clRed;
Button1.OnClick:= Button1Click; //jeżeli Lazarus to @ przed nazwą procedury
//lub
Button1.Tag:= RGB(255, 0, 0);
Button1.OnClick:= Button1Click; //jeżeli Lazarus to @ przed nazwą procedury
Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
begin
   Unit2.ChangeColor(TButton(Sender).Tag);
end;

No właśnie to zacznij korzystać z Tag czasem się przydaje.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
1
lucasp17 napisał(a):

W skrócie to jest właśnie to co napisałem. Załóżmy że mam kilka przycisków w module A. Każdy z nich ma wykonywać inne operacje, ale załóżmy że ma zmieniać Panel na inny kolor.

Niby różne operacje, ale to to samo – zmiana koloru tego samego komponentu.

Być może moje podejście jest niewłaściwe i dla każdego przycisku powinno się tworzyć osobną procedurę OnClick, natomiast przyciski tworzę dynamicznie w tablicy i stworzenie jednej procedury daje mi gwarancję, że tylko ją będę musiał modyfikować.

Zdarzenia tworzy się po coś i jeśli się wie po co się je tworzy, to się wie czy ma być jedno, czy wiele. Jeśli zdarzenia mają wykonywać takie same czynności, to tworzy się jedno i podpina pod zadane komponenty. Wiele dedykowanych zdarzeń tworzy się wtedy, gdy wykonywane w nich operacje są zupełnie różne i nie da się łatwo napisać kodu uniwersalnego.

Ale tak czy siak procedura musi rozróżnić, czy Sender to jest przycisk 1 czy przycisk 2.

To zależy od przeznaczenia. Sender to nic innego jak referencja komponentu wywołującego zdarzenie (zdegradowana do bazowego typu obiektów, więc trzeba skorzystać z rzutowania lub absolute, aby dobrać się do konkretnych składowych). Natomiast właściwość Tag umożliwia dodanie własnych informacji do komponentu, np. jakiejś liczby (lub wskaźnika/referencji), tak aby można je było odczytać z Sendera – to bardzo przydatne.

Nie korzystałem z Tag, nie czytałem jeszcze o tym, zrobię to, ale zakładać że jest to właściwość, którą trzeba nadać przyciskom, by później je rozróżnić.

To zwykła właściwość liczbowa, więc używa się jej tak samo jak innych właściwości liczbowych – nic szczególnego. No może tylko tyle, że nie jest ona komponentowi potrzebna do życia – nie zmienia ustawień kontrolki, a jej modyfikacja nie odpala żadnych zdarzeń. Służy jedynie programiście, do zastosowań dodatkowych.

@kAzek pokazał w jaki sposób wrzucić kolory do tagów kontrolek i jak z tych tagów później skorzystać. Przy czym przypisanie metody do właściwości zdarzeniowej w domyślnym trybie OBJFPC musi być poprzedzone operatorem @. Zresztą jeśli nie wiesz jaka jest różnica pomiędzy tymi trybami i po co się je zmienia to ich nie zmieniaj – korzystaj z domyślnego.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:2 minuty
1

Moduły i klasy powinny jak najmniej "wiedzieć" o innych modułach i klasach , to podstawa dobrego i rozprzężonego kodu. Dobrym rozwiązaniem są interfejsy

edytowany 3x, ostatnio: flowCRANE
Miang
  • Rejestracja:prawie 7 lat
  • Ostatnio:4 minuty
  • Postów:1661
1
lucasp17 napisał(a):

W skrócie to jest właśnie to co napisałem. Załóżmy że mam kilka przycisków w module A. Każdy z nich ma wykonywać inne operacje, ale załóżmy że ma zmieniać Panel na inny kolor.

to każdy ma wykonywać inną rzecz czy wykonywać to samo na innym panelu?


dzisiaj programiści uwielbiają przepisywać kod z jednego języka do drugiego, tylko po to by z projektem nadal stać w miejscu ale na nowej technologii
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
0

Z dotychczasowych opisów wygląda na to, że przycisków jest wiele, a panel jeden. Przy czym prawdziwy problem nie jest znany, bo OP posłużył się uproszczeniem. Dlatego by pasowało poznać prawdziwy problem, bo może się okazać, że trzeba będzie zupełnie inaczej podejść do jego rozwiązania.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

Przycisków wiele, Panel jeden. Kliknięcie przycisku ma powodować kilka tych samym działań, plus kilka kolejnych w zależności od wciśniętego przycisku. Dlatego chciałem to zrobić w jednej procedurze, by w razie zmian edytować tylko to jedną, ale może właściwsze jest wykonania dodatkowej procedury, która ma wykonywać te same działania po kliknięciu każdego przycisku i wtedy tak czy siak w razie poprawy będę poprawiał tylko w jednym miejscu.

Nie będę nigdy programistą i mój kod wygląda na pewno przeciętnie, wiele rzeczy da się zrobić lepiej. Mi przychodzi do głowy jakiś pomysł i od razi staram się go wprowadzić. Mi to wystarcza, jeśli coś działa tak jakbym chciał.

flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
1

Możesz skorzystać z jednego zdarzenia podłączonego pod wszystkie przyciski. Każdemu z nich nadaj inny Tag, na podstawie którego będziesz te przyciski identyfikował – czyli liczby od 0 po kolei aż do n-1. Jeśli każdy przycisk ma przede wszystkim ustalać nowy kolor dla panelu, to zadeklaruj sobie stałą macierz kolorów i tagu przycisku (pobranego ze zrzutowanego Sendera) użyj jako indeksu. Pozostałe operacje wykonaj w następnej kolejności.

Czyli zakładając że masz pięć przycisków z nadanymi właściwościami Tag od 0 do 4 i każdy z nich posiada to samo przypisane zdarzenie, zawartość zdarzenia OnClick może wyglądać tak:

Kopiuj
procedure TForm1.Button1Click(Sender: TObject);
const
  PANEL_COLORS: array [0 .. 4] of TColor = (clRed, clGreen, clBlue, clWhite, clBlack);
var
  Button: TButton absolute Sender;
begin
  // nadanie koloru panelowi
  Panel1.Color := PANEL_COLORS[Button.Tag];

  // dodatkowe operacje w zależności od klikniętego przycisku
  case Button.Tag of
    2: DoSomething();
    4: DoSomethingElse();
  end;
end;

Oczywiście to tylko uproszczenie, ale idea powinna być widoczna.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
L1
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
  • Postów:131
0

Tak, jak najbardziej. Wszystko wydaje mi się być już jasne.

Teraz tylko pytanie nieco inne, odnośnie tag. Dwa przyciski mogą mieć przypisaną taką samą wartość tego atrybutu? Chodzi mi o dwa zupełnie inne przyciski, bo tak czy siak zdarzenie onclick jest podpięte pod konkretne przyciski. Więc jeśli Jakiś inny będzie miał przypisany taki sam tag, to nic się nie wydarzy, bo i tak nie ma tego zdarzenia podpiętego pod siebie. Zupełnie dwie różne tablice przycisków mogą być identyfikowane tymi samymi numerami? Nie musi to być jakiś wyróżniający numer jeden jedyny w całym programie?

GS
  • Rejestracja:ponad 14 lat
  • Ostatnio:2 minuty
1

TAG to dowolna wartość typu INT albo WORD, typu wartości nie jestem pewien a nie mam jak sprawdzić, zresztą to mało ważne.
Same wartości mogą być zupełni dowolne i nie muszą być unikatami

KA
  • Rejestracja:prawie 20 lat
  • Ostatnio:minuta
  • Lokalizacja:Gorlice
2

Dokładnie to Longint w starszych Delphi a w nowych NativeInt
http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TComponent.Tag
ale można tam przechowywać cokolwiek może to być np. wskaźnik na obiekt lub rekord.


Nie odpowiadam na PW w sprawie pomocy programistycznej.
Pytania zadawaj na forum, bo:
od tego ono jest ;) | celowo nie zawracasz gitary | przeczyta to więcej osób a więc większe szanse że ktoś pomoże.
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około 3 godziny
  • Lokalizacja:Tuchów
  • Postów:12168
2

Tag to zwykły Integer PtrInt, a więc LongInt dla 32-bitowych procesorów lub Int64 dla procesorów 64-bitowych. Przypominam że wątek dotyczy Lazarusa, nie Delphi.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 2x, ostatnio: flowCRANE
KA
To FPC ma nadal niezależnie od platformy zawsze 32 bit?
KA
No ja wiem, że Integer czy LongInt ma 32 bit ale nie wiedziałem, że właściwość Tag jest typu PtrInt czyli LongInt ale wszystko na to wskazuje https://www.freepascal.org/docs-html/rtl/classes/tcomponent.tag.html co jest dziwne, bo Lazarus wcześniej niż |Delphi obsługiwał platformy 64 bitowe i myślałem, że będzie to jeżeli nie jak w Delphi NativeInt (który jak się okazuje w FPC też ma zawsze 32 bit) to Int64.
flowCRANE
Dobrze myślisz – faktycznie Tag to PtrInt, a tego rozmiar jest zależny od typu procesora. Muszę poprawić post.
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)