Таймеры API в VBA - Как сделать безопасным. Таймер vba


vba - Таймеры API в VBA - Как сделать безопасным

@CoolBlue: И каков механизм сбоя: что происходит, чтобы заставить Excel сбой?

Я могу дать вам расширение ответа Siddarth Rout, но не полное объяснение.

API-вызовы - это не VBA: они существуют вне обработчиков ошибок VBA, и когда все идет не так, они ничего не сделают или не вызовут ресурс в памяти, который не существует, или попытайтесь прочитать (или написать!), чтобы памяти, которая находится за пределами выделенного пространства памяти для Excel.exe

Когда это произойдет, операционная система войдет и выключит ваше приложение. Мы называли это "Общей защитой" и это еще полезное описание процесса.

Теперь для некоторых деталей.

Когда вы вызываете функцию в VBA, вы просто пишете имя - позвольте ему "CheckMyFile()" - и все, что вам нужно знать в VBA. Если ничего не вызвано "CheckMyFile" для вызова или не указано, где ваш вызов не может его увидеть, компилятор или механизм выполнения вызовут ошибку в виде точки останова или предупреждение перед компиляцией и запуском.

За кулисами имеется числовой адрес, связанный со строкой "CheckMyFile": я немного упрощаю, но мы ссылаемся на этот адрес как Function Pointer - следуем этому адресу, и мы перейти к структурированному блоку памяти, в котором хранятся определения параметров функции, пространство для их сохраненных значений и, кроме того, адреса, направляющие эти параметры в функциональные структуры, созданные для выполнения вашего VBA и возвращающие значения по адресу для выхода функции.

Все может пойти не так, и VBA делает много работы, чтобы гарантировать, что все это будет изящно изгибаться, когда они пойдут неправильно.

Если вы укажете этот указатель на то, что не является VBA - внешним приложением или (скажем) вызовом таймера API - ваша функция все равно может быть вызвана, она все равно может работать, и все будет работать.

Но за этим указателем должна быть правильная функция.

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

Он может просто отказаться от вызова и ничего не делать, если Excel и VBA находятся в состоянии "занято" или иным образом недоступны, когда он пытается использовать этот указатель функции: вам может быть повезло, просто один раз. Но это может вызвать ярость операционной системы в процессе Excel.exe.

Если вызов вызывает ошибку, и эта ошибка не обрабатывается вашим кодом, VBA поднимет ошибку вызывающему абоненту - и, поскольку вызывающий абонент не является VBA, у него, вероятно, не будет способа обработки что: и он вызовет "помощь" из операционной системы.

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

Эти предположения:

  • За этим указателем будет определенная функция;
  • Он определенно будет доступен, когда он будет вызван;
  • ... И это не вызовет ошибок для вызывающего.

При вызове API вызывающий абонент - это операционная система, и его ответ на обнаружение ошибки будет закрывать вас.

Итак, очень простой контур процесса - "почему", а не "какое" объяснение.

Полное объяснение, без упрощения, для разработчиков на С++. Если вы действительно хотите получить подробный ответ, вы должны научиться программировать с помощью указателей; и вы должны свободно говорить о понятиях и практике распределения памяти, исключениях, последствиях плохого указателя и механизмов, используемых операционной системой для управления запущенными приложениями и обнаружения недопустимой операции.

VBA существует, чтобы защитить вас от этих знаний и упростить задачу написания приложений.

qaru.site

vba - Таймер в форме пользователя в Excel VBA

Мне нужен был видимый таймер обратного отсчета, который мог бы оставаться поверх других окон и плавно работать независимо от того, изменяете ли вы рабочую книгу или сворачиваете окно Excel. Итак, я адаптировал код для творчества @don-kirkby выше для моих собственных целей и решил, что я поделился бы результатом. В приведенном ниже коде требуется создание модуля и пользовательской формы, как указано в комментариях, или вы можете загрузить .xlsm в нижней части этого ответа.

