Форум «Всё о Паскале» _ Ада и другие языки _ Builder 6.0
Автор: Fanat 31.01.2008 21:41
Хочу сделать следуюшее...чтобы по определенным клавишам двигалася напиример Button1, а по другим Button2...написал примерно так
void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg, bool &Handled) { // Memo1->Lines->Add(Msg.wParam); const nStep = 1; switch(Msg.wParam) { case 40: Button1->Top += nStep; break; case 38: Button1->Top -= nStep; break; case 37: Button1->Left -= nStep; break; case 39: Button1->Left += nStep; break;
case 83: Button2->Top += nStep; break; case 87: Button2->Top -= nStep; break; case 65: Button2->Left -= nStep; break; case 68: Button2->Left += nStep; break;
}
Но теперь пока одна кнопка движеться вторая не будет...как реализовать независимое движение?.. может как то через много поточность?..можно для каждой кнопки писать свой поток и в нём ждать нажатия определённой кнопки и его уже орабатывать...но как ето сделать?..
Автор: volvo 31.01.2008 23:32
Цитата
можно для каждой кнопки писать свой поток и в нём ждать нажатия определённой кнопки и его уже орабатывать...
Угу... Чтобы наконец убедиться, что весь GUI должен всегда работать в одном потоке, иначе проблем не оберешься... Вообще-то можно сделать и так:
typedef struct { int x, y; bool b; } RMove;
RMove moving[2];
void __fastcall TForm1::ApplicationEvents1Message(tagMSG &Msg, bool &Handled) { switch(Msg.message) { case WM_KEYDOWN: // Ну, ты же понимаешь, что все это можно записать и намного короче, // добавив одну-единственную функцию, правда? Это - просто пример... switch(Msg.wParam) { case 40: { moving[0].x = 0; moving[0].y = 1; Handled = moving[0].b = true; break; } case 38: { moving[0].x = 0; moving[0].y = -1; Handled = moving[0].b = true; break; } case 37: { moving[0].x = -1; moving[0].y = 0; Handled = moving[0].b = true; break; } case 39: { moving[0].x = 1; moving[0].y = 0; Handled = moving[0].b = true; break; }
break; case WM_KEYUP: switch(Msg.wParam) { case 40: case 38: case 37: case 39: { Handled = true; moving[0].b = false; break; } case 83: case 87: case 65: case 68: { Handled = true; moving[1].b = false; break; } }
Хотелось бы всё таки узнать как сделать через потоки... мне непонятно к в потоке узнать что нажата клавиша?..
А зачем Handled ( - признак обработки события) выставлять в true?..
Цитата
// Ну, ты же понимаешь, что все это можно записать и намного короче, // добавив одну-единственную функцию, правда? Это - просто пример...
Я как то об этом не задумывался даже... Я так понимаю эта функция просто внутри себя будет проверять клавиши, да и кнопку которую двигать ей тоже отправлять надо...и она уже будет двигать ету кнопку...
Автор: volvo 1.02.2008 5:29
Цитата
Хотелось бы всё таки узнать как сделать через потоки...
Ты действительно этого хочешь? Тогда посмотри присоединенный файл, там описание того, как это можно сделать. Один из способов, скажем так...
А зачем Handled ( - признак обработки события) выставлять в true?..
Затем, что если ты этого не сделаешь, и у тебя на форме будет, например, Edit, и фокус будет на нем, то этот Edit будет заполняться символами, которые ты вводишь (нажимая клавишу). А если ничего из текстовых контролов не будет - то программа будет пищать. А установкой Handled = true ты говоришь обработчику ApplicationMessage, что это событие уже обработано, дальше по цепочке его передавать не надо...
Автор: Fanat 1.02.2008 15:53
Цитата(volvo @ 1.02.2008 1:29)
Ты действительно этого хочешь? Тогда посмотри присоединенный файл, там описание того, как это можно сделать. Один из способов, скажем так...
Затем, что если ты этого не сделаешь, и у тебя на форме будет, например, Edit, и фокус будет на нем, то этот Edit будет заполняться символами, которые ты вводишь (нажимая клавишу). А если ничего из текстовых контролов не будет - то программа будет пищать. А установкой Handled = true ты говоришь обработчику ApplicationMessage, что это событие уже обработано, дальше по цепочке его передавать не надо...
Да...интересно..я вроде во всём разобрался...
И я так понимаю Sleep(100); чтобы мы успели нажать какую либо кнопку...но при етом слишком скорость маленькая...а при Sleep(10) у меня в конце концов всё таки зависало =(... А вообще при отключения Sleep кнопки почему то движуться с разными скоростями и зависает быстро..=( Не мог бы ты привести пример ещё какого либо способа...
(не обязательно на счёт данной задачи...я могу разобраться и сам попрбовать сделать..=)...в общем как тебе удобней...)
Автор: volvo 1.02.2008 16:24
Цитата
а при Sleep(10) у меня в конце концов всё таки зависало =(...
Поменял в Execute() условие выхода на
... } while(!Terminated);
(как я мог написать там Suspended - не понимаю ), гонял программу минут 20 со Sleep(5) и nStep = 2: скорости движения одинаковые, зависаний никаких не обнаружено. Я надеюсь, ты в OnDestroy формы прописал завершение потоков?
Автор: Fanat 1.02.2008 16:34
Цитата(volvo @ 1.02.2008 12:24)
Поменял в Execute() условие выхода на
... } while(!Terminated);
(как я мог написать там Suspended - не понимаю ), гонял программу минут 20 со Sleep(5) и nStep = 2: скорости движения одинаковые, зависаний никаких не обнаружено. Я надеюсь, ты в OnDestroy формы прописал завершение потоков?
Да..так лучше... Теперь написал...они же и так сами должны завершаться при завершении приложения?..
Автор: volvo 1.02.2008 16:47
Должны... Но их должна завершить система, а это требует дополнительного времени, будет подвисать при выходе. А если ты напишешь
for(int i = num_threads - 1; i >= 0; i--) { thr[i] -> Terminate(); }
, то дело пойдет быстрее...
Автор: Fanat 1.02.2008 17:10
Цитата(volvo @ 1.02.2008 12:47)
Должны... Но их должна завершить система, а это требует дополнительного времени, будет подвисать при выходе. А если ты напишешь
for(int i = num_threads - 1; i >= 0; i--) { thr[i] -> Terminate(); }
, то дело пойдет быстрее...
Понятно...А как отловить нажатие двух кнопок сразу?..хочу добавить движение по диагоналям... А какой компонент лучше использовать для движения?...хочу написать что то вроде Ice hockey, так что это могут быть и TPanel и просто прямоугольник нарисованый...
Автор: volvo 1.02.2008 18:45
Цитата
А как отловить нажатие двух кнопок сразу?..хочу добавить движение по диагоналям...
Ну, например, вот так:
const int dirLt = 0; const int dirRg = 1; const int dirUp = 2; const int dirDn = 3;
// Делаем множество направлений typedef Set<int, dirLt, dirDn> TDir;
const int num_threads = 2; TMyThread *thr[num_threads];
void __fastcall TMyThread::Execute() { const int nStep = 2;
do {
int dx = 0, dy = 0; for(int dir = dirLt; dir <= dirDn; dir++) { // если текущее направление присутствует во множестве if(FState.Contains(dir)) { // то высчитываем, куда двигаться... switch(dir) { case dirLt: dx = -nStep; break; case dirRg: dx = +nStep; break; case dirUp: dy = -nStep; break; case dirDn: dy = +nStep; break; }
Это мы свойства добавляем?..синтаксис не понятен..=( И:
thr[thread_n]->GetState << dir
<< это что значит?..
Автор: volvo 2.02.2008 8:22
Цитата
Это мы свойства добавляем?
Угу... Именно свойства. А что непонятно? Описываешь свойство (имя и тип), и указываешь что для чтения обращение к свойству аналогично обращению к FState. Поскольку нет write=, то это свойство только для чтения. И не является свойством "по умолчанию".
Цитата
<< это что значит?..
для типа Set перегружены операторы << (через него реализовано добавление элемента в множество) и >> (извлечение элемента из множества, если он там присутствует)
Автор: Fanat 2.02.2008 17:27
Цитата(volvo @ 2.02.2008 4:22)
Угу... Именно свойства. А что непонятно? Описываешь свойство (имя и тип), и указываешь что для чтения обращение к свойству аналогично обращению к FState. Поскольку нет write=, то это свойство только для чтения. И не является свойством "по умолчанию".
Вроде разобрался...а почему используется свойство?...можно так
TDir GetState() {return FState;};
Через свойство лучше чем то?..
Цитата
для типа Set перегружены операторы << (через него реализовано добавление элемента в множество) и >> (извлечение элемента из множества, если он там присутствует)
Понял...
Автор: volvo 2.02.2008 17:41
Цитата
можно так
TDir GetState() {return FState;};
Можно. Только тогда придется делать:
Handled = thr[thread_n]->SetState( thr[thread_n]->GetState() >> dir // <--- вызов функции GetState );
, правда? А не боишься, что у тебя будет постоянно создаваться новая копия множества, и ты потом получишь тормоза при выходе из программы? А при работе с __property ты работаешь с одной и той же переменной...
Автор: Fanat 2.02.2008 18:01
Цитата(volvo @ 2.02.2008 13:41)
Можно. Только тогда придется делать:
Handled = thr[thread_n]->SetState( thr[thread_n]->GetState() >> dir // <--- вызов функции GetState );
, правда?
Ну это понятно...
Цитата
А не боишься, что у тебя будет постоянно создаваться новая копия множества, и ты потом получишь тормоза при выходе из программы? А при работе с __property ты работаешь с одной и той же переменной...
Я так понимаю что они создаються при возвращении значения...но разве эта копия будет существовать до самого выхода из программы?..они не будут удаляться при выходе за '}' ?.. Согласен, что твой вариант работать все равно будет лучше...