vb TableLayoutPanel - Getting button next to the button clicked - vb.net

I created a simple TableLayoutPanel (6 by 6) with buttons in each cell. I have a click handler that executes whenever any of the button is pressed (in my case, change color of the button from red to green)
see eg.
But now I need to change the color of the button next to the button i clicked (eg. When I click on button 2 3, the button 3 3 will also change color).
Any ideas?

You can cast the Sender argument on the click handler to a Control and then use that to determine the clicked control's position. Then you can use that position to compute you adject controls and retrieve a reference to them.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ctrl As Control = TryCast(sender, Control)
If ctrl IsNot Nothing Then
Dim pos As TableLayoutPanelCellPosition = TableLayoutPanel1.GetCellPosition(ctrl)
If pos.Row < (TableLayoutPanel1.RowCount - 1) Then
Dim nextCtrl As Control = TableLayoutPanel1.GetControlFromPosition(pos.Column, pos.Row + 1)
If nextCtrl IsNot Nothing Then
' do something with nextCtrl
nextCtrl.BackColor = Color.Red
End If
End If
End If
End Sub

Related

How to remove the white lines surrounding a button appearing when I click it

It works fine until I click it and pop up a file dialog box,and then white lines appears surrounding it.
I don't know how to remove these ugly lines.
The only code is openFileDialog1.ShowDialog().
It's a Button whose FlatStyle is flat and whose BackgroundImage is a PNG image.
After that the white lines appears, and if I click the Form it will disappear.
A simple workaround is to set the Button FlatAppearance.BorderColor to its Parent.BackColor. It will overwrite the focus rectangle. The MouseUp event can be used to set the value, it will be raised before a new Window is opened (the Control.Leave event will never be raised):
Private Sub SomeButton_MouseUp(sender As Object, e As MouseEventArgs) Handles SomeButton.MouseUp
Dim ctl As Button = DirectCast(sender, Button)
ctl.FlatAppearance.BorderColor = ctl.Parent.BackColor
End Sub
Using the Control.Paint event, we can also use the Control.BackColor property to paint the border, both with the ControlPaint class DrawBorder method (simpler than using the ButtonRenderer class):
Private Sub SomeButton_Paint(sender As Object, e As PaintEventArgs) Handles SomeButton.Paint
Dim ctl As Button = DirectCast(sender, Button)
ControlPaint.DrawBorder(e.Graphics, ctl.ClientRectangle, ctl.BackColor, ButtonBorderStyle.Solid)
End Sub
and painting the Control's border ourselves:
(Note that the ClientRectangle size must be shrinked, by 1 pixel, both in the Width and Height dimensions. This is by design).
Private Sub SomeButton_Paint(sender As Object, e As PaintEventArgs) Handles SomeButton.Paint
Dim ctl As Control = DirectCast(sender, Control)
Dim r As Rectangle = ctl.ClientRectangle
Using pen As Pen = New Pen(ctl.BackColor, 1)
e.Graphics.DrawRectangle(pen, r.X, r.Y, r.Width - 1, r.Height - 1)
End Using
End Sub

How can I add Button controls inside a RichTextBox programmatically?

How to add (via code) one or more Buttons in a WinForm TextBox or RichTextBox? Specifically, I want to add buttons at the end of each text line, before the VbCrLf character.
It will be something like this:
Friend WithEvents Button1 As Button
Private Sub RichTextBox1_Click(sender As Object, e As EventArgs) Handles RichTextBox1.Click
Button1 = New Button ' Create new instance
Me.Button1.Size = New System.Drawing.Size(75, 23) ' give the button a size
Button1.Text = "My button" ' set the button text
Me.Button1.UseVisualStyleBackColor = True ' make it look windows like
Dim pos As Point = RichTextBox1.GetPositionFromCharIndex(RichTextBox1.SelectionStart) 'determine the button position
RichTextBox1.Controls.Add(Button1) ' get it inside the rich text box
Button1.Location = New Point(RichTextBox1.Right - Button1.Width, pos.Y + RichTextBox1.Top) ' set the button position
End Sub
Of course it does not need to be in the Click event, you perhaps may use the KeyPress event to determine if the user pressed enter and then insert it at that point. Also play with the position (POS variable) to change the button position.
Nandostyle

