• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:VB2005でデリゲートというものを始めて使っています)

VB2005でデリゲートとは?

このQ&Aのポイント
  • VB2005でデリゲートというものを始めて使っています。メインスレッドのテキストコントロールのTextプロパティに、別のスレッドからデータをセットする場合、デリゲートという機能を使わないといけないということで、以下のようにしています
  • 別スレッドでデータをセットするためにはデリゲートを使用する必要がありますが、個々のテキストコントロール毎にデリゲートを記述しなければなりません。そのため、デリゲートの使用方法や記述の手間について質問したいです。
  • 別スレッドの書き込みでデリゲートを使う方法は可能ですが、デリゲートの記述が複雑であるため、個々のテキストコントロールごとにデリゲートを作成する必要があります。デリゲートの使用方法やより簡単にデータをセットする方法について教えていただけると嬉しいです。

質問者が選んだベストアンサー

  • ベストアンサー
  • anmochi
  • ベストアンサー率65% (1332/2045)
回答No.1

> セットするコントロール毎にこれが必要???  もちろんそれを回避するテクニックは色々あるのですが、最初はそこから始めてください。ここを理解しないで応用編に進むと後で絶対に泣きます。もし、今仕事で開発してて、時間がねぇ原理は要らねぇ動くモノだけよこせという事態なのであれば・・・・むしろ時間が無いなら確実に動く今の形を一生懸命実装する方が最終的に泣かなくてすむかと。  ちなみに、基本形として一般的には以下のように記述します。 Private Delegate Sub dlgWriteText(ByVal text As String) Public Sub DlSettxtUserName(ByVal text As String)  If Me.txtTest.InvokeRequired Then ' Delete   Static Dim d As dlgWriteText = New dlgWriteText(AddressOf Me.DlSettxtUserName)   Me.txtTest.Invoke(d, text)   Return  End If  Me.txtTest.Text = text End Sub  これで、フォームスレッドの中からでも外からでもDlSettxtUserNameを呼ぶとtxtTestに文字をセットし、かつ必要があれば勝手にInvokeしてくれます。必要かどうかの判断も.Net Frameworkが自動でやってくれるのでとっても楽チン。  応用編としては、最も安直で泥臭いモノだとdlgWriteTextにIntegerの引数を一つ増やしてそれの値によってコントロールを選択する、とかね。第二引数にテキストボックスを直接食わせても良いんですけど、まずはDelegate(というかInvoke)について後ろで動いているカラクリを理解する事です。後、BeginInvokeは非同期Invokeを行うもので、使うならきちんとEndInvokeを呼び出してあげるべきです。今回の文字列一つコピーのような場合は同期InvokeのInvokeを使うのが良いと思います。

hdkoa
質問者

補足

