I'm currently working through a rather odd issue that I can't seem to figure out. I'm a novice programmer who is currently using VB.net to automate some lab equipment via the GPIB interface.
I'm using Excel to collect and tabulate my data. So the core of my problem is that I'm using a Backgroundworker to perform the "saving" of my data that I obtain from various lab equipment. Often times, I will have to record the assembly data of the specimens I'm testing. Here, I created another form with relevant fields to fill out all the data I'd ever desire to remember.
The backgroundworker thread will go into the secondary form, I've named it DAq6.vb, and pull the data. However, I've been noticing that it returns "" rather than the actual string that is present.
Public Function GetControlValue(ByVal ctl As Object) As String
Dim text As String
Try
If ctl.InvokeRequired Then
text = ctl.Invoke(New GetControlValueInvoker(AddressOf GetControlValue), ctl)
Else
If TypeName(ctl) = "ComboBox" Then
text = ctl.Text
ElseIf TypeName(ctl) = "NumericUpDown" Then
text = ctl.value
ElseIf TypeName(ctl) = "TextBox" Then
text = ctl.Text
ElseIf TypeName(ctl) = "RadioButton" Then
text = ctl.Checked
ElseIf TypeName(ctl) = "Decimal" Then
text = ctl.Value
ElseIf TypeName(ctl) = "Label" Then
text = ctl.Text
Else
text = "Type name unknown"
End If
End If
Return text
Catch ex As Exception
MsgBox("Error: " & Err.Description)
End Try
End Function
Above is the function that I use to safely retrieve a "control value" from a different thread.
And below is representative of the method I use to obtain values from the form I'm currently in (DAq1.vb). This code works, and it successfully retrieves the strings.
objRange = objSheet1.Range("B1")
objRange.Value = GetControlValue(txtDate)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objRange)
Here is code that doesn't work, curiously. I'm baffled as to why it wouldn't work.
objRange = objSheet6.Range("G2")
objRange.Value = GetControlValue(DAq6.txtLotNum1)
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(objRange)
Why would this be the case? Again, I'm a novice programmer that is primarily self-taught in VB.net syntax, so I apologize if this causes any cringing. But I have dug around the internet looking for an issue for a few days now, and I'm stumped.
Thank you so much for even just reading all of this!
Edit: I've adjusted the function according to Bjørn-Roger's suggestions. After inserting a breakpoint right before the error producing lines of code, I see that it correctly goes to the TypeName(ctl) = "TextBox" portion of the if statement. Yet, it still returns a "" rather than the correct value.
Ensure you return code on all paths and that you reference the correct instance of DAq6.
Here's a simple example:
Public Class DAq1
'Inherits Form
Public Sub New()
Me.InitializeComponent()
End Sub
Public Function GetControlValue(ByVal ctl As Control) As String
If (ctl Is Nothing) Then
Throw New ArgumentNullException("ctl")
End If
Try
If (ctl.InvokeRequired) Then
Return CStr(ctl.Invoke(New GetControlValueInvoker(AddressOf GetControlValue), ctl))
Else
If (TypeOf ctl Is NumericUpDown) Then
Return DirectCast(ctl, NumericUpDown).Value.ToString()
ElseIf (TypeOf ctl Is RadioButton) Then
Return DirectCast(ctl, RadioButton).Checked.ToString()
Else
'Fallback to Control.Text
Return ctl.Text
End If
End If
Catch ex As Exception
MessageBox.Show("Error: " & Err.Description)
End Try
Return Nothing
End Function
Private Sub _DoWork(s As Object, e As DoWorkEventArgs) Handles worker.DoWork
Dim f As DAq6 = DirectCast(e.Argument, DAq6)
e.Result = Me.GetControlValue(f.txtLotNum1)
End Sub
Private Sub _Completed(s As Object, e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
If (e.Error Is Nothing) Then
MessageBox.Show(CStr(e.Result), Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
Else
MessageBox.Show(e.Error.Message, Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Error)
End If
End Sub
Private Sub _Shown(s As Object, e As EventArgs) Handles Me.Shown
Dim f As New DAq6()
f.txtLotNum1.Text = "YES!"
Me.worker.RunWorkerAsync(f)
End Sub
Private WithEvents worker As New BackgroundWorker
Public Delegate Function GetControlValueInvoker(ctl As Control) As String
Public Class DAq6
Inherits Form
Public ReadOnly txtLotNum1 As New TextBox
End Class
End Class
Related
i'm new here and I do VB.net programming.
I want to do something very specific but i don't know how to aproach it. I have one ClickEvent that i want to use for various Buttons. The problem is that i want to make that each button changes one TextBox. I don't want to do this in 4 separate ClickEvents because i would be repeating a lot of code.
Here is what i want to do:
Private Sub btnOpenDial1_Click(sender As Object, e As EventArgs) Handles btnOpenDial1.Click, btnOpenDial2.Click, btnOpenDial3.Click, btnOpenDial4.Click
Dim UnitLetter As String = Environment.CurrentDirectory.Substring(0, 3)
SaveFileDialog1.InitialDirectory = UnitLetter
SaveFileDialog1.Filter = "rtf file (*.rtf)|*.rtf"
If SaveFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Try
'name is a TextBox variable that i have at the top of the program
name = SaveFileDialog1.FileName
If (name IsNot Nothing) Then
' I press btnOpenDial1, this textbox changes
txtDoc1.Text = nombre
' I press btnOpenDial2, this textbox changes
txtDoc2.Text = nombre
' I press btnOpenDial3, this textbox changes
txtDoc3.Text = nombre
' I press btnOpenDial4, this textbox changes
txtDoc4.Text = nombre
End If
Catch Ex As Exception
MessageBox.Show("No se ha podido grabar el archivo: " & Ex.Message)
End Try
End If
End Sub
I hope i explained good enough. English is not my main language. I just don't want to repeat more code on my program. Thanks in advance
You can use something like this:
You can use one ClickEventHandler Method for all buttons (better of the same type as EventArgs may be different for different types).
On click Event of each button you can detect it from its name (as code shows). At this point, when you have detected the button that is clicked you can run specific code in relation with that button.
Hope was what you wanted.
Private Sub btnOpenDial1_Click(sender As Object, e As EventArgs) Handles btnOpenDial1.Click,
btnOpenDial2.Click,
btnOpenDial3.Click,
btnOpenDial4.Click
Dim pressedButton As Control = CType(sender, Control)
Dim UnitLetter As String = Environment.CurrentDirectory.Substring(0, 3)
SaveFileDialog1.InitialDirectory = UnitLetter
SaveFileDialog1.Filter = "rtf file (*.rtf)|*.rtf"
If SaveFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
Try
'name is a TextBox variable that i have at the top of the program
Name = SaveFileDialog1.FileName
If (Name IsNot Nothing) Then
Select Case pressedButton.Name
Case "btnOpenDial1" : txtDoc1.Text = nombre
Case "btnOpenDial2" : txtDoc2.Text = nombre
Case "btnOpenDial3" : txtDoc3.Text = nombre
Case "btnOpenDial4" : txtDoc4.Text = nombre
End Select
End If
Catch Ex As Exception
MessageBox.Show("No se ha podido grabar el archivo: " & Ex.Message)
End Try
End If
End Sub
What I want to do is import a CSV file (called fwlist.txt), that looks like this:
modelname,power type,pic,part number,firmware, option1, option 1, etc
End result, i would like a combobox that shows the modelname, and when the model name is selected from the pulldown, it updates various labels and text boxes on the form with other information.
Here's what I have so far:
Dim filename As String = "fwlist.txt"
Dim pwrtype As String
Dim pic As String
Dim partnum As String
Dim lineread As String
Dim FirmwareName As String
Private Sub ReadFirmwaresLoad(sender As Object, e As EventArgs) Handles Me.Load
' Load the items into the NameComboBox list.
Dim ResponseDialogResult As DialogResult
Try
Dim FirmwareStreamReader As StreamReader = New StreamReader(filename)
' Read all the elements into the list.
Do Until FirmwareStreamReader.Peek = -1
lineread = FirmwareStreamReader.ReadLine()
Dim fields As String() = lineread.Split(",")
FirmwareName = fields(0) 'Take First Field
cbFW.Items.Add(FirmwareName)
'Set Text labels based on position in line.
pwrtype = fields(1)
pic = fields(2)
partnum = fields(3)
(...etc through options)
Loop
' Close the file.
FirmwareStreamReader.Close()
Catch ex As Exception
' File missing.
ResponseDialogResult = MessageBox.Show("File not Found!", "File Not Found",
MessageBoxButtons.OK, MessageBoxIcon.Question)
If ResponseDialogResult = DialogResult.OK Then
' Exit the program.
Me.Close()
End If
End Try
End Sub
Private Sub cbFW_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbFW.SelectedIndexChanged
lblPwrType.Text = pwrtype
lblPic.Text = pic
lblPartNum.Text = parnum
....etc thruogh options
End Sub
This code works, but only sort of. If i select anything from the combo box, it only gives me the information from the very last line of the CSV file - even if its the first entry in the box. I'm pretty sure it's something simple that I'm messing up.. anyone help?
First we read the lines into Firmware objects then we set this List(Of Firmware) as the DataSource of the ComboBox.
Then we handle the SelectedIndexChanged event of the ComboBox which will get the currently selected firmware and loads its data to the TextBox controls.
This is a tested, working example below:
Public Class Firmware
Public Property ModelName As String
Public Property PowerType As String
Public Property Pic As String
Public Property PartNumber As String
Public Property Firmware As String
Public Property Option1 As String
End Class
Public Class MainForm
Private Sub btnLoad_Click(sender As Object, e As EventArgs) Handles btnLoad.Click
Dim lines As String() = Nothing
Try
' Read the file in one step
lines = File.ReadAllLines("fwlist.txt")
Catch ex As Exception
Dim dialogResult As DialogResult = MessageBox.Show(Me, "File not found! Would you like to exit program?", "Error reading file", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2)
If dialogResult = DialogResult.Yes Then
Me.Close()
End If
Exit Sub
End Try
Dim firmwares As List(Of Firmware) = New List(Of Firmware)
For Each line As String In lines
Dim rawData As String() = line.Split({","}, StringSplitOptions.None)
' Create Firmware object from each line
Dim firmware As Firmware = New Firmware() With
{
.ModelName = rawData(0),
.PowerType = rawData(1),
.Pic = rawData(2),
.PartNumber = rawData(3),
.Firmware = rawData(4),
.Option1 = rawData(5)
}
' We store the read firmwares into a list
firmwares.Add(firmware)
Next
' Set the list as the data source of the combobox
' DisplayMember indicates which property will be shown in the combobox
With cboModelNames
.DataSource = firmwares
.DisplayMember = "ModelName"
End With
End Sub
Private Sub cboModelNames_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboModelNames.SelectedIndexChanged
RefreshForm()
End Sub
Private Sub RefreshForm()
' Get the selected item as Firmware object
Dim currentFirmware As Firmware = DirectCast(cboModelNames.SelectedItem, Firmware)
' Refresh all the textboxes with the information
With currentFirmware
txtPowerType.Text = .PowerType
txtPic.Text = .Pic
txtPartNumber.Text = .PartNumber
txtFirmware.Text = .Firmware
txtOption1.Text = .Option1
End With
End Sub
End Class
Every time you set the value of a variable like pwrtype, its old value is thrown away and there is no way to get it back. And even if you did save multiple values for each variable, you would need a way to figure out which value goes with the currently selected item in the combo box. To resolve these two issues you need:
a way to group values from the same line together
a way to save all values read from the file, not just the most recent ones
Let's start with the first issue, grouping values together. In the example code below, I created a Structure type called FirmwareInfo to serve that purpose. Each FirmwareInfo has its own pwrtype, pic, etc.
The other piece of the puzzle that you are missing is a way to save more than one Firmware. The easiest way to do this is to add each FirmwareInfo to the combo box's item list, instead of adding just the display string. The combo box will convert each item to a string in the UI; the ToString() method tells it how you want this conversion to be done.
I haven't run this example code so I can't guarantee there aren't mistakes in there, but hopefully it's enough to show the general idea.
Dim filename As String = "fwlist.txt"
Structure FirmwareInfo
Public pwrtype As String
Public pic As String
Public partnum As String
Public FirmwareName As String
Public Overrides Function ToString() As String
Return FirmwareName
End Function
End Structure
Private Sub ReadFirmwaresLoad(sender As Object, e As EventArgs) Handles Me.Load
' Load the items into the NameComboBox list.
Dim ResponseDialogResult As DialogResult
Try
Dim FirmwareStreamReader As StreamReader = New StreamReader(filename)
' Read all the elements into the list.
Do Until FirmwareStreamReader.Peek = -1
Dim lineread = FirmwareStreamReader.ReadLine()
Dim fields As String() = lineread.Split(",")
Dim info As New FirmwareInfo With {
.FirmwareName = fields(0),
.pwrtype = fields(1),
.pic = fields(2),
.partnum = fields(3)
}
cbFW.Items.Add(info)
Loop
' Close the file.
FirmwareStreamReader.Close()
Catch ex As Exception
' File missing.
ResponseDialogResult = MessageBox.Show("File not Found!", "File Not Found",
MessageBoxButtons.OK, MessageBoxIcon.Question)
If ResponseDialogResult = DialogResult.OK Then
' Exit the program.
Me.Close()
End If
End Try
End Sub
Private Sub cbFW_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbFW.SelectedIndexChanged
Dim currentInfo = DirectCast(cbFW.SelectedItem, FirmwareInfo)
lblPwrType.Text = currentInfo.pwrtype
lblPic.Text = currentInfo.pic
lblPartNum.Text = currentInfo.parnum
' ....etc through options
End Sub
I have been tasked with creating a cinema booking system in VB.net by my teacher. So far I have created 50 CheckBoxes and I am trying to rename them all to seat (number). I have this code in my Form1.load but it is not working because it is a type and not an expression. I tried using a variable for this but it did not work.
Here is my code:
For count As Integer = 1 To 54 Step 1
CheckBox(count).text = "Seat " & count
Next
Please help, and or recommend me another way to accomplish this.
set the name of the checkbox when you create it. To find out how to create a checkbox programmatically add a checkbox to a form then look at .designer.vb
dim cb as new checkbox
cb.name = "1"
cb.text = "Seat 1"
you need to also add the location and other properties
If you have already created your textboxes with names like 1, 2 then iterate through and get the numbers like this: If you call them CB_1 then cut the CB_ off before looking for the number.
dim cbNumber as int16
For Each c As Control In myContainer.Controls
If c.GetType() Is GetType(CheckBox) Then
cbnumber = cint(c.name)
c.text = "Seat" & cbnumber
End If
Next
Well, here's my approach. In order to test just drop on a FlowLayoutPanel, a Button, and a NumericUpDownonto the form.
Option Strict On
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For count As Integer = 1 To 54 Step 1
' Make a new CheckBox
Dim chkBox As New CheckBox()
' Setup the Checkbox
With chkBox
.Tag = count.ToString
.Name = CStr("seatCheckBox" & count.ToString)
.Text = String.Format("Seat {0}", count)
.ThreeState = False
.Checked = False
End With
' add an event listener for the checkbox checkstate changed event
AddHandler chkBox.CheckStateChanged, AddressOf Me.CheckBox_CheckStateChanged
' Add the checkbox to the control
Me.FlowLayoutPanel1.Controls.Add(chkBox)
' Keep the user from picking something that doesn't exist
Me.NumericUpDown1.Maximum = CDec(count)
Next
' Add and event listener for the find button click event
AddHandler Button1.Click, AddressOf Me.FindButton_Clicked
End Sub
' Find the checkbox in the form and return it
Private Function GetCheckBox(ByVal seatNumber As Integer) As CheckBox
Dim chkbox As CheckBox
' Try to find the Checkbox
Try
chkbox = TryCast(Me.Controls.Find(CStr("seatCheckBox" & seatNumber.ToString), True).First, CheckBox)
Catch ex As Exception
chkbox = Nothing
End Try
'Check if the trycast worked
If IsNothing(chkbox) Then
Throw New ArgumentOutOfRangeException("seatNumber", "The seat number to be searched for was not found")
Else
Return chkbox
End If
End Function
' Handle the Chekbox checkState event.
Private Sub CheckBox_CheckStateChanged(sender As Object, e As EventArgs)
' Convert to Checkbox
Dim chkBox As CheckBox = DirectCast(sender, CheckBox)
' Simple result string
Dim resultstring As String = CStr("Seat Number {0} is now {1}.")
' Set the values
Select Case chkBox.Checked
Case True
resultstring = String.Format(resultstring, chkBox.Tag, "taken")
Case False
resultstring = String.Format(resultstring, chkBox.Tag, "available")
End Select
' Display it
MsgBox(resultstring)
End Sub
Private Sub FindButton_Clicked(sender As Object, e As EventArgs)
Try
' Get the checkbox and return it's name
MsgBox(GetCheckBox(CInt(Me.NumericUpDown1.Value)).Name.ToString)
Catch ex As Exception
' Display the error
MsgBox(ex.Message)
End Try
End Sub
End Class
I'm new to VB.NET and have been struggling all afternoon with something. I've found similar questions on the forum but none of them seemed to describe my problem exactly. I'm fairly sure that I'm missing something very basic.
I have made a main form which currently holds only one button which purpose is to open up a second form and close the main form. Based on the settings the user will select on the 2nd form the first form might have to be adapted to match with the new settings. But the problem occurs even before that.
The 'settings' form has 15 textboxes which I drew onto the form in development mode. They are called ID1, ID2,..,ID15. The values which I want to display in there are saved in an array:
Dim ids(15) as integer
Next, I created a module to simulate what you could call a control array as I used to use them in VB6.
Public sources() As TextBox = [frmSettings.ID1, frmSettings.ID2, //and so on
I did this to be able to iterate through all the 15 textboxes:
For i = 0 To 14
Sources(i).Text = ids(i + 1)
Next
Then I added on the main form this code to the Button1_Click() event:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmSettings.Show()
Me.Close()
End Sub
I did the same thing for the 'exit ' button on the frmSettings form.
This seems to work, but only once. I launch the application, push the button and frmSettings pops up and shows all the values from the array in the textboxes. When I push the 'close' button, I return to the main page.
So far so good, but if I try to return to frmSettings a second time, all the textboxes remain blank as if the code I added to the form never gets executed.
Any help would be greatly appreciated!
First, make sure the array that holds your data is accessible to both forms:
Module Module1
Public ids(15) As Integer
End Module
There should not be a declaration for "ids" in either form.
Next, make frmSettings itself responsible for loading and saving the data:
Public Class frmSettings
Private Sub frmSettings_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
TB.Text = ids(i)
End If
Next
End Sub
Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
Dim valid As Boolean = True
Dim matches() As Control
For i As Integer = 0 To 14
matches = Me.Controls.Find("ID" & (i + 1), True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is TextBox Then
Dim TB As TextBox = DirectCast(matches(0), TextBox)
Dim value As Integer
If Integer.TryParse(TB.Text, value) Then
ids(i) = value
Else
MessageBox.Show(TB.Name & ": " & TB.Text, "Invalid Value", MessageBoxButtons.OK, MessageBoxIcon.Warning)
valid = False
End If
End If
Next
If valid Then
Me.Close()
End If
End Sub
End Class
Okay, basically, I'm assigning an array values inside a function of the class. But after the class executes, the array resets to nothing. Here's my code:
Public Class MoisacDialog
Public imgArray(,) As Bitmap
Private Sub cmdCancel_Click(sender As Object, e As EventArgs) Handles cmdCancel.Click
DialogResult = DialogResult.Cancel
End Sub
Private Sub cmdOK_Click(sender As Object, e As EventArgs) Handles cmdOK.Click
Try
Dim rows As Integer = Convert.ToInt32(txtRows.Text)
Dim cols As Integer = Convert.ToInt32(txtCols.Text)
If rows > 0 And cols > 0 Then
ReDim imgArray(rows - 1, cols - 1)
For i As Integer = 0 To cols - 1
For j As Integer = 0 To rows - 1
Using fileImage As New OpenFileDialog
If fileImage.ShowDialog() = DialogResult.OK Then
imgArray(i, j) = CType(Bitmap.FromFile(fileImage.FileName), Bitmap)
End If
End Using
Next
Next
DialogResult = DialogResult.OK
Else
MessageBox.Show("Rows/columns entered are out of range.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
End If
Catch ex As FormatException
MessageBox.Show("Invalid rows/columns entered.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
End Class
After cmdOK_Click executes, the whole array imgArray resets to nothing. If I use it like this in a calling form:
Using sizeDialog As New MoisacDialog
If MoisacDialog.ShowDialog() = DialogResult.OK Then
Dim ImageArray(,) As Bitmap = sizeDialog.imgArray
_img = ImProc.PixelEffects.Moisac(ImageArray)
picImage.Image = CType(_img, Image)
End If
End Using
and use debugging view, ImageArray is set to Nothing after the third line, while it's still there by the end of cmdOK_Click.
UPDATE: I changed line 4 of my second snippet to _img = ImageArray(0,0). The problem persists, a NullReferenceException is thrown and handled in the code enclosing my second snippet.
It’s not reset, it was never set in the first place.
Using sizeDialog As New MoisacDialog
If MoisacDialog.ShowDialog() = DialogResult.OK Then
Dim ImageArray(,) As Bitmap = sizeDialog.imgArray
Note that you’re using sizeDialog and MoisacDialog indiscriminately. MoisacDialog, when used as an object, is a default instance of the class of the same name. It’s unfortunate that VB allows this instead of catching the obvious error here at compile time.
To correct the error, simply use sizeDialog.ShowDialog().