2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему
 
 Помогите разобраться с таймером...
Сообщение02.12.2008, 20:02 


22/09/08
20
Иваново
Здраствуйте. Ситуация такова - имеется программа, автоматически отрисовываящая рандомный график. Все это делается в Timer...
Но проблема в том, что выбор 1 милисекунды в качестве интервала таймера и 1000 милисекунд никакой видимой разницы не дает.
Скажите пожалуйста, что не так в этом коде:

Код:
//---------------------------------------------------------------------------

#include <vcl.h>
#include <windef.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
        : TForm(Owner)
{
Timer1->Enabled = false;
Form1->DoubleBuffered = true;
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Graphics::TBitmap *btm1=new Graphics::TBitmap;
float ypos=0;
    float  st, x, y, z, min;
    float shirina;
    shirina = 150;
    y=250;
    z=250;
    st = 4;
    min = 10;

    btm1->Canvas->Pen->Style = psSolid;
    btm1->Canvas->Pen->Width = st;

      btm1->Canvas->Brush->Color = clBlack;
      btm1->Canvas->FillRect(Rect(0, 0, btm1->Width,
      btm1->Height));
                        btm1->Width = (shirina*(st+1));
btm1->Height = z;
ypos = btm1->Height;
ypos+=min;
x=-(st/2);
btm1->Canvas->Pen->Color = clLime;
randomize();
for (int k=0; k<150; k++)
{
x+=(st+1);
btm1->Canvas->MoveTo(x, ypos);
btm1->Canvas->LineTo(x, ypos-(random(y)));
}
PaintBox1->Canvas->CopyMode = cmSrcCopy;
PaintBox1->Canvas->Draw(0,0, btm1);
delete btm1;
}
//---------------------------------------------------------------------------

 Профиль  
                  
 
 
Сообщение02.12.2008, 20:39 
Аватара пользователя


31/10/08
1244
В таймере лучше поставить refresh или repaint. А отрисовку делать в обработчике OnPaint

 Профиль  
                  
 
 
Сообщение03.12.2008, 18:14 
Заслуженный участник


15/05/05
3445
USA
Возможно 1 мсек - слишком маленький интервал времени.
Попробуйте сравнить 1000 мсек и, скажем, 5000 мсек.

Хотя это и не имеет прямого отношения к вопросу, к совету Pavia присоединяюсь.

 Профиль  
                  
 
 
Сообщение04.12.2008, 08:46 


21/03/06
1545
Москва
Практика показывает, что меньше 10 мс ставить бесполезно, а будет ли заметна разница между 10 мс и 1000 мс - зависит от сложности кода (сколько он займет проц. времени) в функции таймера.

 Профиль  
                  
 
 
Сообщение04.12.2008, 11:36 


22/09/08
20
Иваново
Всем спасибо! буду пробовать...

Добавлено спустя 23 минуты 23 секунды:

Pavia писал(а):
В таймере лучше поставить refresh или repaint. А отрисовку делать в обработчике OnPaint

Вы такой код имели ввиду? :
Код:
.......
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
Refresh();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::PaintBox1Paint(TObject *Sender)
{
Graphics::TBitmap *btm1=new Graphics::TBitmap;
float ypos=0;
    float  st, x, y, z, min;
    float shirina;
    shirina = 150;
    y=250;
    z=250;
    st = 4;
    min = 10;

    btm1->Canvas->Pen->Style = psSolid;
    btm1->Canvas->Pen->Width = st;

      btm1->Canvas->Brush->Color = clBlack;
      btm1->Canvas->FillRect(Rect(0, 0, btm1->Width,
      btm1->Height));
                        btm1->Width = (shirina*(st+1));
btm1->Height = z;

PaintBox1->Width = btm1->Width;
PaintBox1->Height = btm1->Height;

ypos = btm1->Height;
ypos+=min;
x=-(st/2);
btm1->Canvas->Pen->Color = clLime;
randomize();
for (int k=0; k<150; k++)
{
x+=(st+1);
btm1->Canvas->MoveTo(x, ypos);
btm1->Canvas->LineTo(x, ypos-(random(y)));
}
PaintBox1->Canvas->CopyMode = cmSrcCopy;
PaintBox1->Canvas->Draw(0,0, btm1);
delete btm1;
}
//---------------------------------------------------------------------------


