Avatar billede angelenglen Nybegynder
06. september 2011 - 10:35 Der er 12 kommentarer og
1 løsning

Start form i ny thread

I min applikation har jeg en form (formExtra) udover min main-form (formMain).
Denne ekstra form ønsker jeg at åbne i en ny thread, men jeg kan ikke finde ud af hvordan jeg gør.

Det er vigtigt at jeg efterfølgende kan ændre fx baggrundsfarve på en label (Label1) i den ekstra form, fra min main-form.
Det er desuden vigtigt at jeg kan lukke formen igen, fra min main-form.

Af fejlbeskeder jeg har fået indtil nu er bl.a.:
"Starting a second message loop on a single thread is not a valid operation."
:-(
Avatar billede arne_v Ekspert
06. september 2011 - 15:08 #1
Du skal lave alt win form fra event traaden.

Skal du fra en anden traad lave noget GUI, saa brug Invoke til at faa det udfoert paa event traaden.
Avatar billede angelenglen Nybegynder
06. september 2011 - 17:23 #2
Jeg er lidt ny inden for threading, så jeg forstår ikke helt det du siger.

Har du evt. nogle hints til hvordan det gøres, sådan rent kodemæssigt?
Avatar billede arne_v Ekspert
06. september 2011 - 17:41 #3
Jeg lavede engang et simpelt klokke eksempel:

Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Threading

Public Class MainForm
    Inherits Form
    Private time As Label
    Private start As Button
    Private abort As Button
    Private t As Thread

    Public Sub New()
        time = New Label()
        start = New Button()
        abort = New Button()
        SuspendLayout()
        time.Location = New Point(50, 50)
        time.Size = New Size(300, 50)
        time.Font = New Font(FontFamily.GenericSerif, 16F)
        start.Location = New Point(50, 150)
        start.Size = New Size(200, 50)
        start.Name = "Start Button"
        start.Text = "Start clock"
        AddHandler start.Click, AddressOf StartClick
        abort.Location = New Point(50, 250)
        abort.Size = New Size(200, 50)
        abort.Name = "Abort Button"
        abort.Text = "Abort clock"
        AddHandler abort.Click, AddressOf AbortClick
        ClientSize = New Size(400, 350)
        Controls.Add(time)
        Controls.Add(start)
        Controls.Add(abort)
        Name = "Main Form"
        Text = "Main Form"
        ResumeLayout(False)
    End Sub
    Public Sub Run()
        While True
            If time.InvokeRequired Then
                time.Invoke(DirectCast(Sub() time.Text = DateTime.Now.ToString(), Action))
            Else
                Update()
            End If
            Thread.Sleep(1000)
        End While
    End Sub
    Public Sub StartClick(sender As Object, e As EventArgs)
        t = New Thread(AddressOf Run)
        t.Start()
    End Sub
    Public Sub AbortClick(sender As Object, e As EventArgs)
        t.Abort()
    End Sub
    <STAThread> _
    Public Shared Sub Main(args As String())
        Application.Run(New MainForm())
        Application.Exit()
        Environment.Exit(0)
    End Sub
End Class
Avatar billede angelenglen Nybegynder
07. september 2011 - 10:27 #4
har lige prøvet den, men får fejl i følgende linie:

time.Invoke(DirectCast(Sub() time.Text = DateTime.Now.ToString(), Action))

Too few type arguments to 'System.Action(Of T)'
Avatar billede angelenglen Nybegynder
07. september 2011 - 11:08 #5
Jeg prøvede at ændre din Run() sub til:

    Public Sub Run()
        While True
            If time.InvokeRequired Then
                time.Invoke(DirectCast(Sub()
                                          time.Text = DateTime.Now.ToString()
                                      End Sub, MethodInvoker))
            Else
                Update()
            End If
            Thread.Sleep(1000)
        End While
    End Sub

Umiddelbart får det programmet til at virke, men jeg kan ikke gennemskue hvordan jeg kan få det til at virke som jeg vil: åbne en form i en ny tråd, og kunne ændre indholdet i denne nye form efterfølgende.
Avatar billede angelenglen Nybegynder
07. september 2011 - 13:34 #6
Har lige leget lidt med det, tror jeg har fået det til at gøre som jeg vil nu :-)
Avatar billede angelenglen Nybegynder
07. september 2011 - 14:50 #7
hmm er stødt ind i problemer :-/


