C++ (Builder) - Timer.

2

Witam!

Zaczynam zabawę na lekcji w C++ Builderze - jako zadanie dostałem coś oto takiego:

Po kliknięciu w BUTTON - przesunie się on od jednej krawędzi do drugiej, następnie gdy dojdzie do krawędzi to "odbije się" i zawróci.

No to zrobiłem to następująco, iż wrzuciłem Button1->Left++; - w pente.

Nauczyciel coś mówił na temat użycia Timera - próbowałem - tylko:
-ma on opcje enabled (true/false).
-interval (w ms).
-OnClik (np Button1).

Problem w tym, że nie rozumiem za bardzo co z czym się je. Co to jest w ogóle ten Timer? Jest to coś takiego jak funkcja Sleep?
Że robi pewnego rodzaju zatrzymanie? Czy bardziej jak pętla - powtarza określoną czynność.

Początkowo zrobiłem coś takiego - klikłem dwa razy na button, następnie wpisałem:
Timer1->Interwal=5000;
Button1->Caption="test";

Problem w tym, że u mnie niczym to się nie różni od tego, jak bym tylko wpisałem Button1->Caption="test";

Ten timer trzeba jakoś wystartować? (standardowo mam - Enable - True.).

Mógłby mi ktoś podesłać jakiś link z lekturą w J. Polskim? Lub też wytłumaczyć - albo podesłać kod zadania z timerem - to podejrzewam, iż rozkminie "co z czym się je".

PS2. Mam małe pytanko - świeżo co przeszedłem ze programowania strukturalnego i nie rozumiem jednej rzeczy.

Gdy w button wpisze - Button1->Left=Left+10; - to po kliknięciu przesunie się o 10 pikseli - a jak drugi trzeci itd - kliknę, to nie przesuwa się już w ogóle - czemu tak jest? I jak to zmienić?

Pozdrawiam i czekam na odpowiedź - Mikołaj N.

1

Timer to po prostu kontrolka, która odmierza czas i wykonuje czynność po upłynięciu danego okresu czasu np. 10ms. Nie rozumiem tego zdania:

Gdy w button wpisze - Button1->Left=Left+10; - to po kliknięciu przesunie się o 10 pikseli - a jak drugi trzeci itd - kliknę, to nie przesuwa się już w ogóle - czemu tak jest? I jak to zmienić?

Co drugi, trzeci klikniesz?

1

Zrób sobie zmienną globalną np.

 
 int pozycja = 0;

a w timmerze wpisz interwal na jakąś liczbę całkowitą np. 500 (500 milisekund czyli 0,5 sekundy).
teraz wygeneruj zdarzenie timmera przez 2-klik na zakładce events i zrób mniej więcej tak: (pisze z palca)

 
pozycja++;
Label1->Caption = pozycja;

co każde 0,5 sek. powinna się zmieniać wartość label'a o 1.

myślę że z resztą sobie teraz poradzisz. Aha ustawienie enabled na true rozpoczyna działanie "zegarka" więc ustaw go na true

0

Okej - postanowiłem zrobić konto - więc od początku:
Moim zadaniem jest zrobienie tego pseudo pływającego guzika wykorzystując przy tym Timer.

void __fastcall TForm1::Button1Click(TObject *Sender)
{
Timer1->Interwal=5000;
Button1->Caption="test";
}

Według tego zapisu - po kliknięciu w button - powinno upłynąć 5000 MS (5 sek) i zmienić się napis - niestety - napis zmienia się od razu.

A co do:
Gdy w button wpisze - Button1->Left=Left+10; - to po kliknięciu przesunie się o 10 pikseli - a jak drugi trzeci itd - kliknę, to nie przesuwa się już w ogóle - czemu tak jest? I jak to zmienić?
To nie jest zadanie tylko takie moje małe testy. Mam coś takiego:

void __fastcall TForm1::Button1Click(TObject *Sender)
{
Button1->Left=Left+10;
}

Klikam raz na button - przesuwa się o 10 pikseli - klika później obojętnie ile razy w ten button - i nie przesuwa się - lecz stoi w miejscu. Pytanie Dlaczego?

1
void __fastcall TForm1::Button1Click(TObject *Sender)
{
Button1->Left=Button1->Left+10;
}
1

