Jak przekazać wskaźnik do nowego komponentu?

Jak przekazać wskaźnik do nowego komponentu?
KA
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 11 lat
  • Postów:5
0

Witam, jestem nowy na forum i zaczynam uczyć się dopiero Delphi.
Mam zadanie zrobić listę jednokierunkową korzystając ze wskaźników i klas lub rekordów.
Wygląda to tak:

Kopiuj
Wsk = ^pacjet;
pacjet = record
  imie: String;
  nazwisko: String;
  diagnoza: String;
  next: Wsk;
end;

Wszystko mi działa, ale muszę zrobić jeszcze własny komponent. W komponencie jest jedna procedura, która zlicza ilość osób chorych z rekordu diagnoza. Do użycia tego komponentu potrzebuję dostępu do tej listy lub wskaźnika. I właśnie nie wiem jak to zrobić. Gdy przenoszę Wsk=^pacjet do zmiennych publicznych to nie widzi mi go w dalszej części programu. Proszę o pomoc i z góry dziękuję.

edytowany 1x, ostatnio: kalhusak
szopenfx
aha i pacjent nie pacjet
szopenfx
  • Rejestracja:ponad 20 lat
  • Ostatnio:4 miesiące
0

kod wstawiaj w odpowiednie znaczniki. Napisz dokładnie jak tworzysz ten wskaźnik i jak go przekazujesz.

MA
  • Rejestracja:ponad 16 lat
  • Ostatnio:10 dni
0

Nie wiem, czy skumałem o co dokładnie ci chodzi, ale tu masz przykład użycia komponentu i wskaźników:

Kopiuj
 type
   Wsk = ^pacjent;
   pacjent = record
               imie: String;
               nazwisko: String;
               diagnoza: String;
               next: Wsk;
             end;

   TMojKomponent = class(TComponent)
     private
        FMKWsk: Wsk; //pole komponentu przechowujące wskaźnik podany jako parametr metody "Wyswietl"
     public
       procedure Wyswietl(w: Wsk); //metoda komponentu, która coś tam robi z danymi przekazanymi wskaźnikiem "w"
       property MKWsk: Wsk read FMKWsk write FMKWsk; //property zapewniające dostęp do pola FMKWsk komponentu (odczyt i modyfikacja)
     end;

Var
 W: Wsk;
 MojKomponent: TMojKomponent;

implementation

{$R *.dfm}

procedure TMojKomponent.Wyswietl(w: Wsk); //metoda komponentu, która coś tam robi z danymi przekazanymi wskaźnikiem "w"
begin
  FMKWsk := w; //zapamiętanie wskaźnika przez komponent
  ShowMessage('Imie wyświetlone w metodzie "Wyswietl" komponentu: '+w^.imie);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  New(W); //utworzenie nowej zmiennej dynamicznej
  MojKomponent := TMojKomponent.Create(Self); //utworzenie komponentu
  try
    W^.imie := 'Ferdek'; //przypisanie przykładowego imienia
    ShowMessage('Imie odczytane z W: ' + W^.imie);

    MojKomponent.wyswietl(W); //wykonanie metody komponentu z użyciem wskaźnika "W"
    ShowMessage('Imie odczytane z komponentu: '+MojKomponent.MKWsk^.imie); //tu komponent użyje swojego zapamiętanego wskaźnika (bo property MojKomponent.MKWsk (czyli też pole FMKWsk) wskazuje na "W")

    MojKomponent.MKWsk^.imie := 'Boczek'; //imie zmienione przez komponenent (przez użycie property MKWsk)
    ShowMessage('Imie po zmianie przez komponenent, odczytane z W: ' + W^.imie);
  finally
    Dispose(W); //zwolnienie zmiennej dynamicznej z pamięci
    MojKomponent.Free; //zwolnienie komponentu z pamięci
  end;
end;
 
szopenfx
  • Rejestracja:ponad 20 lat
  • Ostatnio:4 miesiące
0

Przykład działa jak chcesz chyba? Komponent od momentu użycia metody Wyswietl będzie zwracał poprawny wskaźnik na przekazany rekord z właściwości MKWsk co zresztą udowodniłeś "Boczkiem". Pamiętać tylko musisz, że po wyjściu z Button1Click zostanie zwolniona pamięć pod tym wskaźnikiem (blok finally) i wszystkie pozostałe wskaźniki będą wskazywać na złe (zwolnione) miejsce w pamięci, ale to i tak nie ma znaczenia bo w tym samym miejscu zwalniasz sam komponent.
Pisałeś o rekordzie diagnoza z którym masz problem, ale tu takiego nie ma.

MA
Powyższy komentarz, dotyczący mojego przykładowego kodu, napisałeś dla mnie, czy pytacza @kalhusak-a? Edit: Zauważyłem, że w moim kodzie jest jeden błąd: "Boczek" to nie imię, tylko nazwisko, więc przypisanie do pola "imie" rekordu powinno być "Arnold" ;)
szopenfx
ale gafa - myślałem że to ta sama osoba - zmylił mnie ten sam avatar i kod, w którym jest to co mnie interesowało od autora tematu :P
KA
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 11 lat
  • Postów:5
0

Dzięki za porady. Zrobiłem podobnie do @marogo. Mój komponent wygląda tak:

Kopiuj
 
unit IloscChorych;

interface

uses
  System.SysUtils, System.Classes, Vcl.Controls, Vcl.StdCtrls;

 type
   Wsk = ^pacjet;

  pacjet = record
    Imie: string;
    Nazwisko: string;
    Data: string;
    Oddzial: string;
    Diagnoza: string;
    Next: Wsk;
  end;

type
  TIloscChorych = class(TLabel)
  private
  protected
  public
    procedure licz_chorych(root:Wsk);
  published
  end;

procedure Register;

var
temp : Wsk;
liczba_zdrowych, liczba_chorych : Integer;

implementation

procedure Register;
begin
  RegisterComponents('Standard', [TIloscChorych]);
end;


procedure TIloscChorych.licz_chorych(root:Wsk);
begin

  temp:=root;
  liczba_chorych:=0;
  liczba_zdrowych:=0;
  while temp<>Nil do
  begin

    if temp^.diagnoza='Chory' then
      begin
        liczba_chorych := liczba_chorych +1;
      end;

    if temp^.diagnoza='Zdrowy' then
      begin
        liczba_zdrowych := liczba_zdrowych +1;
      end

  end;
  Self.Caption := 'Chorych: ' + IntToStr(liczba_chorych) + #13#10 +'Zdrowych: ' + IntToStr(liczba_zdrowych);
end;
end.

W programie wywołuje procedurę:

Kopiuj
 TIloscChorych.licz_chorych(Root);

Root to adres początku listy.
Ale to i tak nie chce zadziałać. Gdy kompiluję wywala błąd: [DCC Error] Pacjeci.pas(396): E2010 Incompatible types: 'IloscChorych.Wsk' and 'Pacjeci.Wsk'.
Już naprawdę nie wiem jak przekazać wartość Root do komponentu.

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

[DCC Error] Pacjeci.pas(396): E2010 Incompatible types: 'IloscChorych.Wsk' and 'Pacjeci.Wsk'.

Bo jak widać (albo i nie widać) są to różne typy;

Swoją drogą jeśli potrzebujesz koniecznie wykorzystać swoją implementację listy, to opakuj ją w klasę i tak z niej korzystaj - unikniesz wielu problemów; I niepotrzebnie pakujesz takie rzeczy do komponentu, który de facto służy do wyświetlania danych treści, a nie do obliczeń.


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
  • Rejestracja:ponad 11 lat
  • Ostatnio:ponad 11 lat
  • Postów:5
0

Wiem, że wydaje się to dziwne, ale takie mam zadanie i muszę zrobić jakiś komponent. Chciałem zrobić taki, który zliczy mi liczbę chorych z listy. Na inny nie mam pomysły. Masz może jakiś pomysł na komponent?

babubabu
  • Rejestracja:około 13 lat
  • Ostatnio:2 miesiące
  • Lokalizacja:Łódź
  • Postów:648
0

Moja klasa obsługi logów oparta na liście jednokierunkowej:
Lista jednokierunkowa za mała pojemność. StringGrid się zawiesza przy wczytaniu dużej ilości danych.

A tu jej zmodyfikowana (moim zdaniem lepsza) wersja:

Kopiuj
unit Logs;

{==============================================================================}

{$mode objfpc}{$H+}

{==============================================================================}

interface

{==============================================================================}

uses
  Classes, SysUtils;

{==============================================================================}

// Typ określający priorytet logu.
//---------------------------
type
  TPriority = (pLowest, pLow, pNormal, pHigh, pHighest);

// Typ rekordowy określający co ma zawierać log.
//----------------------------------------------
type
  TLogData = packed record
    Time     : String[20];  // Czas w którym zapisano log.
    Msg      : String[100]; // Wiadomość logu.
    Priority : TPriority;   // Priorytet logu.
  end;

// Typ uzywany w klasie do budowania listy jednokierunkowej.
//----------------------------------------------------------
type
  PLogRec = ^TLogRec; // Typ wskaźnikowy.
  TLogRec = record
    Next : PlogRec;   // Wskaźnik na nastepny rekord na liście.
    Log  : TLogData;  // Główne dane logu.
  end;

{------------------------------------------------------------------------------}

// Klasa logów pomaga zapisywać logi z różnych prac aplikacji.
//------------------------------------------------------------
type
  TLogClass = class(TObject)
  private
    First    : PLogRec;          // Wskaźnik na pierwszy rekord w liście
    Last     : PLogRec;          // Wskaźnik na ostatni rekord w liście
    FileName : string;           // Nazwa pliku do którego klasa zapisuje logi
    LogFile  : file of TLogData; // Plik do którego klasa zapisuje logi
    Count    : QWord;            // Ilość logów na liście.
    Max      : QWord;            // Maksymalna ilość logów na liście.
  public
    constructor Create(aBuff : QWord);
    destructor Destroy; override;

    procedure Add(aMsg : String; aPriority : TPriority);
    function GetFirst : PLogRec;
    procedure Clear;
    procedure SaveToFile;
  end;

{==============================================================================}

implementation

{==============================================================================}

// Konstruktor klasy. Nadaje wartości polom FileName (aktualna data i godzina),
// First, Last, Max, Count oraz przygotowuje plik logów do zapisu.
//------------------------------------------------------------------------------
constructor TLogClass.Create(aBuff : QWord);
begin
  inherited Create;
  FileName := StringReplace(DateTimeToStr(now), '-', '.', [rfReplaceAll]);
  FileName := StringReplace(FileName, ':', '-', [rfReplaceAll]);
  FileName := FileName + '.log';
  AssignFile(LogFile, FileName);
  Rewrite(LogFile);
  First := nil;
  Last := nil;
  Max := aBuff;
  Count := 0;
end;

{------------------------------------------------------------------------------}

// Destruktor klasy. Zapisuje listę do pliku, czyści ją a następnie zamyka plik.
//------------------------------------------------------------------------------
destructor TLogClass.Destroy;
begin
  if First <> nil then
  begin
    SaveToFile;
    Clear;
  end;
  CloseFile(LogFile);
  inherited Destroy;
end;

{------------------------------------------------------------------------------}

// Dodaje log "aMsg" o priorytecie "aPriority" do listy.
// Jesli lista się przepełni jest zapisywana do pliku, a nastepnie czyszczona.
//----------------------------------------------------------------------------
procedure TLogClass.Add(aMsg : String; aPriority : TPriority);
var
  NewLog : PLogRec;
begin
// Tworzenie nowego rekordu do listy
  New(NewLog);
  NewLog^.Log.Msg := aMsg;
  NewLog^.Log.Priority := aPriority;
  NewLog^.Log.Time := DateTimeToStr(Now);
  NewLog^.Next := nil;
// Zwiększenie o 1 zmiennej przechowującej ilość logów na liście
  Inc(Count);
// Dodanie logu na koniec listy.
  if First = nil then
  begin
    First := NewLog;
    Last := First;
  end
  else
  begin
    Last^.Next := NewLog;
    Last := NewLog;
  end;
// Sprawdzanie czy lista nie jest pełna.
// Jeśli tak to zapisz listę do pliku, wyczyść i ustaw ilość na 0.
  if Count = Max then;
  begin
    SaveToFile;
    Clear;
    Count := 0;
  end;
end;

{------------------------------------------------------------------------------}

// Zwraca wskaźnik na pierwszy element listy.
//-------------------------------------------
function TLogClass.GetFirst : PLogRec;
begin
  result := First;
end;

{------------------------------------------------------------------------------}

// Czyści listę
//-------------
procedure TLogClass.Clear;
var
  ToDelete : PLogRec;
begin
  while First <> nil do
  begin
    ToDelete := First;
    First := First^.Next;
    Dispose(ToDelete);
  end;
  inherited Destroy;
end;

{------------------------------------------------------------------------------}

// Zapisuje listę do pliku
//------------------------
procedure TLogClass.SaveToFile;
var
  ToSave : PLogRec;
begin
  ToSave := GetFirst;
  while ToSave <> nil do
  begin
    Write(LogFile, ToSave^.Log);
    ToSave := ToSave^.Next
  end;
end;

{==============================================================================}

end.

Idealna nie jest ale spełnia w 100% swoje zadanie. Przy okazji sugestie dotyczące zmian/optymalizacji mile widziane w komentarzach ;)
I tak wiem, że miałem zmienić

Kopiuj
FileName := StringReplace(DateTimeToStr(now), '-', '.', [rfReplaceAll]);
FileName := StringReplace(FileName, ':', '-', [rfReplaceAll]);

na FormatDateTime ale najpierw chce zrozumieć tą funkcję a dopiero potem jej używać a ostatnio nie mam czasu na kodzenie.

edytowany 2x, ostatnio: babubabu
MA
  • Rejestracja:ponad 16 lat
  • Ostatnio:10 dni
1
kalhusak napisał(a):

Dzięki za porady. Zrobiłem podobnie do @marogo. Mój komponent wygląda tak:
W programie wywołuje procedurę:

Kopiuj
 TIloscChorych.licz_chorych(Root);

Root to adres początku listy.

Ale to i tak nie chce zadziałać. Gdy kompiluję wywala błąd: [DCC Error] Pacjeci.pas(396): E2010 Incompatible types: 'IloscChorych.Wsk' and 'Pacjeci.Wsk'.
Już naprawdę nie wiem jak przekazać wartość Root do komponentu.

Wygląda na to, że typ "Wsk" zadeklarowałeś nie tylko w module "IloscChorych", ale też jego klon w (głównym?) module programu "Pacjeci", stąd ten konflikt.

Po prostu wywal deklarację tego typu z modułu "Pacjeci", bo skoro na liście "uses" tego modułu jest moduł "IloscChorych", to dzięki temu moduł "Pacjeci" będzie
"znał" typ "Wsk".

A tak poza tym, to co to za wywołanie metody "licz_chorych":

Kopiuj
TIloscChorych.licz_chorych(Root); 

Jak już, to jeśli położyłeś komponent "TIloscChorych" na formatce modułu "Pacjeci", to wywołanie metody "licz_chorych" powinno wyglądać np. tak:

Kopiuj
Var
 IloscChorych1: TIloscChorych; //to ci się samo dopisało w definicji klasy formatki głównej

 IloscChorych1.licz_chorych(Root);

A jeśli tworzysz komponent dynamicznie (nie położyłeś go na formatce tego modułu "Pacjeci"):

Kopiuj
Var
 IloscChorych: TIloscChorych;

IloscChorych:=TIloscChorych.Create;
try
  IloscChorych.licz_chorych(Root);
  (...)
finally
  IloscChorych.Free;
end;
edytowany 3x, ostatnio: marogo
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:około godziny
  • Lokalizacja:Tuchów
  • Postów:12156
0
marogo napisał(a)

A tak poza tym, to co to za wywołanie metody "licz_chorych":

Kopiuj
TIloscChorych.licz_chorych(Root);

Jako ciekawostka - można by było w ten sposób wywołać metodę poprawnie, ale trzeba ją zrobić metodą statyczną klasy:

Kopiuj
type
  TIloscChorych = class(TLabel)
  public
    class procedure licz_chorych(root:Wsk); static;
  end;

Wtedy będzie można z niej korzystać bez tworzenia instancji klasy w pamięci (za pomocą konstruktora):

Kopiuj
TIloscChorych.licz_chorych(Root); //nie spowoduje stworzenia wyjątku EAccessViolation

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
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)