Hele projektet er at jeg har en browser i min mainform, denne browser viser skiftevis noget video, eller noget html-indhold.

Så vil jeg have en "ticker" eller "marquee" om man vil, til at køre hen over skærmen over videoen.

Det er denne "ticker" jeg skal have kørende i sin egen tråd, da browseren ellers sløver tickeren meget ned, så snart den laver noget intenst, som fx at vise video, animationer eller overgangs-effekter.

Umiddelbart er det lykkedes mig at få oprettet min form i en ny tåd, og få den til at indeholde min ticker.

Men jeg har lidt bøvl med efterfølgende at styre formens placering (tickeren skal kunne flyttes).
selve tickeren er en ScrollerMarquee som jeg fandt her:
http://www.vbforums.com/showthread.php?t=545150
den virker som sådan fint, og jeg kan sagtens ændre på selve ticker-objektets egenskaber såsom tekst og farve.
Det er selve formen jeg ikke kan flytte.

Når jeg forsøger at flytte formen, er der pludselig to af dem.
Én der indeholder min ticker, og en der ikke gør.

Her er lidt udsnit af min kode, håber det giver mening... jeg har ikke ryddet op i det, så noget er måske lidt irrelevant..
()


i min main-form har jeg:


Public Class frmMain
    Public TickerForm As Form
    Private TickerThread As Thread
    Public TickerScroller As ScrollingMarquee

    Public Sub InitializeTickerForm()
        doInitializeTickerForm(TickerForm, TickerScroller)
    End Sub

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

        Thread.Sleep(100) 'giv lige ticker-formen 0,1 sekundt til at initialisere, inden vi checker for InvokeRequired.

        If TickerForm.InvokeRequired Then
            TickerForm.Invoke(DirectCast(Sub()
                TickerForm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
                                                  TickerForm.ShowInTaskbar = False
                                            'TickerForm.Visible = False
                                            End Sub, MethodInvoker))
        End if
End Sub




følgende funktioner har jeg liggende i et Module:


    Public Sub doInitializeTickerForm(ByRef TargetForm As Form, ByRef TargetScroller As ScrollingMarquee)
        Try
            TargetForm = New Form()
            TargetScroller = New ScrollingMarquee()
            TargetForm.SuspendLayout()
            TargetScroller.Parent = TickerForm
            TargetScroller.Dock = DockStyle.Fill
            TargetScroller.MarqueeText = "test"
            TargetScroller.ScrollSpeed = 1
            TargetForm.Controls.Add(TargetScroller)
            TargetForm.Location = New Point(0, 0)
            TargetForm.Size = New Size(1000, 150)
            TargetForm.ResumeLayout(False)
            TargetForm.Show()
            TargetForm.BringToFront()
            TargetForm.TopMost = True
            Application.Run(TargetForm)
        Catch ex As Exception

        End Try
    End Sub


