Padding/ Size / Margin, when using ToolstripControlHost for a popup control - vb.net

I'm using VB2008 Express. And I've been working on a "popup" to select a date range. The DateTimePicker isn't ideal because the purpose is to pick a date range, which will always be one full week, from Sunday through Saturday. The control works just fine and I'm pretty proud of it. My problem has to do with the border added when using ToolstripControlHost for this. I've included a screenshot and my code.
In the code below, assume there exists a button named "btnTimePeriod", below which I desire to show a panel, which contains a few custom items, and the panel's name is "pnlDateRangePicker".
IT WORKS... but it doesn't look right. The panel itself is 147 x 326 pixels, but notice in the attached graphic that it's adding a border around the panel which I don't want. There's a border on the top, bottom, and left... but for some reason the border on the right one is especially large. Although my code doesn't expressly set it, AutoSize = true so I would have expected it to shrink around the panel.
As required, my code already does set ShowCheckMargin and ShowImageMargin false. I haven't included the code for the DrawDateCalander Sub because it's not relevant. I believe even a blank panel would yield the same result. I have no idea where this margin is coming from. Any guidance?
Private Sub btnTimePeriod_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTimePeriod.Click
Call DrawDateCalendar(DatePart(DateInterval.Month, FirstDisplayedSunday), DatePart(DateInterval.Year, FirstDisplayedSunday))
Call ShowControlBelow(btnTimePeriod, pnlDateRangePicker)
End Sub
Sub ShowControlBelow(ByVal Showbutton As Control, ByVal ShownControl As Control)
Dim PopupContainer As New ToolStripControlHost(ShownControl)
PopupContainer.Margin = New Padding(0)
Dim mnuDropDown As New ContextMenuStrip
mnuDropDown.Padding = New Padding(0)
mnuDropDown.ShowCheckMargin = False
mnuDropDown.ShowImageMargin = False
mnuDropDown.Items.Add(PopupContainer)
ShowMenuBelow(Showbutton, mnuDropDown)
End Sub
Sub ShowMenuBelow(ByVal Showbutton As Control, ByVal WhichMenu As ContextMenuStrip, Optional ByVal AlignRight As Boolean = False)
Dim x As Integer = 0
Dim y As Integer = 0
Dim itscontainer As Control = Showbutton.Parent
x = Showbutton.Location.X
y = Showbutton.Location.Y
If Not itscontainer Is Nothing Then
Do Until TypeOf itscontainer Is Form
x = x + itscontainer.Location.X
y = y + itscontainer.Location.Y
itscontainer = itscontainer.Parent
If itscontainer Is Nothing Then Exit Do
Loop
End If
y = y + Showbutton.Height
If AlignRight = True Then
x = x - WhichMenu.Width + Showbutton.Width
End If
Dim xy As New Point(x, y)
WhichMenu.Show(Showbutton.FindForm, xy)
End Sub

I've never used a ContextMenuStrip for that, and maybe that's the problem.
You can try using a ToolStripDropDown instead:
Private Sub ShowControl(ByVal fromControl As Control, ByVal whichControl As Control)
'\\ whichControl needs MinimumSize set:
whichControl.MinimumSize = whichControl.Size
Dim toolDrop As New ToolStripDropDown()
Dim toolHost As New ToolStripControlHost(whichControl)
toolHost.Margin = New Padding(0)
toolDrop.Padding = New Padding(0)
toolDrop.Items.Add(toolHost)
toolDrop.Show(Me, New Point(fromControl.Left, fromControl.Bottom))
End Sub
Private Sub btnTimePeriod_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnTimePeriod.Click
Call DrawDateCalendar(DatePart(DateInterval.Month, FirstDisplayedSunday), DatePart(DateInterval.Year, FirstDisplayedSunday))
'\\Call ShowControlBelow(btnTimePeriod, pnlDateRangePicker)
Call ShowControl(btnTimePeriod, pnlDateRangePicker)
End Sub

Related

Is it possible to group multiple PictureBoxes?

