Moikka kaikille.
Nyt kun kesä alkaa oleen ohi niin pääseepi taas ohjelmointiharrastuksen ja toisinaan tyhmien kysymysten pariin.
Aloin kokeileen ohjelman "säikeistystä" ja aika helposti sain luotua yksinkertaisen säieohjelman.
Nyt haluaisin säieohjelman lisäävän textboxiin ohjelman kulusta kertovia kommentteja, mutta nämä kommentit eivät päivity textboxiin. Säieohjelma kyllä rullaa kokoajan, mutta textboxin päivitystä ei tapahdu.
Kun sama säieohjelma kutsutaan tavallisena aliohjelmana, niin kaikki menee hienosti.
Säieohjelmasta löytyy .refresh ja .doevents, mutta ei niistäkään ole apua.
Mikäs tässä nyt mättää?
Onko toi taas niitä salaisia ohjelmia, joiden lähdekoodeja ei voi näyttää muille?
Vaikea koodia näkemättä sanoa. Ilmeisesti kuitenkin käytät delegaattia, koska muutenhan se ohjelma kai kaatuisi kokonaan siinä vaiheessa kun yrität päivittää.
Ei se salainen ole, en vaan jaksanut liittää sitä viestiin. Ajattelin, että jospa joku osaisi auttaa ilman koodin näkemistä.
Koodi on työkoneella joten en voi sitä nytkään tähän liittää.
Mitä tarkoitat delegaatilla?
lainaus:
Mitä tarkoitat delegaatilla?
No kun toisen threadin kontrolleja ei voi käyttää suoraan, niin delegaatin avullahan se onnistuu.
Eli jos kerran et ole delegaattia käyttänyt, niin ihmettelen kyllä että et saa poikkeusta tuosta kun yrität muuttaa sitä textboxin arvoa. Olisiko sulla siellä joku "virheenkäsittely" try-catch'em'all rakenne, joka ei käsittele mitään vaan syö vaan poikkeukset.
lainaus:
Ei se salainen ole, en vaan jaksanut liittää sitä viestiin. Ajattelin, että jospa joku osaisi auttaa ilman koodin näkemistä.
Siis voihan sitä arvailla. Ainoa vaan, että jos arvaan mitä olet tehnyt (alla), niin sen pitäisi heittää poikkeus, ellei niitä ole järjenvastaisesti "syöty".
Jos ihan vaan lyön formille Button1 painikkeen ja TextBox1 tekstilaatikon ja teen seuraavan koodin:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MunSäie As New Threading.Thread(AddressOf SäieOhjelma) MunSäie.Start() End Sub Private Sub SäieOhjelma() TextBox1.Text = "Testi" 'Tästä tulee poikkeus End Sub
Eli kun painaa nappia niin tuolta merkityltä riviltä tulee seuraava poikkeus:
System.InvalidOperationException was unhandled
Message="Cross-thread operation not valid: Control 'TextBox1' accessed from a thread other than the thread it was created on."
Eli tuossahan se sanotaan selvällä englannilla, että yritettiin muuttaa controllin arvoa väärästä säikeestä. Jos tuo poikkeus vaan "syödään" niin lopputuloksena tekstiboksi ei päivity.
Tässä vielä sama delegaatilla tehtynä (toimivana)
Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MunSäie As New Threading.Thread(AddressOf SäieOhjelma) MunSäie.Start() End Sub 'Textboxin päivittävä aliohjelma Private Sub AsetaTextBox1Text(ByVal UusiArvo As String) TextBox1.Text = UusiArvo End Sub 'Delegaattimääritys edellisen aliohjelman käyttämiseen Invokella Private Delegate Sub dlgAsetaTextBox1Text(ByVal UusiArvo As String) Private Sub SäieOhjelma() 'Tehdään delegaatti Dim dlg As New dlgAsetaTextBox1Text(AddressOf AsetaTextBox1Text) 'Pyydetään Textbox1:n säiettä käynnistämään delegaatti TextBox1.Invoke(dlg, "Testi") End Sub End Class
Kiitos Grez.
Uskon, että se puuttuva "lenkki" oli juuri tuo delegointi. Sitä ei minulla koodissa ole. Ja poikkeus on syöty tällä:
Control.CheckForIllegalCrossThreadCalls = false
Pääsen vasta maanantaina testaileen koodia.
Ihan vaan selvennyksen vuoksi haluaisin vielä kysäistä, että:
Entäpä jos haluaisin laittaa kaiken muun paitsi tuon säieohjelman moduliin (ihan vaan selkeyden vuoksi) alla olevan tyyliin, niin joudunko tosiaan aina Kommentoi-ohjelmaa kutsuttaessa kertomaan myös textboxin nimen (joka on tässä tapauksessa aina sama)? Vai onko jokin muu keino?
Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim MunSäie As New Threading.Thread(AddressOf SäieOhjelma) MunSäie.Start() End Sub Private Sub SäieOhjelma() Kommentoi(TextBox1, "Plaaplaaplaa, plaaplaaapla") End Sub End Class
Moduliin:
Module Module1 Private Delegate Sub dlgAsetaTextBox1Text(ByVal UusiArvo As String) Public Sub Kommentoi(ByVal TB As TextBox, ByVal teksti As String) 'Tehdään delegaatti Dim dlg As New dlgAsetaTextBox1Text(AddressOf AsetaTextBox1Text) 'Pyydetään Textbox1:n säiettä käynnistämään delegaatti TB.Invoke(dlg, teksti) End Sub 'Textboxin päivittävä aliohjelma Private Sub AsetaTextBox1Text(ByVal UusiArvo As String) Form1.TextBox1.Text = UusiArvo End Sub End Module
Haa! Nyt tajusin ton systeemin mikä siinä on ideana. Asia luultavasti loppuunkäsitelty!
Voit tosiaan käyttää ilmaisua "Form1.TextBox1", kuten olet toisessakin kohti jo tehnyt.
Ei muuten onnistu Metabolix.
Miksei? :o Onko se ehkä Private?
Tuleepi seuraava virheilmoitus:
Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
Tiedät varmaan itse peremmin mitä tuo tarkoittaa.
No eikös tuossa sanota. Yritit käyttää invokea ennen kuin sitä toista ikkunaa oli luotu.
Mitä toista ikkunaa?
tämä rivi siis aiheuttaa virheen:
Form1.Textbox1.Invoke(dlg, teksti)
Ja väitätkö nyt, että muuten aivan sama koodi toimii, jos funktiot ovatkin Form1:n sisällä ja/tai annat boksin funktiolle parametrina?
Juuri näin.
Oletko aivan varma, ettet yritä muuttaa tekstiä, ennen kuin ikkuna ja boksi on luotu?
Testaapa tuosta vielä. Tämä ainakin minulla toimii aivan hyvin riippumatta siitä, mitkä osat ovat Testi-luokassa ja mitkä m1-moduulissa, eikä sillä mitään merkitystä pitäisi ollakaan. Tässä säie ajetaan, kun formia klikataan.
Imports System.Windows.Forms Imports System.Drawing Imports System.Threading Public Class Testi Inherits Form Public tb As TextBox Public Sub New() Me.Text = "Testi" Me.Size = new Size(200, 200) Me.CenterToScreen() Me.tb = new TextBox() Me.tb.Parent = Me Me.tb.Location = new Point(0, 0) Me.tb.Size = new Size(100, 24) Me.Controls.Add(Me.tb) AddHandler Me.Click, AddressOf Me.OnClick End Sub Private Sub OnClick(btn As Object, e As EventArgs) Dim t As Thread t = new Thread(AddressOf UpdateBox_Thread) t.Start() End Sub Private Sub UpdateBox_Thread Dim i As Integer For i = 1 To 500 m1.UpdateBox_Caller(i) Next End Sub End Class Module m1 Dim form As Testi Public Sub UpdateBox_Caller(i As Integer) form.tb.Invoke(new UpdateBox_Delegate(AddressOf UpdateBox_Real), i.ToString()) End Sub Public Sub UpdateBox_Real(str As String) form.tb.Text = str End Sub Public Delegate Sub UpdateBox_Delegate(s As String) Public Sub Main form = new Testi() Application.Run(form) End Sub End Module
Edit: Antti hoi, VB-kooditagi syö edelleenkin tabulaattorit!
novice kirjoitti:
Mitä toista ikkunaa?
No sitä Form1 ikkunaa.
Koodiasi piti hieman muokata jotta sain editorin hyväksymään sen (miksiköhän?):
Imports System.Windows.Forms Imports System.Drawing Imports System.Threading Public Class Testi Inherits Form Public tb As TextBox Private Sub Testi_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load Me.Text = "Testi" Me.Size = New Size(200, 200) Me.CenterToScreen() Me.tb = New TextBox() Me.tb.Parent = Me Me.tb.Location = New Point(0, 0) Me.tb.Size = New Size(100, 24) Me.Controls.Add(Me.tb) AddHandler Me.Click, AddressOf Me.Testi_Click End Sub Private Sub Testi_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click Dim t As Thread t = New Thread(AddressOf UpdateBox_Thread) t.Start() End Sub Private Sub UpdateBox_Thread() Dim i As Integer For i = 1 To 500 m1.UpdateBox_Caller(i) Next End Sub End Class Module m1 Dim form As Testi Public Sub UpdateBox_Caller(ByVal i As Integer) form.tb.Invoke(New UpdateBox_Delegate(AddressOf UpdateBox_Real), i.ToString()) End Sub Public Sub UpdateBox_Real(ByVal str As String) form.tb.Text = str End Sub Public Delegate Sub UpdateBox_Delegate(ByVal s As String) Public Sub Main() form = New Testi() Application.Run(form) End Sub End Module
Ja nyt pukkaa virhettä:
Object reference not set to an instance of an object.
riviltä:
form.tb.Invoke(New UpdateBox_Delegate(AddressOf UpdateBox_Real), i.ToString())
Edit: Ohjelman ajo menee toisinaan läpi ilman virheitä????? (kestää vaan n.10sek), mutta boxissa ei ole kertaakaan näkynyt merkkiäkään.
Aihe on jo aika vanha, joten et voi enää vastata siihen.