- PR -

何かをするまで待つ処理をしたい

投稿者投稿内容
わちゃ
大ベテラン
会議室デビュー日: 2005/12/05
投稿数: 162
お住まい・勤務地: 東京
投稿日時: 2007-03-30 10:45
みなと様、kanai 様

アドバイスありがとうございます。

ちょっと事情がありまして、Form でなく、Control を継承して
ダイアログ風のものを作ろうとしています。

ここでいうダイアログ風というのは、ユーザの入力を待つ関数が
あるという意味です。

そのため、今のコードのイメージとしましては、次のようになっています。
一応、現在はこれで UI の仕様としては十分に要件を満たしています。

Class CustomControl
 Inherits Control

 Public Function 入力()
  入力値.Clear();
  While 入力値.IsEmpty()
   Application.DoEvents
  Wend
  Return 入力値
 End Sub
End Class

ただ、DoEvents をずっと回しているのがいまいちかなと思って相談させていただいておりました。
わちゃ
大ベテラン
会議室デビュー日: 2005/12/05
投稿数: 162
お住まい・勤務地: 東京
投稿日時: 2007-03-30 10:55
かるあ様

引用:

たとえば次の動きはあっていますか?
フォームに次の3つのボタンがあり

ボタン1−処理1を開始
ボタン2−処理1を一時的に停止
ボタン3−処理1の処理を再開

として、ボタン3をクリックした場合に処理1に対して何らかのメッセージ(返却値)を送り処理を再開する。



そのようなイメージです。

引用:

この場合 処理1 をクラスとして切り出して、フォームとは別スレッドで動かしてあげればいい気がします。



そうですね、私もそのように考えて、次のようなコードを組んでみたのですが、
別スレッドでも結局次のようになってしまい、別スレッドにした意味がなくなってしまって、実行さえしていません。
なんか、アホな事してます??

Class CustomControl
 Inherits Control

 Public Function 入力()
  入力値.Clear();
  signal.Reset();
  別スレッドスタート( AddressOf 入力待ち )
  signal.WaitOne()
  Return 入力値
 End Sub

 Private Sub 入力待ち()
  While 入力値.IsEmpty()
   Application.DoEvents
  Wend
  signal.Set()
 End Sub

End Class


[ メッセージ編集済み 編集者: わちゃ 編集日時 2007-03-30 10:56 ]
甕星
ぬし
会議室デビュー日: 2003/03/07
投稿数: 1185
お住まい・勤務地: 湖の見える丘の上
投稿日時: 2007-03-30 11:02
引用:

わちゃさんの書き込み (2007-03-30 10:45) より:
ただ、DoEvents をずっと回しているのがいまいちかなと思って相談させていただいておりました。


はい。私も最低だと思います。ただどのような解決方法が有るのかは「ちょっと事情」が分からないと最適解は得られない予感があります。

なぜFormクラス相当の機能を自作しているのでしょうか?
普通にユーザー入力のイベントを待つわけには行かないのでしょうか?
ワーカースレッドと同期クラスを使って解決できないのでしょうか?
ぼのぼの
ぬし
会議室デビュー日: 2004/09/16
投稿数: 544
投稿日時: 2007-03-31 00:30
CustomControlの外部仕様。
それを使って最終的に何がしたいのか。
この2点がわからない限りなんとも言えませんが。

憶測で、単純にダイアログを使わずにダイアログっぽいUIを作りたいのかなーと思って
適当につくってみたら、こんなんなりました。
#1メソッドにまとめるのは思いつかなかったけど、
#つづきを並べて書けばコードの見通しはそんなに悪くないかな〜とw

コード:

