したらばTOP ■掲示板に戻る■ 全部 1-100 最新50 | メール | |

デリゲートについて(VB2005)

1こじら:2009/04/21(火) 22:18:44
今晩は。以前はRS-232Cの件有難う御座いました。頂いたコード元に
新たなソフト作成しているのですが、デリゲートでつまってます。
 わかりやすい資料ないでしょうか。現在 複数のボタンにRS232C
コマンドを登録し、それぞれのボタンの結果を異なるtextboxへ表示、
ボタンAの結果はboxA、ボタンBの結果はboxB、
ボタンCの結果はboxC1,C2,C3(3byte)というように、
(ボタンAの時、boxB,Cは変化なし、同様にBの時boxA,Cは変化なし)
以前頂いたプログラムは 1ボタンに1textboxで、これを真似て
みたのですが根本分かってないからエラーになります。
 また VBで値をシフトをする
(10進7=2進0111これを左シフトすると2進1110=10進14)
は、2倍する事で実現するものなのでしょうか?コマンドあるので
しょうか
 それから 現在の値に対し2進にしたあるbitだけを1にしたり0
にしたり、またはbitの値をチェックするコマンドなどもあります
でしょか
 5=b0101 1bit目を1にセット→ b0111=7
 5=b0101 2bit目を0にセット→ b0011=3
 5=b0101 0bit目が1かどうか→ 1ならtrue
 5=b0101 3bit目が0かどうか→ 0ならtrue 
(PICのレジスタを操作したいため) すみません初歩的な質問
ばかりで。

2igoten:2009/04/22(水) 09:51:49
こんにちは、
デリゲートがわからないと言う質問が圧倒的に多いですね。
長くなりますので分けて書きます。

まず基本的に次のことを抑えておきましょう。
マルチスレッドの場合(RS-232Cの受信はマルチスレッド
で行われます。)はメインスレッドのTextBoxにセカンドスレッド
から書き込めません、なぜならその様なルールにしてあるからです。
ではメインスレッドのサブルーチン(メソド)を呼び出すことは出来るのでしょうか?
もしこれが出来れば、そのサブルーチンの中にTextBoxに書き込む動作を
埋め込んでおけば良いと言うことになります。
答えは条件付きでYesです。
条件は2つあります1つはサブルーチンをアドレスで呼び出すこと、
2つ目はサブルーチンをセカンドスレッドではなくてメインスレッドから
呼び出すことです。
サブルーチンをアドレスで呼び出す方法がデリゲートです。

'メインスレッドに書き込むデリゲート
Delegate Sub dlgAddText(ByVal str As String)

これは引数に1つのStringを取って、アドレスでサブルーチンを
呼び出しますよと言う宣言です。
このように宣言すると戻り値がなくStringの引数を一つとるサブルーチン
なら何でも呼び出すことが出来ます。

3igoten:2009/04/22(水) 09:52:41
2番目のサブルーチンをセカンドスレッドから呼び出す方法ですが、
Invokeメソドを使用します。
Me.Invoke(デリゲート)とする、メインスレッドでデリゲートが実行されます。

さて私が書いた下のコードですが、言葉で説明してみます。
まずアドレスで呼び出されるサブルーチンAddTextを書いてあります。
これは引数をテキストボックスに書き込むサブルーチンです。

'メインスレッドのテキストに追加する
Me.Invoke(New dlgAddText(AddressOf AddText), New Object() {strIn})

AddTextというサブルーチンをstrInというString型の引数を1つつけて
メインスレッドから(Me.Invoke)アドレス(AddressOf AddText)で
呼び出しなさい、と言うことになります。

これでわからない場合は具体的に何をしたいかを書いていただければ
アドバイス出来ると思います。

4igoten:2009/04/22(水) 09:55:49
VB.NETの場合はビット演算が簡単に使えます。
先ずSiftですが左Siftは<<、右Siftは>>です。
>10進7=2進0111これを左シフトすると2進1110=10進14は
Dim i As Integer = (7 << 1) 又は
Dim i As Integer = 7
i = i << 1 又は
i <<= 1
となります、2つシフトしたければ i<<2とします。

ある数のあるビットが立っているかいないか調べることをビットテストと言います。
ビットテストにはAnd演算子を使います。
これはテストしたいビットだけが立った数値とテストしたい数値のAndで実現します。
1100100 (10進 100)
And 0000100 (10進   4)
-------------------------
    0000100
