質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

4回答

9911閲覧

C# ボタンをクリックしている間に指定の関数を実行し続けたい

yar

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2020/07/14 06:41

編集2020/07/15 02:57

ボタンを右クリックし続けている間に指定した関数を実行し続けたいと考えています。
MouseDown.Up等で実装できるかもしれないと思い試してみたのですが長押しにうまく対応することができません。

具体的に「テキストに100と入力されている→ボタンを押す→テキストが99になりラベル0が1になる」処理を長押しでリアルタイムで確認できるように実装したいと考えています。

どうすれば実装することができるでしょうか?ご教授お願い致します。

C#のFormApplicationを使用しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Zuishin

2020/07/14 12:34

実行し続けたいということは中でループが実行されているんだと思います。ループを外からのイベントで終了するのは、CancellationToken を使うのが定石です。またそのループはフォームの動きを止めてしまうので、非同期で行うと良いでしょう。 または System.Reactive を使います。こちらの方が簡単かもしれません。
YAmaGNZ

2020/07/15 03:08

ご自身が回答に対して試されたことを具体的なコードも出さずに「出来ませんでした。どうやればいいですか?」とだけ聞かれても回答者の方は困るのではないでしょうか?
YAmaGNZ

2020/07/15 03:21

「テキストに100と入力されている→ボタンを押す→テキストが99になりラベル0が1になる」とのことですが ボタンを押している間、テキストは1づつ減っていき、ラベルは1づつ増えていくということですか? それはどれくらいのスピードですか? ただループで減らす(増やす)のであれば、100くらいであれば一瞬で終わってしまい視認することは無理だと思います。
Zuishin

2020/07/15 03:22

UI の話なら一瞬で数字がいくつも変わったのでは使いにくいのでタイマー処理は必須でしょうね。それも押し始めと中頃では速度を変える方が使いやすくなると思います。System.Reactive の出番ですね。
yar

2020/07/15 03:24

>YAmaGNZ >テキストは1づつ減っていき、ラベルは1づつ増えていくということですか? それを想定しています。スピードに関しては視認できるものを想定していたのですが厳しいですかね...
yar

2020/07/15 03:25

>Zuishin timerの処理調べて試してみます!ありがとうございます。
guest

回答4

0

  • MouseDown で目的の処理を開始
  • MouseUp で目的の処理を終了

すればよいです。

ただし、マウスイベントのハンドラに目的の処理をまんま書いてしまうと UI の処理がブロックしてしまうので、目的の処理は

  • BackgraoundWorker
  • Task
  • Thread

などから、用途に適したものを使用して、UI 処理とは異なるスレッドで実行してください。

投稿2020/07/14 12:54

hidori

総合スコア403

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yar

2020/07/15 02:59

回答ありがとうございます。 非同期処理について調べ、中でもTaskが適していると思い、試したのですが1つ1つ実行されずに規定数一気に実行されてしまいます。 1つ1つ実行される方法はないでしょうか?
hidori

2020/07/15 03:08 編集

どういう動作を望んでいて、どういうコードを書いたのでしょうか? 何の脈絡もなく、「1つ1つ」や「規定数」と言われても、よく分からないです。
hidori

2020/07/15 03:11 編集

仮に、要件が * 実行するべき処理がいくつかあって、ボタンを押している間にそれらを1つずつ実行したい * ボタンを離したら、処理を中断したい だとして * ボタンを離した時に実行中の処理はどうしますか?(中断?継続?) * 再度ボタンを押された時には、どの処理から実行しますか? などなど。
yar

2020/07/15 03:12

動作に関しては追記させていただきました。 コードに関しては >for(i;i<規定数;i++) >await Task.Run(() => Lottery(i)); のように書きました。説明不足で申し訳ありません。
hidori

2020/07/15 03:18 編集

そのコードをどこに書きましたか? MouseDown イベントのハンドラの中ですか? どこに書いてるかにもよりますが、await が機能してるなら、Task.Run() は並列ではなく、順次実行されるはずですよ。
yar

2020/07/15 03:22

MouseButtondown内に書きました。
hidori

2020/07/15 03:24

Windows Forms では、イベントハンドラの中に await が書けなかったような気がするのですが、ビルド出来てますか?
yar

2020/07/15 03:27

awaitでエラーが起こりビルドできなかったので調べたところasyncをMouseButtonに追記することで使用することができるとサイトい書いてありビルドエラーは回避することができました。
hidori

2020/07/15 03:39 編集

なるほど。WPF ではそれで良かった気がしますが、Windows Forms でもそれでいいんですね。 で、話は戻りますが ``` for(i;i<規定数;i++) >await Task.Run(() => Lottery(i)); ``` には「MouseUp で処理を中断する」実装が無いですよね。 処理を中断するコードが書かれていなければ、例えば規定数=100であれば、中断されることなく100回ループが回るのは当然な気がしますが。。
Zuishin

