Nadanie zdarzenia dynamicznemu komponentowi

0

Witam. Zacząłem pisać sudoku. Wszystko pięknie, aż do czasu.
Mam problem w przypisaniem zdarzenie do dynamicznego komponentu.

//prototyp
procedure shows(Sender: TObject);
    procedure pop(Sender: TObject);

//definicja
procedure TForm1.pop(Sender: TObject);
begin
   showmessage('byle co');
end;    

procedure TForm1.shows(Sender: TObject);
  var i:integer;
    j:integer;
begin
   for i:=0 to 8 do
      for j:=0 to 8 do
           l[i][j]:=nil;
   for i:=0 to 8 do
      for j:=0 to 8 do
      begin
       if(t[i][j] <> 0) then
       begin
          l[i][j]:=TLabel.Create(self);
          l[i][j].caption:=inttostr(t[i][j]);
          l[i][j].left:=y+25*i;
          l[i][j].top:=x+25*j;
          l[i][j].width:=25;
          l[i][j].height:=25;
          l[i][j].visible:=true;
          l[i][j].parent:=self;
          l[i][j].Font.Size:=25;
          l[i][j].OnClick:=pop;
       end;
      end;
end;

Błąd:

unit1.pas(78,31) Error: Wrong number of parameters specified for call to "pop"

Chciałbym, aby po naciśnięciu w TLabel pojawiło mi się ten tekst (chodź w przyszłości to zmienię).
Dziękuje.

0

Czego tablicą jest l? Bo u mnie taki kod jak poniżej, kompiluje się i działa bez problemów.

//...
  public
    a : array of TLabel;
    procedure Pop(Sender : TObject);
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

procedure TForm1.Pop(Sender : TObject);
begin
  ShowMessage('Test');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SetLength(a, 1);
  a[0] := TLabel.Create(Self);
  a[0].Caption := 'Kliknij mnie';
  a[0].Left := 10;
  a[0].Top := 100;
  a[0].Parent := Self;
  a[0].OnClick := Pop;
end;
0

@olesio Podsyłam deklaracje klasy:
Ale coś mi się wydaję, że źle zrobiłem :D

unit Unit1;
{$mode objfpc}{$H+}
interface
uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls;
type
  { TForm1 }
  TForm1 = class(TForm)
    btn1: TButton;
    btn2: TButton;
    btn3: TButton;
    Button1: TButton;
    procedure btn1Click(Sender: TObject);
    procedure btn2Click(Sender: TObject);
    procedure btn3Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure los(Sender: TObject);
    procedure clear(Sender: TObject);
    procedure shows(Sender: TObject);
    procedure pop(Sender: TObject);
  private
    { private declarations }
  public
    type tab = array[0..8, 0..8] of integer;
    type lab = array[0..8, 0..8] of TLabel;
      type res = array[0..8, 0..8] of TEdit;
    var t : tab;
     l : lab;
     s : res;
    poziom : integer;
    x : integer;
    y : integer;
    var obiekt: TCanvas;
  end; 
1

Nazywanie tak dziwnie typów i jednoliterowo zmiennych to na pewno zajebisty pomysł. Nie można po prostu - po ludzku tak jak poniżej. I żeby to miało "ręce i nogi"?

//...
  public
    procedure KombinujOrazPomyslZanimNapiszesz(Sender : TObject);
  end;

var
  Form1 : TForm1;

implementation

{$R *.dfm}

type
  TLabArray = array[0..8, 0..8] of TLabel;

procedure TForm1.KombinujOrazPomyslZanimNapiszesz(Sender : TObject);
begin
  ShowMessage('"Smarowanie" na forum to ZAWSZE ostateczność!');
end;

procedure TForm1.FormCreate(Sender : TObject);
var
  Arr : TLabArray;
begin
  Arr[0][0] := TLabel.Create(Self);
  with Arr[0][0] do
  begin
    Caption := 'Ech te, podstawy';
    Parent := Self;
    Left := 10;
    Top := 100;
    OnClick := KombinujOrazPomyslZanimNapiszesz;
  end;
end;
0

@wolacinio i @olesio - głównym problemem jest deklaracja metody w sekcji innej, niż public; Obstawiam, że jest niewidoczna, dlatego kod nie działa jak należy; U Ciebie @olesio jest w public i wszystko działa tak, jak działać powinno.

