[BC++] Odswieżanie na bieżąco

dział ogólny

[BC++] Odswieżanie na bieżąco

Nowy postprzez ivinnie » czwartek, 12 lutego 2009, 18:11

Witam,
próbuję zrobić coś w rodzaju dynamicznego odświeżania obrazka. Aplikacja MDI, dwie formy Form1 z obrazkiem Image1 i osobna Form2 z polem Edit. Polu edit przypisane zdarzenie:
Kod: Zaznacz cały
void __fastcall TForm2::Edit1Change(TObject *Sender)
{
   Form1->text1(Edit1->Text);
}

Funkcja text1 wygląda tak:
Kod: Zaznacz cały
void TForm1::text1(AnsiString nr)
{
   liczba = nr;
   Form1->Refresh();
}

Po każdorazowym wciśnięciu klawisza, Form1 powinna się odświeżyć ukazując bieżące zmiany na obiekcie Image1, niestety powoduje to wywalenie programu.
Natomiast przypisanie przyciskowi na toolbarze poniższej funkcji, nie powoduje tego błędu (oczywiście Refresh() w text1 zakomentowane i zamiast zdarznia Edit1Change jest zdarzenie Edit1Exit z wywołaniem funkcji Form1->text1(Edit1->Text);):
Kod: Zaznacz cały
void __fastcall TForm1::ToolButton3Click(TObject *Sender)
{
   Image1->Canvas->TextOutA(150, 40, liczba);
   Refresh();
}


Co należałoby zmienić aby móc na bieżąco odświeżać obiekt Image1 ?
Avatar użytkownika
ivinnie
Bladawiec
Bladawiec
 
Posty: 11
Dołączył(a): czwartek, 8 stycznia 2009, 11:58
Podziękował : 0
Otrzymał podziękowań: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » czwartek, 12 lutego 2009, 21:01

Zamiast Form1->Refresh(), spróbuj Image1->Invalidate(), lub Image1->Refresh(); funkcja Invalidate() kompletnie przerysowuje obiekt podczas gdy Refresh() przerysowuje tylko zawartość kontrolowaną przez ekran.

Zdarzenie OnChange jest zbyt często wywoływane co może powodować błędy, gdyż formularz otrzymuje polecenie odświeżenia jedno za drugim, nawet wtedy gdy jedno polecenie nie zostało jeszcze wykonane już nadchodzi drugie.
Odświeżanie całego formularza nie ma sensu skoro chcesz odświeżyć tylko zawartość Image.

Istotne pytanie: co rozumiesz przed odświeżenie Image, jakie zmiany w nim zachodzą, że wymaga dodatkowego odświeżenia - dodatkowego - gdyż Image ma wbudowany mechanizm odświeżania, który jest wywoływany zawsze gdy do Image wczytujesz grafikę.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez ivinnie » piątek, 13 lutego 2009, 01:13

To co piszesz nie działa u mnie - pewnie gdzieś robię błąd przy komunikacji miedzy formami. Programowaniem zajmuje się od niedawna.
Istotne pytanie: co rozumiesz przed odświeżenie Image, jakie zmiany w nim zachodzą, że wymaga dodatkowego odświeżenia - dodatkowego - gdyż Image ma wbudowany mechanizm odświeżania, który jest wywoływany zawsze gdy do Image wczytujesz grafikę.


Program ma generować ankiety, chcę aby można je było sobie wyklikać i efekt składanej ankiety był widoczny od razu na podglądzie. Za podgląd robi u mnie forma z obiektem TImage wyglądającym jak czysta kartka A4, wszelkie zmiany maja się na bieżąco pojawiać na tej kartce. Nie wczytuje obrazka z pliku, tylko sam go tworze.

Proszę zerknij na załączone archiwum z projektem - pliki które biorą udział w procesie wymiany danych to Ankiety_podglad i Dane_ankiety.
http://www.plikos.pl/tb9/Ankiety.zip.html
Avatar użytkownika
ivinnie
Bladawiec
Bladawiec
 
Posty: 11
Dołączył(a): czwartek, 8 stycznia 2009, 11:58
Podziękował : 0
Otrzymał podziękowań: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » piątek, 13 lutego 2009, 09:33

Popełniłeś mnóstwo błędów, ale największy popełniasz gdy tworzysz okno MDIChild (Form3), tworzysz je w oknie SDIAppForm i tylko to okno zna utworzone dynamicznie okno Form3, gdyż jest ono definiowane lokalnie, a więc okno Form2 nie zna adresu okna Form3, gdyż Form3 jest oknem dynamicznym. Nie występuje błąd podczas kompilacji, gdyż oknu Form3 tworzonemu dynamicznie nadałeś taką nazwę jaką ono już ma, czyli Form3, nie jest t co prawda błędem, ale w ten sposób nie widzisz błędu w kodzie, gdybyś zamiast:

Kod: Zaznacz cały
void __fastcall TSDIAppForm::WystawankietClick(TObject *Sender)
{
   TForm3 *Form3 = new TForm3(this);
   Form3->Show();
}


