Tworzenie obrazów z poziomu kodu WindowsForm c++

Witam , na początku chce zaznaczyć iż to mój początek z programowaniem obiektowym. Otóż chce stworzyć aplikację w której z poziomu kodu będę wstawiał obrazki. Dla moich celów stwierdziłem ,że imageList będzie idealny niestety mimo prawidłowego kompilowania kodu obrazka nie widać. Co robię źle?

imageList1->Images->Add(Image::FromFile(“piksel.bmp”));
Graphics^ theGraphics = Graphics::FromHwnd(this->Handle);
imageList1->Draw(theGraphics, panel1->Left + (panel1->Width / 2), panel1->Bottom + panel1->Height/2, 0);

W programowaniu najczęściej błędy są w logice działania kody, an podstawie 3 linijek ciężko coś powiedzieć lub wykluczyć jakiś błąd.

Być może w ogóle nie dodałeś zdjęć do wyświetlenia w form’ie.

PS. Moim zdaniem wybrałeś kiepski sposób na naukę programowania obiektowego.

Zdjęcia są bo sprawdzałem debugerem i się dodają.
Cały kod http://www.wklejto.pl/553523

Tylko ,że dopiero zacząłem to pisać no i cudów tam nie będzie te trzy linijki to praktycznie cała moja ingerencja w ten kod :slight_smile:

Obiektowo już co nieco umiem chciałem popróbować okienkowo :slight_smile:

Sprawdź sobie czy na pewno event w ramach którego dodajesz zdjęcia ma w ogóle miejsce w Twoim programie.

Jeśli robię cokolwiek innego w tym evencie to się wykonuj próbowałem np. dodać sobie label1 i zmieniałem ‘label1->text=’ i to działało więc raczej się wykonuje.

Sorki, padam na twarz i przetwarzanie jakiekolwiek kodu przez mój mózg jest już bardzo czasochłonne.

W linii z theGraphics pobierasz uchwyt z Form’sa, a później rysujesz po współrzędnych panelu. Wydaje mi się, że grafika jeśli się wyświetla to pod panelem, ale lepiej byłoby ją rysować w panelu, a nie w Form’sie bezpośrednio, a może nawet w jakiejś dedykowanej kontrolce.

Jak coś to nie jest to pilne. Jeśli dobrze zrozumiałem to zalecasz wkleić ten kod tutaj

private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) {

}
Dobrze rozumiem? Jeśli tak to to już próbowałem i jest to samo. Próbowałem też X i Y ustawiać na sztywno to także nic nie dało.

Dzięki za wszelkie rady

Chodzi o tą linijkę i następną:

Graphics^ theGraphics = Graphics::FromHwnd(this->Handle);

raczej powinno być:

Graphics^ theGraphics = Graphics::FromHwnd(this->panel1->Handle);

Dalej niestety nic

Jutro zobaczę czy na VM mam VS z C++, jak tak zrobię jakiś swój przykład bo nie wiem nawet czy dobrą drogę wybrałeś. Dziś ją dosłownie przed minutą wyłączyłem i nie mam już na nic siły.

Dobrze zapoznaj się z dokumentacją biblioteki graficznej.Zasady są takie.że najpierw tworzysz obiekt.
Przykładowo:
Graphics g.
g.Moveto(10,10)
g.LineTo(100,100)
g.Rectangle(200,200,200,250)
Chodzi ci chyba o wycinanie i zapamiętywanie obszarów grafiki.
ImageList to jeden z komponentów,poczytaj jakie ma metody.Służy do układania listy obrazów.
Musz sprawdzić klasy Bitmap,ImageList.Funkcje tych klas wywołujesz.
Przykładowe kody.

Oczywiście zapoznałem się z dokumentacją zanim udałem się po pomoc na forum i niestety albo czegoś nie doczytałem albo mam jakiś błąd logiczny w programu.

Nie chodzi mi o jej wycinanie tylko o wczytanie i wyświetlenie.

Kiepsko ogarniam WInForm nie wnikam w detale wyłącznie na logikę:
Dodałeś PaintEvent do kolejki rysującej panel: this->panel1->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &MyForm::panel1_Paint);

W każym wywołaniu odświeżenia panelu przez system (np. zmiana rozmiaru okna) które wywoła rysowanie panelu. Funkcje zaszyte w obiekcie rysują ramki oraz szare tło. Od momentu podania panelowi uchwytu do eventa, twoja funkcja również zostanie wywołana rysując co ty chciałbyś zobaczyć na panelu. W niej zamiast rysować cos na Panelu zrobileś jednak wszystko inne poza rysowaniem.: Dodajesz do listy obrazów plik imageList1->Images->Add(Image::FromFile("piksel.bmp")); Za każdym razem lista się będzie powiększać o jeden element otwierając wciąż ten sam plik z dysku dodając go znowu do listy. Po co to powtarzać? Wystarczy więc że przysłonisz okno innym oknem oknem. System wywoła Event, panel się odświeży, a lista obrazów się będzie rozrastać w nieskońćzoność z nim zajęta pamięć. Żeby jej nie było jej smutno za każdym wywołaniem PaintEvent tworzysz również nowy obiekt Graphics którego wskaźnik zapamiętujesz w zmiennej lokalnej. Wskaźnik zniknie ze stosu jak tylko funkcja się skończy obiekt w pamięci pozostanie na stercie, zniknie jedynie wskaźnik. Powiększysz zajętą pamięć - w nieskończonosć.

