none
Set Value of progressBar on Tabbed form from a module or a different form RRS feed

  • Question

  • Hi Gurus,

    I've been searching all morning & can't find a reference to updating a progressbar from anywhere other than it's own parent form. The closest I've got is DirectCast(frmMainMenu.TabControl1.SelectedTab.Controls(ProgressBar1), ProgressBar).Value but the .Controls shows as Value of type ProgressBar cannot be converted to integer.

    I've added the ProgressBar to the form frmMainMenu as ProgressBar1 as I need to update the value from a module & sometimes from another form depending on the report I'll ultimately produce. What am I missing or misunderstanding?

    Wednesday, November 21, 2018 12:01 PM

Answers

  • Here a beginners type basic way. Just declare the form as public in the module. Then you can reference the progress bar from any where.

    For something more advanced this structure may not be appropriate I guess. But, there is nothing wrong with it for simple things.

    THis is the startup form1:

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            ProgForm.Show()
    
        End Sub
    End Class


    Form 1 starts the ProgForm which is a public instance of form3 declared in the module.

    Public Class Form3
    
        Private Sub Form3_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    
            timer1.Start()
    
        End Sub
    End Class

    A timer is used in the Module to set the progressbar in the Module sub Timer Tick.

    Module Module1
    
        Public ProgForm As New Form3
    
        Public WithEvents timer1 As New System.Windows.Forms.Timer With 
                 {.Interval = 1000, .Enabled = False}
    
        Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
            Static i As Integer
            i += 10
    
            If i > 100 Then
                timer1.Stop()
                i = 0
            End If
    
            ProgForm.ProgressBar1.Value = i
    
        End Sub
    End Module


    Wednesday, November 21, 2018 10:32 PM
  • Hi Karen,

    Thanks for responding. Being still very new to VB.Net & all its funky features that I didn't experience in VBA, This is something new for me to explore so plenty reading to come on delegates & the invoke methods. I'll revert once I put something together.

    Okay let's make this super easy.

    https://1drv.ms/u/s!AtGAgKKpqdWjjGTtJsvSoYFfPUZw

    Download the above project.

    Form1

    Public Class Form1
        Private childForm As New Form2
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            childForm.Left = Left + Width
            childForm.Top = Top
            childForm.Show()
        End Sub
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            For increment As Integer = 1 To 99
                childForm.ShowRecord(increment)
                Threading.Thread.Sleep(6) ' only for this example, otherwise ditch it
            Next
        End Sub
    End Class
    

    Form2

    Public Class Form2
        Public Delegate Sub UpdateRecordDelegate(ByVal value As Integer)
        Public Sub ShowRecord(ByVal sender As Integer)
            If InvokeRequired Then
                Invoke(New UpdateRecordDelegate(AddressOf ShowRecord), sender)
            Else
                ProgressBar1.Value = sender + 1
                Label1.Text = ProgressBar1.Value.ToString() & " percent complete"
                Label1.Refresh()
            End If
        End Sub
    End Class


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Thursday, November 22, 2018 2:17 AM
    Moderator

