Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 7 Professional : Excel 2010)
OnTimeメソッドで登録したタスクを解除したい
投稿日時: 18/09/14 15:42:46
投稿者: George

こんにちわ。
 
<前提>
Excelで作成されたフォームでシート上のセル値を表示しているのですが、
信号を受信すると値が変わるようになっています。
 
<やりたいこと>
フォーム上に値をクリップボードにコピーするボタンがあるのですが、
このサブルーチンをフォームが開いたら1秒おきに実行し、
フォームを閉じるときにOnTimeメソッドで解除したい。
 
<やってみたこと>
実際にUserForm_Initialize()メソッドでOnTimeメソッドを使ってこのようにしました。
なお、LogCopyというのが動かしたいルーチン名です。

    Dim sngTime As Single  'UserFormのグローバル領域で定義

    sngTime = Now()
    Application.OnTime EarliestTime:=sngTime + TimeValue("00:00:01"), Procedure:="LogCopy"

UsrForm_Terminate()メソッドで以下のようにしたが、
Application.OnTime EarliestTime:=sngTime + TimeValue("00:00:01"), Procedure:="LogCopy", Schedule:=False

 
しかし、
引用:
実行時エラー '1004':
'OnTime' メソッドは失敗しました: '_Application' オブジェクト

と出てきました。
 
どこがおかしいのか教えてもらえたらと思います。

回答
投稿日時: 18/09/14 16:03:44
投稿者: WinArrow
投稿者のウェブサイトに移動

>LogCopy
 
のプロシジャ内のコードは?

回答
投稿日時: 18/09/14 16:06:42
投稿者: WinArrow
投稿者のウェブサイトに移動

もう一つ
 
UsrForm_Terminate()
実行時の
sngTime
の値はの?

回答
投稿日時: 18/09/14 16:48:56
投稿者: 渡辺 ひかる

こんにちは
  
エラーの対応についてはWinArrowさんにお任せして。。。。
  
アドバイスですが
  
私も最近 RPAもどきを作っていて Ontime はよく使うのですが、
 一度セットした Ontime を解除するのは面倒なので、
モジュールレベルで Bool 型のフラグを作って
 デフォルトは True、やめたい場合は、False にしてます。
  
それで Ontime で走らせる プロシージャの最初にそのフラグを見に行って
Falseなら 何もしないで終了・・というフローを作ってます
  
これだと、Ontimeのセット時間を気にしないでも済みますし
複数のOntime の制御なども楽なので。
  
参考まで

回答
投稿日時: 18/09/14 17:24:02
投稿者: WinArrow
投稿者のウェブサイトに移動

質問の内容とは、少し離れますが、
 
そもそも、

引用:
Excelで作成されたフォームでシート上のセル値を表示しているのですが、
 信号を受信すると値が変わるようになっています。


引用:
フォーム上に値をクリップボードにコピーするボタンがあるのですが

の関連が分かりません。
 
なぜ、Ontimeメソッドを使うのか?
そのあたりを説明してもらうとよいのですが・・・

回答
投稿日時: 18/09/15 11:11:23
投稿者: simple

LogCopyは一度でも正常に動いているのでしょうか?
終了時だけエラーになるのですか?
LogCopyがもしUserForm内に置かれているとするとうまく動きませんよ。
LogCopyは標準モジュールに置いてください。
 
なお、以下は付け足しですが。

 sngTime = Now()
 Application.OnTime EarliestTime:=sngTime + TimeValue("00:00:01"), Procedure:="LogCopy"
のところは、
 sngTime = Now() + TimeValue("00:00:01")
 Application.OnTime EarliestTime:=sngTime , Procedure:="LogCopy"
として、予約時刻そのものを変数に持った方が間違いないのではないですか?
 
そして、
Application.OnTime EarliestTime:=sngTime, Procedure:="LogCopy", Schedule:=False
とするほうが自然かと思います。気のせいかな。

回答
投稿日時: 18/09/17 19:20:50
投稿者: WinArrow
投稿者のウェブサイトに移動

>とするほうが自然かと思います。気のせいかな。
 
気のせいではありません。
解除は、予約した時刻を指定しないとエラーになります。
 
 

回答
投稿日時: 18/09/17 20:22:03
投稿者: simple

コメントありがとうございます。
さすがにそれは承知しています。
 
私が気にしていたのは、
(1)
sngTimeを変数に持っていて、
sngTime + TimeValue("00:00:01")でセットし、
sngTime + TimeValue("00:00:01")で取り消すのと、
(2)
1秒後の時刻を変数に持って、
その変数で設定して、
その変数で取り消すのと、違いが出るものかどうか、ということ。
端数誤差の話が混入するのかどうか、という話だったのです。
実際に確かめるのも面倒だったので、気のせいと言ったのですが、誤解を招きました。

回答
投稿日時: 18/09/17 22:50:52
投稿者: WinArrow
投稿者のウェブサイトに移動

