This is my first question ever, so please spare me if I did something wrong.
I have a small survey form that automatically draw questions and answers from a SQL server table, and create a question label (Label_Questionnaire(i)), a panel to nest all radiobuttons for the answer of each question (Panel_Response(i)), and 3 radiobuttons(yes, no, n/a), named RadioButton_Answers(i)_1 . All questions and answers are inside a big panel (Panel_Survey) to allow user to scroll up and down (around 50 questions).
When I run the program, I can only see questions but none of the radiobuttons are showing. What I did try are:
Use .BringToFront to bring the Panel_Response and all radiobuttons to front.
Change .Parent to Controls.Add . Instead of using .Parent, I use Panel_Survey.Controls.Add(Panel_Response) and Panel_Response.Controls.Add(RadioButton_Answers_1)
Force Panel_Response.Visible = True and all radiobuttons visible = true
(I know it might sound stupid, but I'm out of trick)
How do I make those radiobuttons show up? If not, are there any better designs for this kind of survey form? Thank you for any advice, in advance!
Below is my code:
Protected Overrides Sub OnLoad(e As EventArgs)
Dim PanelCount As Integer
Dim QuestionName As String
Dim Response1 As String
Dim Response2 As String
Dim Response3 As String
Dim InitialX As Integer = Panel_Survey.Left
Dim InitialY As Integer = Panel_Survey.Top
Dim SizeX As Integer = 1000
Dim SizeY As Integer = 25
'Load the survey
Try
'Get a list of questions and answers into array of list
Dim ListofQuestionandAnswers As New List(Of List(Of String))
Dim conn As New SqlClient.SqlConnection
conn.ConnectionString = ConnectionString
Dim CommandString As String = "SELECT [QuestionID], [QuestionName] ,[Response1],[Response2],[Response3] FROM [Question_List] ORDER BY [QuestionID]"
Dim Command As New SqlClient.SqlCommand
Command.CommandText = CommandString
Command.Connection = conn
Dim dr As SqlClient.SqlDataReader
conn.Open()
dr = Command.ExecuteReader
While dr.Read
Dim ls As New List(Of String)
ls.Add(dr.GetValue(0).ToString)
ls.Add(dr.GetValue(1).ToString)
ls.Add(dr.GetValue(2).ToString)
ls.Add(dr.GetValue(3).ToString)
ls.Add(dr.GetValue(4).ToString)
ListofQuestionandAnswers.Add(ls)
End While
conn.Close()
PanelCount = ListofQuestionandAnswers.Count
For i = 0 To ListofQuestionandAnswers.Count - 1
QuestionName = ListofQuestionandAnswers(i)(1)
Response1 = ListofQuestionandAnswers(i)(2)
Response2 = ListofQuestionandAnswers(i)(3)
Response3 = ListofQuestionandAnswers(i)(4)
Dim Label_Questionnaire As New Label
Dim Panel_Response As New Panel
Dim RadioButton_Answers_1 As New RadioButton
Dim RadioButton_Answers_2 As New RadioButton
Dim RadioButton_Answers_3 As New RadioButton
'Condition the label
With Label_Questionnaire
.Parent = Panel_Survey
.Name = "Label_Questionnaire" + i.ToString
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = QuestionName
.ForeColor = Color.Black
.Location = New Point(InitialX, InitialY)
.AutoSize = True
End With
'Condition the panel
With Panel_Response
'Panel_Survey.Controls.Add(Panel_Response)
.Parent = Panel_Survey
.Name = "Panel_Questionnaire" + i.ToString
.Location = New Point(InitialX + 880, InitialY)
.Width = 250
.Height = 25
.BringToFront()
End With
Dim j As Integer
Dim h As Integer
j = Panel_Response.Left
h = Panel_Response.Top
'Condition the radiobuttons for answers
With RadioButton_Answers_1
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_1"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response1
.ForeColor = Color.Black
.Location = New Point(j, h)
.AutoSize = True
h += RadioButton_Answers_1.Height
End With
With RadioButton_Answers_2
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_2"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response2
.ForeColor = Color.Black
.Location = New Point(RadioButton_Answers_1.Right, h)
.AutoSize = True
End With
With RadioButton_Answers_3
.Parent = Panel_Response
.Name = "RadioButton_Answers" + i.ToString + "_3"
.Font = New Font("Calibri", 11, FontStyle.Regular)
.Text = Response3
.ForeColor = Color.Black
.Location = New Point(RadioButton_Answers_2.Right, h)
.AutoSize = True
End With
InitialY = InitialY + SizeY + 10
Next
Catch ex As Exception
MessageBox.Show(String.Format("Error: {0}", ex.Message), "Error while creating questions and answers", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Few basic problems here:
You seem to assume that when a control is placed inside a panel, it must be placed at a location relative to the form. It doesn't; it places relative to the Panel which has its own coordinate system starting at 0,0 in the top left of the panel - you initialize j and h (for locations of the radio buttons) to the Left and Top of the panel they're in, but they should be inited to 0,0 if you want the radiobuttons to start at the top left of the panel. If the Panel is placed at 300,300 on a form, and you place a radiobutton inside the panel also at 300,300 (because you copied its left and top) then the radio button will look like it's at 600,600 on the form because its at 300,300 inside a panel that is at 300,300
You only make your panel 250 wide - it's barely wide enough to show a single radio button
You increment h once, by an amount that means the next radiobutton disappears off the bottom of the panel (which is 25 pixels high)
Here:
With Panel_Response
'Panel_Survey.Controls.Add(Panel_Response)
.Parent = Panel_Survey
.Name = "Panel_Questionnaire" + i.ToString
.Location = New Point(InitialX + 880, InitialY)
.Width = 2500
.Height = 25
.BringToFront()
.BackColor = Color.Red
End With
Dim j As Integer
Dim h As Integer
j = 0
h = 0
Paste that over your app code and run it again. I made the panel BackColor red so you can more easily see where the panel is
I guess you need to decide how you want your UI to look. If the radiobuttons are laid out vertically, don't increment X when you add them to the panel (by setting the parent property). Make the panel tall enough to accommodate them (25 px not enough)
Use a FlowLayoutPaanel or TableLayoutPanel instead
Related
So
I need to create an array of labels and I dont know the final size of the array.
I declare it in the class section
Dim myPoints() As Label
in the program I fill the array
Dim l As New Label
l.Width = 4
l.Height = l.Width
l.BackColor = Color.Red
l.Visible = True
l.Left = pointA.X - 2
l.Top = pointA.Y - 2
l.Name = CStr(i)
myPoints(i) = New Label
myPoints(i) = l
AddHandler l.Click, AddressOf l_Click
Panel1.Controls.Add(myPoints(i))
when I run the program I get object reference not set Error
is there a way to to do it with no declaration of the array size ?
Arrays are fixed length collections. If you need a collection that can grow and/or shrink, then use a List(Of T) (documentation)
Dim myPoints = New List(Of Label)()
Dim l = New Label() With {
.Width 4,
.Height = .Width,
.BackColor = Color.Red,
.Visible = True,
.Left = pointA.X - 2,
.Top = pointA.Y - 2,
.Name = i.ToString()
}
myPoints.Add(l)
In an application I'm developing, the user can select a number of items (max. 6) in a datagrid. These items should then be printed in a matrix style on pre-printed forms (see it like CD labels, 6 on a page).
I'm generating these images dynamically containing the selected content from a database. I then put these in a grid so they can be printed on the pre-printed forms.
I have the following code that creates the grid, generates the images from a user control and adds them to the grid and then prints these images.
I'm not following the MVVM pattern for the printing action. I created a reference to my view model in my code-behind.
Private Sub PrintButton_Click(sender As Object, e As RoutedEventArgs) Handles ButtonPrint.Click
Dim dlg As New PrintDialog
dlg.PrintTicket.PageMediaSize = New PageMediaSize(PageMediaSizeName.ISOA4)
Dim pageWidth As Double = GetPageWidth(dlg)
'Since the label is a perfect square: labelWidth = labelHeight
Dim labelWidthInPx As Integer = Utilities.ConvertMmToPixels(My.Settings.LabelWidthInMm)
'Set spacing distances in pixels
Dim horizontalLabelSpacing As Integer = Utilities.ConvertMmToPixels(My.Settings.HorizontalLabelSpacinginMm)
Dim verticalLabelSpacing As Integer = Utilities.ConvertMmToPixels(My.Settings.VerticalLabelSpacingInMm)
Dim topMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.TopMarginInMm)
Dim leftMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.LeftMarginInMm)
Dim bottomMargin As Integer = Utilities.ConvertMmToPixels(My.Settings.BottomMarginInMm)
'Create the table/grid
Dim tbl As New Grid
If CheckBoxPrintGridLines.IsChecked Then
tbl.ShowGridLines = True
Else
tbl.ShowGridLines = False
End If
'Add 3 columns (2 for the labels, 1 for spacing)
Dim col1 As New ColumnDefinition With {
.Width = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim col2 As New ColumnDefinition With {
.Width = New GridLength(horizontalLabelSpacing, GridUnitType.Pixel)
}
Dim col3 As New ColumnDefinition With {
.Width = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
tbl.ColumnDefinitions.Add(col1)
tbl.ColumnDefinitions.Add(col2)
tbl.ColumnDefinitions.Add(col3)
'Add 5 Rows (3 for labels, 2 for spacing)
Dim row1 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim row2 As New RowDefinition With {
.Height = New GridLength(verticalLabelSpacing, GridUnitType.Pixel)
}
Dim row3 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
Dim row4 As New RowDefinition With {
.Height = New GridLength(verticalLabelSpacing, GridUnitType.Pixel)
}
Dim row5 As New RowDefinition With {
.Height = New GridLength(labelWidthInPx, GridUnitType.Pixel)
}
tbl.RowDefinitions.Add(row1)
tbl.RowDefinitions.Add(row2)
tbl.RowDefinitions.Add(row3)
tbl.RowDefinitions.Add(row4)
tbl.RowDefinitions.Add(row5)
'Add label images
Dim reelData = CType(DataGridReels.ItemsSource, List(Of ReelInfo))
Dim rowIndex As Integer = 0
Dim colIndex As Integer = 0
For Each reel In reelData.Where(Function(r) r.IsSelected = True)
Dim partNumberData = ViewModel.DataService.GetPartNumberDataAsync(reel.PartNumber)
Dim batchData = ViewModel.DataService.GetBatchDataAsync(reel.PartNumber, reel.HENBatchNumber)
LabelImageControl.IsPrinting = True
LabelImageControl.PartNumberData = partNumberData.Result
LabelImageControl.BatchData = batchData.Result
LabelImageControl.ReelData = reel
LabelImageControl.Refresh
UpdateUI()
Dim labelImage As New Image
labelImage = GetImageFromLabel(LabelImageControl)
labelImage.Width = labelWidthInPx
labelImage.Height = labelWidthInPx
Grid.SetRow(labelImage, rowIndex)
Grid.SetColumn(labelImage, colIndex)
tbl.Children.Add(labelImage)
tbl.Refresh
colIndex += 1
If colIndex > 1 Then
colIndex = 0
rowIndex += 1
End If
Next
Dim iuc As New InlineUIContainer(tbl)
Dim p As New Paragraph(iuc)
'Create print dialog
If dlg.ShowDialog.GetValueOrDefault Then
'Create a flow document
Dim doc As New FlowDocument With {
.Name = "LabelPage",
.ColumnWidth = pageWidth,
.PagePadding = New Thickness(leftMargin, topMargin, 0, bottomMargin)
}
doc.Blocks.Add(p)
'Create IDocumentPagniatorSource from FlowDocument
Dim idpSource As IDocumentPaginatorSource = doc
Try
Me.Cursor = Cursors.Wait
dlg.PrintDocument(idpSource.DocumentPaginator, "Label Page")
Catch ex As Exception
Me.Cursor = Cursors.Arrow
MessageBox.Show("An error occurred during printing: " & ex.Message, "Print error")
Finally
Me.Cursor = Cursors.Arrow
End Try
End If
End Sub
When I send the output to the PDF printer I only get one image in the top left corner of the page/grid.
Since the user control (LabelImageControl) is in the XAML, I can see it changing while debugging. So the data is coming into the user control correctly.
When I check the grid with the XML Visualiser I see it has the same number of children as the items I selected in the datagrid.
Can anyone point me in the right direction on how to get the grid printing correctly?
The problem is importing Microsoft.Office.Interop.Word (which I need elsewhere in this class) breaks "New Frame()". The error is
'New' cannot be used on an interface
My guess is that Interop.Word redefines "frame". How do I fix this?
My code:
Imports C1.WPF
Imports Microsoft.Office.Interop.Word
End Sub
Private Sub btn_SendQuote_Click(sender As Object, e As RoutedEventArgs) Handles btn_SendQuote.Click
Dim tab_SendQuote As New C1TabItem()
Dim frame_SendQuote As New Frame()
Dim scroller_SendQuote As New ScrollViewer()
Dim str_Name As String = "Send Quote"
Dim str_NavigationLink As String = "PM_SendQuote.xaml"
createNewTab(tab_SendQuote, frame_SendQuote, scroller_SendQuote, str_Name, str_NavigationLink)
End Sub
Private Sub createNewTab(tab As C1TabItem, frame As Frame, scroller As ScrollViewer, str_TabName As String, str_NavigationLink As String)
'Function to be used for adding tabs
'Add and name new tab
tab.Header = tabcontrol.Items.Count + 1 & ". " & str_TabName
tab.CanUserClose = True
tabcontrol.Items.Add(tab)
'Add frame to the tab and include new job subform page
With frame
.NavigationService.Navigate(New Uri(str_NavigationLink, UriKind.Relative))
.HorizontalAlignment = HorizontalAlignment.Stretch
.VerticalAlignment = VerticalAlignment.Top
.Margin = New Thickness(0, 0, 0, 0)
End With
With scroller
.CanContentScroll = vbTrue
.VerticalScrollBarVisibility = ScrollBarVisibility.Auto
.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto
.Content = frame
End With
tab.Content = scroller
' Set new tab as active tab
tabcontrol.SelectedIndex = tabcontrol.Items.IndexOf(tab)
End Sub
I put two solid circles (shapes) onto a form, change their colors, and move them around. When I get them into the right position, I want to capture the full-color image of the form and put it into an array as quickly as possible. How can I do this?
Here is how I draw the objects:
I get an OvalShape from VB PowerPacks in VB2010Express and draw it as a circle on the form. After that, I adjust it in code:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
OccultSize1 = 100
OccultSize2 = 50
OvalShape1.Width = OccultSize1
OvalShape1.Height = OccultSize1
OvalShape2.Width = OccultSize2
OvalShape2.Height = OccultSize2
OvalShape1.Left() = 155 - OvalShape1.Width / 2
OvalShape1.Top() = 153 - OvalShape1.Height / 2
OvalShape2.Left() = 155 - OvalShape2.Width / 2
OvalShape2.Top = 85 'temporary
OvalShape1.FillColor = Color.Yellow
OvalShape1.BorderColor = Color.Yellow
OvalShape2.FillColor = Color.Blue
OvalShape2.BorderColor = OvalShape2.FillColor
Label1.Text = "100"
Label2.Text = "50"
Label3.Text = "xxx"
tbHue.Value = OvalShape2.FillColor.GetHue
RadioButton1.Checked = False
RadioButton2.Checked = True
LineShape1.Visible = False
LineShape2.Visible = True
OvalShape3.Visible = False
End Sub
Here is what I have tried with DrawToBitmap (copied most of it from Stack Overflow): Button1.Click is my addition.
Private Function GetFormImage(ByRef GetBitmap As String) As Bitmap
' Make the bitmap.
Dim wid As Integer = Me.Width
Dim hgt As Integer = Me.Height
Dim bm As New Bitmap(wid, hgt)
' Draw the form onto the bitmap.
Me.DrawToBitmap(bm, New Rectangle(0, 0, wid, hgt))
bm.Save("E:\rhtempsave\bm.bmp")
' Make a smaller bitmap without borders.
wid = 240 'Me.ClientSize.Width
hgt = 320 'Me.ClientSize.Height
Dim bm2 As New Bitmap(wid, hgt)
' Get the offset from the window's corner to its client
' area's corner.
Dim pt As New Point(0, 0)
pt = PointToScreen(pt)
Dim dx As Integer = 37 'pt.X - Me.Left
Dim dy As Integer = 10 'pt.Y - Me.Top
' Copy the part of the original bitmap that we want
' into the bitmap.
Dim gr As Graphics = Graphics.FromImage(bm2)
gr.DrawImage(bm, 0, 0, New Rectangle(dx, dy, wid, hgt), _
GraphicsUnit.Pixel)
bm2.Save("E:\rhtempsave\bm2.bmp")
Return bm2
End Function
This is bm2.
For some reason, the bitmaps appeared on my disk today, but not yesterday. The only thing I did in the meantime was shutdown and restart my computer. Strangely, the bmps are not readable by Photoshop, Photoshop Elements or Win10's photo reader yet they show up as icons in the disk file dialog. Probably a header problem. I think I'm good to go with the next step of putting the bmp into an array for later retrieval. Thanks. I'm very grateful for your prompt response.
Here is my code to add a combobox array to a groupbox array
Dim gbQuoteProduct(5) As GroupBox
Dim cmboBoxQuoteProduct(5) As ComboBox
gbQuoteProduct(n) = New GroupBox
With gbQuoteProduct(n)
.Text = ""
.Location = New Point(10, 5 + n * 70)
.Width = 300
.Height = 70
End With
pnlQuoteProducts.Controls.Add(gbQuoteProduct(n))
cmboBoxQuoteProduct(n) = New ComboBox
With cmboBoxQuoteProduct(n)
.Items.Add("A")
.Items.Add("B")
.Items.Add("C")
.Items.Add("D")
.Text = ""
.Location = New Point(60, 15)
End With
gbQuoteProduct(n).Controls.Add(cmboBoxQuoteProduct(n))
This works fine but I want to add another combobox array to the groupbox array when something is selected from the existing combobox array.
When I try the following:
Private Sub cmboBoxQuoteProduct_SelectedIndexChanged(ByVal sender A
_ Object, ByVal e As System.EventArgs) Handles
_cmboBoxQuoteProduct().SelectedIndexChanged
End Sub
I get the error: "Expected "."" where I have the "()" after cmboBoxQuoteProduct
Any help is much appreciated.
Thanks in advance