nadał oknu tworzonemu dynamiczne nową nazwę, czyli np:

Kod: Zaznacz cały
void __fastcall TSDIAppForm::WystawankietClick(TObject *Sender)
{
   TForm3 *New_Form3 = new TForm3(this);
   New_Form3->Show();
}


to dalej musiałbyś postąpić tak:

dla Form2:
Kod: Zaznacz cały
void __fastcall TForm2::Edit1Change(TObject *Sender)
{
   New_Form3->text1(Edit1->Text);
}



gdyż przy takim zapisie:

Kod: Zaznacz cały
void __fastcall TForm2::Edit1Change(TObject *Sender)
{
   Form3->text1(Edit1->Text);
}


nie odwoływałbyś się do utworzonego okna Form3 a tylko do istniejącego okna i błąd występowałby dalej.
Co jest o tyle prawidłowe, że Form2 nie wie nic o lokalnie tworzonym oknie dynamicznym.
Poza tym jeżeli utworzysz kilka okien dynamicznych o takiej samej nazwie to okno Form2 i tak nie będzie wiedziało do którego ma się odwołać, dlatego zawsze odwoła się do okna utworzonego jako ostatnio.
Kolejna sprawa jeżeli z poziomu FOrm3 wywołujesz okno Modalne Form2, to niestety okno Modalne nie będzie mogło się bezpośrednio (w czasie rzeczywistym), w zdarzeniu OnChange obiektu Edit1 odwoływać się do okna Form3, gdyż zwyczajnie Form3 jest zablokowane dopóki aktywne jest okno modalne, dlatego powinieneś wywoływać okno Form2 jako niemodalne, czyli Form2->Show()

Co do pierwszego problemu nie bardzo wiem jak można by zdefiniować dowolną liczbę dynamicznych okien MDIChild jako okna globalne, potrzebny byłby tutaj jakiś mechanizm nadawania nazw, co akurat dałoby się zrobić,
Można by zadeklarować Form3 jako okno globalne i tworzyć lokalnie jako dynamiczne, ale to mija się z celem, gdyż równie dobrze można zrezygnować z okien MDI i dynamicznego tworzenia okna Form3.

Musisz dokładniej przemyśleć ten projekt.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » piątek, 13 lutego 2009, 10:56

Trochę nie dawało mi to spokoju, więc znalazłem rozwiązanie dla tego problemu, chociaż nieco inne niż wstępnie zakładałem.



Sposób pierwszy:
Po pierwsze przeniosłem funkcję tekst1 z pliku Ankieta_podgląd do pliku Dane_ankiety. Następnie pobieram uchwyt do dynamicznie stworzonego obiektu za pośrednictwem zmiennej typu HWND zadeklarowanej jako globalna w pliku Dane_ankiety.h. Funkcja tekst1 pobiera uchwyt do okna dynamicznego Form3 korzystając z rzutowania polimorficznego. Istotne jest tutaj to by Form3 zaraz po wywołaniu okna Form2 przekazało do zmiennej typu HWND (Form2) uchwyt do własnego okna, w ten sposób Form2 zawsze będzie się odwoływać.

► 




Drugi sposób działa tak samo jak pierwszy z tym, że pozostawiłem funkcję tekst1 w pliku Ankieta_podglad:

► 


Jeżeli zrozumiesz mechanizm to będziesz go w stanie wykorzystać w dalszym rozwoju aplikacji, jeżeli nie to oczywiście nadal będziesz miał problemy.
Wrzucam Twoją aplikację:
Nie masz wystarczających uprawnień, aby zobaczyć pliki załączone do tego postu.
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez polymorphism » piątek, 13 lutego 2009, 11:21

Kolejna sprawa jeżeli z poziomu FOrm3 wywołujesz okno Modalne Form2, to niestety okno Modalne nie będzie mogło się bezpośrednio (w czasie rzeczywistym), w zdarzeniu OnChange obiektu Edit1 odwoływać się do okna Form3, gdyż zwyczajnie Form3 jest zablokowane dopóki aktywne jest okno modalne

Oj chyba nie do końca. Okno modalne przechwytuje (blokuje) tylko zdarzenia myszy/klawiatury. Rzeczy odpowiedzialne za odrysowanie okna są nadal aktywne (w każdym razie być powinny).
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » piątek, 13 lutego 2009, 11:38

Zgadza się. W tym przypadku może to być okno modalne, trzeba jednak ten fragment kodu:

Kod: Zaznacz cały
void __fastcall TForm3::ToolButton1Click(TObject *Sender)
{
   Form2->ShowModal();
   Form2->hWndForm3 = this;
}



zastąpić tym:

Kod: Zaznacz cały
void __fastcall TForm3::ToolButton1Click(TObject *Sender)
{
   Form2->hWndForm3 = this;
   Form2->ShowModal();
}


gdyż okno Form3 nie prześle informacji do Form2 dopóki jest ono modalne.

Nie wiem jednak czy w przypadku tego programu, dla dalszego jego rozwoju lepiej byłoby nie wywoływać Form2 jako okna modalnego, lecz niemodalane z FormStyle ustawionym na fsStayOnTop
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez polymorphism » piątek, 13 lutego 2009, 11:55