|ご忠告、ありがとうございます。 なるほど、意識して使わなくても済むように、一元化するのですね。 応用編で申し訳ないのですが、こういう事でしょうか? noを引数の前に入れています。 Private Delegate Sub dlgWriteText(Byval no as Integer, ByVal text As String) Public Sub DlSetText(Byval no as Integer, ByVal text As String) Select case no case 1: 'txtTestの場合   If Me.txtTest.InvokeRequired Then ' Delete    Static Dim d As dlgWriteText = New dlgWriteText(no, AddressOf Me.DlSettxtUserName)    Me.txtTest.Invoke(d, no, text)    Return   End If   Me.txtTest.Text = text case 2: 'textExampleの場合 '省略 End Select End Sub ここで疑問が2つ出てきました。 (1)Static Dim dのところで、なぜStaticとする必要があるのか (2)非同期Invokeはどういう時に使われるのでしょうか?サンプルもあれば助かります。 よろしくお願いいたします。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • VB2008でデリゲートの代わりにラムダ式が使えるというので、試してみ

    VB2008でデリゲートの代わりにラムダ式が使えるというので、試してみたのですが、うまくいきません。 試したコードは下記です。WindowsFormアプリで、Form1にButton1とLabel1を貼りつけております。 Button1を押すとLabel1に"はじめました"と表示し、2秒待ってから"おわりました"と表示するつもりです。 デリゲートを使った(2)は意図した動作をしますが、ラムダ式を使った(1)はLabel1に何も表示しません。 このようなことはできないのでしょうか? Public Class Form1 Private Delegate Sub longTaskDelegate() Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Label1.Text = "" Dim dlg As New longTaskDelegate(AddressOf LongTask) dlg.BeginInvoke(AddressOf longTaskCallback, dlg) End Sub Private Sub longTaskCallback(ByVal ar As IAsyncResult) Dim dlg As longTaskDelegate = DirectCast(ar.AsyncState, longTaskDelegate) dlg.EndInvoke(ar) End Sub Private Delegate Sub displayMessageDelegate(ByVal msg As String) Private Sub DisplayMessage(ByVal msg As String) If Label1.InvokeRequired Then Label1.Invoke(Function() Label1.Text = msg) ' --- (1) 'Label1.Invoke(New displayMessageDelegate(AddressOf Me.DisplayMessage), msg) ' --- (2) Else Label1.Text = msg End If End Sub Private Sub LongTask() DisplayMessage("はじめました") System.Threading.Thread.Sleep(2000) DisplayMessage("おわりました") End Sub End Class

  • VB.NETのデリゲートについて

    VB.NETのデリゲートについて質問です。 以下のプログラムなのですが、 デリゲート型をインスタンス化しているところで、コンストラクタにパラメータを渡していますが、 そのコンストラクタはどこに定義されているのでしょうか。 (AddressOf t1.Ohayou)というパラメータが渡されていますが、このパラメータを受け取っているコンストラクタがどれなのかが分かりません。 ご教示よろしくお願いいたします。 Delegate Sub Myprint(ByVal s As String) Module Module1 Sub Main() Dim t1 As Test1 = New Test1() Dim t2 As TEst2 = New Test2() Dim d As Myprint = New Myprint(AddressOf t1.Ohayou) d.Invoke("VB太郎") d = New Myprint(AddressOf t2.Konbanwa) d.Invoke("VB太郎") End Sub End Module Class Test1 Sub Ohayou(ByVal s As String) Console.WriteLine("おはようございます。{0}です。", s) End Sub End Class Class Test2 Sub Konbanwa(ByVal s As String) Console.WriteLine("こんばんわ。{0}です。", s) End Sub End Class

  • デリゲートについて

    初心者です。デリゲートを初めて使うのですが、 スレッド処理でWebClientでイベントハンドラを作成した後、 以下の Delegate Sub MyDelegate() Private Sub downloadClient_DownloadProgressChanged(ByVal sender As Object, ByVal e As System.Net.DownloadProgressChangedEventArgs) If InvokeRequired Then Invoke(New MyDelegate(AddressOf DownloadProgressA)) '終わり Else ProgressBar1.Value = e.ProgressPercentage Label1.Text = e.ProgressPercentage & "%" End If End Sub でDownloadProgressAには ProgressBar1.Value = e.ProgressPercentage Label1.Text = e.ProgressPercentage & "%" と書いたのですが、 メソッド 'Private Sub DownloadParmertar(sender As Object, e As System.Net.DownloadProgressChangedEventArgs)' に、デリゲート 'Delegate Sub MyDelegate()' と互換性があるシグネチャがありません とエラーが発生します。 スレッド処理やDelegate、Invokeを初めて使うので よく分かりません。どうすれば進行度を処理表示 出来るでしょうか…。 お優しい方教えて下さい。

  • Visual Basic 2005 でのデリゲート、Invokeについて

    卒論の関係で、Visual Basic 2005 Express Editionを使用して、システムを構築しています。 スレッドまたはフォームが複数あるため、デリゲートを使用することになったのですが、invokeの対象であるメソッドで引数を使用することはできるのでしょうか? 引数なしの場合、現時点では次のように記述しています。 A.show() A.Invoke(New MethodInvoker(AddressOf A.Status_Timer)) Public Sub Status_Timer()   処理 End Sub MethodInvokerは、デリゲート宣言なしでinvokeを使えることができ、本来?のデリゲート宣言して、invokeを使う場合は以下のようになります。 A.show() A.Invoke(New SetFocusDelegate(AddressOf A.Status_Timer)) Delegate Sub SetFocusDelegate() Public Sub Status_Timer()   処理 End Sub ここで、Status_Timer()に引数を指定して、たとえば、 Public Sub Status_Timer(ByVal data As integer)   処理 End Sub とした場合、invokeでの記述がうまくいきません。 もともと、invokeではそんなことはできないかもしれませんが、何か方法ありますでしょうか?現時点では、引数を使用することができないので、スレッドまたはフォーム間で、プロパティを使用して、情報を渡しています。以下のような形です。できれば、プロパティを使用したくないのですが・・・ Public Property test() As state Get Return _test End Get Set(ByVal value As state) _test = value End Set End Property

  • VB.NET デリゲートへのコールバック関数の設定

    VB.NET デリゲートへのコールバック関数の設定 VB.NETとネイティブC/C++ DLL間でのコールバックについての質問です。 ネイティブDLLからVOID*で得られるコールバック関数をVB.NETのデリゲートに 登録するには、どのようにコーディングすればよいのでしょうか。 ---------- VB.NETソース ---------- Public Delegate Sub CALLBACK_00(ByVal Arg1 As Integer, ByVal Arg2 As Integer) Declare Function FuncPtrGet Lib "test.dll" () As CALLBACK_00 Dim Func As new CALLBACK_00(FuncPtrGet()); 2行目は、実際にはVOID*が帰るDLL関数です。 3行目がコンパイルで通りません。AddressOfで関数を指定するようにメッセージが出ます。

  • VB.NET スレッドからのイベント受信について

    はじめて質問させていただく、VB.NET初心者です。 ただいまスレッド、イベント処理を作成中で Form1にButton1、Label1を貼り付け以下の様なプログラムを記述しました。 (スレッドにて5秒ごとにイベントを発生させます。) 'イベント引数 Public Class EventArgs Inherits System.EventArgs Public nowTime As String End Class 'イベント発行 Public Class EventTest Public Event _event(ByVal sender As Object, ByVal e As EventArgs) Public Sub Go() Dim args As New EventArgs() args.nowTime = Now.ToString RaiseEvent _event(Me, args) End Sub End Class 'フォーム内処理 'スレッド宣言 Dim MyThread As New System.Threading.Thread(AddressOf _Thread) Private WithEvents _test As New EventTest() 'イベント受信   Private Sub Handler(ByVal sender As System.Object, ByVal e As EventArgs) Handles _test._event Label1.Text = e.nowTime End Sub 'スレッド(5秒間隔でイベント発行) Private Sub _Thread() Dim i As Integer For i = 0 To 99 System.Threading.Thread.Sleep(5000) _test.Go() Next End Sub 'スレッド起動 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click MyThread.Start() End Sub End Class 開発環境から普通に実行すれば正常に動作している様なのですが、 イベント受信部(Handler)のLabel1.Text = e.nowTime部に ブレークポイントを置いてLabel1のウォッチをするとその時点で 処理がとまってしまいます。なぜとまるのかが知りたいです。 作成方法がまずいのでしょうか? 皆様よろしくお願いいたします。

  • マルチスレッド[ VB.NET 2005 ]

    VB.NET 2005 VC++で作成した通信DLLをマルチスレッドで呼び出すプログラムを作成しています。 マルチスレッドについてご質問です。 ---------------------------------------------------------------- Private Sub ThreadMethod(ByVal aiIndex As UInt32) fSockInit() ← スレッドスタートなので別スレッドで動く End Sub '************************************************** ' フォームロード '************************************************** Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load wkThread(Index) = New Thread(New ThreadStart(AddressOf ThreadMethod)) wkThread(Index).Start() End Sub '************************************************** ' 接続ボタン押下 '************************************************** Private Sub btConnect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btConnect.Click fConnect() ← スレッドを指定して動かしたい End Sub '************************************************** ' パラメータ設定ボタン押下 '************************************************** Private Sub btParm_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btParm.Click fParmSet() ← スレッドを指定して動かしたい End Sub ---------------------------------------------------------------- 上記の例では、fSockInitはスレッド別に動作しますが、fConnect、fParmSetはメインスレッドで動作するようになっています。 frmMain_Loadで作成したスレッドを指定(※1)して関数を呼び出すことは出来ないのでしょうか? ※1.「クリックイベント(メインスレッド)→実行するスレッドを指定→関数呼び出し→メインスレッドに戻す」の様に。。。

  • VB添削

    このプログラムは 例えば3 3 4とテキストボックスに数字が打ち込まれると 3×3行列が4個分 のテキストボックスがでてきます。 ここに数字を打ち込んでいき、ボタン2を押すと3×3のテキスト トボックスが出てくると同時に足し算した結果が出てくるようにしたいです。 以下のプログラムはできたところまで作成しています。 どこを直せばよいのでしょうか。 Public Class Form1 Private number As Integer Private rows As Integer Private columns As Integer Private Sub Form11_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load For i As Integer = 1 To 3 AddHandler Me.Controls("TextBox" & i).TextChanged, AddressOf TextBox_TextChanged Next End Sub Private Sub TextBox_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) If System.Text.RegularExpressions.Regex.IsMatch(CType(sender, TextBox).Text, "[^0-9]") Then MessageBox.Show("数字で入力してください", Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error) With CType(sender, TextBox) .Text = .Text.Substring(0, .Text.Length - 1) .SelectionStart = .Text.Length End With End If Dim cnt1 As Integer Dim cnt2 As Integer Dim cnt3 As Integer If Integer.TryParse(TextBox1.Text, cnt1) And Integer.TryParse(TextBox2.Text, cnt2) And Integer.TryParse(TextBox3.Text, cnt3) Then For k = 1 To cnt3 For i = 1 To cnt1 For j = 1 To cnt2 Dim tb As TextBox = New TextBox() tb.Name = "tb" + i.ToString() Me.Controls.Add(tb) tb.Top = (i - 1) * 28 + 55 tb.Left = (j - 1) * 30 + 40 * (cnt2 * (k - 1)) + 10 tb.Width = 25 Next Next Next End If End Sub Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Bounds = New Rectangle(10, 10, 1350, 800) Me.AutoScroll = True End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim sum As Double Dim cnt As Integer = 0 For i As Integer = 1 To rows For j As Integer = 1 To columns Dim tb As TextBox = New TextBox() cnt += 1 : If cnt > rows * columns Then cnt = 1 tb.Name = "tb" + cnt.ToString Me.Controls.Add(tb) tb.Top = (i - 1) * 30 + (80 + 40 * rows) tb.Left = (j - 1) * 60 + 10 tb.Width = 40 sum = 0 For k As Integer = 1 To number sum += Double.Parse(CType(Me.Controls("tb" + (cnt + (rows * columns * (k - 1))).ToString()), TextBox).Text) Next tb.Text = sum.ToString() Next Next End Sub Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged End Sub Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged End Sub Private Sub TextBox3_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox3.TextChanged End Sub End Class

  • VBでシリアル通信がうまくいきません

    VisualBasicのシリアルポートメソッドを使い、RS232-C通信を試そうとしている初心者です。 現在、別のPCからTeratermより文字を送り、自分のPCで受信結果を得ようとしているのですが 別PCから単発で文字を送っても、自分のPCでは反応せず キーボードを押しっぱなしにすると、自分のPCのウィンドウに受信結果が表示されます。 一体、何が原因なのでしょうか? さっぱり、わからず途方に暮れています。 下記にソースコードを記載しますので、詳しい方は教えて下さると幸いです。 ------------------------------------------------------------------------ Public Delegate Sub MyDelegate(ByVal intData As Integer) Private Sub AddData(ByVal str As String) TextBox1.Text = str End Sub Private Sub SerialPort1_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived Dim dlgByte As MyDelegate = New MyDelegate(AddressOf AddData) Dim ByteRead(SerialPort1.BytesToRead - 1) As Byte SerialPort1.Read(ByteRead, 0, SerialPort1.BytesToRead) For i As Integer = 0 To ByteRead.Length - 1    Me.Invoke(dlgByte, ByteRead(0)) Next End Sub ------------------------------------------------------------------------

  • スレッドで Byref の引数を渡したい場合

    VB2005 の初心者です。 スレッドに Byref の引数を渡すやり方が分かりません。 Byval だとエラーは出ないのですが、 Byref だとどうしてもエラーが消えません。 ソースは下記です。 Private CDF As clsCDF Public Class clsCDF Public LOOP1 As clsLoop1 Public LOOP2 As clsLoop2 End Class Protected Overrides Sub OnStart(ByVal args() As String) Thread = New Thread(AddressOf ABC) Thread.Start(CDF) End Sub Private Sub prvABC ( ByRef CDF As Object ) End Sub 何かヒントになることでも良いので、 皆様の知恵をお借りできれば幸いです。 よろしくお願い致します。