2020/07/15 03:34

> Windows Forms では、イベントハンドラの中に await が書けなかったような気がするのですが、 最近できるようになりました。
guest

0

長押し

「押した」と「離した」とをハンドリングすればよいのではないでしょうか.
(「押されてから→離されるまで」が処理実行期間)

投稿2020/07/14 07:43

fana

総合スコア11996

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yar

2020/07/15 02:49

回答ありがとうございます。 ハンドリングについて調べ試してみたのですが1度しか実行されず求めてる処理にならないです... 具体的にどうすれば繰り返すことが出きるでしょうか?
fana

2020/07/15 02:59

現状がどのような実装になっているのか不明なので何とも言えませんが, 「質問への追記・修正、ベストアンサー選択の依頼」や,他の回答にて,より具体的な方法の話が記述されているようですので,それらを参考にした実装を行ってみてはどうでしょうか.
guest

0

ベストアンサー

一番単純なのは、
ボタン押したらタイマー開始
ボタン離したらタイマー停止

で、タイマーの処理で
テキストを1減らす
ラベルを1増やす

といった感じですかね。
増減のスピードはタイマーのIntervalで調整する
タイマーに関してはTimerクラスを参照してください。

投稿2020/07/15 03:58

YAmaGNZ

総合スコア10489

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yar

2020/07/15 08:25

回答ありがとうございます。 試してたところ、1度長押しした際には1づつ増減するのですが、1度離し再度長押ししたところ1づつ増減するのではなく、2づつ増減するようになりました。その後同じように離して長押しすると3づつになっていしまいました。コードは下記のように行いました。 timer.Elapsed += (sender, e) => { int a+=1; int b-=1; text=a; label=b; } 常に1づつ増減する場合は+=や-=ではうまくいかないのでしょうか?
YAmaGNZ

2020/07/15 08:46 編集

ボタンを押した時にイベントハンドラを登録しているなら、離した時にイベントハンドラを削除しなけばなりません。 そうしないのであれば、フォームのロード等で1回だけイベントハンドラを登録し、ボタンの押した/離したのところはタイマーの開始/停止のみにしてください。
yar

2020/07/15 10:24 編集

timerのイベントハンドラの削除していませんでしたが、削除方法が調べてもよくわかりませんでした... timer.Elapsed -= new ElapsedEventHandler(); の()にどの引数を指定すればハンドラ削除できますでしょうか?またはまずハンドラ削除の方法が違いますでしょうか?併せて教えてほしいです。
YAmaGNZ

2020/07/15 10:48

ラムダ式を使ってのイベントハンドラを登録すると削除できません。 EventHandler handler; handler = (sender, e) => といった感じで一旦変数に受けてから timer.Elapsed += handler; と追加 timer.Elapsed -= handler; と削除してください。 handlerは適切なスコープで宣言してください。
yar

2020/07/15 11:06

ElapsedEventHandler handler; // タイマーを開始する timer.Start(); // タイマーの処理 handler = (c, a) => { timer.Elapsed += handler; . . . } のように書いた場合「割り当てされていないローカル変数が使用されました」とビルドエラーが起こってしまいます...
YAmaGNZ

2020/07/15 11:37

何故、ハンドラーの定義の中でハンドラーの追加を行うのですか? ボタンが押されたときにイベントハンドラを追加するのではなく、フォームのロードなど、起動されてすぐに1回だけ追加してください。 もしくは、フォームデザイナーでタイマーを追加してイベントハンドラを設定してください。 そのほうが簡単です。
yar

2020/07/16 02:15

>フォームデザイナーでタイマーを追加してイベントハンドラを設定してください。 そのほうが簡単です。 試してみたらできました!ありがとうございます!
guest

0

ボタンを右クリックし続けている間

マウスの右クリックという事でしたら、ボタンのマウスイベントを使えば、良いのでは?

例えば、bool progRun とかいうメンバ変数を用意して、
MouseDown(右ボタンを検出し)で、progRun = true;
MouseUpで、progRun = false;
別スレッドで、動いているメソッドで、この progRunが、trueの間だけ、処理を行うようにすれば、出来ます。

投稿2020/07/14 12:18

pepperleaf

総合スコア6385

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yar

2020/07/15 03:01

回答ありがとうございます。 trueの間do..whileで実行するように試してみたのですが、一気に実行されてしまい1つ1つ実行されずに規定数一気に実行されてしまいました... 1つ1つ実行する方法はないでしょうか?
pepperleaf

2020/07/15 13:36

他の回答へのコメントまで追い切れてませんので、解決済みかもしれませんが。 > 1つ1つ実行する方法はないでしょうか? 1つ終わったら、true->false にするだけでは?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問