Private TickerSettingsErrorCounter As Integer = 0 'anti-infinite-loop
    Public Sub ApplySettingsToTicker()
        If TickerSettings.ContainsKey("height") Then
            TickerSettingsErrorCounter = 0
            'settings er indlæst, brug dem:

            TickerForm.Size = New Size(frmMain.ClientSize.Width, TickerSettings("height"))
            If TickerSettings("placering") = "top" Then
                TickerForm.Location = New Point(0, 0)
            Else
                TickerForm.Location = New Point(0, frmMain.ClientSize.Height - TickerSettings("height"))
            End If
            frmMain.TickerScroller.Location = New Point(0, 0)
            frmMain.TickerScroller.Font = New Font(TickerSettings("fontfamily"), TickerSettings("fontsize"), FontStyle.Regular, GraphicsUnit.Pixel)
            frmMain.TickerScroller.BackColor = ColorTranslator.FromHtml(TickerSettings("backgroundcolor"))
            frmMain.TickerScroller.ForeColor = ColorTranslator.FromHtml(TickerSettings("fontcolor"))
            frmMain.TickerScroller.ScrollSpeed = TickerSettings("scrollspeed")
            Select Case TickerSettings("backgroundrepeat")
                Case "center"
                    frmMain.TickerScroller.BackgroundImageLayout = ImageLayout.Center
                Case "none"
                    frmMain.TickerScroller.BackgroundImageLayout = ImageLayout.None
                Case "stretch"
                    frmMain.TickerScroller.BackgroundImageLayout = ImageLayout.Stretch
                Case "tile"
                    frmMain.TickerScroller.BackgroundImageLayout = ImageLayout.Tile
                Case Else '"zoom"
                    frmMain.TickerScroller.BackgroundImageLayout = ImageLayout.Zoom
            End Select
            If File.Exists(TickerSettings("backgroundimage")) Then
                Try
                    frmMain.TickerScroller.BackgroundImage = Image.FromFile(TickerSettings("backgroundimage"))
                Catch ex As Exception
                    Logger.LogInfo(ex)
                End Try
            End If

        Else
            'settings er ikke indlæst, forsøg at læse dem og prøv igen.
            If TickerSettingsErrorCounter < 1 Then
                TickerSettingsErrorCounter = TickerSettingsErrorCounter + 1
                LoadTickerSettings()
                ApplySettingsToTicker()
            End If
        End If
    End Sub




    Private Sub ShowTicker(ByVal TickerDBID As Integer, ByVal TickerText As String, ByVal TickerRSS As String)
        'TickerRSS er ikke implementeret endnu...
        ApplySettingsToTicker()
        frmMain.TickerScroller.MarqueeText = TickerText
        If TickerForm.InvokeRequired Then
            TickerForm.Invoke(DirectCast(Sub()
                                            TickerForm.Tag = TickerDBID
                                            TickerForm.Visible = True
                                            TickerForm.BringToFront()
                                            TickerForm.TopMost = True
                                        End Sub, MethodInvoker))
        Else
            TickerForm.Update()
        End If
    End Sub






Den sidste ShowTicker() fyres af fra en timer, hvis visse betingelser er opfyldt.

Det er når den fyres af, at der pludselig er to forms.
Meget mystisk.
Avatar billede arne_v Ekspert
08. september 2011 - 03:31 #8
Var det ikke bedre med 1 form med 2 panels end 2 forms?
Avatar billede angelenglen Nybegynder
08. september 2011 - 11:00 #9
Nej, for formen med min ticker ligger oven på formen med browseren.

Desuden, ville jeg ikke have det samme problem med at tickeren bliver langsom, mens browseren arbejder?
Avatar billede angelenglen Nybegynder
08. september 2011 - 14:53 #10
Eller mener du at jeg kan oprette to paneler, smide browseren i den ene, og tickeren i den anden.
- og så flytte panel nummer to, til at ligge oven på en del af det første panel, så tickeren vises oven på browseren?

Jeg har bare svært ved at forestille mig at det ændrer på at browseren sløver tickeren, når browseren laver noget, fx viser video... - for de vil jo stadig køre i samme tråd, eller?
Avatar billede angelenglen Nybegynder
09. september 2011 - 15:29 #11
Damn, har nu prøvet i flere dage, og kan bare ikke få det til at virke :-/

Kan det virkelig passe at det er så svært at åbne en ny form i en ny tråd?
Ligemeget hvad jeg har prøvet indtil nu, bliver min tickers hastighed påvirket at krævende aktiviteter i browseren på min mainform :-(
Avatar billede angelenglen Nybegynder
06. oktober 2011 - 13:11 #12
Er blevet truet til at lukke mine spørgsmål, så accepterer bare denne, selvom jeg ikke har nået at teste det :-/
Avatar billede arne_v Ekspert
06. oktober 2011 - 16:47 #13
Det er godt at faa spoergsmaal afsluttet paa en god maade. Det er ikke godt bare at lukke.

Hvem har truet dig?
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester