Unable to resize form on a TabPage - vb.net

I have a Project which has a main Form which uses part of the screen as Tab Pages.
Then I load other Forms into the Tab Pages.
The problem is that the users are using larger screens that the one that I am developing on and I need to increase the size of the loaded Forms to make it easier for them to read.
I can make the Controls larger on the Forms but the Form stays the same size, so Controls to the right hand side and down at the bottom are cut off. The enlarged Form is displayed at the top left of the Tab Page, as required.
If I then use the Size command to make the Form larger, it does make it larger but moves the Form into roughly the centre of the Tab Page, once again cutting off Controls to the right hand side and down at the bottom.
Does anyone have any idea how I can keep the Form at the top left of the Tab Page?
Using Location = new Point (0,0) has no effect.
Dim frm As New frmCreateQuotation
Display_Form(frm, "Create Quotations")
Private Sub Display_Form(fourm As Form, tekxt As String)
Dim ThisControl As Control, HorizRatio As Single, VertRatio As Single, Iter As Integer 'V2.0.0.01
Dim tabby As New TabPage
tabby.Text = tekxt
TabControl1.Controls.Add(tabby)
TabControl1.SelectedTab = tabby
tabby.AutoScroll = True
tabby.AutoScrollMinSize = New System.Drawing.Size(1000, tabby.Height) 'V1.0.3.03
fourm.TopLevel = False
fourm.Parent = tabby
fourm.FormBorderStyle = Windows.Forms.FormBorderStyle.None
fourm.Anchor = AnchorStyles.Top
HorizRatio = tabby.Width / xaxis 'fourm.Width 'V2.0.0.01
VertRatio = tabby.Height / yaxis 'fourm.Height 'V2.0.0.01
ReDim Preserve ControlInfos(0 To 0)
For Each ThisControl In fourm.Controls
ReDim Preserve ControlInfos(0 To UBound(ControlInfos) + 1)
On Error Resume Next ' hack to bypass controls with no size or position properties
With ControlInfos(UBound(ControlInfos))
.Left = ThisControl.Left
.Top = ThisControl.Top
.Width = ThisControl.Width
.Height = ThisControl.Height
End With
On Error GoTo 0
Next
Iter = 0 'V2.0.0.01 + For Next loop
For Each ThisControl In fourm.Controls
Iter = Iter + 1
On Error Resume Next ' hack to bypass controls
With ThisControl
.Left = ControlInfos(Iter).Left * HorizRatio
.Top = ControlInfos(Iter).Top * VertRatio
.Width = ControlInfos(Iter).Width * HorizRatio
.Height = ControlInfos(Iter).Height * VertRatio
End With
On Error GoTo 0
Next
'fourm.Size = New Size(tabby.Width, tabby.Height) 'V2.0.0.01
fourm.Show()
fourm.Focus()
End Sub

Related

Rotate / Scroll picture boxes

I have a row of PictureBoxes created at run time which occupy more of the form's visible width. I want them to scroll at certain intervals so the user sees all of them if he waits.
I believe I must code to a Timer.
But what is the code for that? (The Form is set scrollable, but I do not want the user to interact with it. Just click the PB he likes)
Code for PB creation
'' In Form_Load:
Dim allSeries As IEnumerable(Of String) =
Directory.EnumerateFiles(root, "*.jpg", SearchOption.AllDirectories)
For i = 0 To allSeries.Count - 1
pb(i) = New PictureBox With {
.Name = "pb" + i.ToString,
.BackColor = Color.Transparent,
.Size = New Point(250, 300),
.BorderStyle = BorderStyle.None,
.SizeMode = PictureBoxSizeMode.Zoom,
.Top = 10,
.Left = pbLeft,
.Cursor = Cursors.Hand,
.Image = Image.FromFile(allSeries(i).ToString), 'Get the Image from the Directory
.Tag = Path.GetDirectoryName(allSeries(i)) 'Store Direcyory path
}
Controls.Add(pb(i))
pbLeft = pbLeft + 300 'position next to previous
'Next
Next
Thanks!

adjust form controls according to the size of the window

I am trying to resize/ re-position controls based on the size of the form. This is the class i am using :
Public Class Resizer
'----------------------------------------------------------
' ControlInfo
' Structure of original state of all processed controls
'----------------------------------------------------------
Private Structure ControlInfo
Public name As String
Public parentName As String
Public leftOffsetPercent As Double
Public topOffsetPercent As Double
Public heightPercent As Double
Public originalHeight As Integer
Public originalWidth As Integer
Public widthPercent As Double
Public originalFontSize As Single
End Structure
'-------------------------------------------------------------------------
' ctrlDict
' Dictionary of (control name, control info) for all processed controls
'-------------------------------------------------------------------------
Private ctrlDict As Dictionary(Of String, ControlInfo) = New Dictionary(Of String, ControlInfo)
'----------------------------------------------------------------------------------------
' FindAllControls
' Recursive function to process all controls contained in the initially passed
' control container and store it in the Control dictionary
'----------------------------------------------------------------------------------------
Public Sub FindAllControls(thisCtrl As Control)
'-- If the current control has a parent, store all original relative position
'-- and size information in the dictionary.
'-- Recursively call FindAllControls for each control contained in the
'-- current Control
For Each ctl As Control In thisCtrl.Controls
Try
If Not IsNothing(ctl.Parent) Then
Dim parentHeight = ctl.Parent.Height
Dim parentWidth = ctl.Parent.Width
Dim c As New ControlInfo
c.name = ctl.Name
c.parentName = ctl.Parent.Name
c.topOffsetPercent = Convert.ToDouble(ctl.Top) / Convert.ToDouble(parentHeight)
c.leftOffsetPercent = Convert.ToDouble(ctl.Left) / Convert.ToDouble(parentWidth)
c.heightPercent = Convert.ToDouble(ctl.Height) / Convert.ToDouble(parentHeight)
c.widthPercent = Convert.ToDouble(ctl.Width) / Convert.ToDouble(parentWidth)
c.originalFontSize = ctl.Font.Size
c.originalHeight = ctl.Height
c.originalWidth = ctl.Width
ctrlDict.Add(c.name, c)
End If
Catch ex As Exception
Debug.Print(ex.Message)
End Try
If ctl.Controls.Count > 0 Then
FindAllControls(ctl)
End If
Next '-- For Each
End Sub
'----------------------------------------------------------------------------------------
' ResizeAllControls
' Recursive function to resize and reposition all controls contained in the Control
' dictionary
'----------------------------------------------------------------------------------------
Public Sub ResizeAllControls(thisCtrl As Control, Optional wform As Form = Nothing)
Dim fontRatioW As Single
Dim fontRatioH As Single
Dim fontRatio As Single
Dim f As Font
If IsNothing(wform) = False Then wform.Opacity = 0
'-- Resize and reposition all controls in the passed control
For Each ctl As Control In thisCtrl.Controls
Try
If Not IsNothing(ctl.Parent) Then
Dim parentHeight = ctl.Parent.Height
Dim parentWidth = ctl.Parent.Width
Dim c As New ControlInfo
Dim ret As Boolean = False
Try
'-- Get the current control's info from the control info dictionary
ret = ctrlDict.TryGetValue(ctl.Name, c)
'-- If found, adjust the current control based on control relative
'-- size and position information stored in the dictionary
If (ret) Then
'-- Size
ctl.Width = Int(parentWidth * c.widthPercent)
ctl.Height = Int(parentHeight * c.heightPercent)
'-- Position
ctl.Top = Int(parentHeight * c.topOffsetPercent)
ctl.Left = Int(parentWidth * c.leftOffsetPercent)
'-- Font
f = ctl.Font
fontRatioW = ctl.Width / c.originalWidth
fontRatioH = ctl.Height / c.originalHeight
fontRatio = (fontRatioW +
fontRatioH) / 2 '-- average change in control Height and Width
ctl.Font = New Font(f.FontFamily,
c.originalFontSize * fontRatio, f.Style)
End If
Catch
End Try
End If
Catch ex As Exception
End Try
'-- Recursive call for controls contained in the current control
If ctl.Controls.Count > 0 Then
ResizeAllControls(ctl)
End If
Next '-- For Each
If IsNothing(wform) = False Then wform.Opacity = 1
End Sub
End Class
The problem with this code is that
1) It flickers a lot while resizing the controls or moving them around.
2) Some labels and buttons are moved around to random positions on the form and,
3) the size of the background image is not responsive to the size of the form (Not much knowledge on how to execute this.)
Any sort of help is appreciated.
Instead of manually doing this, look into properties on the form such as "Dock", "Anchor".
Examples:
Setting dock to top (or bottom) will allow a module to always cover
the entire top (or bottom) of the form, keeping the height the same.
Setting dock to left (or right) will allow a module to always cover the entire left (or right) of the form, keeping the height the
same.
Setting the anchor property to all of Top, Left, Right, Down will allow the control to expand as the form grows, but keep it's x/y top-left position.
Setting the anchor property to Top, Left, Right will allow the control to expand to the right as the form grows, but keep it's x/y top-left position
Setting the anchor property to Bottom, Right will allow the control to stay in a fixed position relative to the bottom corner of the form.

