- わちゃ
- 大ベテラン
- 会議室デビュー日: 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回目であるかをチェック
するだけで良かったと思います。
自分の発想がいまいちだと感じた場合、最初の発想の延長で
物事を考えるのではなく、ゼロからの発想でもう一度考え
直すことが大事でしょう。
|