Ehhh, jednak się pomyliłem :]

Bez względu na to, czy przypisywana do zdarzenia metoda jest w sekcji prywatnej czy publicznej - działa za każdym razem bez problemu; Sprawdziłem na prostym przykładnie i zawsze pokazuje się stosowny komunikat:

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    procedure PrivateLabelClick(Sender: TObject);
  public
    procedure PublicLabelClick(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.PrivateLabelClick(Sender: TObject);
begin
  Application.MessageBox('Private method click', 'Private', MB_OK);
end;

procedure TForm1.PublicLabelClick(Sender: TObject);
begin
  Application.MessageBox('Public method click', 'Public', MB_OK);
end;

procedure TForm1.FormCreate(Sender: TObject);
var
  lblDynamic: TLabel;
begin
  lblDynamic := TLabel.Create(Self);

  with lblDynamic do
  begin
    Parent := Self;
    Caption := 'Dynamic label';
    Left := 50;
    Top := 50;
    OnClick := PrivateLabelClick;
  //OnClick := PublicLabelClick;
  end;
end;

end.

Tu w przykładnie lblDynamic nie jest zwalniany ręcznie z pamięci w destruktorze, ale zajmuje się tym klasa formularza (to tylko przykładowy kod testujący przypisanie metody).

0

Dziękuję za pomoc, lecz dalej nie działa. Przekopiowałem do siebie wasze kody i ten sam błąd co wcześniej :(
Czy to problem Lazarusa ?
W załączniku podsyłam projekt, sami zobaczcie. Wykomentowałem linikę

l[i][j].OnClick:=pop;

Odkomentujcie i sami zobaczcie.

unit1.pas(97,31) Error: Wrong number of parameters specified for call to "pop"

1

Ech, nie doczytałem o tym że to ma być pod Lazarusem. Nie ogarniam FPC i nie wiem jak tam należy to robić. Ale przecież logiczne, że jeśli się czepia kodu, który jest pod Delphi ok, to należy na próbę dać mu następującą dyrektywę kompilatora: {$mode DELPHI}. I widzisz, pokombinował byś najpierw sam, pogooglował, a dopiero później pisał. Nieważne czy to podstawy czy nie. Zawsze trzeba najpierw SAMODZIELNIE POKOMBINOWAĆ.

0

Ehhh, całkiem wyleciało mi z głowy...

Żeby przypisać nową metodę do komponentu musisz użyć operatora odniesienia się do adresu, czyli @; Dzięki temu kod się poprawnie skompiluje i poprawnie będzie działać:

l[i][j].OnClick := @pop; // razem z małpką

Nie wiem dlaczego akurat tak wymyślono to w FPC, ale pod Delphi wcale nie trzeba dodawać tego operatora; A ja wcześniej myślałem, że kod kompilujesz pod Delphi, dlatego upierałem się, że powinno działać...

Możesz także skorzystać z dyrektywy {$MODE DELPHI}, ale w tym przypadku nie ma takiej potrzeby.


A tak całkiem przy okazji, jeśli chodzi o interfejs (a konkretniej pola tego sudoku):

sudoku.png

dorób sobie mały offset pomiędzy polami - będzie przejrzyściej wyglądać :]

0

@olesio i @Furious Programming - jesteście najlepsi :) pięknie działa :)
A powiedz mi czy przypadkiem w Lazarusie nie powinno być oryginalnie {$mode DELPHI} bo przecież korzysta z VCL ?

0

@wolacinio - nie powinno być, bo Delphi to osobne środowisko; Ta dyrektywa służy do przystosowania kompilatora do kodu zgodnego z Delphi; I raczej nie korzysta z VCL, tylko z LCL (Lazarus Component Library).

0

Rozumiem.
Wracając do sudoku to chcę zrobić coś takiego, że po naciśnięciu pustego miejsca tam gdzie nie została wylosowana liczba, ukazywało się okienko z wyborem przycisków od 1 do 9.
Proszę sprawdzić czy dobrze mówię. W metodzie pop utworzyć dynamiczny TFrame i w TFrame utworzyć 9 przycisków TButton tak ? coś takiego ?

procedure TForm1.pop(Sender: TObject);
var
 frame: TFrame;
begin
  frame:=TFrame.Create(Form1);
  frame.Parent:=Form1;
  frame.width:=100;
  frame.height:=100;
  frame.color:=clBlack;
  frame.show;