simpleさん、大変失礼しました。
Ontimeを1秒後に予約しておいて
その1秒間のうちに解除する
ってことになるけど・・・
本当にそうなのかな?

回答
投稿日時: 18/09/18 07:17:04
投稿者: simple

LogCopyのなかで処理実行後、自分自身を再予約していると思っていました。
処理終了と再予約の間に取り消しが割り込むとエラーになるかもしれないが、
そう言う話よりも、それ以前の何か勘違いがあるのではないかと懸念しています。
何かバグを踏んでいるような微妙な話なら、質問者さんに失礼かもしれないが。
いずれにしても質問者さんからの説明が待たれますね。

投稿日時: 18/09/18 08:45:50
投稿者: George

少し議論が進んでいますので、まとめてになりますが回答させていただきます。
 
まず、LogCopyについては以下のソースコードで標準モジュール内に書いています。

Sub LogCopy()
    With Sheets(<対象のシート名>)
        .Range("Y24:Z24").Copy
    End With
End Sub

 
あと、OnTimeメソッドの引数EarliestTimeについてですが、
もともとこのメソッドを使おうと思ったきっかけが別のExcelも使いながら
今回ソースなどを公開させていただいたExcelブック内のフォーム内の
ボタンを押してLogCopy()メソッドを動かしながらやっていてブックの遷移が
大変なことから自動的にクリップボードに値をコピー(LogCopyメソッドで)して
貼り付けることだけに専念できればと思って改良を加えようとしたところ
行き詰ったため質問させていただいた次第です。
 
他に良い方法があれば、そちらも検討させていただきたいと思っていて
OnTimeメソッドにこだわっているわけではありません。
 
以上、よろしくお願いします。

回答
投稿日時: 18/09/18 11:42:04
投稿者: WinArrow
投稿者のウェブサイトに移動

いくつか質問します。
 
(1)ユーザーフォームをどのようなモードで開いているのですか?
 ※セルの値が変わる(変える)との関係でお聞きしています。
 ※ユーザーフォームモーダルで開いている場合、
  シートを操作できないと思います。
  従って、セルの値を手操作で変えることはできない。
  もしマクロ(ユーザーフォームの中のコマンド等操作)でセルに埋め込んでいるならば、
  OnTimeメソッドで変わったかキャッチする必要はないと思います。
 
(2)クリップボードに「Copy」する目的はなんですか?
  クリップボードの値をどこで使っているんですか?
 
(3)LogCopyプロシジャの中に「OnTime」メソッドがない・・
  つまり、このマクロは1回しか起動されない。
  しかも、セルの値が変わる以前(多分)に起動され、その後、起動されることはない。
 
(4)セルの値が変わったことを検知するイベントプロシジャをなぜ使わないのですか?
  OnTimeを無駄に動かすことは、得策ではない。
 
個別に疑問符を書きましたが、全体の動きがりかいできていないので
整合とれていません。
 
全体として、何をどのようにしたいのか?
を説明すると、別な観点でアドバイスがもらえるかも?
 
 
 
 
 
 

投稿日時: 18/09/18 16:02:32
投稿者: George

WinArrowさん
ご質問にお答えいたします。
 

引用:
(1)ユーザーフォームをどのようなモードで開いているのですか?
 ※セルの値が変わる(変える)との関係でお聞きしています。
 ※ユーザーフォームモーダルで開いている場合、
  シートを操作できないと思います。
  従って、セルの値を手操作で変えることはできない。
  もしマクロ(ユーザーフォームの中のコマンド等操作)でセルに埋め込んでいるならば、
  OnTimeメソッドで変わったかキャッチする必要はないと思います。

ユーザーフォームはShowModalプロパティをFalseにした上で
[UserForm名].Show

で開いています。
 
引用:
(2)クリップボードに「Copy」する目的はなんですか?
  クリップボードの値をどこで使っているんですか?

目的はセルの値を別のWorkbookに貼り付けるためです。
現状は今回話題にしているWorkbook(※1)とは別にWorkbook(※2)を立ち上げています。
PCに接続した送受信機(治具)からのデータを送受信したら※1のセルの値が変わります。
その値を※2のWorkbookに貼り付けていますが、毎回フォーム上のボタンを押下して行っているので、
なんとかボタンの押下をせずとも送受信でーたが変わったらクリップボードにコピーされれば
※2に貼り付けることだけに専念できるために思いついた次第です。
 
引用:
(3)LogCopyプロシジャの中に「OnTime」メソッドがない・・
  つまり、このマクロは1回しか起動されない。
  しかも、セルの値が変わる以前(多分)に起動され、その後、起動されることはない。

はい。そうです。
私がOnTimeメソッドの使い方をわかっていないためのものと思いますが、
UserForm_Initialize()メソッドで設定して、UserForm_Terminate()メソッドで解除できればと思い、
今回のことを考えました。
 
引用:
(4)セルの値が変わったことを検知するイベントプロシジャをなぜ使わないのですか?
  OnTimeを無駄に動かすことは、得策ではない。

この方法が一番良さそうなので(4)にて試してみます。