Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Передвижение формы по экрану 
:(
    Опции темы
bagos
Дата 30.11.2010, 20:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 275
Регистрация: 17.6.2006

Репутация: нет
Всего: 1



Уважаемые поделитесь идеями, как сделать максимально сглаженным эффект передвижения формы по экрану.
то что сделал не устраивает
Код

procedure TForm1.Button1Click(Sender: TObject);
var
  i:integer;
begin
if form1.Top < 0 then
begin
 for i:=0 to Height*6 - 1 do
  begin
    if Top <> 100*3 then
      Top := Top + 1;
      //Sleep(1);
  end;
end else
begin
for i:=0 to (Height*6 - 1) div 5 do
begin
  if Top <> - Height then
  form1.Top := Form1.Top-5;
  Sleep(1);
end;
end;
          end;


PM MAIL   Вверх
Xenag
Дата 30.11.2010, 23:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Awaiting Authorisation
Сообщений: 51
Регистрация: 6.3.2010

Репутация: нет
Всего: нет



Добавь в оба цикла перед Sleep
Application.ProcessMessages;

Это сообщение отредактировал(а) Xenag - 30.11.2010, 23:12
PM   Вверх
remax
Дата 1.12.2010, 00:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Sleep надо совсем убрать. Эта безусловная задержка не учитывает, что параллельно с Вашей программой выполняются и другие процессы. Для того, чтобы организовать "нормальную" равномерную задержку - надо использовать функцию GetTickCount. 
Да, и конечно использовать Application.ProcessMessages; - иначе не будет нормально отрисовываться форма...


===========
function GetTickCount: Longint;

Считывает вpемя, пpошедшее с момента запуска системы.
Возвpащаемое значение - Пpошедшее вpемя (в миллисекундах). 
 

Это сообщение отредактировал(а) remax - 1.12.2010, 00:39


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
bagos
Дата 1.12.2010, 01:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 275
Регистрация: 17.6.2006

Репутация: нет
Всего: 1



Спасибо за ответы!
Код

var
  i:integer;
  formtop : integer;
begin
    GetTickCount;
    Application.ProcessMessages;
    formtop := form1.Top;
    for i:=0 to formtop do
      if form1.Top > 0 then
        form1.Top := form1.Top - 5;


также пихал процесмесаг в цикл и геттиккаунт не помогает, шлейф солидный
PM MAIL   Вверх
remax
Дата 1.12.2010, 10:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



не-не, GetTickCount нужен не сам по себе, а нужен результат который он возвращает. Именно его использовать при определении задержки между отображением.

Кроме того, скорость отрисовки формы СУЩЕСТВЕННО зависит от ее содержимого.

И, самое главное, если недостаточные видеоресурсы или неправильно настроена система, то хоть что делай а толку не будет. Для начала надо убедиться, что, например, окно Блокнота перемещается (мышкой) без шлейфа...


Вариант с таймером (интервал = 20)
Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls;

type
  TForm1 = class(TForm)
    Timer1: TTimer;
    procedure Timer1Timer(Sender: TObject);
  private
    n:integer;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  timer1.Enabled:=false;
  n:=(n+3) mod 360;
  top:=150+round(75*sin(n/57.3));
  left:=150+round(75*cos(n/57.3));
  Application.ProcessMessages;
  timer1.Enabled:=true;
end;

end.


Вариант с синхронизацией по GetTickCount (интервал перерисовки - те же 20 мс)

Код

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure MyView;
  public
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


procedure TForm1.Button1Click(Sender: TObject);
begin
  MyView;
end;

// 10 секунд крутим форму по кругу, затем закроем прогу
procedure TForm1.MyView;
var
  n,tm,old:integer;
begin
  tm:=GetTickCount;
  old:=tm;
  repeat
   if (GetTickCount-tm>20) then
    begin
      n:=(n+3*((GetTickCount-tm)div 20)) mod 360;
      top:=150+round(75*sin(n/57.3));
      left:=150+round(75*cos(n/57.3));
      Application.ProcessMessages;
      tm:=GetTickCount;
    end;
  until (tm-old>10000);
  close;
end;

end.




Это сообщение отредактировал(а) remax - 1.12.2010, 10:49


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
Snowy
Дата 1.12.2010, 12:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Цитата(remax @  1.12.2010,  00:38 Найти цитируемый пост)
Sleep надо совсем убрать. Эта безусловная задержка не учитывает, что параллельно с Вашей программой выполняются и другие процессы. 
Это с какого такого перепоя?
Как раз в этом и смысл Sleep - замораживать текущий тред на указанное время и передавать уплавление системе.
Если его не ставить, то загрузка процессора будет 100%
PM MAIL   Вверх
remax
Дата 1.12.2010, 14:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Цитата(Snowy @ 1.12.2010,  12:50)
Цитата(remax @  1.12.2010,  00:38 Найти цитируемый пост)
Sleep надо совсем убрать. Эта безусловная задержка не учитывает, что параллельно с Вашей программой выполняются и другие процессы. 
Это с какого такого перепоя?
Как раз в этом и смысл Sleep - замораживать текущий тред на указанное время и передавать уплавление системе.
Если его не ставить, то загрузка процессора будет 100%


1. Да, Sleep - замораживает текущий тред. Но, его применение в лоб не позволяет обеспечить одинаковые задержки, особенно когда речь идет о малых временнЫх интервалах. А тем более, если система загружена другими ресурсоемкими приложениями, работающими в параллель.

Обратите внимание на параметр Sleep у ТС. Точность 1мс Sleep не обеспечит - обычно речь идет о 10-15 мс.  Т.е., при выборе значения параметра менее 15 задержка через Sleep обеспечит либо 15 мс, либо 0. И это без учета паралельных задач....

2. Для передачи управления системе, обычно, вполне хватает  Application.ProcessMessages; И при разумном его использовании ни о каких 100% загрузки проца речь не идет. (см. примеры из моего предыдущего топика).



Это сообщение отредактировал(а) remax - 1.12.2010, 15:10


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
Snowy
Дата 1.12.2010, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Цитата(remax @  1.12.2010,  14:33 Найти цитируемый пост)
Да, Sleep - замораживает текущий тред. Но, его применение в лоб не позволяет обеспечить одинаковые задержки, особенно когда речь идет о малых временнЫх интервалах.
Сколько вешать в граммах? К чему такая точность?
При постоянных условиях, интервал будет примерно одинаков. Для большинства задач этого за глаза.

Цитата(remax @  1.12.2010,  14:33 Найти цитируемый пост)
Для передачи управления системе, обычно, вполне хватает  Application.ProcessMessages; И при разумном его использовании ни о каких 100% загрузки проца речь не идет.
Ок. Речь идёт о 100% загрузке ядра процессора.
В случае 2-х ядерного процессора, загрузка будет 50%...
Ты вхолостую крутишь процессор без перерыва. Конечно там 100% загрузка.
PM MAIL   Вверх
remax
Дата 1.12.2010, 18:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Цитата(Snowy @ 1.12.2010,  15:34)
Сколько вешать в граммах? К чему такая точность?
При постоянных условиях, интервал будет примерно одинаков. Для большинства задач этого за глаза.

Пишем такой сложнейший код (на форме кнопка и мемо):
Код

procedure TForm1.Button1Click(Sender: TObject);
var n,t1,t2:integer;
begin
  memo1.Lines.Clear;
  for n:=1 to 2000 do
    begin
      t1:=GetTickCount;
      sleep(1);
      t2:=GetTickCount;
      memo1.Lines.Append(inttostr(t2-t1));
    end;
end;


Запускаем. И, о чудо, смотрим результат. Результат представляет собой примерно такую повторяющуюся последовательность:

0
0
0
0
0
0
15
0
0
0
0
0
0
0
16
0
...

Что, конечно, практически не отличается от ожидаемой последовательности
1
1
1
1
1
1
...

Может быть эта проблема точности GetTickCount? По крайней мере "0" - это возможно меньше "1".  Чтож, проверим - заменим  sleep(1) на sleep(5). И что, что мы видим. Наверное ряд 5 или, хотя бы, 4?
Нет, мы опять видим  
16
0
15
0
0
16
0
0
16
0
15
0
16
0
0
Т.е., можно сделать вывод, что маленькая задержка через sleep  либо вообще не делается либо в пределах точности 15 мс. Это  при незагруженном процессоре. Теперь запустим наш тест и чем-то еще загрузим. Я, например, потаскаю по экрану окно другой программы. Смотрим результат:
0
63
0
0
125
62
63
62
47
0
16
0
15
32
31
31
....
На мой взгляд, это, во первых, сильно отличается от поставленной задачи. во вторых, далеко не равномерные интервалы.

Выводы:
1. Использование Sleep не обеспечивает правильных программных задержек. Реализуемая точность  +-15 мс.  (зависит от конкретного компьютера) 
2. При высокой загрузке системы и использовании Sleep возможны многократные увеличения интервалов паузы.
3.  Соответственно, нежелательно использовать Sleep для малых интервалов - величина которых соизмерима с 10-15 мс. Это, если нам нужна точность, то  паузу меньше чем 0.1 с  через Sleep не делаем. 
4. Не используем Sleep и для больших (больших, чем 1 с) интервалов - при этом, внешне прога выглядит как зависшая. т.е. Использовать Sleep можно для неточных пауз в интервале от 0.1 до 1.0 с.
 


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
remax
Дата 1.12.2010, 18:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Цитата(Snowy @ 1.12.2010,  15:34)
Цитата(remax @  1.12.2010,  14:33 Найти цитируемый пост)
Для передачи управления системе, обычно, вполне хватает  Application.ProcessMessages; И при разумном его использовании ни о каких 100% загрузки проца речь не идет.
Ок. Речь идёт о 100% загрузке ядра процессора.
В случае 2-х ядерного процессора, загрузка будет 50%...
Ты вхолостую крутишь процессор без перерыва. Конечно там 100% загрузка.

Я так понял, что уважаемый Snowy не счел нужным запустить указанные примеры.
Тогда бы он увидел, что загрузка не все время 100%, а похожа на пилу. Всплески во время движения формы и провалы практически до 0 между движениями. Конечно, абсолютные цифры зависят от параметров каждой конкретной системы. Да и от выбранной дискретности движения. Но, это зависит не от применения/неприменения Sleep, а зависит оттого сколько ресурсов тратится на непосредственно отрисовку движения формы.   

Что, в прочем, совсем не удивительно, по крайней мере для меня. Поскольку применение Application.ProcessMessages позволяет корректно решить задачу эффективного использования ресурсов во время вынужденного простоя программы.

П.С. Кстати, у ТС никак не было оговорена необходимость уменьшения загрузки проца. А необходимо было обеспечить плавность перемещения. Даже, если бы была 100% загрузки при равномерном перемещении, то задача была бы выполнена. В отличие от применения sleep...  smile 


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
Snowy
Дата 2.12.2010, 13:21 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 11363
Регистрация: 13.10.2004
Где: Питер

Репутация: 192
Всего: 484



Я не собираюсь спорить на тему, что Sleep не даёт высокой точности.
Это очевидно.
Я говорил о том, что для данной задачи, такая точность совершенно ни к чему.

Что касается загрузки.
Да, при вызове ProcessMessages она падает.
Но потом следует несколько сотен циклов полной нагрузки.
То есть мы имеем 100% нагрузку с редкими спадами.
Получается вот такая "пила"
user posted image

А теперь возьмём вариант со Sleep:
Код
var
  n,i:integer;
  w, h: integer;
begin
  w := (Screen.Width - Width) div 2;
  h := (Screen.Height - Height) div 2;
  for i := 1 to 400 do
  begin
    Left := Round((-Cos(pi / 200 * i) + 1) * h);
    Top := Round((Sin(pi / 80 * i) + 1) * h);
    Application.ProcessMessages;
    Sleep(20);
  end;
end;
Получаем:
user posted image
PM MAIL   Вверх
RinOSpro
Дата 2.12.2010, 14:33 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











remax ты до этого прошивку для атомных часов что ли писал)) Жжешь, смотрю на это "чудо" 

