C++ Forms - tablica struktur, przechowywanie 96 elementów

0

Mam pewien projekcik do opracowania, a ostatni raz pisałem cos takiego 25 lat temu na studiach, więc moje wybory były podyktowane daleką przeszłością.
W skrócie aplikacja komunikująca się z urządzeniem laboratoryjnym (spektrofotometr) po RS232 i odczytuje 96 wartości pomiaru na próbkach (może to być np. w kierunku African Swine Feaver, czyli powszechnej wsród dzików ASF, ale może być także Covid-19 - zależy od testu, który obsługujemy). Na tych wynikach należy przeprowadzić proste obliczenia, żeby ocenić zgodnie ze specyfikacją testu czy konretna próbka jest POSITIVE (zarażony), czy NEGATIVE (zdrowy). Dla użytkownika ma to być w miarę przyzwoicie zwizualizowane i "klikalne".
screenshot-20200831224203.png

Od kilku ładnych dni pracowałem nad zakodowaniem wymaganych podstawowych funkcjonalnosci w MS Visual Studio z wykorzystaniem C++, Forms'ów i biblioteki System::Drawing oraz komunikacją po RS232. Mam też "podsłuchany" protokół komunikacji konkretnego urządzenia diagnostycznego, ale utknąłem na pozornie prostym zagadnieniu - jak zadeklarować i przechowywać dane o tych 96 próbkach w pamięci zanim je aplikacja przetworzy przed zapisaniem/eksportem wyników do pliku?
Wyobrażałem to sobie jako tablicę 96 struktur, ale nijak nie ogarniam jak to konkretnie zakodować, a żaden ze znalezionych przykładów nie pozwolił mi złapać analogii. Symbol "daszka" (ang. "hat") w różnych konfiguracjach dla metod formularza w miarę ogarniam, ale jak to określił mój kolega zapis ^>^ to raczej "kotek z dziubkiem w prawa stronę" (oczywiście patrząc na mordkę kotka, ale to lewa strona jego kociej mordki)... Chciałbym się odwoływać do poszczególnych obiektów w możliwie zrozumiały sposób, np. well_array[i].well_result = "jakaśwartośćFloat".

Kwestia również miejsca w projekcie, w którym powinienem te dane zadeklarować i zainicjalizować, aby je później napełniać danymi odczytanymi ze spektrofotometru używając metod zakodowanych w moim formularzu. Z okna formularza także manipuluję np. typami poszczególnych pól (próbka S, pozytywna próbka kontrolna PC, itd.), albo przypisuję im numer ewidencyjny (barcode naklejany na fiolce z próbką).

struct well {                           // 8x12=96 tzw. "studzienek" (ang. "well"), dla każdej studzienki poniższe dane:
    //String ^ well_name1;                  // A1, A2, .. H12
    char well_name[4];                      //H12+"\n"
    short well_type;                    // 0=empty, 1=sample S, 2=positive control PC, 3=negative control NC, 255=blanking, 254=other?
    //String ^ well_barcode1;               // EAN, CODE 128, CODE 39, UPCA
    char well_barcode[128];
    float well_value;                   // from laboratory device
    short well_blocking;                    // blocking % of the samples - do obliczenia
    short well_result;                  // 0=negative, 1=positive, 2=doubt, -1=unknown - do obliczenia
    bool well_selected;
};
well well_array[96];

Obecnie mam jeden formularz, ale z pewnością kolejne funkcjonalności będa realizowane w osobnych oknach.

Będę zobowiązany za jakiekolwiek uwagi, bo utknąłem, nie mam już chyba chęci na kolejne eksperymenty z ref struct, value struct, non-manage vs managed class, opluwaniem przez kompilator. W zasadzie jedynym sensownym pomysłem jaki mam jest wyrzucenie tego wszystkiego do śmieci i może przepisanie funkcji kontrolek formularza oraz obsługi RS232 w C#, które okazałoby się bardziej zrozumiałe...