Microsoft ActiveX Controls

Is there a way to change the index value of a ActiveX Button that inserted onto a spreadsheet. I currently have four buttons and two are hidden and two are visible. I would like to re-order the them to not have a large gap between objects. I have some VBA code that runs when the document is opened to ensure that they are the right size and location. Because it loops through the OLEObjects Collection; it will not matter what order they are in on the spreadsheet they will always appear with a gap because of the index value in the OLE Object collection. Below is the code:
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.EvaluateToError = False
ActiveWorkbook.Worksheets("SITE").Activate
Dim button As OLEObject
Dim name As String, top As Integer
top = 15
For Each button In ActiveWorkbook.Worksheets("SITE").OLEObjects
Debug.Print button.name & " " & button.ZOrder
name = button.name
If button.OLEType = xlButtonOnly And InStr(name, "btn") = 1 Then
With button
.Height = 21.75
.Width = 174.75
.Left = 1114.5
.top = top
End With
top = top + 30
End If
Next button
End Sub
If you give them proper names with an integer code in it reflecting their intended position (e.g.: "btn...01", "btn...02",...) then you could try this code (sorry for not being able to format it as code by now):
Private Sub Workbook_Open()
Application.ErrorCheckingOptions.EvaluateToError = False
ActiveWorkbook.Worksheets("SITE").Activate
Dim button As OLEObject
Dim name As String
Dim btnRnk As Long
For Each button In ActiveWorkbook.Worksheets("SITE").OLEObjects
name = button.name
If button.OLEType = xlButtonOnly And InStr(name, "btn") = 1 Then
btnRnk = CLng(Right(name,2))
With button
.Height = 21.75
.Width = 174.75
.Left = 1114.5
.top = 15 + (btnRank - 1) * 30
End With
End If
Next button
End Sub

Fitting runtime buttons inside a form