I can drag a PictureBox onto a Form Control, a Tab Control or a Panel Control, etc. And I can import an image into a PictureBox. However, I don't know how to group multiple PictureBoxes together in Visual Studio 2017. Looks like there is no such a function. I need this function because I want to generate a big picture based on the user's input. That big picture consists of multiple small pictures, the visibility of which is controlled by the user through multiple checkboxes.
In Excel, I could put multiple pictures in it, group them together, use the VBA to control the visibility of each picture, and finally copy that picture group into a Word file. I would do this in a VSTO Word Document project in Visual Studio 2017 using vb.net.
I added some pictures for demonstrate the expected function.
Picture 1 shows the small pictures to be used in a big picture. (Please ignore the .vslx file)
Picture 2 shows a possible result based on user's input.
You can make your own custom control. here is an example/suggestion how to do it with a User control that can be reused across your application. the user control is holding panels in a matrix, you can set a drag&drop Event to each Panel control and the user will be able to drop a picture box on each panel:
USER CONTROL:
Public Class UserControl1
Public NumberOfPanelsInRow As Integer
Sub New(ByVal height As Integer, width As Integer, Optional ByVal numberofPanelsInRow As Integer = 3)
' This call is required by the designer.'
InitializeComponent()
' Add any initialization after the InitializeComponent() call.'
Me.Height = height
Me.Width = width
Me.NumberOfPanelsInRow = numberofPanelsInRow
End Sub
Private Sub UserControl1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
' grouped panels to hold picturebox you can drag & drop to them...'
Dim panelHeight As Integer = Me.Height / NumberOfPanelsInRow
Dim panelWidth As Integer = Me.Width / NumberOfPanelsInRow
Dim colors() As Color = {Color.Pink, Color.Black, Color.Red, Color.Cyan, Color.Green, Color.Orange,
Color.Red, Color.Pink, Color.Black, Color.Red, Color.Cyan, Color.Green, Color.Orange, Color.Red}
Dim total As Integer = NumberOfPanelsInRow * NumberOfPanelsInRow
Dim currentYlocation As Integer = 0
Dim currentXlocation As Integer = 0
Dim location As Point = New Point(0, currentYlocation)
Dim rowcounter As Integer = 0
Dim itemcounter As Integer = 0
For i = 1 To total
If rowcounter >= NumberOfPanelsInRow Then
rowcounter = 0
currentYlocation += panelHeight
currentXlocation = 0
End If
' to each one of this panel you can drag a picture box'
Dim p As New Panel
p.Size = New Size(panelWidth, panelHeight)
p.Location = New Point(currentXlocation, currentYlocation)
p.BackColor = colors(itemcounter)
Me.Controls.Add(p)
rowcounter += 1
itemcounter += 1
currentXlocation += panelWidth
Next
End Sub
End Class
CALLING THE USER CONTROL FROM FORM1:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim uc = New UserControl1(300, 300)
Me.Controls.Add(uc)
End Sub
End Class
GUI OUTPUT:

Making labels in charts selectable/editable in VB

Just like in excel for a graph you can double click on a title, series name, or axis label and then you are able to type in that space. What do I need to do so I can do that for my charts? Clueless on where to start. Seems I may have to create a custom label?
Use the HitTest method of the chart.
Imports System.Windows.Forms.DataVisualization.Charting
Public Class Form1
Private Sub Chart1_MouseDoubleClick(sender As Object, e As MouseEventArgs) Handles Chart1.MouseDoubleClick
Dim h As HitTestResult = Chart1.HitTest(e.X, e.Y) 'Perform the HitTest with the mouse position that was clicked
If h.ChartElementType = ChartElementType.AxisTitle OrElse _
h.ChartElementType = ChartElementType.Axis Then 'Check the type of the element of the chart that was clicked
Dim s As String = InputBox("Please enter a new title!", "", h.Axis.Title) 'Prompt for a new title
If s <> "" Then h.Axis.Title = s 'Assign the new title
End If
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = 1 To 20 'Put some data in the chart to make the axes visible
Chart1.Series(0).Points.AddXY(i, i ^ 2)
Next
End Sub
End Class
You basically use the mouse location for the HitTest method. The ChartElementType defines what element was clicked at the position. If it's the title of the axis or the axis itself it will prompt you with an InputBox for a new title and assigns this title.
The InputBox is pretty old and shouldn't really be used but I was lazy and it works :-)
Apparently, what I'm referring to lives in DataVisualization.Charting.TextAnnotation. Along with that one, are many more type of annotations.
A TextAnnotation allows: AnchorMoving, Moving, PathEditing, Resizing, Selecting, and TextEditing. All of which I'm looking for.
Simple setup:
Dim anno As New DataVisualization.Charting.TextAnnotation
anno.AllowTextEditing = true
anno.AllowSelecting = true
anno.AllowMoving = true
anno.AllowResizing = true
anno.x = 50
anno.y = 50
anno.text = "Your Text"
chart.annotations.add(xAxisAnno)