Nie bardzo rozumiem, dlaczego hWndForm3 jest typu HWND zamiast być wskaźnikiem na TForm3? Nie trzeba wtedy robić rzutowań, a kod staje się czytelniejszy (no i bezpieczniejszy).
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez ivinnie » piątek, 13 lutego 2009, 12:24

Dzięki za pomoc. Dopiero uczę się pisania aplikacji okienkowych dlatego wyskakują takie problemy. Myślę, że już rozumię ideę działania operatora reinterpret_cast i użycia wskaźnika (sprawdzę to podczas dalszego pisania programu).
Pozostanę przy wyświetlaniu okna Form2 jako niemodalnego z ustawieniem FormStyle na fsStayOnTop z tego powodu, że w miarę uzupełniania dokumentu użytkownik może chcieć przewinąć stronę w dół. Pozostawienie okna jako modalne nie pozwoli przewinąć podglądu.

Po ukończeniu aplikacji umieszczę ją na forum.
Avatar użytkownika
ivinnie
Bladawiec
Bladawiec
 
Posty: 11
Dołączył(a): czwartek, 8 stycznia 2009, 11:58
Podziękował : 0
Otrzymał podziękowań: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » piątek, 13 lutego 2009, 13:04

Oczywiście, że można, nie zrobiłem tego, gdyż wstępnie nie zakładałem użycia wskaźnika na Form3, lecz zrobiłem to tak:

Kod: Zaznacz cały
reinterpret_cast<TForm3*>(hWndForm3)->text1(Edit1->Text);


a potem już poszedłem tym tropem, gdy zaczęło działać, nie drążyłem dalej tematu, no i umknęło mi to, że tak naprawdę niepotrzebnie stosuję rzutowanie w Form3 i polimorfizm w Form2, skoro wystarczy samo rzutowanie.

a kod staje się czytelniejszy (no i bezpieczniejszy)


dla mnie to co napisałem jest czytelne, nie dostrzegam w przedstawionym kodzie żadnego niebezpieczeństwa.

Użycie wskaźnika bezpośrednio na Form3 wymaga dodatkowej zmianie, trzeba wpis #include #include "Ankieta_podglad.h" przenieść z pliku źródłowego Dane_ankiety.cpp do pliku nagłówkowego Dane_ankiety.h

► kod nieco zoptymalizowany 
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez polymorphism » piątek, 13 lutego 2009, 13:50

dla mnie to co napisałem jest czytelne

No ale ten kod pisałeś dla ivinnie, a nie dla siebie (tak sądzę). I z tego co widzę, ivinnie zastosuje to rzutowanie, choć zapewne sam nie wie po co. Inna sprawa to to, że widząc HWND od razu przychodzi na myśl uchwyt okna WinAPI, a tu niespodzianka - wskaźnik na TForm3 8-)

nie dostrzegam w przedstawionym kodzie żadnego niebezpieczeństwa

Niebezpieczeństwo polega na tym, że do hWndForm3 możesz przypisać wskaźnik na cokolwiek.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez Cyfrowy Baron » piątek, 13 lutego 2009, 15:01

Niebezpieczeństwo polega na tym, że do hWndForm3 możesz przypisać wskaźnik na cokolwiek.


Mógłbym to zrobić gdybym nie wiedział po co ten wskaźnik stworzyłem i do czego ma służyć, a tymczasem doskonale wiem po co tam jest, no i ta nazwa wskaźnika...
Avatar użytkownika
Cyfrowy Baron
Administrator
Administrator
 
Posty: 4716
Dołączył(a): niedziela, 13 lipca 2008, 15:17
Podziękował : 12
Otrzymał podziękowań: 442
System operacyjny: Windows 7 x64 SP1
Kompilator: Embarcadero RAD Studio XE2
C++ Builder XE2 Update 4
SKYPE: cyfbar
Gadu Gadu: 0
    NieznanyNieznana

Re: [BC++] Odswieżanie na bieżąco

Nowy postprzez polymorphism » piątek, 13 lutego 2009, 15:28

Istnieje jeszcze kwestia zasadności w przypadku, gdy wiesz, że nic innego jak wskaźnik na TForm3 (i jej pochodne) nie będziesz przypisywał.
C++ Reference - opis wszystkich klas STL-a i funkcji C.
Avatar użytkownika
polymorphism
Doświadczony Programista ● Moderator
Doświadczony Programista ● Moderator
 
Posty: 2156
Dołączył(a): piątek, 19 grudnia 2008, 13:04
Podziękował : 0
Otrzymał podziękowań: 200
System operacyjny: Windows 8.1
Windows 10
Linux Mint 21.1
Kompilator: Visual Studio
Visual Studio Code
MSYS2 (MinGW, clang)
g++
clang
Gadu Gadu: 0
    NieznanyNieznana


  • Podobne tematy
    Odpowiedzi
    Wyświetlone
    Ostatni post

Powrót do Ogólne problemy z programowaniem

Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zalogowanych użytkowników i 1 gość