none
Fechar Form através de Thread RRS feed

  • Pergunta

  • Estou utilizando Socketes e gostaria de fechar um FORM através de uma Thread.

    Dim trFechar As Thread

    Chamo a thread assim, só que dá erro (Operação entre threads inválida: controle 'form1' acessado de um thread que não é aquele no qual foi criado.)

    trFechar = New Thread(AddressOf Fechar)

    trFechar.Start()

     

    Sub Fechar()

    Me.Close()

    End Sub

     

    terça-feira, 13 de fevereiro de 2007 00:57

Respostas

  • Você não pode utilizar controles em uma thread diferente daquela em que eles foram criados. Para permitir a interação de controles com outras threads você deve utilizar os métodos Invoke() e BenginInvoke() dos controles para executar um método na thread da UI. Exemplo:

    Private Delegate Sub FecharDelegate()

    Sub Fechar()
        ' Verifica se estamos na thread da UI
        If Me.InvokeRequired Then
            ' Não estamos. Invoca este método na thread da UI.
            Dim del As New FecharDelegate(AddressOf Fechar)
            Me.BeginInvoke(del)
        Else
            ' Estamos. Fecha o Form.
            Me.Close()
        End If
    End Sub

     

     

    terça-feira, 13 de fevereiro de 2007 01:38
  • Gutemberg,

    Um exemplo de como chamar um método usando Invoke()

    Public Class Form1

    Delegate Sub fechar_delegate()

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim form_delegate As fechar_delegate = New fechar_delegate(AddressOf fechar_form)

    trFechar = New Thread(AddressOf Fechar)

    trFechar.Start()

    End Sub

    Sub Fechar()

    Me.Invoke(form_delegate)

    End Sub

     

    Sub fechar_form()

    Me.Close()

    End Sub

    End Class

    Basicamente você deve definir um delegate (fechar_delegate) que nada mais é do que um evento.

    Depois você cria uma váriável para o delegate (form_delegate). Esta variável é que será usada no método Invoke().

    []s,
    Carlos.

    terça-feira, 13 de fevereiro de 2007 01:56