Я использовал Windows Timer API для более точного и плавного обратного отсчета (а также настраиваемого до ~ 100 миллисекундного разрешения таймера в зависимости от вашего процессора. Там даже звук "тик-тук".

Вставьте новый модуль и сохраните его как modUserFormTimer. Добавьте на рабочий лист две команды управления формой, обозначенные Start Timer и Stop Timer, и назначенные процедуры btnStartTimer_Click и btnStopTimer_Click.

Option Explicit 'modUserFormTimer Public Const showTimerForm = True 'timer runs with/without the userform showing Public Const playTickSound = True 'tick tock (a WAV sounds could be embedded: 'https:// goo.gl/ ReuUyd') Public Const timerDuration = "00:00:20" 'could also Insert>Object a WAV for tick or alarm Public Const onTimerStart_MinimizeExcel = True 'minimize Excel? (countdown remains visible) Public Const onTimerStart_MaximizeExcel = True 'maximize Excel when timer completes? 'timer could be on top of other applications; instructions here: 'https:// goo.gl/ AgmWrM' 'safe for 32 or 64 bit Office: Private Declare PtrSafe Function SetTimer Lib "User32" (ByVal hWnd As Long, ByVal nIDEvent As Long, _ ByVal uElapse As Long, ByVal lpTimerFunc As LongPtr) As Long Private Declare PtrSafe Function KillTimer Lib "User32" (ByVal hWnd As Long, ByVal nIDEvent As Long) As Long Public Declare PtrSafe Function Beep Lib "kernel32" (ByVal dwFreq As Long, ByVal dwDuration As Long) As Long Public schedTime As Date 'this is the "major" timer set date Private m_TimerID As Long Public Sub OnTimerTask() 'the procedure that runs on completion of the "major timer" (timer won't reschedule) Unload frmTimer '''''''''''''''''''''''''''''' MsgBox "Do Something!" ' < < < < < Do Something Here '''''''''''''''''''''''''''''' End Sub Public Sub btnStartTimer_Click() schedTime = Now() + TimeValue(timerDuration) InitTimerForm End Sub Public Sub btnStopTimer_Click() 'clicking the 'x' on the userform also ends the timer (disable the close button to force continue) schedTime = 0 frmTimer.UserForm_Terminate End Sub Public Sub InitTimerForm() 'run this procedure to start the timer frmTimer.OnTimer Load frmTimer If showTimerForm Then If onTimerStart_MinimizeExcel Then Application.WindowState = xlMinimized frmTimer.Show 'timer will still work if userform is hidden (could add a "hide form" option) End If End Sub Public Sub StartTimer(ByVal Duration As Long) 'Begin Millisecond Timer using Windows API (called by UserForm) If m_TimerID = 0 Then If Duration > 0 Then m_TimerID = SetTimer(0, 0, Duration, AddressOf TimerEvent) If m_TimerID = 0 Then MsgBox "Timer initialization failed!", vbCritical, "Timer" End If Else MsgBox "The duration must be greater than zero.", vbCritical, "Timer" End If Else MsgBox "Timer already started.", vbInformation, "Timer" End If End Sub Public Sub StopTimer() If m_TimerID <> 0 Then 'check if timer is active KillTimer 0, m_TimerID 'it active, so kill it m_TimerID = 0 End If End Sub Private Sub TimerEvent() 'the API calls this procedure frmTimer.OnTimer End Sub

Затем создайте пользовательскую форму, сохраните ее как frmTimer. Добавьте текстовое поле с именем txtCountdown. Установите свойство ShowModal в значение False. Вставьте следующее в окно кода формы:

Option Explicit 'code for userform "frmTimer" 'requires a textbox named "txtCountdown" and "ShowModal" set to False. Dim nextTriggerTime As Date Private Sub UserForm_Initialize() ScheduleNextTrigger End Sub Public Sub UserForm_Terminate() StopTimer If schedTime > 0 Then schedTime = 0 End If If onTimerStart_MaximizeExcel Then Application.WindowState = xlMaximized 'maximize excel window Unload Me End Sub Private Sub ScheduleNextTrigger() 'sets the "minor" timer (for the countdown) StartTimer (1000) 'one second End Sub Public Sub OnTimer() 'either update the countdown, or fire the "major" timer task Dim secLeft As Long If Now >= schedTime Then OnTimerTask 'run "major" timer task Unload Me 'close userForm (won't schedule) Else secLeft = CLng((schedTime - Now) * 60 * 60 * 24) If secLeft < 60 Then 'under 1 minute (don't show mm:ss) txtCountdown = secLeft & " sec" Else 'update time remaining in textbox on userform If secLeft > 60 * 60 Then txtCountdown = Format(secLeft / 60 / 60 / 24, "hh:mm:ss") Else 'between 59 and 1 minutes remain: txtCountdown = Right(Format(secLeft / 60 / 60 / 24, "hh:mm:ss"), 5) End If End If If playTickSound Then Beep 16000, 65 'tick sound End If End Sub

Загрузите демо-версию .xksm. здесь. Существует множество способов, которыми это можно настроить или адаптировать к конкретным потребностям. Я собираюсь использовать его для расчета и отображения статистики в реальном времени с популярного сайта Q & A в углу экрана...

Обратите внимание: поскольку он содержит макросы VBA, файл может содержать ваш антивирусный сканер (как и в любом другом нелокальном файле с VBA).Если вы обеспокоены, не загружайте и вместо этого создавайте его с предоставленной информацией.)

qaru.site

Таймер в Excel / Песочница / Хабрахабр

Не помню кто из великих сказал… И не помню что. Но в процессе разработки vba-приложений время от времени возникает необходимость использовать таймер. «Из коробки» решения, к сожалению, нет.
Application.OnTime?
Данный метод отложенных вызовов сам по себe решает проблему, но лишь один раз. В том смысле, что таймер срабатывает лишь единожды — указать переодичность вызовов, увы, нельзя.
Application.OnTime + рекурсия?
Очевидно, что в конце необходимой процедуры можно вызывать её же с помощью данного метода, но не менее очевидны и недостатки этого решения — отсутствие достаточного контроля и неудобство вызова:
  • не таймер вызывает действие;
  • чтобы остановить цикл придётся объявлять глобальную переменную;
  • добавление «костыля» в тело отдельно взятой процедуры. Если в следующий раз будет нужно вызвать по таймеру другую — то и в неё придётся переносить данный «костыль».
Evaluate в помощь?
Написать свой класс и вызывать внутри необходимую процедуру с помощью Application.Evaluate. Особо упорные в стремлении создать приемлемый метод вызова таймера доходят до этого решения и упираются в стран/ш/ный баг, отловить который достаточно сложно: udf-функция переданная в переменной будет вызываться каждый раз по два(!) раза.
Потому что гладилус
Способ обойти этот баг пока найден лишь один:ActiveSheet.Evaluate "0+" & nameOfProcedure
Решение
Для простоты вызова написан не класс, а метод. Достаточно указать интервал, имя вызываемой процедуры и, опционально, кол-во необходимых вызовов:StartTimer 60, "CalculateTotal()", 30 'вызов CalculateTotal() каждую минуту в течении получаса. StopTimer 'остановка таймера модульOption Explicit Private Type Timer interval As Long procedure As String times As Long enabled As Boolean initialized As Boolean ticks As Long End Type Private Timer As Timer Public Sub StartTimer(ByRef interval As Long, _ ByRef procedure As String, _ Optional ByRef times As Long) With Timer .interval = interval .procedure = procedure .times = times .enabled = True .initialized = False .ticks = 0 End With InvokeTimer End Sub Public Sub StopTimer() Timer.enabled = False End Sub Private Function InvokeTimer() If Timer.ticks > Timer.times And Not Timer.times = 0 Then StopTimer If Not Timer.enabled Then Exit Function If Timer.initialized Then ActiveSheet.Evaluate "0+" & Timer.procedure Else Timer.initialized = True End If Timer.ticks = Timer.ticks + 1 Application.OnTime Now + 1 / 86400 * Timer.interval, "InvokeTimer" End Function

habr.com

Visual Basic с нуля. Глава 3. Переменные, оператор If, таймер.

Переменные. Инструкция Option Explicit.

Все, пора поговорить о переменных. Перегружать информацией я тебя не буду, но минимум знать надо.

Очень желательно, чтобы программа начиналась с инструкции Option Explicit в секции General. Эта инструкция заставляет программиста явно объявлять переменные. При ее отсутствии всякое слово, не противоречащее синтаксису VB, может быть переменной. Что происходит, если мы не используем инструкцию Option Explicit? А то, что мы вообще можем не объявлять переменные. Это ведь здорово! А вот и нет! А почему нет, видно из следующего:

При отсутствии Option Explicit, если нам нужна новая переменная, мы просто вводим ее в код программы, например,

NewChislo=7

и опс, Visual Basic уже подсуетился и зарезервировал для переменной памяти, причем зарезервировал по полной программе - максимально. Дело в том, что если явно не задавать тип переменнной, VB считает переменную типом Variant, так как такая переменная может содержать почти любые данные: и целые, и дробные, и строковые. Зато и памяти эта переменная использует очень много. Если же мы явно объявим переменную и зададим ее тип сообразно с нашими потребностями, то рациональное использование памяти - на лицо. Если тебя это соображение не убедило, то представим ситуацию, когда ты повторно используешь свою переменную для, например, изменения ее значения. И при этом делаешь опечатку (а опечаток делается очень много), пропускаешь букву h:

NewCislo=NewCislo+1

Для Visual Basic в этом никакой ошибки нет. Он при компиляции быстренько резервирует память под новую переменную NewCislo, считая ее типом Variant и у него никаких проблем. Проблемы у тебя. И критичные. Во-первых, ты имеешь ненужную переменную NewCislo со значением 1, о которой ты знать не знаешь. Во-вторых, если ты ожидаешь, что значение твоей начальной переменной NewChislo увеличилось на 1 и стало 8, то это совершенно напрасно. А вот ожидать, что результат выполнения твоей программы даст непредсказуемый результат можно смело.

Иное дело, если ты использовал инструкцию Option Explicit. В этом случае, при запуске программы, Visual Basic тут же найдет новую необъявленную переменную и остановит выполнение программы на строке с ошибкой.

Если я тебя убедил, тогда, чтобы не писать инструкцию Option Explicit в каждом новом проекте, нажми кнопку “Инструменты” (Tools), выбери “Опции” и в окрывшемся окне на вкладке “Редактор” поставь галочку напротив надписи “Требовать определение переменной”, потом OK. Теперь, всякий раз при создании нового проекта (но только нового, в старые эту инструкцию надо прописывать в (General) вручную.), VB сам, автоматически, будет прописывать Option Explicit.

Любое слово, кроме зарезервированных VB, можно сделать именем переменной. Но начинаться имя должно с буквенного символа. Например Peremenaia, Ima1, X, LastNumber, z001. Не надо использовать в именах математические операторы. И нельзя объявлять две переменные с одинаковыми именами. В принципе, для удобства чтения кода и солидности существуют определенные рекомендованные правила (что-то вроде стандартов) написания имен переменных. Но, так как использование этих правил - сугубо личное дело каждого, я их придерживаться не буду. Если охота, поищи в Интернете что-нибудь про Венгерское соглашение, Венгерскую нотацию или соглашение Реддика.

Итак, при явном объвлении переменной очень желательно явно задавать ее тип. В крайне редких случаях, когда тип хранимых данных в переменной заранее неизвестен, используется как раз тип Variant. В Visual Basic наиболее часто используются следующие типы данных (а соответственно переменных):

Long ‘длинное целое число со знаком от –2 147 483 648 до 2 147 483 647

Integer ‘целое число со знаком от –32 768 до 32767

String ‘строка символов

Boolean ‘логическое, принимает два значения или “True” (Истина) или “False” (Ложь)

Пока что нам этого хватит. Если интересно, то перечень типов данных, поддерживаемые VB, можно посмотреть здесь.

Теперь, где и как их объявлять. Если ты объявишь переменную в теле процедуры объекта, например кнопки, то доступна она будет только в этой процедуре. В другой, скажем, кнопке, ее использовать нельзя. Чтобы переменную использовать во всей форме, надо объявить ее в разделе деклараций (это в самом верху кода – (General) – (Declarations). Для этих случаев можно использовать инструкцию Dim. Ну, а чтоб она была доступна во всей программе (в разных, например, формах) она должна быть объявлена в стандартном модуле с ключевым словом Public. Но модулей мы пока не создавали и оставим это до поры в стороне. Ну вот, на первое время этого о переменных хватит. Чтобы было совсем понятно, вот пример объявления переменных:

Option Explicit

Dim MyStream As String Dim K14 As Long Dim Flag As Boolean Dim Numder As Integer

Private Sub Form_Load()Dim Flag2 As Boolean Dim m99little As String End Sub

Таймер. Программа “Часики”.

Теперь разберем использование нового объекта - Timer (таймера). Слева, где компоненты формы, они же инструменты-элементы, нарисован такой будильничек. Это таймер и есть. Он всегда невидимый, но нужный элемент. Всего их одновременно можно использовать около 30 штук. Но нам такое количество таймеров не надо.

Создадим новый exe-проект и поместим один таймер на форму. На основе его мы сделаем сейчас маленькие часики. В свойствах этого таймера поставьте следующие установки:

Enabled – False (по умолчанию True) означает, что таймер выключен

Interval – 1000 (время, в миллисекундах, через которое таймер срабатывает, если конечно включен). Таймер будет срабатывать каждые 1000 мск, т.е. каждую секунду, как в нормальных часах.

Кроме того, нам понадобятся три лейбла: Label1 для секунд, Label2 для минут и Label3 – сами догадайтесь для чего. Правильно, для часов. Все.

Изменим свойства лейблов следующим образом:

Alignment – 2-Центровка (Это чтоб цифры были по центру лейблов)BorderStyle – 1-Фиксировано (это чтоб размер формы нельзя было изменить)Caption – 00 (на всякий случай, т.е. значение лейблов изначально будет “00”)

Нажми Font и выбери размер шрифта 14, а начертание – полужирное. После этого подбери подходящий размер окон Лейблов, чтобы цифры в них выглядели симпатично.

Должно получиться как на рис.8.

Рисунок 8.

Создадим процедуру Form_Load .

Option Explicit

Private Sub Form1_Load()

Затем в теле процедуры, как у всякой приличной программы, меняем заголовок формы.

Form1.Caption = "Часики"

Дальше, для того, чтобы наши часы сразу показывали текущее время, надо его взять из компьютера. Чтобы получить системное время, есть функция Time (Label1.Caption=Time). Но она дает полное время одной строкой (16:23:42). Нам тогда придется выбирать из нее секунды, минуты и часы, чтобы распихать по свои лейблам. А чтобы этого не делать, можно взять готовые функции, которые предоставят нам это все по частям:

Label1.Caption = Second(Time) 'стало быть секундыLabel2.Caption = Minute(Time) 'ну, минутыLabel3.Caption = Hour(Time) ' и часы

Теперь, при запуске того, что мы наваяли, у нас будет показываться текущее время. Это, конечно, прогресс, но вот только часики-то стоят. Трясти монитор не стоит, они от этого не пойдут, а вот запустить таймер одной простой строчкой мы сможем:

Timer1.Enabled = True

Вот она, булева алгебра (ну еще не алгебра, но уже кое-что). То есть Timer1.Enabled может быть либо включен (True), либо выключен (False). На этом процедура Form1_Load() закончена:

End Sub

Чтобы получить хоть какие-нибудь блага от запущенного таймера и заставить наши часики ходить, создадим процедуру, которая будет исполняться при наступлении события срабатывания таймера. Событие это у таймера единственное и называется тоже .Timer. Возникает оно в тот момент, когда таймер досчитывает до предела, установленного в свойстве Interval и соответственно сбрасывается на ноль.

Private Sub Timer1_Timer()

Наши секунды должны увеличиваться на одну за каждое срабатывание таймера. Поэтому пишем счетчик, который будет увеличивать значение наших секунд на единицу при каждом срабатывании таймера:

Label1.Caption = Label1.Caption + 1

И вот мы вплотную подошли к проблеме условного оператора (а лучше инструкции) If, без которого - никуда. Суть этой инструкции в том, что он позволяет при неком создавшемся условии производить изменения в ходе программы в зависимости от этого условия.

Инструкция условия If.

Этоу инструкцию можно использовать в блоковой форме: полном (развернутом) виде и неполном (без строк ElseIf), а также в одну строку. В полном виде в блоковой форме синтаксис этой инструкции будет выглядеть следующим образом:

If Условие1 Then группа операторов1ElseIf Условие2 Then группа операторов2 ..............ElseIf УсловиеN Then группа операторовNElse Последняя группа операторовEnd If

Условие представляет из себя оператор, значение которого может принимать True (Истина) или False (Ложь). Например, если Условие1 представляет из себя выражение X>1, то оно истинно, если X равно 2, то оно ложно при значении X равном 1. Если Условие1 истинно, то выполняется группа операторов1, остальные группы операторов не выполняются, если даже в каких-нибудь последующих ветках УсловиеN истинно. Если Условие1 ложно, то группа операторов1 не выполняется, а производится проверка Условие2 в следующей ветке ElseIf. И опять же, если Условие2 истинно, то выполняется группа операторов2, последующие группы операторов не выполняются и их условия не проверяются. В противном случае происходит переход к следующей ветке ElseIf. Если ни в одной ветке нет истинных операторов, выполняется последняя группа операторов вне зависимости от каких-либо условий. Логическая схема инструкции If представлена в таблице:

Наиболее часто инструкция If используется в блоковой форме в неполном (усеченном) виде. В этом случае строки ElseIf отсутствуют:

If Условие Then группа операторов1Else группа операторов2End If

В этом случае, если Условие - истинно, то выполняется группа операторов1, а если нет, то группа операторов2.

Также довольно часто возникает необходимость в зависимости от условия выполнить один оператор. Тогда Инструкция If может использоваться одной строчкой, без строки End If.

If Условие Then Оператор1 Else Оператор2

или еще короче

If Условие Then Оператор1

Все очень просто. Это вообще мой любимый оператор (куда удобнее и универсальней, чем Select... Case).

А теперь применим знание этого оператора на практике. Чтобы у нас показания времени в нашей программе «Часики» до десятка были с ноликами 01, 02, 03, а не 1, 2, 3 мы проверяем условие, меньше ли двух длина числа, записанного в лейбле. Если да, то прибавляем впереди нолик. Для этого используем функцию Len("строка"), которая определит число символов в строке. Если в строке, например, 2 символа, то Len даст число 2. У нас получится:

If Len(Label1.Caption) < 2 Then Label1.Caption = "0" & Label1.Caption ‘для первого лейбла

Но ведь и при загрузке системного времени в процедуре Form1_Load нам тоже нужна такая проверка. Не будем же мы переписывать одно и тоже в двух разных процедурах. Мы сделаем свою общую процедуру и будем обращаться к ней по мере необходимости. Назовем ее, к примеру, Zero. В конце нашей программы на свободном месте набираем на клавиатуре новую процедуру:

Private Sub Zero()If Len(Label1.Caption) < 2 Then Label1.Caption = "0" & Label1.CaptionIf Len(Label2.Caption) < 2 Then Label2.Caption = "0" & Label2.CaptionIf Len(Label3.Caption)< 2 Then Label3.Caption = "0" & Label3.CaptionEnd Sub

Таким образом, у нас теперь есть своя собственная процедура, которая называется Zero. Никаких событий для ее выполнения нет и, чтобы она работала, ее нужно пробудить из нужного места программы, для чего просто пишем ее имя Zero. А нужные эти места находятся в последней строчке в процедурах Form1_Load() и Timer1_Timer(), прямо (перед End Sub).

Ну вот, с ноликами все в порядке, зато часы не работают. В подпрограмме Timer1_Timer() у нас всего один оператор. Чтобы часы работали, как настоящие, нам надо, чтобы, когда секунд становилось больше 59, они обнулялись, при этом минуты увеличивались бы на один. Используя оператор If это сделать очень легко:

If Label1.Caption > 59 ThenLabel1.Caption = "0" Label2.Caption = Label2.Caption + 1End If 'То же самое для Лейбла2:If Label2.Caption > 59 ThenLabel2.Caption = "0" Label3.Caption = Label3.Caption + 1End If

Аналогично для Label3 . Нам надо, чтоб, при значении часов больше 23 часов, Label3 показывал не 24, а ноль:

If Label3.Caption > 23 Then Label3.Caption = "0"

Теперь ставим ссылочку на нашу процедуру проверки ноликов Zero :

Zero

И готово, т.е.

End Sub

Вот полный листинг того, что получилось. Кто хочет, может скачать исходник примера вверху страницы.

Option Explicit

Private Sub Form_Load() Form1.Caption = "Часики" Label1.Caption = Second(Time) Label2.Caption = Minute(Time) Label3.Caption = Hour(Time) Timer1.Enabled = TrueZeroEnd Sub

Private Sub Timer1_Timer() Label1.Caption = Label1.Caption + 1If Label1.Caption > 59 ThenLabel1.Caption = "0" Label2.Caption = Label2.Caption + 1End If If Label2.Caption > 59 ThenLabel2.Caption = "0" Label3.Caption = Label3.Caption + 1End If If Label3.Caption > 23 Then Label3.Caption = "0" ZeroEnd Sub

Private Sub Zero()If Len(Label1.Caption) < 2 Then Label1.Caption = "0" & Label1.CaptionIf Len(Label2.Caption) < 2 Then Label2.Caption = "0" & Label2.CaptionIf Len(Label3.Caption) < 2 Then Label3.Caption = "0" & Label3.CaptionEnd Sub

Теперь вот что. Тебе надо самостоятельно разобраться с другой программой – «Однорукий бандит». Если сможешь - будешь программировать, если нет, читай все сначала. Я даю исходник с подробнейшими-преподробнейшими комментариями. Скачай его здесь. «Однорукий бандит» - имитация работы известного аппарата для азартных игр. В трех Лейблах отображаются меняющиеся цифры от 1 до 7. Для работы с ними используются три переменные Number. Их изменение управляется тремя таймерами. Первоначально интервалы у таймеров одинаковы – 10 мск. В трех переменных Zamedlenie генерируются случайные числа.

Zamedlenie1 = Int(Rnd * 20) + 10

Работает это так. Rnd генерирует псевдослучайное число от 0 до 1. На двадцать умножаем, чтобы получить целую часть числа (можно умножать на что угодно, но не меньше 10, а то не получится целая часть). Функция Int отбрасывает дробную часть. Прибавляем в конце 10, чтобы исключить значение 0, а то таймер не остановится. Т.е., если Rnd генерирует, например, число 0,156, то

Zamedlenie1= Округляем (0,156*20) + 10 = 3 + 10 = 13. Очень просто.

При каждом срабатывании таймераувеличивается его интервал на значение замедления, пока интервал не становится больше 300 (это задано программно: Timer1.Interval > 300

После этого таймер выключается. Чтобы узнать, все ли таймеры выключились, я использую переменную Flag, которая накапливает в себе количество выключившихся таймеров. Когда Flag=3, считаем, что все три таймера закончили работу (а так оно и есть) и начинаем обрабатывать результаты (подпрограмма Raschet()). Изначальный капитал игрока хранится в переменной Summa, которая при различных выигрышах изменяется на сумму трех переменных Bonus, а при проигрыше на переменную BonusMinus. Почему ее значение отрицательное? Просто мне так захотелось, хотя это, конечно,совершенно необязательно. В Лейблах 4 и 5 выводятся всякие прикольные надписи, в зависимости от результата игры. Ну и кроме того, чтобы во время работы таймеров кнопка не нажималась, она, по состоянию переменной FlagClick, либо позволяет запустить таймеры, либо меняет свою надпись.

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

В этой программе мы впервые объявляем переменные. Ничего в этом сложного нет. Главное, чтоб тип переменной приблизительно соответствовал нашим надобностям. Просто посмотри, как это деляется.

Ну вот, практически и все. Остальное ты должен додумать сам. Удачи.

Copyright © 2004 4us

Сайт создан в системе uCoz

vbzero.narod.ru