Interwał jeżeli nie musisz w kodzie, to zawsze umieszczaj we właściwościach Timer'a w Object Inspector'rze. Ustaw tam te 100ms czy ileś i w metodzie, która wykonuje się po kliknięciu button'a wklej samo to co Timer1->Enabled = true, a w metodzie Timer'a wpisz to co nobody napisał. Musi zadziałać.

I nie Interwal tylko Interval.

0

Tak tak - naturalnie - już rozumiem całą koncepcje timera - jak go startować i tak dalej ;).

Problem leży w czymś innym - jak napisać, to zadanie z "pływającym guzikiem".

zrobiłem tak:

if(Button1->Left<168)
Button1->Left++;

I stanąłem (168 to krawędź końcowa mojego okienka) - nie wiem jak napisać żeby wracał w miejsce 8 (początkowa krawędź).

0

Button1->Left = 0 ;
zmniejszanie jak łatwo się domyślić Button1->Left--; :>
warto też pobierać aktualny rozmiar okna w zdarzeniu bo co gdy user np. zrobi maksymalizacje :>

1

Lepiej będzie jak dasz w miejsce 168 faktyczny, aktualny rozmiar rect formy. To chyba jest nazwa_formy->ClientWidth dla długości, a wysokości
nazwa_formy->ClientHeight.
Tak jak teraz byś chciał zrobić nie będzie do końca tak jak chcesz. Tu gotowy kod na odbijanie i ruch.

if (Button1->Left + Button1->Width >= Form1->ClientWidth)
    Button1->Left--;
else if (Button1->Left <= 0) 
    Button1->Left++;

I teraz dojedzie w prawo i się "odbije", a potem "odbije się" od lewa itd.

0

Tak - można by było zrobić tak jak myślisz - ale tu chodzi o efekt "pływania" - tak jak daje Button1->Left++; inkrementacja w prawo o 1 - tak trzeba zrobić dekrementacje w prawo o 1 - czyli Button1->Left --;

Lecz gdy zrobię:
if(Button1->Left<168)
Button1->Left++;
if(Button1->Left>8)
Button1->Left--;

Kicha - bo one będą kolidować ze sobą...

0

Chyba nie zdążyłeś przeczytać mojego postu. Zrób tak jak napisałem, ale jeżeli chcesz żeby tylko raz się to wykonało, czyli odbicie od prawa i powrót, to możesz na 2 sposoby, zależnie od tego co wymaga zadanie. Jak musi ten przycisk od samego lewa czyli Left = 0 lub jeżeli może być np. od Left = 1 (w tym przypadku obejdzie się bez dod. zmiennej) położenie początkowe. Więc jak musisz to zrobić?

0

Tak - nie zdążyłem - lecz Twój kod = zero reakcji - wkleiłem go do Timera, następnie do Buttona dodałem Timer1->Interval=500; Timer1->Enabled=true;
I nic - Nie mam określone gdzie button ma się znajdować początkowo - po prostu - klikam i on "Płynie" w prawo - po czym odbija się od krawędzi prawej i wraca do krawędzi lewej.

1

Ajj źle to zrobiłem, już późno :D

Zadeklaruj globalnie zmienną int direction = 1;.

// W metodzie Timer'a
if (Button1->Left + Button1->Width >= Form1->ClientWidth)
    direction = -1;
if (Button1->Left = 0) 
    Timer1->Enabled = false;
Button1->Left += direction;

Teraz powinno być ok.

0

Okej działa ;) Dzięki wielkie !

0

Witam!

Korzystając z informacji - których się dziś dowiedziałem, chciałem zrobić guzik, który "pływał by" dookoła okienka (Forma).

Przez godzinę udało mi się wymyślić to (oczywiście wszystko w Timerze.)

Zmienne globalne (poza timerem)

int direction;
int roz=1;
int rozz=-1;

Timer:

if ((Button1->Left + Button1->Width >= Form1->ClientWidth) && (Button1->Top == 1))
direction = 1;
else
{
        if ((Button1->Left + Button1->Width <= Form1->ClientWidth) && (Button1->Top == 388))
        direction = 2;
        else
        {
                if((Button1->Left == 387) && (Button1->Top + Button1->Height <= Form1->ClientHeight))
                direction = 3;
                else
                {
                        if((Button1->Left == 1) && (Button1->Top == 388))
                        direction = 4;
                }
        }
}
if(direction==1)
{
Button1->Left+=roz;
Button1->Caption="Prawo";
}
if(direction==2)
{
Button1->Left+=rozz;
Button1->Caption=Button1->Top;
}
if(direction==3)
{
Button1->Top+=roz;
Button1->Caption="Dół";
}
if(direction==4)
{
Button1->Top+=rozz;
Button1->Caption="Góra";
}

Szczerze mówiąc - warunki wolał bym w takiej formie Button1->Left + Button1->Width >= Form1->ClientWidth gdyż, zawsze to zabezpiecza przy zmianie okienka. - jak widać mi troszkę tam nie wyszło :P - połowę musiałem ustawić na sztywno - ostatni warunek - pomimo ustawienia go na "sztywno" nie wykonuje się. To znaczy, nie podjeżdża do góry - lecz wyjeżdża poza lewą krawędź. Jakieś sugestie? Najbardziej chodzi tu o warunki.

Ps. Gdy z tego warunku

if ((Button1->Left + Button1->Width >= Form1->ClientWidth) && (Button1->Top == 1)) direction = 1;

Zrobię -

if ((Button1->Left + Button1->Width >= Form1->ClientWidth) && (Button1->Top == 1)) Button->Left++;

To w tym drugim przypadku button nie wykonuje polecenia - dlaczego?

Ps2. Efekt ma być taki jak tu - - film mojego autorstwa - tylko, że wszystko na pętli for.

0

tym ostatnim tekstem pozbawiłeś się chyba dalszej pomocy pozdro szejset :)

0
nobody napisał(a)

tym ostatnim tekstem pozbawiłeś się chyba dalszej pomocy pozdro szejset :)

Co masz na myśli ?

Ostatni tekst - to jest z tym filmikiem z youtube. Film jest mojego autorstwa - sam to robiłem - ruch guzika od jednej krawędzi jest zrobione w pętli for - oraz czterema warunkami - jeśli kod będzie potrzebny byście uwierzyli - mogę wstawić - tylko chcę zrobić to samo - lecz używając do tego Timera - dlatego nie rozumiem aluzji którą chciałeś mi przekazać - to na temat PS2.

Co do PS. - jestem początkującym programistą - więc pytam dlaczego tak nie można - nie wiem - a kto pytanie nie błądzi - czyż nie?

A co do tego że warunki wolał bym w takiej formie - naturalnie, że chodziło mi o if(Button1->Left + Button1->Width >= Form1->ClientWidth) - tylko nie wiem czy tak się da.

Po prostu nie wiem czego tyczą się Twoje słowa kolego.

0

Co do

if ((Button1->Left + Button1->Width >= Form1->ClientWidth) && (Button1->Top == 1)) Button->Left++;

Tu tylko przejedzie ci jeden piksel w prawo przycisk, jeżeli warunek jest prawdziwy.
A co do ruchu w różne strony, nie ma sensu się bawić tyloma warunkami i tylko direction'ami. Zrób 2 zmienne - każda określa ruch w każdą stronę (kierunek) lub zrób typ wyliczeniowy. Chodzi mi o coś takiego:

int directionY = 0;
int directionX = 0;

Jak w lewo to dirX = -1, prawo 1. Jak w górę to dirY = -1, jak w dół to 1. I zmieniasz tylko właśnie te kierunki aktualne.

W onClick przycisku zmień dany kierunek, np. dla ruchu już w lewo daj directionX = -1;, a w Timer'rze po prostu linijki

Button1->Left += directionX
Button1->Top += directionY

Jeżeli sam ruch w lewo to wtedy dirY = 0, czyli pozycja Y nie zmieni się, a przycisk będzie jechał w lewo.

No i oczywiście warunki żeby nie nastąpiła kolizja lub przejście poza formę. Czyli dla ruchu X sprawdzasz boczne obramówki, a dla ruchu Y górną i dolną czy się nie zderzają z przyciskiem/są w odpowiedniej odległości czyli stop (directionX lub Y = 0;)

0

Już zrobiłem - dzięki.

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