ANDの結果が0ならビットが立っていません。
コードは
Dim i As Integer = 100
Dim j As Integer = 2 '番目のビット
Dim k = i And 2 ^ j
If (i And 2 ^ j) > 0 Then
MessageBox.Show((j + 1).ToString + "番目のビットが立っています")
Else
MessageBox.Show((j + 1).ToString + "番目のビットが立っていません")
End If

5igoten:2009/04/22(水) 09:59:31
あるビットを強制的に1にしたり0にすることをビットマスクといいます。
Andを使うとあるビットだけを0に出来ます。
3ビット目を強制的に0にしています
    1100100 (10進 100)
And  1111011 (10進 123)
---------------------------
    1100000 (10進 96)

i = 100
i = i And 123
MessageBox.Show(i.ToString())


強制的に1にするにはOrを使います
3ビット目を強制的に1にしています
    1100000 (10進 96)
Or   0000100 (10進  4)
---------------------------
    1100100  (10進 100)
i = 32
i = i Or 4
MessageBox.Show(i.ToString())
以上です

6こじら:2009/04/23(木) 00:06:56
ありがとうございます。項目4,5は分かりやすく理解できました。有難うございます。
でもデリゲートのイメージがなかなかつきません。アドレスで参照する事を
宣言する事をデリゲート宣言で行うというのはなんとなく(あっているのか??)
 したい事は ボタン1を押すとRS232C通信でPICへ送信し、結果(Read)が
TextBox1へ表示。 ボタン2を押すとRS232C通信でPICへ別命令が送られ、また
その結果が別のTextBox2へ表示される、ボタン3も同様で、その結果がTextbox3へ。
と、 各ボタンに対し、それぞれに対応したtextboxにのみだけ結果が反映される。
以前頂いたサンプルは1ボタン、1textBoxだったので、複数あった場合は
どのようにするのか。現在うまくいってません。
 僕の認識ではデリゲートはサブルーチンのアドレスで、メインとなる各ボタン
を実行した際に呼び出され、処理をし、呼び出し元へ値を返すような認識で
適当にプログラム書いてみたのですが。 すみません教えて下さい。
 それからもう一つ別件で、TextBoxに値を打ち込む時、文字の制限
(0-9、A-F、a-f)をかけたいと思って textbox1_presskey---を使用、
IF文で書いてみたのですがVB6の書き方ではうまくいかなかったので
そちらも教えていただけないでしょうか。 すみません。

7igoten:2009/04/23(木) 08:58:28
デリゲート:
大体そんな感じですね。
テキストボックス3つとぼたん3つを置いて、ボタンを押すと
ボタンと同じ番号のTextBoxに書き込むコードを示します。
これを応用してみてください。
Delegate Sub degaddText(ByVal textBoxNo As Integer, ByVal textBoxText As String)
Private Sub addText(ByVal textBoxNo As Integer, ByVal textBoxText As String)
Select Case textBoxNo
Case 1
TextBox1.Text += textBoxText
Case 2
TextBox2.Text += textBoxText
Case 3
TextBox2.Text += textBoxText
End Select
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button1.Click
Dim textBoxNo As Integer = 1
Dim textBoxText = "Button1"
Me.Invoke(New degaddText(AddressOf addText), New Object() {textBoxNo, textBoxText})
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button2.Click
Dim textBoxNo As Integer = 2
Dim textBoxText = "Button2"
Me.Invoke(New degaddText(AddressOf addText), New Object() {textBoxNo, textBoxText})
End Sub
Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles Button3.Click
Dim textBoxNo As Integer = 3
Dim textBoxText = "Button3"
Me.Invoke(New degaddText(AddressOf addText), New Object() {textBoxNo, textBoxText})
End Sub

8igoten:2009/04/23(木) 09:01:27
文字フィルタ:
ちゃんとやろうとすると結構面倒なのです。
TextChangedイベントを使って一文字ずつ比べ、想定外の文字が入力されたら
元の文字列に戻し、キャレットも元の位置に戻します。
元の文字列を覚えておくにはStaticを使っています、位置も同じです。
TextBox1.Text(i)でi番目の文字が取得できます。
これは配列ではなくインデクサ(プロパティの一種)というものです。
理解できなければまあそんな物だと覚えてください。
文字を元に戻す時は、TextChangedの中から再度TextChangedが呼ばれます。
そうすると処理が重複するため、フラグではじきます。

9<削除>:<削除>
<削除>