Код

   if (GetTickCount-tm>20) then
    begin
      n:=(n+3*((GetTickCount-tm)div 20)) mod 360;

      tm:=GetTickCount;
    end;
  until (tm-old>10000);


и хочется спросить где ты такую траву берешь)?

Цитата(remax @  1.12.2010,  14:33 Найти цитируемый пост)
Точность 1мс Sleep не обеспечит - обычно речь идет о 10-15 мс

Твой цикл с GetTickCount тоже не обеспечит. Ты слышал что ни будь про вытесняющую многозадачность, и планирование потоков в виндовс? Почитай) Ссылку кидать не буду ибо она прикреплена на очень видном месте)

Ах да, прочти еще раз название темы. Автор и в правду не атомные часы делает у него цель менее амбициозная.
  Вверх
remax
Дата 2.12.2010, 18:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Цитата(RinOSpro @ 2.12.2010,  14:33)
remax ты до этого прошивку для атомных часов что ли писал)) Жжешь, смотрю на это "чудо" 

Код

   if (GetTickCount-tm>20) then
    begin
      n:=(n+3*((GetTickCount-tm)div 20)) mod 360;

      tm:=GetTickCount;
    end;
  until (tm-old>10000);


и хочется спросить где ты такую траву берешь)?

Цитата(remax @  1.12.2010,  14:33 Найти цитируемый пост)
Точность 1мс Sleep не обеспечит - обычно речь идет о 10-15 мс

Твой цикл с GetTickCount тоже не обеспечит. Ты слышал что ни будь про вытесняющую многозадачность, и планирование потоков в виндовс? Почитай) Ссылку кидать не буду ибо она прикреплена на очень видном месте)

Ах да, прочти еще раз название темы. Автор и в правду не атомные часы делает у него цель менее амбициозная.

Жаль, что приходится объяснять очевидные вещи, но видно без этого не обойтись.
1. Для отображения красивого перемещения формы необходимо обеспечить высокую степень равномерности. Очевидно?
2. Если делать ни с чем не синхронизированные задержки разной величины (от 0 до 15), то равномерности не будет. Очевидно?
3. Мой пример при незагруженном компьютере обеспечивает задержки 20мс с точностью до 1 мс. Очевидно?
4. В случае высокой загрузки компьютера возможны просчеты, которые не нарушат равномерности движения. Почему? Смотрим на код: n:=(n+3*((GetTickCount-tm)div 20)) mod 360;  Если для кого не дошло - объясняю: если  пауза прошла больше, чем рассчитано в разы, то и перемещение будет выполнено пропорционально больше. Ясно?

Кстати, не надо объяснять из каких соображений был выбран интервал 20мс?

П.С. Snowy, Вы не будете возражать, что если использовать Sleep(1000) или Sleep(1000000)  smile загрузка процессора вообще станет равной 0? Только, наверное, это не будет красивым движением формы...