programmatically select and highlight a row of a ListView in VB.NET

I want to do something seemingly simple - programmatically select and highlight a row of a ListView in VB.NET.
VB.NET: How to dynamically select a list view item?
tells me what should to be all that is needed, but it isn't. The row is selected, but not highlighted.
http://vbcity.com/forums/t/28260.aspx
tells me about the "HideSelection" property and the .Focus() method (also referenced at Select programmatically a row of a Listview), which sounded hopeful, but the best I can get is the faint highlight mentioned, I want the full monty. I tried a Noddy example with just a ListView, in Details mode, FullRowSelection = true, HideSelection = False, one columnheader defined and then
ListView1.Items.Add("Red")
ListView1.Items.Add("Orange")
ListView1.Items.Add("Yellow")
ListView1.Items.Add("Green")
ListView1.Items(2).Selected = True
I get this
but I want this
I can simulate highlighting by adding these lines
ListView1.SelectedItems(0).BackColor = Color.CornflowerBlue
ListView1.SelectedItems(0).ForeColor = Color.White
but then how can I be sure to undo the artificial highlight if the row can be implicitly as well as explicitly deselected? Do I have to think of all the possible cases? That's too much work for what should be a simple operation. Plus, since I want to color-code my rows, there is an additional challenge that when I undo the highlight color, I have to figure out what color is appropriate at that point. Is there a better, simpler way?
You can access the Graphics object used to draw each item, and draw them yourself.
Make a new project with a Button and ListView. Paste the following code:
Form_Load to use multiple subitems
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.ListView1.OwnerDraw = True ' or else can't handle DrawItem event
ListView1.Columns.Add("ColumnHeader1")
ListView1.Columns.Add("ColumnHeader2")
ListView1.Columns.Add("ColumnHeader3")
Me.ListView1.Items.Add("Red")
Me.ListView1.Items.Add("Orange")
Me.ListView1.Items.Add("Yellow")
Me.ListView1.Items.Add("Green")
ListView1.Items(0).SubItems.Add("Strawberry")
ListView1.Items(0).SubItems.Add("Apple")
ListView1.Items(1).SubItems.Add("Pepper")
ListView1.Items(1).SubItems.Add("Apricot")
ListView1.Items(2).SubItems.Add("Plum")
ListView1.Items(2).SubItems.Add("Banana")
ListView1.Items(3).SubItems.Add("Apple")
ListView1.Items(3).SubItems.Add("Lime")
End Sub
Three handlers for the ListView's drawing related events. Code copied from this answer
Private Sub listView1_DrawColumnHeader(sender As Object, e As DrawListViewColumnHeaderEventArgs) Handles ListView1.DrawColumnHeader
e.DrawDefault = True
End Sub
Private Sub listView1_DrawSubItem(sender As Object, e As DrawListViewSubItemEventArgs) Handles ListView1.DrawSubItem
Const TEXT_OFFSET As Integer = 1
' I don't know why the text is located at 1px to the right. Maybe it's only for me.
Dim listView As ListView = DirectCast(sender, ListView)
' Check if e.Item is selected and the ListView has a focus.
If Not listView.Focused AndAlso e.Item.Selected Then
Dim rowBounds As Rectangle = e.SubItem.Bounds
Dim labelBounds As Rectangle = e.Item.GetBounds(ItemBoundsPortion.Label)
Dim leftMargin As Integer = labelBounds.Left - TEXT_OFFSET
Dim bounds As New Rectangle(rowBounds.Left + leftMargin, rowBounds.Top, If(e.ColumnIndex = 0, labelBounds.Width, (rowBounds.Width - leftMargin - TEXT_OFFSET)), rowBounds.Height)
Dim align As TextFormatFlags
Select Case listView.Columns(e.ColumnIndex).TextAlign
Case HorizontalAlignment.Right
align = TextFormatFlags.Right
Exit Select
Case HorizontalAlignment.Center
align = TextFormatFlags.HorizontalCenter
Exit Select
Case Else
align = TextFormatFlags.Left
Exit Select
End Select
TextRenderer.DrawText(e.Graphics, e.SubItem.Text, listView.Font, bounds, SystemColors.HighlightText, align Or TextFormatFlags.SingleLine Or TextFormatFlags.GlyphOverhangPadding Or TextFormatFlags.VerticalCenter Or TextFormatFlags.WordEllipsis)
Else
e.DrawDefault = True
End If
End Sub
Private Sub listView1_DrawItem(sender As Object, e As DrawListViewItemEventArgs) Handles ListView1.DrawItem
Dim listView As ListView = DirectCast(sender, ListView)
' Check if e.Item is selected and the ListView has a focus.
If Not listView.Focused AndAlso e.Item.Selected Then
Dim rowBounds As Rectangle = e.Bounds
Dim leftMargin As Integer = e.Item.GetBounds(ItemBoundsPortion.Label).Left
Dim bounds As New Rectangle(leftMargin, rowBounds.Top, rowBounds.Width - leftMargin, rowBounds.Height)
e.Graphics.FillRectangle(SystemBrushes.Highlight, bounds)
Else
e.DrawDefault = True
End If
End Sub
Button click handler to simulate item(2) selected
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.ListView1.Items(2).Selected = True
End Sub
This will draw the background color regardless of focus. You have a lot of control over other colors and fonts going this route too.
Here, the button has been clicked, to select item 2, while the button still has focus, and item 2 is selected.
Easiest thing,
Just allocate the LST_ItemIndex = lstList.FocusedItem.Index everytime you select a different item
and then fire the below whenever you want the highlight
If lstList.Items.Count > 0 Then
lstList.Items(LST_ItemIndex).Selected = True
lstList.Items(LST_ItemIndex).EnsureVisible()
End If