1
struct well 
{ 
    float value;
    short type,blocking,result;
    bool selected;
    char name[4],barcode[128];
};
vector<vector<well>> Well(8,vector<well>(12));
Well[0][0].selected=false;
Well[7][11].selected=true;
4
dstachur napisał(a):

Będę zobowiązany za jakiekolwiek uwagi, bo utknąłem, nie mam już chyba chęci na kolejne eksperymenty z ref struct, value struct, non-manage vs managed class, opluwaniem przez kompilator.

Welcome to C++/CLI.

Najprościej:

  • class od struct różni się tylko tym, że w class pola są domyślnie private, a w struct są domyślnie public.

  • przeczytać powyższy punkt 3 razy i pamiętać podczas czytania następnych.

  • samo class albo samo struct oznacza obiekt natywny. w takim obiekcie nie zmieścisz zarządzanego Stringa, chyba że będzie opakowany w odpowiedni smartpointer, jak auto_gcroot.
    (tu uwaga: msclr::auto_gcroot jest wzorowane na wycofanym std::auto_ptr więc ma tę samą irytującą cechę przenoszenia własności podczas kopiowania smartpointera)

  • ref class / ref struct to odpowiednik class z C#

  • value class / value struct to odpowiednik struct z C#.

0

W przypadku twojego struct well możesz posłużyć się klasą marshal_as do konwersji stringów jeśli nie chcesz męczyć się z klasą zarządzaną:

#include <msclr\marshal_cppstd.h>
#include <string>

int main()
{
    std::wstring s1 = L"Ala ma kota";
    System::String ^s2 = msclr::interop::marshal_as<System::String^>(s1);
    std::wstring s3 = msclr::interop::marshal_as<std::wstring>(s2);
}

(std::string też będzie działać ale wtedy konwersja jest stratna, bo wstring i String są unikodowe)

0

Nie pisz w C++/CLI. Siedzi okrakiem na dwóch światach i niczego nie robi dobrze.
https://4programmers.net/Forum/Ci.NET/196733-o_naduzywaniu_c++cli

Jak chcesz mieć funkcjonalność Win Forms, pisz w C# (basic też jest, gdyby to miało znaczenie)

0