Todas as Respostas

  • Gutenberg,

    O problema é que o form principal também é uma thread, neste caso quando você inicia a thread trFechar, ela roda em outro processo.

    No seu caso não seria melhor um timer ? Caso seja necessário usar thread, você deverá criar uma função e chamr através de Invoke().

    []s,
    Carlos.

    terça-feira, 13 de fevereiro de 2007 01:17
  • Carlos  obrigado...

    Estou utilizando sockets e o fechamento do Form é através de um PC remoto então tenho que utilizar Thread mesmo, como seria o uso de INVOKE()?

     

    terça-feira, 13 de fevereiro de 2007 01:26
  • Você não pode utilizar controles em uma thread diferente daquela em que eles foram criados. Para permitir a interação de controles com outras threads você deve utilizar os métodos Invoke() e BenginInvoke() dos controles para executar um método na thread da UI. Exemplo:

    Private Delegate Sub FecharDelegate()

    Sub Fechar()
        ' Verifica se estamos na thread da UI
        If Me.InvokeRequired Then
            ' Não estamos. Invoca este método na thread da UI.
            Dim del As New FecharDelegate(AddressOf Fechar)
            Me.BeginInvoke(del)
        Else
            ' Estamos. Fecha o Form.
            Me.Close()
        End If
    End Sub

     

     

    terça-feira, 13 de fevereiro de 2007 01:38
  • Gutemberg,

    Um exemplo de como chamar um método usando Invoke()

    Public Class Form1

    Delegate Sub fechar_delegate()

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

    Dim form_delegate As fechar_delegate = New fechar_delegate(AddressOf fechar_form)

    trFechar = New Thread(AddressOf Fechar)

    trFechar.Start()

    End Sub

    Sub Fechar()

    Me.Invoke(form_delegate)

    End Sub

     

    Sub fechar_form()

    Me.Close()

    End Sub

    End Class

    Basicamente você deve definir um delegate (fechar_delegate) que nada mais é do que um evento.

    Depois você cria uma váriável para o delegate (form_delegate). Esta variável é que será usada no método Invoke().

    []s,
    Carlos.

    terça-feira, 13 de fevereiro de 2007 01:56
  • Carlos e Angus era isso mesmo... obrigado aos dois, marquei as duas respostas
    terça-feira, 13 de fevereiro de 2007 02:10
  •  

    Olá, estou tendo um probleminha parecido vou tentar exemplificar meu caso:

     

    Tenho uma função principal que abre uma thread que irá carregar um grafico, como são vários graficos abro várias threads, uma para cada gráfico.

    Pois então a função chamada pela thread precisa usar um painel de um form que abri antes de criar estas threads.

     

    quando tento adicionar um objeto no painel, recebo o erro "Pesquisa de Indicadores: InsrirGraficoIndicadores - Operação entre threads inválida: controle '4' acessado de um thread que não é aquele no qual foi criado."

     

    Código resumido é o seguinte.

     

    Botão Carregar graficos:

    frmIndicadores = New frmIndicadores

    NormalizarForms(Me)

    frmIndicadores.MdiParent = Me.MdiParent

    frmIndicadores.Show()

    frmIndicadores.Focus()

    CarregarIndicadores(cmbCategoria.SelectedItem)

     

    Função CarregarIndicadores:

    ...

    For shAux As Short = 0 To dsRetorno.Tables(0).Rows.Count - 1

    Dim obThread As New Threading.Thread(AddressOf CarregarIndicesMultiThread)

    obThread.Name = shAux

    obThread.Start()

    Next

     

    CarregarIndicesMultiThread :

    ...

    Me.Invoke(New RodarThreadCarregarValor(AddressOf Me.InsrirGraficoIndicadores), New Object() {obchart, shItensCategoria, shLinhaIndicadores})

     

    InsrirGraficoIndicadores:

    With Me.frmIndicadores

    .pnlIndicadores.Controls.Add(Grafico)

    shItensCategoria += 1

    If (.pnlIndicadores.Left + (275 * CInt(shItensCategoria + 1))) > .pnlIndicadores.Width Then

    shItensCategoria = 0

    shLinhaIndicadores += 1

    End If

    .AjustarIndicadores()

    End With

     

    Helpe-me por favor =)

    segunda-feira, 25 de fevereiro de 2008 15:07
  • Thiago,

     

    O problema é que os controles de um form não podem ser acessados diretamente pela thread, você precisa usar o Invike(), como explicado no post acima.

     

    []s,

     

    segunda-feira, 25 de fevereiro de 2008 16:36
  •  

    Sim, tenho a função dalegate com a mesma sign da função que adiciona o objeto grafico no painel, e dentro da função que eu chamo a thread tenho o invoke usando o delegate e mesmo assim não fuinciona.

    segunda-feira, 25 de fevereiro de 2008 16:43
  • Thiago,

     

    Você poderia postar um trecho do seu código ?

     

    []s,

    segunda-feira, 25 de fevereiro de 2008 16:47
  • 'Delegate para carregar os indices multithread

    Friend Delegate Sub RodarThreadCarregarValor( _

    ByVal Grafico As WinChartViewer, _

    ByVal shItensCategoria As Short, _

    ByVal shLinhaIndicadores As Short _

    )

     

    Private Sub btnConfirmar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnConfirmar.Click

    If VerificarData() Then

    minMes = CInt(cmbMesPesquisa.SelectedIndex + 1) : minAno = CInt(nudAnoPesquisa.Text)

    If cmbCategoria.SelectedItem <> "" Then

    frmIndicadores = New frmIndicadores

    NormalizarForms(Me)

    frmIndicadores.MdiParent = Me.MdiParent

    frmIndicadores.Show()

    frmIndicadores.Focus()

    CarregarIndicadores(cmbCategoria.SelectedItem)

    Else

    MostrarStatus(Me.Text & ": Escolha uma categoria de indicador!")

    End If

    Else

    MostrarStatus(Me.Text & ": Digite uma data válida!")

    End If

    End Sub

     

    Public Sub CarregarIndicadores(Optional ByVal stCategoria As String = "")

    'Dim shContador As Short

    Dim dsRetorno As New Data.DataSet

    Dim stSQL As String = ""

    Dim row As DataRow

    Try

    'Consulta SQL

    stSQL = "spbscCarregarIndicadores"

    If stCategoria <> "" Then stSQL &= " '" & stCategoria & "'"

    ReDim marIndicadores(0)

    ExecutarQuery(stSQL, dsRetorno)

    frmIndicadores.pnlIndicadores.Controls.Clear()

    For shAux As Short = 0 To dsRetorno.Tables(0).Rows.Count - 1

    With marIndicadores(shAux)

    'Processos carregados no dataSet

    End With

    Next

    For shAux As Short = 0 To dsRetorno.Tables(0).Rows.Count - 1

    Dim obThread As New Threading.Thread(AddressOf CarregarIndicesMultiThread)

    obThread.Name = shAux

    obThread.Start()

    Next

    End If

    Catch ex As Exception

    LogPrograma(Me.Text & ": CarregarIndicadores - " & stSQL)

    LogPrograma(Me.Text & ": CarregarIndicadores - " & ex.Message, True, True)

    End Try

     

    Private Sub CarregarIndicesMultiThread()

    Dim shItensCategoria, shLinhaIndicadores As Short

    Dim obchart As WinChartViewer

     

    Try

    ' Metodos para montar o grafico

    ' retirei esta parte porque é um monte de calculo

    obchart.SetBounds(Me.frmIndicadores.pnlIndicadores.Left + (275 * CInt(shItensCategoria)), (200 * shLinhaIndicadores), 250, 180)

    Me.frmIndicadores.Invoke(New RodarThreadCarregarValor(AddressOf InserirGraficoIndicadores), New Object() {obchart, shItensCategoria, shLinhaIndicadores})

    End With

    End Sub

     

    Então no click desse botão abre um form e chama uma função que carrega um array que não monstrei e faz um FOR para abrir varias threads que irão carregar os graficos separadamente. Então da função que esta em thread eu chamo o INVOKE para alterar o frmIndicadores.pnlIndicadores e recebo aquele erro.

     

    e aqui esta a função chamada pelo invoke que gera o erro:

    Private Sub InserirGraficoIndicadores(ByVal Grafico As WinChartViewer, ByVal shItensCategoria As Short, ByVal shLinhaIndicadores As Short)

    If Me.frmIndicadores.pnlIndicadores.InvokeRequired Then

    Dim d As New RodarThreadCarregarValor(AddressOf InserirGraficoIndicadores)

    Me.Invoke(d, New Object() {Grafico, shItensCategoria, shLinhaIndicadores})

    Else

    With Me.frmIndicadores

    .pnlIndicadores.Controls.Add(Grafico)

    shItensCategoria += 1

    If (.pnlIndicadores.Left + (275 * CInt(shItensCategoria + 1))) > .pnlIndicadores.Width Then

    shItensCategoria = 0

    shLinhaIndicadores += 1

    End If

    .AjustarIndicadores()

    End With

    End If

    End Sub

     

    o erro é gerado na linha .pnlIndicadores.Controls.Add(Grafico)

    segunda-feira, 25 de fevereiro de 2008 16:57
  • Tiago,

     

    O seu problema é que tem uma thread chamando outra, você nào consegue fazer somente uma thread que executa os gráficos?

     

    []s,

    segunda-feira, 25 de fevereiro de 2008 17:30
  • inicialmente os código executado na função InserirGraficoIndicadores estava junto com os cálculos feitos para gerar o gráfico, que é a minha thread criada, mas deu erro, então tentei pelo invoke dentro da thread, que é o explicado nos posts anteriores, mas mesmo assim não funcionou.

    Tem MSN?
    segunda-feira, 25 de fevereiro de 2008 17:42
  • Thiago,

     

    O seu problema é que você está criando controles em um thread e tentando acessar em outro. Tente colocar os controles como publicos a todos os threads.

     

    Cada thread é como se fosse uma instância do programa separada da outra, imagine que você criou o controle em um forms e está tentando chamar em outro.

     

    []s,

     

    segunda-feira, 25 de fevereiro de 2008 18:30
  • Bom... resolveu uma parte, agora ele não dá erro mas também não mostra nada no painel.

    segunda-feira, 25 de fevereiro de 2008 19:30
  • Thiago,

     

    Você fez um debug do código ? Veja se não existe outro ponto limpando o controle.

     

    []s,

    segunda-feira, 25 de fevereiro de 2008 20:33
  • Carlos,

    Só limpo o painel uma vez antes de carregar qualquer coisa, e no debug quando chega na linha frmIndicadores.pnlIndicadores.Controls.Add(obchart) aparece o erro "Operação entre threads inválida: controle 'pnlIndicadores' acessado de um thread que não é aquele no qual foi criado."




    terça-feira, 26 de fevereiro de 2008 10:55