Enable other event while dragging an object

I'm developing a console where I want to drag a button to a grid:
To drag the button, I use the following procedure:
Public drag As Boolean = False
Public ptX As Integer = 0
Public ptY As Integer = 0
Public btn As Button
Private Sub MoveButton_MouseDown(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseDown
drag = True
btn = CType(sender, Button)
ptX = e.X : ptY = e.Y
End Sub
Private Sub MoveButton_MouseMove(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseMove
If drag Then
btn.Location = New Point(btn.Location.X + e.X - ptX, btn.Location.Y + e.Y - ptY)
Me.Refresh()
End If
End Sub
Private Sub MoveButton_MouseUp(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseUp
drag = False
End Sub
So far, so good! This works fine for that matter.
However, I'm trying to highlight the cell while hoovering the button on it like this:
To do so, I tried to do the following:
Private Sub CellA1_MouseHover(sender As Object, e As EventArgs) Handles CellA1.MouseHover
If drag Then
CellA1.BackColor = Color.Red
End If
End Sub
Of course I can't do that, unless I, somehow, enable the CellA1.MouseHover event while dragging the MoveButton.
Can anyone help me with this?
If, however, you're having a struggling will to help me further, my last goal is to place the MoveButton on the red cell place:
But feel free to don't help me at all with this part of the procedure since I have no code to perform this yet.
Any help will be very appreciated. And, as always, thank you all in advance.
Since your mouse is not actually on the PictureBox when you drag the button it will never raise any mouse events. What you can do instead is to call the GetChildAtPoint() method of your form to get the control behind the button. Once you have that just verify that the name starts with "Cell" and change the back color.
To snap to the cell's location you'll need to indicate to MouseUp which cell we're currently at. Simply store the cell control in a variable and you can then just set yourButton.Location = currentCell.Location
Here are the changes I've made to your code, commented for clarity:
Public drag As Boolean = False
Public ptX As Integer = 0
Public ptY As Integer = 0
Public btn As Button
Public prevCtrl As Control = Nothing 'Store the previous Cell the button was dragged over.
' We need this to be able to reset the BackColor of the Cell,
' and also so that you can snap to its location once you drop the button.
Private Sub MoveButton_MouseDown(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseDown
'No changes made here.
drag = True
btn = CType(sender, Button)
ptX = e.X : ptY = e.Y
End Sub
Private Sub MoveButton_MouseMove(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseMove
If drag Then
btn.Location = New Point(btn.Location.X + e.X - ptX, btn.Location.Y + e.Y - ptY)
'Go 1 pixel up, or else GetChildAtPoint() will return the button instead of the control behind it.
Dim LookPoint As Point = Point.Subtract(btn.Location, New Size(0, 1))
'Get the control located below/behind the button.
Dim ControlBelow As Control = Me.GetChildAtPoint(LookPoint, GetChildAtPointSkip.Invisible Or GetChildAtPointSkip.Disabled) 'Ignore invisible or disabled controls.
'Check so that the previous cell is not also the current cell. If they're the same then we won't change anything.
If prevCtrl IsNot ControlBelow Then
'Ok, the current cell and the previous cell are not the same.
'Now check if there was any previous cell at all.
If prevCtrl IsNot Nothing Then
'There was a previous cell, but since the button
'is no longer hovering over it we reset its BackColor.
prevCtrl.BackColor = Color.White
prevCtrl = Nothing
End If
'Check that there infact is a control behind the button,
'and also check that its name starts with "Cell".
If ControlBelow IsNot Nothing AndAlso ControlBelow.Name.StartsWith("Cell", StringComparison.OrdinalIgnoreCase) Then
'The control behind the button is a valid Cell. Change its BackColor.
ControlBelow.BackColor = Color.Red
prevCtrl = ControlBelow 'The previous cell is now the current cell.
End If
End If
'Me.Refresh() - this is a very unnecessary call, it will just eat CPU. The form does not need to be redrawn at this point.
End If
End Sub
Private Sub MoveButton_MouseUp(sender As Object, e As MouseEventArgs) Handles MoveButton.MouseUp
'Check if we dragged the button. At this point prevCtrl is the current cell (if it's not Nothing).
If drag = True AndAlso prevCtrl IsNot Nothing Then
btn.Location = prevCtrl.Location 'Snap to the cell's location.
prevCtrl.BackColor = Color.White 'Reset the cell's BackColor.
prevCtrl = Nothing 'Reset this since we're no longer dragging the button.
End If
drag = False
End Sub
And it works like a charm!

Open Tabs Control

I'm using MDI container to run my bussiness application I created for my client.
Since using MDI means that when I open several forms they will still run in background all the time untill I close them manualy.
What I need is to make User Control or anything else that could preview all opened forms in Tab Form so my client can easily close all or some of opened forms without closing a form he is curently viewing.
For now I have used this code, so for now only first clicked item from menu appears as button, but not others clicked menu items.
Private Sub MenuStrip1_ItemClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ToolStripItemClickedEventArgs) Handles MenuStrip1.ItemClicked
Dim Button As New Button
Me.Panel5.Controls.Add(Button)
Button.Text = e.ClickedItem.Name
Button.Width = 50
Button.Height = 25
End Sub
Now I need to write a code to add more buttons bellow, also should add a code for adding buttons only when I click on SubMenu item (The one when is clicked new Form appear).
And also, I should now add a little Close button into previewed User-Button-Control.
From your comments, I understand that your ideas regarding adding buttons at runtime are not too clear and thus I am including a small code which hopefully will help you on this front. Start a new project and put a Panel (Panel5) and a Button (AddButtons) on it, and write this code:
Dim lastButtonIndex, lastLeft, lastTop As Integer
Private Sub Button_Click(sender As System.Object, e As System.EventArgs)
Dim curButton As Button = DirectCast(sender, Button)
If (curButton.Name = "Button1") Then
'do Button1 stuff
End If
'etc.
End Sub
Private Sub addNewButton()
lastButtonIndex = lastButtonIndex + 1
lastLeft = lastLeft + 5
lastTop = lastTop + 5
Dim Button As New Button
With Button
.Name = "Button" + lastButtonIndex.ToString()
.Text = "Button" + lastButtonIndex.ToString()
.Width = 50
.Height = 25
.Left = lastLeft
.Top = lastTop
AddHandler .Click, AddressOf Button_Click
End With
Me.Panel5.Controls.Add(Button)
End Sub
Private Sub ButtonAddButtons_Click(sender As System.Object, e As System.EventArgs) Handles AddButtons.Click
addNewButton()
End Sub
This code will add a new button to the panel every time you click on AddButtons. All the buttons will have an associated Click Event (the same one for all of them): Button_Click. The way to know which button is the current one inside this method is via sender, as shown in the code (you can put as many conditions as buttons. The names are given sequentially starting from 1; but you can take any other property as reference, curButton is the given Button Control).
Bear in mind that one of the problems you have to take care of is the location of the buttons. The code above has a very simplistic X/Y values (Left/Top properties) auto-increase which, logically, will not deliver what you want.