Странно, но лишь при первом нажатии кнопки график обновляется с нужной частотой=( далее идет по-старому. Что 15 мс, что 1000. Да и код тут вроде не такой сложный, чтобы занимать много процессорного времени.

 Профиль  
                  
 
 
Сообщение04.12.2008, 13:39 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
Скорее всего, всё дело в randomize().

Дело в том, что randomize, скорее всего, реализована примерно так, как у меня в BDS 2006:
Код:
inline void _RTLENTRY randomize(void)
{
    srand((unsigned) time(NULL));
}

Т.е. последовательность "случайных" значений, возвращаемых функцией random(), будет полностью определяться тем, что вернёт функция time() в момент вызова randomize(), а time() возвращает разные значения не чаще, чем раз в секунду :D
Соответственно, Ваши графики исправно рисуются 100 или там 1000 раз в секунду (зависит от того, насколько шустра видеокарта), но в течение секунды выводят одно и то же. Если убрать из конструктора
Код:
Form1->DoubleBuffered = true;
, то это должно стать хорошо заметно.

Мораль: нет никакой необходимости вызывать функцию randomize() чаще, чем один раз за всё время работы приложения (т.е. в самом начале программы).
Уберите randomize() из рисующей функции и поставьте её в конструктор формы (например). Всё должно заработать на ура.

 Профиль  
                  
 
 
Сообщение04.12.2008, 18:48 


22/09/08
20
Иваново
worm2 писал(а):
Скорее всего, всё дело в randomize().

Дело в том, что randomize, скорее всего, реализована примерно так, как у меня в BDS 2006:
Код:
inline void _RTLENTRY randomize(void)
{
    srand((unsigned) time(NULL));
}


Мораль: нет никакой необходимости вызывать функцию randomize() чаще, чем один раз за всё время работы приложения (т.е. в самом начале программы).
Уберите randomize() из рисующей функции и поставьте её в конструктор формы (например). Всё должно заработать на ура.

worm2, СПАСИБО ВАМ ГРОМАДНОЕ! Вы даже не представляете, сколько времени я бился над этой ерундой! Спасибо!
PS а что дает doublebuffered? я когда разбирался с мерцанием экрана, просто мне посоветовали его включить, и все, не обьясняя сути свойства.

 Профиль  
                  
 
 
Сообщение04.12.2008, 19:31 
Заслуженный участник
Аватара пользователя


01/08/06
3131
Уфа
Насколько я помню (смотреть сейчас лень, можно поискать в справке по билдеру), при включении этого свойства всё рисование на PaintBox1->Canvas выполняется в памяти, и лишь по его окончании выводится на форму, чем снижает мерцание.
Но у Вас, вроде бы, рисование на холсте элемента PaintBox1 выполняется только один раз:
Код:
PaintBox1->Canvas->Draw(0,0, btm1);

поэтому, возможно, в предыдущем сообщении я не прав и, вроде как, DoubleBuffered не играет роли, только лишнюю память использует...

Добавлено спустя 4 минуты 51 секунду:

А может быть, DoubleBuffer всё-таки помогает, потому что перед вызовом обработчика события OnPaint Windows очищает элементы на форме, заливая их цветом фона... В общем, точно не знаю...

 Профиль  
                  
 
 
Сообщение05.12.2008, 21:57 


22/09/08
20
Иваново
worm2 писал(а):
Насколько я помню (смотреть сейчас лень, можно поискать в справке по билдеру), при включении этого свойства всё рисование на PaintBox1->Canvas выполняется в памяти, и лишь по его окончании выводится на форму, чем снижает мерцание.
Но у Вас, вроде бы, рисование на холсте элемента PaintBox1 выполняется только один раз:
Код:
PaintBox1->Canvas->Draw(0,0, btm1);

поэтому, возможно, в предыдущем сообщении я не прав и, вроде как, DoubleBuffered не играет роли, только лишнюю память использует...

Добавлено спустя 4 минуты 51 секунду:

А может быть, DoubleBuffer всё-таки помогает, потому что перед вызовом обработчика события OnPaint Windows очищает элементы на форме, заливая их цветом фона... В общем, точно не знаю...

Все-таки он помогает! Я когда создавал компонент на основе пэйнтбокса, специально включил его в код для проверки. Даже с использованием канвы битмапа с последующим копированием ее на канву самого компонента непосредственно происходит некоторое мерцание(разумеется, при малых значениях интервала таймера). При включении буферизации мерцание практически сводится на нет.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 9 ] 

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group