10<削除>:<削除>
<削除>

11igoten:2009/04/23(木) 09:48:07
...続き
インデントが無くて読みにくいため、半角スペース2つを全角スペースに置き換えてみました。
  Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
      Handles TextBox1.TextChanged
    Static strBstr As String '前の文字列を覚えている
    Static intPos As Integer '前のキャレットの位置を覚えている
    Static boolFlg '文字修正時の再突入を防ぐフラグ
    If boolFlg Then
      Return
    End If
    boolFlg = True
    'TextBox1.Text(i)でi番目の一文字を取り出します。
    'TextBox1.Text(i)は配列でなくインデクサというプロパティです。
    For i As Integer = 0 To TextBox1.Text.Length - 1
      If (TextBox1.Text(i) < "0"c Or TextBox1.Text(i) > "9"c) _
        And (TextBox1.Text(i) < "a"c Or TextBox1.Text(i) > "z"c) _
        And (TextBox1.Text(i) < "A"c Or TextBox1.Text(i) > "Z"c) Then
        '入力文字が想定外
        MessageBox.Show("入力文字が違います")
        TextBox1.Text = strBstr '前の文字に戻す
        TextBox1.SelectionStart = intPos '前の位置に戻す
        boolFlg = False
        Return
      End If
    Next
    strBstr = TextBox1.Text  '文字列を記憶
    intPos = TextBox1.SelectionStart 'キャレットの位置を記憶
    boolFlg = False
  End Sub

12こじら:2009/04/24(金) 21:20:01
今晩は。 有難うございます。分かりやすい例でイメージがつかめました。
所で、話戻ってしまうのかもしれないのですが、RS232CでREADする際の
事で教えて頂きたいのです。先の質問のように複数のボタンでRS232Cにコマンド
を乗せPICを操作し、それに対する値を各コマンドボタンに対するTextBoxに
表示させたいと考えているのですが、デリゲートが理解できてないから
と考えてましたが、それだけではなくSerialPort1_DataReceived のイベント
も考えなくてはならないのではと思ってます。 というのも
 Sub ボタン1_click
  コマンド1送信 → (PIC実行) 
  (PIC)    →  コマンド受信1byte
  TextBox1へ表示
 end
 sub ボタン2_click
  コマンド2送信 → (PIC実行)
  (PIC)    →  コマンド受信2byte
  TextBox2へ表示
 end
 sub ボタン3_click
  コマンド3送信 → (PIC実行)
  (PIC)    → コマンド受信(任意
  TextBox3へ表示
 end
 sub SerialPort1_DataReceived
   受信処理
 end
とした時、 受信は SerialPort1_DataReceived の1箇所で処理され、
受信した値はどのボタンによるものか分からず該当Textboxへの表示指定が
不明になるような気がしてます。
 このような時はどのようにすればよいのでしょうか? SerialPort1_DataReceived
処理内で どこからのREAD命令制御なのかを判断させる グローバルな変数
を使う感じになるのでしょうか?
 あと、コマンドによっては数バイト受信することもあるのですが、SerialPort1_DataReceived
は1byte毎に処理をしているようで、例えは AAh,5Ah,33hと3byte受信して
strIn += inByte(i).ToString + ","としても これを表記すると 33h,1byte
のみとなっています。 
 連続取得する事って出来ないのでしょうか? SerialPort1.BytesToRead - 1
で数byteとれるような気がしたのですが。 PICの問題でしょうか?

13igoten:2009/04/25(土) 13:43:23
>グローバルな変数を使う感じになるのでしょうか?
そういうことですね。

結局送られてくるデータを貯めておいて、更新の度にSelect Case
等で判断する方法が一番簡単かなと思います。
「RS-232C Hex表示モニタの作成 」
http://www.geocities.jp/hatanero/rs232c5.html
を参考にして考えられたらいかがでしょうか。
このプログラムではメインスレッドにあるテキストボックスに
表示させていますが、メインスレッドの中のグローバルな変数に
保持させる様にします。

14<削除>:<削除>
<削除>

15<削除>:<削除>
<削除>

16<削除>:<削除>
<削除>

17<削除>:<削除>
<削除>


新着レスの表示


名前: E-mail(省略可)

※書き込む際の注意事項はこちら

※画像アップローダーはこちら

(画像を表示できるのは「画像リンクのサムネイル表示」がオンの掲示板に限ります)

掲示板管理者へ連絡 無料レンタル掲示板