П.П.С. Мне казалось, что пора менять свой старенький ноут. Но! Если он настолько быстрее работает, чем компьютер   Snowy, тонаверное, еще подожду  smile 



--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
remax
Дата 2.12.2010, 18:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Доцент
**


Профиль
Группа: Участник Клуба
Сообщений: 686
Регистрация: 7.4.2002
Где: Украина, Харьков

Репутация: 1
Всего: 5



Ага, понятно почему у Snowy такой график загрузки. На более мощном компе, действительно, пила на уровне 100% ядра (50% проца). И причина понятна - больше "холостых" циклов. Правда, непонятно почему так мало зубьев у пилы. Спишем на дискретность измерений.

Выводы:
1. Точность sleep на малых значениях никуда не годится. Можно с уверенностью говорить, что на значениях интервала меньше 10 мс он вообще практически не делает паузу (при стандартных настройках ОС). А на 20 мс он, в среднем, дает ошибку до 5% даже на "незагруженном" копьютере. Однако, если не использовать sleep, особенно на быстрых компьютерах - возможна необоснованная 100% загрузка компа.
  
2. Самый эффективный подход - мой вариант с таймером: никаких лишних действий, никакой неравномерности, никакой лишней загрузки системы. Единственное, что в нем надо для 100% правильности тоже надо привязать движение не к событиям таймера, а к GetTickCount.

Это сообщение отредактировал(а) remax - 2.12.2010, 19:20


--------------------
Как бы ты не старался быть хорошим и правильным человеком с принципами и уважительным отношением к другим, всегда найдется кто-то, кто бросит в тебя какашку
PM MAIL ICQ Skype   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1438 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.