Display output on the form in VB 2010 - vb.net

I'm designing a windows form. I have output to be displayed on the form it self.
Tried using print, but it is not working.
How do I do that?
I'M NOT PRINTING THE FORM.
ADDED:
I need to display 3 numbers with text string next to each number.
I want to do this in a way that it shows in the form or label in the form without overwriting the previous results.
example:
3 (wrong) 1 (right) 8 (wrong)
2 (wrong) 1 (right) 5 (right)
9 (right) 1 (right) 5 (right)
ADDED:
Thanks for the help everyone. one more question and i think i'm good.
I was thinking of doing something like this inside a loop, problem is I can't add a string and an int together to make a new var:
Xnum1 = Xnum1 + 50
Xnum2 = Xnum1 + ".0F"
Ynum1 = Ynum1 + 50
Ynum2 = Ynum1 + ".0F"

In VB6 you could use the Print statement to draw to the surface of the form. In VB.NET, however, you should be using the Form.CreateGraphics method to create a new Graphics object that can be used to draw to the form's surface. For instance:
Private Sub PrintText(text As String, x As Single, y As Single)
Dim g As Graphics = Me.CreateGraphics()
g.DrawString(text, New Font("Arial", 16), New SolidBrush(Color.Black), New PointF(x, y))
End Sub
That would be the closest equivalent to using the VB6 Print statement like that.
However, I would strongly recommend using a control to display the data. It looks like for the data you need to display, a simple multi-line text box or label would be sufficient. For instance:
Private Sub AppendResult(index As Integer, right As Boolean)
If right Then
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (right)"
Else
TextBox1.Text = TextBox1.Text & " " & index.ToString() & " (wrong)"
End If
End Sub
If you want to get more fancy, you could look into using a data grid, a list box, a list view, or even a table layout control instead.

I believe that the most efficient way is to use a tableLayoutPanel with 6 columns. Add in each cell a label showing in the first cell the number, in the second the indicator for that number (right/wrong). Do the same for second and third number.(second number = third and fourth cell, third number =fifth and sixth cell)
For the next set of numbers you can add a new row with with labels in each cell.
I'll add some code to make my answer more professional.
First you add the tableLayoutPanel in your form. You size it as you like (make its width, long enough to handle the data)
You delete the lastRow and then you add columns (you want to have 6 columns). You edit the size of the columns to be Percentage =16.67%
Public Class Form1
Private rowIndex
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
For i = 0 To 4 Step 2
Dim val As Integer = 3
AddLabels(val, i, 0)
Next
For i = 1 To 5 Step 2
Dim val As String = "right"
AddLabels(val, i, 0)
Next
End Sub
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
rowIndex = rowIndex + 1
Me.TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Absolute, 30))
Me.TableLayoutPanel1.Height = Me.TableLayoutPanel1.Height + 30
For i = 0 To 4 Step 2
Dim val As Integer = 3 'here you have to put your number
AddLabels(val, i, rowIndex)
Next
For i = 1 To 5 Step 2
Dim val As String = "right" 'here you have to put your indicator
AddLabels(val, i, rowIndex)
Next
End Sub
Private Sub AddLabels(ByVal lblValue As String, ByVal column As Integer, ByVal row As Integer)
Dim lblHeader As New Label
lblHeader.AutoSize = True
lblHeader.Margin = New Padding(0)
lblHeader.BackColor = Color.Transparent
lblHeader.TextAlign = ContentAlignment.MiddleLeft
lblHeader.Dock = DockStyle.None
lblHeader.Text = lblValue
'Put the lblHeader in the right cell
Dim lblHeaderPos As New TableLayoutPanelCellPosition(column, row)
TableLayoutPanel1.SetCellPosition(lblHeader, lblHeaderPos)
TableLayoutPanel1.Controls.Add(lblHeader)
End Sub
Let me know if you facing any problems.
Also if you don't know how many rows you will add, put the tableLyoutPanel inside a panel. Make the panel's property AutoScroll=True and then you can add infinite number of new rows.

Related

Remove specific row of TableLayoutPanel using dynamically created button of each row