end;  
0

Czemu nie zrobisz normalną drugą formatkę?

0

Wracając do sudoku to chcę zrobić coś takiego, że po naciśnięciu pustego miejsca tam gdzie nie została wylosowana liczba, ukazywało się okienko z wyborem przycisków od 1 do 9.

Do tego celu przydałoby się, żeby była narysowana kratka dla całej planszy sudoku; Poza tym do tego celu wystarczy jeden np. TEdit, który pokazuje się w danym polu po jego kliknięciu i znika po deaktywowaniu; Komponent byłby ukrywany, a nie usuwany z pamięci;

To by było dużo lepsze rozwiązanie, niż zabawa z przyciskami, które nie dają możliwości podawania liczb z klawiatury;

0

Zastanów się też nad PopupMenu.
W mojej wersji na czarno wpisane, na zielono wyliczone, szarym - ilość możliwych, jak najedziesz na szare to widać co można wpisać.
Można wpisać przyciskami lub przez prawy klawisz.
63009898fd.png

0

@_13th_Dragon - Formatkę czyli ?
A jak to będzie wyglądać jak bym chciał zrobić tak jak ja chce zrobić ? Tzn. po naciśnięciu pustego miejsca otwiera się okienko z przyciskami lub jakiś TPanel ? Może kawałek programu ? :D
Próbuje z TEdit i nie daję sobie radę ;/ ehh

0

Formatkę czyli pod Lazarusem po polsku, wybrać z menu "Plik" polecenie "Nowy formularz". A w ogólę to zdaje się mi, że wziąłeś sobie za ciężki program do napisania. Najpierw powinieneś ogarnąć podstawy obsługi używanego środowiska IDE. To raz, a dwa to poznać podstawy języka. Bo tak będziesz się motał i motał, ten wątek rozrośnie się do 35 podstron, a Ty dalej będziesz stał niemal w miejscu z końcowym efektem lub robił niewielkie postępy, co chwile pytając o coś nowego. A często na prawdę banalnego. Banalnego ponieważ po lekturze kursu, nawet tego o Delphi na 4p, wiedział byś znacznie więcej.

0

@wolacinio - a co to za różnica czy wyświetlisz TEdit, TComboBox, TPanel czy TForm? Rządzą tym takie same prawa, tyle że przy wyświetlaniu dodatkowego formularza musisz dodatkowo oprogramować obsługę zdarzenia OnDeactivate, żeby po deaktywacji okienka (np. kliknięciu poza nim) okenko znikało i ewentualnie pojawiało się gdzie indziej (jeśli klikniesz na inne pole);

Dlatego podałem pomysł na wykorzystanie komponentu TEdit (lub np. TComboBox czy TSpinEdit), bo taki komponent zmieści się w polu danej liczby (w jednej kratce), a np. TPanel z przyciskami już nie (tym bardziej okienko), dlatego będzie zasłaniać inne pola; Według mnie dobrze by było pokazywać TEdit i w prosty sposób sprawdzać do wpisał użytkownik; TEdit możesz utworzyć na początku programu czy na początku gry i go schować (metoda Hide lub właściwość Visible), a po kliknięciu na dane pole przesunąć go w odpowiednie miejsce i pokazać (metoda Show lub znów właściwość Visible); Po deaktywacji pola - pole znika (jest ukrywane);

Widzę, że jakoś słabo Ci to idzie, więc później postaram się przedstawić moją wizję i podam Ci przykładowy kod na jej zrealizowanie (ale nie gotowca - sam będziesz musiał zaimplementować go w swoim programie).

0

Nie mam zdarzenia

OnDeactivate

:(

Haha zrobiłem :)
Mówiłem, że nigdy się nie poddaje ? Teraz już wiecie. Sprawdzajcie, gra w załączniku :P

Edit:
Takie ważne, bardzo ważne pytanie. Czy w Lazarusie nie ma funkcji w OOP ? Bo potrzebuję zwrócić wartość, a nie chce tworzyć dodatkowych zmiennych ?

0

Standardowo pewnie nie ma zdarzenia OnDeactivate - nie ma tak lekko :]

Czy w Lazarusie nie ma funkcji w OOP ? Bo potrzebuję zwrócić wartość, a nie chce tworzyć dodatkowych zmiennych ?

W OOP nie ma czegoś takiego jak funkcje czy procedury - są metody (prywatne, chronione i publiczne) jeśli to masz na myśli; Może najpierw poczytaj co nieco o programowaniu obiektowym i o tworzeniu klas, bo jak widać jeszcze się w tym motasz;


A co do kodu, to to:

  public
    type tab = array[0..8, 0..8] of integer;
    type res = array[0..8, 0..8] of TEdit;
    type arr = array [0..2] of integer;
    type but = array[1..9] of TButton;
    var t : tab;
    b : but;
    s : res;
    a : arr;
    poziom : integer;
    x : integer;
    y : integer;
    min : integer;
    sek : integer;
    godz : integer;
    frame: TFrame;
    czas : integer;
  end;

Powinno być albo prywatne i udostępniać ewentualnie odczyt lub modyfikację przez odpowiedni zestaw właściwości, albo sensowniej być opakowane osobną klasą, która zarządza grą;

Dwa zdarzenia z poniższych:

procedure TForm1.btn1Click(Sender: TObject);
begin
     clear(self);
     poziom:=35;
     los(self);
end;

procedure TForm1.btn2Click(Sender: TObject);
begin
     clear(self);
     poziom:=25;
     los(self);
end;

procedure TForm1.btn3Click(Sender: TObject);
begin
   clear(self);
   poziom:=15;
   los(self);
end;

są zbędne, bo wystarczy mieć tylko jedno i podpiąć je do wszystkich trzech przycisków; W właściwości Tag każdego z nich ustaw wartość dla zmiennej poziom, po czym odczytaj ją w argumencie Sender - reszta jest taka sama:

procedure TForm1.btn1Click(Sender: TObject);
begin
  Clear(Self);
  Poziom := TButton(Sender).Tag;
  Los(Self);
end;

i podepnij to zdarzenie pod przyciski btn2 i btn3;

Poza tym zwróć uwagę w jaki sposób tworzysz panel i go wyświetlasz; Niepotrzebnie za każdym razem w metodzie TForm1.Pop w pętli najpierw usuwasz przycisk, po czym tworzysz go znowu, ponadto pokazujesz panel zanim utworzysz przyciski, więc dziwnie ta animacja wygląda... No i zobacz co się stanie z panelem z przyciskami po kliknięciu kilka razy na tę samą pustą kratkę - to też wygląda źle.

0

Wiem, że w OOP funkcje i procedury nazywają się metody, ale znam kilku doktorów informatyki i też mówią funkcje i procedury :)
Spoko. Znajdę czas to poprawię błędy.
A w skali od 0 ~ 10 jaką mi wystawisz ocenę za program ? Weź pod uwagę, że wcześniej nie znałem LCL i VCL(delphi) i ostatni program w Pascalu napisałem 3 lata temu.

0

Spoko :)
Pochwalę się kolejną apką :D konwerter decybelowy :p
Testuj.

0

Niestety twoje sudoku nawala i to w najistotniejszym punkcie. Losowanie (tworzenie) diagramu.
Zgodnie z zasadami cyfra nie może się powtarzać w wierszu, kolumnie i małym kwadracie. Tego ostatniego nie sprawdzasz!(metoda los()).
W metodzie shows() dodałbym:

l[i][j].Transparent:=true;

Rusunek diagramu ładuj do Image1 w inspektorze obiektów (teraz nie jest używany).
Nie jest to bład, ale brakuje mi mozliwości usunięcia wstawionej cyfry.

0

@Rekman - Tak tak, miałem to uzupełnić. Zaraz poprawię.
Można zmienić liczbę. Też dodam możliwość kasowania :)

0

@wolacinio - dlatego też ten wątek traktuj jako pomoc w rozwiązaniu problemu z przypisywaniem zdarzenia do tworzonych dynamicznie komponentów, a nie jako pomoc w zrobieniu gry czy wątek typowo do oceny Twojej twórczości;

Póki nie skończysz gry to nie ma zbytnio sensu oceniać czy poprawiać co chwilkę, więc sugeruję skończyć grę i albo w tym dziale forum pytać o poprawienie jakichś błędów czy o optymalizacje kodu, a jeśli potrzebujesz typowo poddać program do oceny, to założyć stosowny wątek w dziale Off-Topic :: Oceny i recenzje, gdzie otrzymasz tylko i wyłącznie odpowiedzi dotyczące używania czy wyglądu Twojego programu.

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