'めんどくさかったのでTextBoxを1個はっつけたユーザーコントロールを使用
Public Class UserControl1

    Private EnabledProperties As New ArrayList()
    Public Event 入力完了()

    Private Sub UserControl1_Load( _
    ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        TextBox1.Visible = False
    End Sub

    Public Sub 入力待ち()
        TextBox1.Text = ""
        TextBox1.Visible = True
        EnabledProperties.Clear()
        For i As Integer = 0 To ParentForm.Controls.Count - 1
            If Not ParentForm.Controls(i).Equals(Me) Then
                EnabledProperties.Add(ParentForm.Controls(i).Enabled)
                ParentForm.Controls(i).Enabled = False
            Else
                EnabledProperties.Add(True)
            End If
        Next
    End Sub

    Private Sub TextBox1_KeyDown( _
    ByVal sender As Object, _
    ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown
        If e.KeyCode = Windows.Forms.Keys.Enter Then
            For i As Integer = 0 To ParentForm.Controls.Count - 1
                If Not ParentForm.Controls(i).Equals(Me) Then
                    ParentForm.Controls(i).Enabled = CBool(EnabledProperties(i))
                End If
            Next
            TextBox1.Visible = False
            RaiseEvent 入力完了()
        End If
    End Sub

    Public ReadOnly Property 入力データ() As String
        Get
            Return Me.TextBox1.Text
        End Get
    End Property

End Class

'そのユーザーコントロールをはっつけたForm
Public Class Form1

    Private Sub Button1_Click( _
    ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        AddHandler UserControl11.入力完了, AddressOf Button1_Click_つづき
        UserControl11.入力待ち()
    End Sub

    Private Sub Button1_Click_つづき()
        RemoveHandler UserControl11.入力完了, AddressOf Button1_Click_つづき
        MsgBox("Button1:" & UserControl11.入力データ)
    End Sub

    Private Sub Button2_Click( _
    ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        AddHandler UserControl11.入力完了, AddressOf Button2_Click_つづき
        UserControl11.入力待ち()
    End Sub

    Private Sub Button2_Click_つづき()
        RemoveHandler UserControl11.入力完了, AddressOf Button2_Click_つづき
        MsgBox("Button2:" & UserControl11.入力データ)
    End Sub

End Class

Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2007-03-31 01:24
こんばんは。

引用:

わちゃさんの書き込み (2007-03-30 10:45) より:

ここでいうダイアログ風というのは、ユーザの入力を待つ関数が
あるという意味です。

そのため、今のコードのイメージとしましては、次のようになっています。
一応、現在はこれで UI の仕様としては十分に要件を満たしています。

Class CustomControl
 Inherits Control

 Public Function 入力()
  入力値.Clear();
  While 入力値.IsEmpty()
   Application.DoEvents
  Wend
  Return 入力値
 End Sub
End Class

ただ、DoEvents をずっと回しているのがいまいちかなと思って相談させていただいておりました。



おそらく、わちゃさんはモーダルループ処理をしたいのでしょう。
たとえばC言語+WinAPIでモーダルループを書けば次のような感じになります。

コード:
for (;;)
{
	MSG msg;
	GetMessage(&msg, NULL, 0, 0);

	switch (msg.message) {
	case WM_AAAA:
		if (モーダルループを抜ける条件)
		goto ExitLoop;

	case WM_BBBB:
		// モーダルなメッセージ処理1
		break;

	case WM_CCCC:
		// モーダルなメッセージ処理2
		break;

	case WM_DDDD:
	case WM_EEEE:
		// これらのメッセージはディスパッチする
		DispatchMessage(&msg);
		break;

	・・・

	}
}



イメージとしてはDoEventsを使ったメッセージループに近いですが、
メッセージをディスパッチする前に処理を行うので、
完全に特殊モードとして制御することが出来ます。
(わちゃさんの場合、入力待ちモードにしたい訳ですが)

心配は、.NET Framework上でモーダルループ処理した場合、
問題(副作用など)が起きないか?なのですが、試したことないので分かりません。
Tdnr_Sym
ぬし
会議室デビュー日: 2005/09/13
投稿数: 464
お住まい・勤務地: 明石・神戸
投稿日時: 2007-03-31 01:57
こんばんは。

すいません。先ほどの回答は早とちりしました。

引用:

わちゃさんの書き込み (2007-03-30 10:45) より:

一応、現在はこれで UI の仕様としては十分に要件を満たしています。



WinAPIのWaitMessage関数あたりをループ内で呼べば良いだけではないでしょうか?

コード:
Public Class CustomTextBox
    Inherits System.Windows.Forms.TextBox

    Public Function 入力() As String

        Me.Text = String.Empty

        Do Until Me.Text.Length >= 5
            WaitMessage()
            Application.DoEvents()
        Loop

        Return Me.Text

    End Function

    Declare Function WaitMessage Lib "user32.dll" () As Boolean
End Class



わちゃ
大ベテラン
会議室デビュー日: 2005/12/05
投稿数: 162
お住まい・勤務地: 東京
投稿日時: 2007-03-31 20:15
みなさん、いろいろアドバイスありがとうございます。

デリゲートを使ってみたり、ワーカースレッドでやってみたり、
Application.Run を細工できないかとやってみたり、
WndProc で、なんとかできないか考えてみたりして、
Tdnr_Sym さんの WaitMessage が一番いいような感じがしました。

ただ、Message の処理で変に API をいじってもなんか危険な感じが
したので、結局 DoEvents ごとに 50ms の Sleep を入れることに
しました。

みなさん、ありがとうございました。
にー
常連さん
会議室デビュー日: 2006/04/30
投稿数: 35
投稿日時: 2007-04-07 12:00
解決された後で、こんな事を言うのは無粋かもしれませんが、
のちに、50msスリープさせる処理プログラムを見た時に、
何と思うでしょうか?

恐らく恥ずかしい気持ちになると思います。

皆さんが言うように、キーベントで2回目であるかをチェック
するだけで良かったと思います。

自分の発想がいまいちだと感じた場合、最初の発想の延長で
物事を考えるのではなく、ゼロからの発想でもう一度考え
直すことが大事でしょう。

スキルアップ/キャリアアップ(JOB@IT)