Po pierwsze bardzo dziękuję za wszystkie podpowiedzi! Miałem ostatnio wrażenie, że ludzie, którzy 15 lat temu pisali w C++ (i Forms'ach + System::Drawing) powymierali już dawno, wszystko co mieli do pokazania, pokazali 10 lat temu i nie ma już kogo zapytać, a teraz to tylko C#, którego z niewyjaśnionych powodów nie chciałem dotykać wierząc, że z C++ cokolwiek jeszcze pamiętam. No i tak brnąłem w temat, a też jakoś niezręcznie było mi zapytać, a do tego rozsądnie zadać pytanie bez ośmieszenia :-)

Jak chcesz mieć funkcjonalność Win Forms, pisz w C# (basic też jest, gdyby to miało znaczenie)
skoro włożył już w to kilka dni to nie wiem czy jest sens teraz przepisywać, bo to bedzie kolejne kilka dni

Włożony czas to nie problem - przypomniałem sobie dużo, mnóstwo się nauczyłem (pisałem na urlopie wieczorami), zmaterializowałem wyobrażenie funkcjonalności potencjalnego użytkownika (laboranta) na ekranie, biblioteka Drawing jest w zasadzie taka sama dla C++ i C# (a niektóre metody opisane w MSDN działają chyba jedynie w C#), więc w 2-3 wieczory przepiszę moje "rysowanki" na C#. Obsługa RS232 wydaje się być niemal identyczna, ale już obsłużenie różnych urządzeń diagnostycznych z różnymi protokołami komunikacji (które NIESTETY nie są w żaden sposób udokumentowane), to jest dopiero kluczowy problem tego projektu i tu trzeba włożyć mnóstwo czasu mając dostęp do fizycznego urządzenia i oryginalnego oprogramowania jego producenta, żeby to podsłuchać, zrozumieć i zakodować po swojemu.

Generalnie nie jestem sprawnym programistą, nie wiem jak ja zaliczyłem programowanie obiektowe na studiach (sic!), zajmuję się zupełnie innym IT... Także jestem trochę skazany na "go simply and stupid". Mogę to też oddać komuś sprawniejszemu do napisania, ale wtedy zostałbym jedynie (za przeproszeniem) "project managerem". Cel tego ćwiczenia to pomóc komuś kogo znam, kto ma realny problem w biznesie na polskim rynku (wytworzyć produkt z polskim interfejsem z podobnymi funkcjonalnościami do produktów konkurencyjnych firm, np. niemieckich, które już dawno takie oprogramowanie napisały). Jeśli moje wyobrażenie zadziała i uda się to wszystko przyzwoicie zakodować, to też nie chciałbym się potem latami wstydzić tego kodu, który pewnie zostanie im przekazany, żeby można go było dalej rozwijać (np. kolejne urządzenia diagnostyczne i obsługa większej ilości patogenów do analizowania, lokalizacja w innych językach europejskich, raporty, komunikacja z innymi systemami, itd.). Także wybór tego w czym to ma być na obecnym etapie będzie rzutował na przyszłość, a ja z pewnością powinienem upraszczać sobie życie jak to tylko możliwe.

Przepraszam za długawe opisy, ale funkcjonalnie ciężko to opisać w trzech zdaniach. Wieczorem spróbuję coś jeszcze przykompilować w C++, ale chyba emocjonalnie już jestem blisko C# - kwestia chyba żeby się nauczyć jak powoływać obiekty graficzne (System.Drawing jest ok), jak rysować w poszczególnych panelach formularza i obsługiwać standardowe kontrolki, tym razem nie zapominając oczywiście o przechowywaniu i obrabianiu danych.

0

Powoli "rozsmakowuję się" w C#, szybko i sprawnie ogarnąłem sprawy mojego głownego formularza (grafiki i "klikalnosci" oraz podstawowej komunikacji po RS232), ale nadal kompletnie nie radzę sobie ze stworzeniem "czegoś" do przechowywania danych w mojej aplikacji. Przepraszam, że nadal pozostaję w gałęzi C/C++, choć sprawa dotyczy już C#, ale nie chcę multiplikować wątków na forum.

screenshot-20200903001851.png

Dla przypomnienia:

  • Do przechowania 96 pól - ang. "plate", czyli płytka laboratoryjna z polami na 96 próbek; typowy rozmiar 8x12 = 96 tzw. studzienek (ang. "well" - dołków na próbki)
  • Każdy z 96 dołków "well" przechowuje:
    float well_value;
    short well_type, well_blocking, well_result;
    bool well_selected;
    char(string?) well_name[4];

Gdzie (Program.cs, Form1.cs, XXX.cs, np. w zakresie class Program, czy w dedykowanej klasie?) i w jaki sposób (class, struct, vector, list?) zdefiniować oraz inicjalizować taki "pojemnik" na dane w strukturze mojej aplikacji tak, aby zapewnić jego widoczność z formularza głownego oraz pozostałych formularzy wołanych z formularza głównego?

Na chwilę obecną w uproszczeniu chcę odczytać dane po RS232 (96 x float well_value), zinterpretować ich wartości (Positive/Negative/Doubt) przypisując to do poszczególnych well_result oraz wyświetlać to w odpowiednich kolorach na formularzu głównym metodami System.Draw (obecnie wyświetlam jakieś statyczne dane). Do tego istotna byłaby funkcjonalność maskowania (pomijania) niektórych dołków, stąd pola well_type, czy well_selected do manipulowania konkretnymi dołkami (z osobnych okienek).

Przeprowadziłem kilka prób nieco "na pałę" patrząc na jakieś typowe przykłady (class, struct), ale co najwyżej udaje mi sie coś powołać i zainicjalizować tablice 96 struktur z wartościami początkowymi, ale już nie bardzo widać to z poziomu mojego Form1.cs, gdy próbuję z obiektów takiej tablicy czytać well_value żeby to odpowiednio wyswietlić.

No i tak kręcę sie w kółko...

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