I have a number of buttons between 5-20 and it's variable each time the form loads based on the user settings. I am trying to fit all these buttons on my form no matter what the size of the form is. The buttons are generated during runtime. I would like the first button to be 20 points from the top bar (at any size) and the rest of the buttons simply to fit in the form. This is what I have now but I have to maximize the form to view them all and also while I'm expanding the form the space between the buttons decreases and they overlap with each other whereas they should keep a relative distance. Any ideas?
Dim iButtonWidth, iButtonHeight, iVerticalSpace As Integer
If UserButtons.Count > 0 Then
iButtonHeight = Me.Size.Height - (Me.Size.Height * 0.85)
iButtonWidth = Me.Size.Width - (Me.Size.Width * 0.5)
iVerticalSpace = iButtonHeight / 3
For Each btn In UserButtons
btn.Size = New System.Drawing.Size(iButtonWidth, iButtonHeight)
btn.Location = New Point(20, 20 + btn.TabIndex * iVerticalSpace * 3)
Next
End If
Here's a quick example using the TableLayoutPanel to play with:
Public Class Form1
Private UserButtons As New List(Of Button)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Static R As New Random
Dim NumButtons As Integer = R.Next(5, 21) ' "a number of buttons between 5-20 and it's variable each time"
UserButtons.Clear()
For i As Integer = 1 To NumButtons
Dim btn As New Button()
btn.Text = i.ToString("00")
btn.Dock = DockStyle.Fill ' Optional: See how you like it with this on vs. off
UserButtons.Add(btn)
Next
DisplayButtons()
End Sub
Private Sub DisplayButtons()
TableLayoutPanel1.SuspendLayout()
TableLayoutPanel1.Controls.Clear()
TableLayoutPanel1.ColumnStyles.Clear()
TableLayoutPanel1.ColumnCount = 5 ' Fixed Number of Columns
For i As Integer = 1 To TableLayoutPanel1.ColumnCount
TableLayoutPanel1.ColumnStyles.Add(New ColumnStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
' Variable Number of Rows:
Dim RowsRequired As Integer = ((UserButtons.Count - 1) \ TableLayoutPanel1.ColumnCount) + 1 ' Integer Division
TableLayoutPanel1.RowStyles.Clear()
TableLayoutPanel1.RowCount = RowsRequired
For i As Integer = 1 To TableLayoutPanel1.RowCount
TableLayoutPanel1.RowStyles.Add(New RowStyle(SizeType.Percent, 911)) ' the size doesn't matter here, as long as they are all the same
Next
TableLayoutPanel1.Controls.AddRange(UserButtons.ToArray)
TableLayoutPanel1.ResumeLayout()
End Sub
End Class
First of all what kind of container are the buttons in? You should be able to set the container's AutoScroll property to true - then when controls within it spill out of the visible bounds you will get a scroll bar.
Then also what you could do is draw each button in more of a table with a certain number next to each other before dropping down to the next line (instead of just 1 button on each line). If that is an option that works for you then you could get more buttons within the visible space.
I happen to have an example to do the same thing with picture boxes (and text boxes under each picture box). Hope this helps:
Dim point As New Point(0, 0)
'create 11 picture and text boxes-you can make this number the number your user selects.
Dim box(11) As PictureBox
Dim text(11) As TextBox
Dim i As UInt16
For i = 0 To 11 'or whatever your number is
box(i) = New PictureBox
box(i).Width = 250 'your button width
box(i).Height = 170 'your button height
box(i).BorderStyle = BorderStyle.FixedSingle
box(i).Location = point
layoutsPanel.Controls.Add(box(i)) 'my container is a panel
text(i) = New TextBox
text(i).Height = 50
text(i).Width = 250
point.Y += box(i).Height
text(i).Location = (point)
layoutsPanel.Controls.Add(text(i))
point.Y -= box(i).Height 'reset Y for next picture box
'Put 4 picture boxes in a row, then move down to next row
If i Mod 4 = 3 Then
point.X = 0
point.Y += box(i).Height + text(i).Height + 4
Else
point.X += box(i).Width + 4
End If
Next

Why can't I get textbox.text values from code generated textboxes

I have a project where I have a form "userform1" which only has a "GO" button and an "EXIT" button on it to begin with. I solicit user input via an inputbox for a number. I use code to then populate the form with that number of labels and textboxes and display the form to allow editting of the created textboxes. Everything works fine up to this point.
I then want the "GO" button to populate an array with the textbox.text values for use elsewhere. This is where I am having a problem.
I tried retrieving the text like I normally do (something like; Xstring = UserForm1.Box1.Text), that didn't work. So then I cycled thru the form controls; UserForm1.Controls.index(), looking for my Textbox .names to confirm they existed. I found them, so I singled one out, index(3), .name = "Box1". See below:
Dim tText As String
tText = UserForm1.Box1.Text
MsgBox tText
returns an ERROR, 'method or data member not found'
But if I change it to this:
Dim x As Object
Dim tText As String
Set x = UserForm1.Controls.Item(3)
tText = x.Text
MsgBox tText
The msgbox returns the .text value
So, QUESTION is, why can't I simply address it normally? I don't want to have to go through all the extra steps to figure out index numbers vs names to populate my array.
for reference, below is partial code of my sub for creating labels/textboxes:
For i = Data(x, 1) To z
Lab = "forms.label.1"
Box = "forms.textbox.1"
Set newlabel = UserForm1.Controls.Add(Lab)
Set newtextbox = UserForm1.Controls.Add(Box)
lbl1 = ("Label" + CStr(i))
With newlabel
.Name = lbl1
.Caption = "No. " + CStr(i)
.Left = Data(x, 3)
.top = top
.Height = 20
.Width = 30
End With
lbl2 = ("Box" + CStr(i))
With newtextbox
.Name = lbl2
.Text = CStr(i)
.Left = (Data(x, 3) + 35)
.top = top
.Height = 20
.Width = 36
End With
top = top + 25
Next i
UserForm1 has no method or data member of that name before run-time. Therefore the VBA interpreter cannot interpret what is meant.
You can nevertheless access the item via through its collection of child controls indexed on either index number or control name, like:
Dim myTxtBox As MSForms.TextBox
Me.Controls.Add bstrProgId:="Forms.Textbox.1", Name:="My Runtime Textbox"
Set myTxtBox = Me.Controls("My Runtime Textbox")
myTxtBox.Text = "Hello"
After reading the comments from Cor_Blimey, this is what I now have working in the code for retrieving my program generated textbox.text data:
Dim i As Integer, num As Integer, ctr As Integer
Dim oCntl As Object
Dim tText() as String
num = UserForm1.Controls.Count
ReDim tText(num)
For Each Control In UserForm1.Controls 'loops thru each control
If TypeOf Control Is TextBox Then
ctr = ctr + 1
tText(ctr) = Control.Text
End If
Next Control
ReDim Preserve tText(ctr)
The .text is being written to the array sequentially (by index#, the order textboxes were created)
In the future, I might consider 2 values in the array, 1 for .name and 1 for .text, just to be sure.