Zakładam że to w zamierzeniach Graphics to bufor na zawartość panelu WinAPI - plutno DC https://msdn.microsoft.com/en-us/library/windows/desktop/dd183490(v=vs.85).aspx Faktycznie jest on przydatny. W parametrach konstruktora podajesz HWND do okna, które go w żaden sposób z nim nie wiaże. To jest wyłącznie baza do klonowania / skopiowania parametrów nowego płutna - bazą jest płutno z okna jej rozmiar, paleta kolorów systemu itd. W WinAPI wywołanie CreateDC nie skopiuje nawet zawartości więc płutno będzie czarne jak smola. A mniej więcej to realnie się kryje za konstruktorem. Jeśli jednak tworzysz coś w funkcji wypadałoby po sobie posprzątać i chociaż usunąć przed koncem funkcji z delete. Najlepiej jednak utworzyć jako obiekt na stałe związany z oknem. Tworzony raz jeden w konstruktorze okna nie potrzeba go tworzyć w PaintEvent.

Po tych dwóch krokach poprawnie wywołujesz funkcje Draw listy plików podając za parametr docelowy płutno (bufor), podając rozmiar docelowy. Za każdym razem uparcie podajesz indeks 0 (ostatni parametr) wskazujący na pierwszy element listy. https://msdn.microsoft.com/en-us/library/53f4a5t3(v=vs.110).aspx?f=255&MSPPError=-2147217396 Nie sprawdzasz czy plik się poprawnie załadował, nie sprawdzasz czy lista wogóle ma jakiś element, tak poprostu zakładasz że musi tam być chociaż jeden - index 0. Przy każdym wywołaniu dodajesz kolejny element wciaz uparcie rysując ten pierwszy. Po 100 wywołaniu lista będzie miala 100 obrazków… z czasem zapełnisz pamięć. Jak Smith z Matrixa :wink:

Zakładam że Draw narysowało poprawnie obrazek na Graphics. Funkcja się kończy Nic nie widzisz - bo jak niby miałbyś coś zobaczyć? Wypadałoby w kolejnym kroku narysować zawartośc Graphics na Panel. Nie wiem jak się nazywa funkcja WInForms rysowania na WInAPI wywołał bym StretchBlt albo BitBlt. Poszukaj sam. Do rysowania kwadratów, kresek DrawLine, DrawArc, itd. Jest nawet funkcja DrawImage wymaga obiektu Image zamiast ImageList. Ale parametrem docelowym jest uchwyt okna… tym mógłbyś narysować obraz bezpośrednio na oknie z pominięciem bufora.

Ogólnie to wypadało by dodawanie bitmapy do listy wyrzucić z funkcji rysowania. Dodać do funkcji np. po przyciśnięciu przycisku albo przy uruchamianiu - tworzony obiekt Graphics, otwierany plik rysowany w obiekcie. Nazwę pliku pobierajac z jakiegoś pola edycyjnego. Numer obrazka do wyświetlenia pobierać z ScrollBara albo z pola edycyjnego itd. jeśli byloby tych obrazów więcej. Funkcja Draw na Graphics wystarczy by była wywołana jeden raz.Draw wypada dodać do Eventa - Resize zamiast Paint. Event jest wywołany przed pojawieniem się okna więc nie potrzeba więcej. W Paint wystarczy rysować zawartość Graphics na Panelu i to wszystko.

Windows to wredny bahor. Okna nie są trwałe. Każde(prawie) przysłonięcie okna, zmiana rozmiaru powoduje nadpisanie zawartości, w kolejce mesedży system wysyłą RECT z obszarem który wymaga przerysowania. Można rysować fragment - pobierając z bufora można odświeżyć całość kwestia detali. Ogólnie to tak jakbyś budował zamek z piasku i przyłaził Bill niszczył ci to złośliwie co chwila. Po to jest Graphics. Jest jak kopia zapasowa tego co chcesz narysować na Panelu. Wyobraź sobie że w funkcji Paint robisz skomplikowaną konstrukcje - linie, kreski, wypełnienia obrazki itd. klikasz w menu i zakrywa to menu. Zamiast konstrukcji system nadpisuje czarnym tłem Panel… musisz rysować od nowa. Po to jest bufor. Konstrukcje rysujesz na buforze, on jest bezpieczny, ten bufor rysujesz na oknie które wciaż jest nadpisywane przez innych. Standardowo więc jeśli funkcja się wywołuje jedyne co robisz to blokujesz rysowanie (mutexem) i kopiujesz na niego bufor. Bufor odświeżasz zależnie od włąsnej woli wtedy kiedy zachodzi realna potrzeba- np. zmiana rozmiaru okna, zmiana grafiki itd.

Nie widzisz obrazka bo narysowałeś plik w buforze ale nie narysowaleś bufora na panelu. Kapisz?

Dziękuje za radę sporo z tego co pisałeś wynika z tego ,że kod nie jest w żadnym stopniu dokończony na razie chciałem tylko osiągnąć narysowanie tego obrazka. Zdaję sobie sprawę ,iż program ten jest na razie takim potworkiem zjadającym ram. Ale to dla tego ,że najpierw chciałem by program narysował mi obrazek i dlatego podaję cały czas na sztywno indeks 0. Docelowa ma być tam podana zmienna.

Dzięki wielki rysowanie już działa poprawiłem parę z tych błędów o których pisałeś

http://www.wklejto.pl/553798

A i miałem jeszcze błąd:

imageList1->Draw(myGraphics, panel1->Left+panel1->Width/2, panel1->Top+panel1->Height/2, currentImage);

Ponieważ ustawiałem Bottom+Height/2 A okazuje się ,że dla visuala Bottom to maksymalna wartość. Trochę to dla mnie nie naturalne no ale cóż

Teraz lepiej? Chyba jeszcze brakuje destruktora tak?