All replies

  • The best way to achieve what you want is by using a Delegate.

    The following starts with form1 which makes a call to a method in a class to get data and while in the method/function Retrieve populates data in form1 while updating a progressbar in a splash form (which could be another form in your case).

    Form1 code

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Dim da As New DataAccess(3)
    
            For Each item In da.Retrieve
                DataGridView1.Rows.Add(item.ItemArray)
            Next
    
    
            ' optional
            DataGridView1.ExpandColumns()
        End Sub
    
    End Class
    

    Class used to pass data in form1.

    Public Class Customer
        Public Property Identifier As Integer
        Public Property Company As String
        Public Property ContactName As String
    
        Public Overrides Function ToString() As String
            Return Identifier.ToString & ", " & Company
        End Function
        ''' <summary>
        ''' Represents an object array of one customer
        ''' </summary>
        ''' <value></value>
        ''' <returns>Customer populated data</returns>
        ''' <remarks></remarks>
        Public ReadOnly Property ItemArray As Object()
            Get
                Return New Object() {Identifier, Company, ContactName}
            End Get
        End Property
    End Class
    

    Data class

    Imports System.Data.OleDb
    ''' <summary>
    ''' Responsible for obtain data from a MS-Access database table,
    ''' create a customer object, push it back to the caller using
    ''' an Iterator routine that pushes data back using Yield statement.
    ''' 
    ''' In the above process we are popping information to a Splash screen
    ''' via a delegate. We could do this in the caller but I see no reason
    ''' why for this simple demonstration.
    ''' </summary>
    ''' <remarks>
    ''' Since there are not many records Threading.Thread.Sleep(25) is used
    ''' to slow things down to see the results in the splash screen.
    ''' 
    ''' The last sleep is there for demo purposes only.
    ''' 
    ''' None of the sleeps would be in production.
    ''' </remarks>
    Public Class DataAccess
    
        Private Builder As New OleDbConnectionStringBuilder With
            {
                .Provider = "Microsoft.ACE.OLEDB.12.0",
                .DataSource = IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Database1.accdb")
            }
    
        Private ConnectionString As String = ""
        Private Delay As Integer = 0
    
        Public Sub New(ByVal Delay As Integer)
            CurrentIndex = 1
            ConnectionString = Builder.ConnectionString
            Me.Delay = Delay
            GetRecordCount()
        End Sub
        Private mRecordCount As Integer
        Public ReadOnly Property RecordCount As Integer
            Get
                Return mRecordCount
            End Get
        End Property
        ''' <summary>
        ''' Get total records to be used with ProgressBar on SplashScreen
        ''' </summary>
        ''' <remarks></remarks>
        Private Sub GetRecordCount()
            Using cn As New OleDbConnection With {.ConnectionString = ConnectionString}
                Using cmd As New OleDbCommand With {.Connection = cn, .CommandText = "SELECT Count(Identifier) FROM Customer"}
                    cn.Open()
                    mRecordCount = CInt(cmd.ExecuteScalar)
                End Using
            End Using
        End Sub
        Public Property CurrentIndex As Integer
        ''' <summary>
        ''' used to return customer data
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Iterator Function Retrieve() As IEnumerable(Of Customer)
            CurrentIndex = 0
            Dim CustomerIdentifierPosition As Integer = 0
            Dim CustomerNamePosition As Integer = 1
            Dim ContactNamePosition As Integer = 2
    
            Using cn As New OleDbConnection With {.ConnectionString = ConnectionString}
    
                Using cmd As New OleDbCommand With
                    {
                        .Connection = cn,
                        .CommandText = "SELECT Identifier, CompanyName, ContactName FROM Customer;"
                    }
    
                    cn.Open()
    
                    Dim Reader As OleDbDataReader = cmd.ExecuteReader
    
                    If Reader.HasRows Then
    
                        Dim CompanyName As String = ""
    
                        While Reader.Read
    
                            'CompanyName = Reader.GetFieldValue(Of String)(CustomerNamePosition)
    
                            Yield New Customer With
                                  {
                                      .Identifier = Reader.GetFieldValue(Of Integer)(CustomerIdentifierPosition),
                                      .Company = Reader.GetFieldValue(Of String)(CustomerNamePosition),
                                      .ContactName = Reader.GetFieldValue(Of String)(ContactNamePosition)
                                  }
    
                            Dim PercentDone As Integer = CInt((CurrentIndex / Me.RecordCount) * 100)
                            SplashScreen1.ShowRecord(PercentDone)
    
                            Threading.Thread.Sleep(Delay)
    
                            CurrentIndex += 1
    
                        End While
    
                    End If
    
                    Reader.Close()
    
                    ' Current index at this point shows 75 thus the last call to ShowRecord
                    ' will not push the progressbar to 100 percent so the next line does using
                    ' 99 as the ShowRecord code adds one to the integer passed in.
    
                    SplashScreen1.ShowRecord(99)
                    '
                    ' Place here else the splashscreen disappears before we can see that
                    ' the progressbar is at 100 percent.
                    '
                    Threading.Thread.Sleep(5)
    
                End Using
            End Using
    
        End Function
    End Class
    

    Splash form

    Public Class SplashScreen1
        Public Delegate Sub UpdateRecordDelegate(ByVal value As Integer)
        Public Sub ShowRecord(ByVal sender As Integer)
            If InvokeRequired Then
                Invoke(New UpdateRecordDelegate(AddressOf ShowRecord), sender)
            Else
                Label1.Text = sender.ToString & " percent complete"
                ProgressBar1.Value = sender + 1
            End If
        End Sub
        Private Const CP_NOCLOSE_BUTTON As Integer = &H200
        Protected Overrides ReadOnly Property CreateParams() As CreateParams
            Get
                Dim myCp As CreateParams = MyBase.CreateParams
                myCp.ClassStyle = myCp.ClassStyle Or CP_NOCLOSE_BUTTON
                Return myCp
            End Get
        End Property
    End Class
    Although I'm working with a database that does not matter, the focus here in how I use the Delegate.

     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Wednesday, November 21, 2018 1:19 PM
    Moderator
  • Hi Karen,

    Thanks for responding. Being still very new to VB.Net & all its funky features that I didn't experience in VBA, This is something new for me to explore so plenty reading to come on delegates & the invoke methods. I'll revert once I put something together.

    Wednesday, November 21, 2018 3:54 PM
  • Here a beginners type basic way. Just declare the form as public in the module. Then you can reference the progress bar from any where.

    For something more advanced this structure may not be appropriate I guess. But, there is nothing wrong with it for simple things.

    THis is the startup form1:

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
            ProgForm.Show()
    
        End Sub
    End Class


    Form 1 starts the ProgForm which is a public instance of form3 declared in the module.

    Public Class Form3
    
        Private Sub Form3_Shown(sender As Object, e As EventArgs) Handles Me.Shown
    
            timer1.Start()
    
        End Sub
    End Class

    A timer is used in the Module to set the progressbar in the Module sub Timer Tick.

    Module Module1
    
        Public ProgForm As New Form3
    
        Public WithEvents timer1 As New System.Windows.Forms.Timer With 
                 {.Interval = 1000, .Enabled = False}
    
        Private Sub timer1_Tick(sender As Object, e As EventArgs) Handles timer1.Tick
            Static i As Integer
            i += 10
    
            If i > 100 Then
                timer1.Stop()
                i = 0
            End If
    
            ProgForm.ProgressBar1.Value = i
    
        End Sub
    End Module


    Wednesday, November 21, 2018 10:32 PM
  • Hi Karen,

    Thanks for responding. Being still very new to VB.Net & all its funky features that I didn't experience in VBA, This is something new for me to explore so plenty reading to come on delegates & the invoke methods. I'll revert once I put something together.

    Okay let's make this super easy.

    https://1drv.ms/u/s!AtGAgKKpqdWjjGTtJsvSoYFfPUZw

    Download the above project.

    Form1

    Public Class Form1
        Private childForm As New Form2
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            childForm.Left = Left + Width
            childForm.Top = Top
            childForm.Show()
        End Sub
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            For increment As Integer = 1 To 99
                childForm.ShowRecord(increment)
                Threading.Thread.Sleep(6) ' only for this example, otherwise ditch it
            Next
        End Sub
    End Class
    

    Form2

    Public Class Form2
        Public Delegate Sub UpdateRecordDelegate(ByVal value As Integer)
        Public Sub ShowRecord(ByVal sender As Integer)
            If InvokeRequired Then
                Invoke(New UpdateRecordDelegate(AddressOf ShowRecord), sender)
            Else
                ProgressBar1.Value = sender + 1
                Label1.Text = ProgressBar1.Value.ToString() & " percent complete"
                Label1.Refresh()
            End If
        End Sub
    End Class


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Thursday, November 22, 2018 2:17 AM
    Moderator