Wspólne zmienne dla kilku formularzy

0

Próbuje w C++ Builderze (wersja C++ Builder Community Edition 11) wykorzystywać na kilku formularzach połączonych ze sobą w ramach jednego projektu (dyrektywami #include) przekazywanie i modyfikowanie zmiennych, które są zadeklarowane w osobnym pliku (rozszerzenie .h), który także dołączony jest do całości projektu. Jeśli chodzi o owy plik i dwie formy z których składa się wygenerowany projekt, to wszystko jest ok tj kompilacja i uruchomienie przechodzą bez "warningów". Problem o którym napiszę nie występował we wcześniejszych wersjach C++ Buildera. I tak najprościej, jeżeli posiadam plik o nazwie zmienne.h i zawartości:


 #ifndef _zmienne_h_
 #define _zmienne_h_

int a;
int b;
int c;
int d;
 #endif _zmienne_h_


Mogę tym zmiennym w głównej formie projektu bardzo łatwo przypisać jakieś wartości np w taki sposób:

a=StrToInt(Edit1->Text);
b=StrToInt(Edit2->Text);
c=StrToInt(Edit3->Text);
d=StrToInt(Edit4->Text);

Z kolei gdybym chciał teraz te 4 zmienne wyświetlić na kolejnej formie (która też przynależy do projektu i dyrektywami #include również jest połączona z plikiem zmienne.h) to wyświetlając ponownie te zmienne już w nowej formie (po uprzednim Form2->Show()), uzyskuje wykonując już np takie działanie w ramach nowej formy:

void __fastcall TForm2::Button1Click(TObject *Sender)
{
 Label1->Caption=IntToStr(a);
 Label2->Caption=IntToStr(b);
 Label3->Caption=IntToStr(c);
 Label4->Caption=IntToStr(d);
}

bardzow dziwne wyniki, mianowicie wszystkie "labele" wynoszą: 0 (mimo, że dostała im przyporządkowana zupełnie inna wartośc!).
I do tego wsykaują długie komunikaty warningów dotyczące zadeklarowanych zmiennych:

italics[ilink32 Warning] Warning: Public symbol '_d' defined in both module C:\USERS\ADMIN\DOCUMENTS\C_PLUS\MODULY\WIN32\DEBUG\NOWA_FORMA.OBJ and C:\USERS\ADMIN\DOCUMENTS\C_PLUS\MODULY\WIN32\DEBUG\PPRZYKLAD.OBJ
Dotyczą te komunikaty wszystkich zmiennych. Jest to o tyle dziwne, że wszystkie moduły/formy/pliki są w jednym katalogu i się "doskonale wdzią" w ramach kompilacji.
Tutaj znalazłem coś podobnego, tylko nie bardzo rozumiem sposób rozwiązania tego problemu:
https://stackoverflow.com/questions/71156202/public-symbol-tpdsc-void-defined-in-both-module-x-and-y

0

Program polega na tym, że te zmienne nie są dzielone pomiędzy różnami plikami obiektów. Najlepszym rozwiązaniem jakie tu widzę to zamiast stworzenia samych zmiennych zrób klase bądź strukture i stwórz obiekt tej klasy w gównym pliku projektu a następnie go przekazuje to poszczególnych form jako referencje.

0
ppitu napisał(a):

Program polega na tym, że te zmienne nie są dzielone pomiędzy różnami plikami obiektów. Najlepszym rozwiązaniem jakie tu widzę to zamiast stworzenia samych zmiennych zrób klase bądź strukture i stwórz obiekt tej klasy w gównym pliku projektu a następnie go przekazuje to poszczególnych form jako referencje.

Tylko w "normalnym środowisku" dla wszystkich takich zewnętrznych plików (.h) z zadeklarowanymi zmiennymi, które mogą być później zmieniane w różnych formach/modułach wystarczy zaznaczenie uprzednie - #infdef #define #endif. Co ciekawe jeżeli w C++ Builderze, coś zadeklaruje w takim pliku (.h) jako #define to jest to już widoczne dla wszystkich form. Gorzej właśnie ze zmiennymi (globalnymi), którym miały by być w różnych formach nadawane nowe wartości. Nie wiem, czy chcę się bawić w struktury/klasy i referencję, raptem dla kilku zmiennych. W g++/gcc takich problemów nie ma.Ale dzięki za podpowiedź.

0

Musisz zrobić inaczej. W headerze głównej formy np. Form1 (w tej co przypisujesz tym zmiennym wartości), w sekcji PUBLIC, deklarujesz te zmienne. Potem w dowolnej FORM wywołujesz je:

np. Form1:
a = StrToInt(Edit1->Text);
....
dalsze Form:
Label1->Caption = IntToStr( Form1->a );

Pamiętaj tylko w każdym pliku CPP Form_X dołączać header z Form1.

0
adolf napisał(a):

Musisz zrobić inaczej. W headerze głównej formy np. Form1 (w tej co przypisujesz tym zmiennym wartości), w sekcji PUBLIC, deklarujesz te zmienne. Potem w dowolnej FORM wywołujesz je:

np. Form1:
a = StrToInt(Edit1->Text);
....
dalsze Form:
Label1->Caption = IntToStr( Form1->a );

Pamiętaj tylko w każdym pliku CPP Form_X dołączać header z Form1.

Dzięki. Działa. Temat można zamknąć.

2
ppitu napisał(a):

Program polega na tym, że te zmienne nie są dzielone pomiędzy różnami plikami obiektów.

Główny problem jest taki, że kolega @davout nie wie jak tworzyć zmienne globalne dostępne z każdego miejsca w kodzie. Gdyby tylko spojrzał jak działa samo IDE, to by wysnuł jakieś wnioski. Mam na myśli jak są deklarowane i definiowane wskaźniki na globalne wskaźniki do formatek.

Zmienne globalne w pliku zmienne.h deklarujemy tak:

#ifndef _zmienne_h_
#define _zmienne_h_
extern int a;
extern int b;
extern int c;
extern int d;
#endif _zmienne_h_

Dodatkowo trzeba mieć plik zmienne.cpp

#include "zmienne.h"
int a;
int b;
int c;
int d;

W IDE musisz stworzyć nowy Unit i będziesz miał dwa pliki .cpp/.h powiązane ze sobą jak formatka, tylko bez pliku *.dfm

Jednak sama propozycja:

ppitu napisał(a):

Program polega na tym, że te zmienne nie są dzielone pomiędzy różnami plikami obiektów. Najlepszym rozwiązaniem jakie tu widzę to zamiast stworzenia samych zmiennych zrób klase bądź strukture i stwórz obiekt tej klasy w gównym pliku projektu a następnie go przekazuje to poszczególnych form jako referencje.

Jest bardzo dobra i mniej więcej jakoś tak można by to było rozwiązać.

0

@Mr.YaHooo: Przyznam się szczerze, że dawno nie używałem zmiennych globalnych w takiej formie jak to robi autor, jednak struktura dla takich dany według mnie powinno to być minimum.

0

@ppitu oczywiście, że używanie gołych zmiennych globalnych do takiego zastosowania jest słabe. Jednak niech autor się nauczy i wie jak je stosować. W końcu to są podstawowe elementy języka ;)

0

Tu wystarczy wykorzystać klase TForm i w public zadeklarować zmienne. Nic nie trzeba kombinować, ani tworzyć nowego.

2

@adolf oczywiście, że trzymanie stanu aplikacji w zmiennych znajdujących się w sekcji public formularza głównego nie jest łamaniem dobrych zasad :D To ja już wolę jednak zmienne globalne ;)

2

Zmienne globalne to samo zło.
Stwórz nową klasę. Zwykle taka klasa nazywa się "Model". Np

class DataModel : public TObject
{
    int a;
    int b;
    int c;
    int d;
public:
    int getA() const;
    int getB() const;
    int getC() const;
    int getD() const;

    void perfromSomeActionOnData(int x, int y);

    void ( __closure *onAChanged)(int);
    void ( __closure *onBChanged)(int);
    void ( __closure *onCChanged)(int);
    void ( __closure *onDChanged)(int);
};

Tworzysz sobie gdzieś instancje tej klasy i przekazujesz skaźnik do nie do poszczególnych formularzy, które korzystają z tej klasy.

Najlepsze w tym wzorcu jest to, że w momencie, kiedy jeden formularz, zrobi jakąś modyfikację inny zainteresowany formularz może dostać notyfikację, że dana wartość się zmieniła i na żywo zaktualizować wyświetlane dane.

Disclaimer: nie korzystam C++ Builder od +15 lat, więc nie pamiętam dokładnie jak korzystać z tych __closure i innych rozszerzeń C++ Builder (VCL).

0

@MarekR22 pomysł bardzo dobry. Pytanie tylko, czy pytający sobie z tym poradzi.

Co do samego działania __closure powinno być dobrze.

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