detect when left mouse button is down while hovering over a button in Visual Basic.net

So I'm attempting to create a schedule grid in VB.net (exactly like the scheduler in UTorrent, if anyone is familiar) in a 24x7 layout. I want to be able to click down and drag over a series of squares to change the values of them.
I've been able to find this sample code that mostly works.
Private Sub DataGridView3_MouseHover(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DataGridView3.CellMouseMove
Dim grvScreenLocation As Point = DataGridView3.PointToScreen(DataGridView3.Location)
Dim tempX As Integer = DataGridView.MousePosition.X - grvScreenLocation.X + DataGridView3.Left
Dim tempY As Integer = DataGridView.MousePosition.Y - grvScreenLocation.Y + DataGridView3.Top
Dim hit As DataGridView.HitTestInfo = DataGridView3.HitTest(tempX, tempY)
cellX = hit.RowIndex
cellY = hit.ColumnIndex
TextBox3.Text = cellX
TextBox14.Text = cellY
End Sub
As written, this produces the desired results, however I need to have it only return cellx and celly to the text boxes only when the mouse button is down.
This can be accomplished by handling mouse left button down, mouse move and mouse left button up.
When you receive a mouse left button down event on the grid, record the mouse position and set a flag. In the mouse move handler if the flag is set, highlight all cells between the initial position and the current mouse position. On receiving a mouse left button up (on the grid when the grid is set) commit the cell selection (and clear the flag).
I've used this technique successfully for a fractal zoom.
Here's a rough outline of what you need to do:
Dim isSelecting As Boolean
Dim selectionStart As Point
Protected Overrides Sub OnMouseLeftButtonDown(e As MouseButtonEventArgs)
MyBase.OnMouseLeftButtonDown(e)
Dim position = e.GetPosition(Me)
Dim hit = VisualTreeHelper.HitTest(MyGrid, position)
If hit IsNot Nothing Then
isSelecting = True
selectionStart = position
End If
End Sub
Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
MyBase.OnMouseMove(e)
If isSelecting Then
Dim position = e.GetPosition(Me)
' Update selection
End If
End Sub
Protected Overrides Sub OnMouseLeftButtonUp(e As MouseButtonEventArgs)
MyBase.OnMouseLeftButtonUp(e)
If isSelecting Then
Dim position = e.GetPosition(Me)
' Commit selection
End If
End Sub
This gave me what I wanted.
Private cellX As Integer = 0
Private cellY As Integer = 0
Private Sub DataGridView3_MouseHover(ByVal sender As System.Object, ByVal e As MouseEventArgs) Handles DataGridView3.CellMouseMove
Dim grvScreenLocation As Point = DataGridView3.PointToScreen(DataGridView3.Location)
Dim tempX As Integer = DataGridView.MousePosition.X - grvScreenLocation.X + DataGridView3.Left
Dim tempY As Integer = DataGridView.MousePosition.Y - grvScreenLocation.Y + DataGridView3.Top
Dim hit As DataGridView.HitTestInfo = DataGridView3.HitTest(tempX, tempY)
cellX = hit.RowIndex
cellY = hit.ColumnIndex
If e.Button = Windows.Forms.MouseButtons.Left Then
TextBoxX.Text = cellX
TextBoxY.Text = cellY
DataGridView3.Rows(cellX).Cells(cellY).Style.BackColor = Color.Red
End If
End Sub

When creating a label a label inside a panel, the text is cut off VisualBasic

I wanted to be able to dynamically create a panel with a label on it, but the label isn't acting as I would expect it too, its cutting most of it off.
When I create a panel then create a label inside the panel, the text isn't displayed correctly. Anyone know how to fix it?
What is was supposed to do was to create a panel with text on it with the newpanel() sub
Dim timetable(5, 5) As String
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.Width = (74 * 5) - 3
Me.Height = My.Computer.Screen.Bounds.Size.Height
Me.Top = My.Computer.Screen.Bounds.Top
Me.Left = My.Computer.Screen.Bounds.Right - Me.Width
GetTimetable()
End Sub
Private Sub newpanel(colour As Color, textT As String)
Dim Npan As New Panel
Npan.Top = 0
Npan.Left = 0
Npan.Width = Me.Width
Npan.Height = 64
Npan.BackColor = colour
Dim NpanT As New Label
NpanT.Parent = Npan
NpanT.Text = textT
Npan.Controls.Add(NpanT)
Me.Controls.Add(Npan)
End Sub
Private Sub GetTimetable()
'Dim path As String = My.Computer.FileSystem.SpecialDirectories.Desktop + "\Timetable"
newpanel(Color.Aqua, "this is a test! test testtesttest test test test")
End Sub
Looking at the MSDN page for the Label.AutoSize Property, it states as was mentioned above that the Labels AutoSize Property defaults to true in the designer, but it is false when created in code.
From above link:
When added to a form using the designer, the default value is true. When instantiated from code, the default value is false.
So you need to change your newpanel method to this:
Private Sub newpanel(colour As Color, textT As String)
Dim Npan As New Panel
Npan.Top = 0
Npan.Left = 0
Npan.Width = Me.Width
Npan.Height = 64
Npan.BackColor = colour
Dim NpanT As New Label
NpanT.Parent = Npan
NpanT.Text = textT
NpanT.AutoSize = True 'Enables Auto sizing
Npan.Controls.Add(NpanT)
Me.Controls.Add(Npan)
End Sub

Setting Combobox Height OwnerDrawVariable ( Unexpected display result )

First of all, i did make a combox box with ownerdrawvariable mod because i wanted to handle a tooltips with the mouse hover. To do this i handled two methods DrawItem and MeasureItem :
Private Sub DrawItem(ByVal sender As Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles cboPneuGlobal.DrawItem
If e.Index = -1 Then
Exit Sub
End If
e.DrawBackground()
Dim p As Point = New Point(CInt(cboPneuGlobal.Location.X * Ratio), CInt(cboPneuGlobal.Location.Y * Ratio))
Dim brColor As Brush = Brushes.Black
If e.State = DrawItemState.Selected Then
ToolTipFormBase.Show(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, Me, p)
brColor = Brushes.White
End If
e.Graphics.DrawString(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, e.Font, brColor, New Point(e.Bounds.X, e.Bounds.Y))
End Sub
Here the second :
Private Sub measureItem(ByVal sender As Object, ByVal e As System.Windows.Forms.MeasureItemEventArgs) Handles cboPneuGlobal.MeasureItem
' fetch the current item we’re painting as specified by the index
Dim comboBoxItem As Object = cboPneuGlobal.Items(e.Index)
' measure the text of the item (in Whidbey consider using TextRenderer.MeasureText instead)
Dim textSize As Size = e.Graphics.MeasureString(CType(cboPneuGlobal.Items(e.Index), clsPneuEtTypeMarque).ToDisplay, cboPneuGlobal.Font).ToSize()
e.ItemHeight = textSize.Height
e.ItemWidth = textSize.Width
End Sub
I got a small display problem which the combo box height doesn't follow the font of my item and stay small. That make my text truncate. See the image :
What i'm doing wrong ??
It's work great with a non ownerdraw combobox