So I am making a function that will populate the TableLayoutPanel from FileDialog Result then make a delete button for each row using a loop. Here's the code
Private PathtoFile1 As New List(Of String) 'this will contain all the selected file in the dialogwindow
Private rowLineDrawing As Integer = 0
Private selectedfilecountLineDrawing As Integer
Public Function AttachFileLineDrawing(TLP As TableLayoutPanel)
Dim dr = OpenFileDialog1.ShowDialog
If (dr = System.Windows.Forms.DialogResult.OK) Then
selectedfilecountLineDrawing = OpenFileDialog1.FileNames.Count
For Each FileName In OpenFileDialog1.FileNames
Try
Console.WriteLine(FileName.ToString)
PathtoFile1.Add(FileName.ToString)
Catch SecEx As Security.SecurityException
MessageBox.Show("Security error. Please contact your administrator for details.\n\n" &
"Error message: " & SecEx.Message & "\n\n" &
"Details (send to Support):\n\n" & SecEx.StackTrace)
Catch ex As Exception
'Could Not Load the image - probably permissions-related.
MessageBox.Show(("Cannot display the image: " & FileName.Substring(FileName.LastIndexOf("\"c)) &
". You may not have permission to read the file, or " + "it may be corrupt." _
& ControlChars.Lf & ControlChars.Lf & "Reported error: " & ex.Message))
End Try
Next
'MAKE SOMETHING HERE TO DISPLAY THE SELECTED ITEMS IN THE TABLELAYOUTPANEL OF THE SUBMIT PROGRESS
TLP.Controls.Clear()
TLP.RowCount = 0
rowLineDrawing = 0
For Each Path In PathtoFile1
Dim filepath As New Label
filepath.Text = Path
filepath.Width = Val(360)
'this button is for previewing the file
Dim btnPreview As New Button
AddHandler btnPreview.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox("This is Preview")
End Sub
'This button is for removing rows in the tablelayoutpanel
Dim btnRmv As New Button
Dim StringToIndex As String = Path 'THIS CATCHES EVERY PATH IN THE LOOP AND STORE IT TO THE VARIABLE WHICH THEN BE USED AS A COMPARABLE PARAMETER FOR THE INDEX SEARCH
Dim index = PathtoFile1.IndexOf(Path)
AddHandler btnRmv.Click,
Sub(s As Object, e As EventArgs)
Dim btn = CType(s, Button)
MsgBox(index)
PathtoFile1.RemoveAt(index) 'THIS LINE OF CODE REMOVE THE SPECIFIC ITEM IN THE LIST USING THE BTNRMV CLICK
'MAKE SOMETHING HERE TO REMOVE THE ROW IN THE TABLELAYOUTAPANEL
End Sub
TLP.SuspendLayout()
TLP.RowStyles.Add(New RowStyle(SizeType.Absolute, 20))
TLP.Controls.Add(filepath, 0, rowLineDrawing)
TLP.Controls.Add(btnPreview, 1, rowLineDrawing)
TLP.Controls.Add(btnRmv, 2, rowLineDrawing)
TLP.ResumeLayout()
rowLineDrawing -= -1
Next
End If
End Function
So I am trying to remove the row in the TableLayoutPanel together with the dynamic control. My approach is removing the selected item in the list and I achieved it properly but can't remove the row in the TableLayoutPanel. Any help is much appreciated!
EDIT
I have tried to use the provided module above but got this error
And got this error
Here is an extension method that will enable you to remove any row from a TableLayoutPanel by index:
Imports System.Runtime.CompilerServices
Public Module TableLayoutPanelExtensions
<Extension>
Public Sub RemoveRowAt(source As TableLayoutPanel, index As Integer)
If index >= source.RowCount Then
Throw New ArgumentOutOfRangeException(NameOf(index),
index,
"The row index must be less than the number of rows in the TableLayoutPanel control.")
End If
'Remove the controls in the specified row.
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, index)
If child IsNot Nothing Then
child.Dispose()
End If
Next
'Move controls below the specified row up.
For rowIndex = index + 1 To source.RowCount - 1
For columnIndex = 0 To source.ColumnCount - 1
Dim child = source.GetControlFromPosition(columnIndex, rowIndex)
If child IsNot Nothing Then
source.SetCellPosition(child, New TableLayoutPanelCellPosition(columnIndex, rowIndex - 1))
End If
Next
Next
'Remove the last row.
source.RowCount -= 1
End Sub
End Module
I tested that on 3 column by 4 row TableLayoutPanel containing a Label in each cell executing the following code twice:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
TableLayoutPanel1.RemoveRowAt(1)
End Sub
The result was as expected, i.e. removing the second-from-top row each time. You may need to fiddle a bit more depending on what you want to happen row heights. I had the row heights set to equal percentages so the remaining rows grew proportionally to fill the space. If you want something different, you can add code accordingly. Note that you could create an almost identical method for removing columns.

Accessing buttons names using variables

In visual basic I want to be able to access a button's name using the number stored in a variable.
For example if I have 24 buttons that are all named 'Button' with the numbers 1, 2, 3... 22, 23, 24 after it. If I want to then change the text in the first eight buttons how would I do that.
Here's my example to help show what I mean:
For i = 1 to 8
Button(i).text = "Hello"
Next
The proposed solutions so far will fail if the Buttons are not directly contained by the Form itself. What if they are in a different container? You could simple change "Me" to "Panel1", for instance, but that doesn't help if the Buttons are spread across multiple containers.
To make it work, regardless of the Buttons locations, use the Controls.Find() method with the "searchAllChildren" option:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ctlName As String
Dim matches() As Control
For i As Integer = 1 To 8
ctlName = "Button" & i
matches = Me.Controls.Find(ctlName, True)
If matches.Length > 0 AndAlso TypeOf matches(0) Is Button Then
Dim btn As Button = DirectCast(matches(0), Button)
btn.Text = "Hello #" & i
End If
Next
End Sub
For index As Integer = 1 To 8
CType(Me.Controls("Button" & index.ToString().Trim()),Button).Text = "Hello"
Next
Use LINQ and you're good to go:
Dim yourButtonArray = yourForm.Controls.OfType(of Button).ToArray
' takes all controls whose Type is Button
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
Or
Dim yourButtonArray = yourForm.Controls.Cast(of Control).Where(
Function(b) b.Name.StartsWith("Button")
).ToArray
' takes all controls whose name starts with "Button" regardless of its type
For each button in yourButtonArray.Take(8)
button.Text = "Hello"
Next
In any case, .Take(8) will iterate on the first 8 items stored inside yourButtonArray

Datagridview not displaying tab character

I use a visual basic program to get information from another program, which we'll call ProgramX.
ProgramX has built in functionality to generate tab-delimited tables, which many users copy over to Excel. My goal(which I've acheived) is to generate and collect upwards of 1,000 of these tables and have the results ready for the user to copy/paste into Excel all at once instead of one at a time. My Dataset keeps the tab-delimited records just as I would like them.
The issue is that when I display my dataset/datatable in my datagridview, all tab characters are removed. When the results are copied/pasted into Excel they take up one column instead of automatically breaking out. I have been using datagridview to preview results/copy to clipboard; Is there any way to retain the tabs in this view?
Expected Result: Result 1 [tab] Result 2 [tab] Result 3
Result in datatable: Result 1 [tab] Result 2 [tab] Result 3
Result in datagridview: Result 1Result 2Result 3
If the only way to achieve this is to copy directly from my datatable, I have seen a few posts on how to accomplish that. Thanks!
You have numerous options available, but in most cases you'll need to perform some looping one way or another - however even with 1000+ records it's performance hardly takes a hit.
So for the first couple of options let's assume I have the following setup - keeping with your one DataGridViewColumn idea:
Me.table = New DataTable()
Me.table.Columns.Add("Data", GetType(String))
For i As Integer = 0 To 999
Dim x As Integer = i * 4
Dim data As String = String.Format("Result {0}" & vbTab & "Result {1}" & vbTab & "Result {2}" & vbTab & "Result {3}", x + 1, x + 2, x + 3, x + 4)
Me.table.Rows.Add(data)
Next
Me.dataGridView1.AllowUserToAddRows = False
Me.dataGridView1.DataSource = Me.table
Possible Solutions
Loop through the DataTable, concatenate the data, and set the clipboard text:
Private Sub button1_Click(sender As Object, e As System.EventArgs) Handles button1.Click
Dim content As String = String.Empty
For Each row As DataRow In Me.table.Rows
content = String.Format("{0}" & vbLf & "{1}", content, row.ItemArray(0).ToString())
Next
content = content.TrimStart(ControlChars.Lf)
Clipboard.SetText(content)
End Sub
Loop through the DataGridView.Rows, concatenate the data, and set the clipboard text:
Private Sub button1_Click(sender As Object, e As System.EventArgs) Handles button1.Click
Dim content As String = String.Empty
For Each row As DataGridViewRow In Me.dataGridView1.Rows
content = String.Format("{0}" & vbLf & "{1}", content, row.Cells(0).Value.ToString())
Next
content = content.TrimStart(ControlChars.Lf)
Clipboard.SetText(content)
End Sub
And to make the grid look a little better for both option 1 and 2, since the display seems to ignore tabs:
Private Sub dataGridView1_CellFormatting(ByVal sender As Object, _
ByVal e As DataGridViewCellFormattingEventArgs) _
Handles dataGridView1.CellFormatting
Dim value As String = e.Value.ToString().Replace(vbTab, " ")
e.Value = value
End Sub
With that your grid might look like:
In addition to the original setup and instead of binding to the original DataTable, split the table's data by the tabs and display them in separate columns:
Dim splitTable As New DataTable()
For Each row As DataRow In Me.table.Rows
Dim splitItems = row.ItemArray(0).ToString().Split(ControlChars.Tab)
For i As Integer = splitTable.Columns.Count To splitItems.Length - 1
splitTable.Columns.Add(String.Empty, GetType(String))
Next
splitTable.Rows.Add(splitItems)
Next
Me.dataGridView1.AllowUserToAddRows = False
Me.dataGridView1.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText
Me.dataGridView1.DataSource = splitTable
Then you can use the built-in clipboard method for the DataGridView:
Private Sub button1_Click(sender As Object, e As System.EventArgs) Handles button1.Click
Me.dataGridView1.SelectAll()
Clipboard.SetDataObject(Me.dataGridView1.GetClipboardContent())
End Sub
With that your grid might look like:
For all three options, clicking button1 to copy the data and hitting Ctrl+V in Excel will produce:
Note that Wrap Text will be on by default.
Pros:
Options 1 and 2 leave the user-selected cells intact. Option 3 looks better with separated DataGridView columns.
Cons:
Options 1 and 2 can look less clean pending the data. Option 3 selects all cells, losing the user's previous selected cells.

Pass values from Numeric control into corresponding cells in DataGridView control with a button

I want to move the values from each of four Numeric Up/Down controls into the DataGridView columns/rows with a button. For instance, the operator sets the values in the up/down numeric controls and then clicks the button. The program should then add a new row to the DataGridView and pass whatever values that are in the Numeric Up/Down controls into the new cells of the new row. As of now, I have the adding new rows part of it working as well as the delete button working (delete last row of the DataGridView). Now, how to pass the Numeric control values into the cell of the new row of the DataGridView with the button? Each new row created of the DatGridView has four cells to correspond to the four Numeric up/down controls. Thank you.
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.RowCount = LftMtr_Data_Grid.RowCount + 1
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
rowNumber = rowNumber + 1
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
rowCount1 = LftMtr_Data_Grid.RowCount
txtBox1.Text = rowCount1
End Sub
Try something like below. Note that you don't need to setup the column headers everytime, just once in the Load() event would do!
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LftMtr_Data_Grid.ColumnCount = 4
LftMtr_Data_Grid.Columns(0).HeaderText = " Spindle Speed (rpm)"
LftMtr_Data_Grid.Columns(1).HeaderText = " Accel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(2).HeaderText = " Decel Rate (rpm/S)"
LftMtr_Data_Grid.Columns(3).HeaderText = " Time (S)"
For Each c As DataGridViewColumn In LftMtr_Data_Grid.Columns
c.Width = 120
Next
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub addStep_btn_Click(sender As Object, e As EventArgs) Handles addStep_btn.Click
Dim values() As Object = {NumericUpDown1.Value, NumericUpDown2.Value, NumericUpDown3.Value, NumericUpDown4.Value}
Dim index As Integer = LftMtr_Data_Grid.Rows.Add(values)
LftMtr_Data_Grid.Rows(index).HeaderCell.Value = "Step " & (index + 1)
LftMtr_Data_Grid.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders)
End Sub
Private Sub delStep_btn_Click(sender As Object, e As EventArgs) Handles delStep_btn.Click
If LftMtr_Data_Grid.Rows.Count > 0 Then
LftMtr_Data_Grid.Rows.RemoveAt(LftMtr_Data_Grid.Rows.Count - 1)
End If
End Sub
End Class
I figured it out on my own. Here is what I came up with:
Dim rowNumber As Integer = 1
For Each row As DataGridViewRow In LftMtr_Data_Grid.Rows
If row.IsNewRow Then Continue For
row.HeaderCell.Value = "Step " & rowNumber
LftMtr_Data_Grid.CurrentCell = LftMtr_Data_Grid.Rows(LftMtr_Data_Grid.RowCount - 1).Cells(0)
LftMtr_Data_Grid.CurrentRow.Cells(0).Value = LftMtr_Speed_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(1).Value = LftMtr_Accel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(2).Value = LftMtr_Decel_Incr.Value
LftMtr_Data_Grid.CurrentRow.Cells(3).Value = test_Time_Incr1.Value
rowNumber = rowNumber + 1
Next
This application works with an empty or partially filled dataGridView. When the user clicks the button, the code creates a new row in the dataGridView, makes the new row the selected row, and then finally populates each of the cells in the new row with the values that are in the four Numeric Up/down controls (could be a text box too depending on your application). This is code copied directly from my specific application. Yours may differ slightly with variable names, label text, etc.

Dynamic reading from file & displaying on form load

I have 2 text files named sQue.txt containing single words in each lines (each word in each line) and sObj.txt also containing single word in each line (but no. of entries are more in this file than in sQue.txt).
Now, I have a blank form in which I want to read both the above files & display them in a manner such that:
Each entry from sQue.txt file gets displayed in separate labels in the form
All the entries of file sObj.txt are put in a CheckedListBox & this CheckedListBox appears for each label displayed in point 1. above.
Example:
sObj.txt contains 3 entries aaa, bbb & ccc (vertically i.e each in new line).
sQue.txt contains 5 entries p,q,r,s & t (vertically i.e each in new line).
Now, when the form loads, 3 labels are seen with texts aaa, bbb & ccc. Also 3 CheckedListBoxes are seen containg p,q,r,s & t in each box.
Can it be done? I'm trying to find a solution with no luck yet.
Please help.
Till now all I have is
Private Sub Form7_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim queue As String() = IO.File.ReadAllLines("C:\temp\sQue.txt")
Dim objects As String() = IO.File.ReadAllLines("C:\temp\sObj.txt")
For i = 0 To queue.Count - 1
'create labels here
For j=0 to objects.Count - 1
'create CheckedListBoxes
Next
Next
End Sub
It is easily done:
Private Sub Form7_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim theAppDirectory = IO.Path.GetDirectoryName(Application.ExecutablePath)
Dim queue As String() = IO.File.ReadAllLines(theAppDirectory & "\que.txt")
Dim objects As String() = IO.File.ReadAllLines(theAppDirectory & "\obj.txt")
Dim top As Integer = 10
Dim left As Integer = 10
Dim I As Integer = 0
Dim J As Integer = 0
Dim aLabel As Label
Dim aListCheckBox As CheckedListBox
Dim aPanel As New Panel
aPanel.Dock = DockStyle.Fill
aPanel.Top = 0
aPanel.Left = 0
aPanel.AutoScroll = True
For I = 0 To queue.Count - 1
aLabel = New Label
aLabel.Text = queue(I)
aLabel.Top = top
aLabel.Left = left
aListCheckBox = New CheckedListBox
aListCheckBox.Top = top
aListCheckBox.Left = left + 100
For J = 0 To objects.Count - 1
aListCheckBox.Items.Add(objects(J), False)
top += 20
Next J
'add event handlers here
aPanel.Controls.Add(aLabel)
aPanel.Controls.Add(aListCheckBox)
Next I
Me.Controls.Add(aPanel)
End Sub
This assumes that you want the files to be in the same directory as the executable.
Also no event handlers are added. You will need to determine what event handlers you want and add them when you create the controls.