How to make a fixed background on a DataGridView - vb.net

I made a custom control that inherits DataGridView in order to have a transparent background. Now I am trying to set up an scroll feature on a timer that scrolls down one row every second. However, when I try to scroll (vertically), the background image is not fixed. Is there any way to make the background image fixed when scrolling?
EDIT: Here is the code for handling the scroll timer.
Private Sub Sub1
'Some previous code
If DataGridView1.Rows.Count > 10 Then
ScrollIndex1 = 0 'Integer for scroll index
DGVAutoScroll()
End If
End Sub
Private Sub DGVAutoScroll()
Timer2.Enabled = True
Timer2.Interval = 1000
End Sub
Private Sub Timer2_Tick(sender As Object, e As EventArgs) Handles Timer2.Tick
If ScrollIndex1 = DataGridView1.Rows.Count - 1 Then
ScrollIndex1 = 0
DataGridView1.FirstDisplayedScrollingRowIndex = ScrollIndex1
ScrollIndex1 += 1
Else
DataGridView1.FirstDisplayedScrollingRowIndex = ScrollIndex1
ScrollIndex1 += 1
End If
End Sub
'Custom DataGridView class
Imports System.ComponentModel
Imports System.Windows.Forms
Public Class MyDGV
Inherits DataGridView
Public Property DGVHasTransparentBackground As Boolean
Get
Return Nothing
End Get
Set()
SetTransparentProperties(True)
End Set
End Property
Public Property ScrollBar
Get
Return Nothing
End Get
Set(value)
BackgroundColor = Color.Transparent
End Set
End Property
Public Sub New()
DGVHasTransparentBackground = True
End Sub
Private Sub SetTransparentProperties(ByRef SetAsTransparent As Boolean)
MyBase.DoubleBuffered = True
MyBase.EnableHeadersVisualStyles = False
MyBase.ColumnHeadersDefaultCellStyle.BackColor = Color.Transparent
MyBase.RowHeadersDefaultCellStyle.BackColor = Color.Transparent
SetCellStyle(Color.Transparent)
End Sub
Protected Overrides Sub PaintBackground(graphics As System.Drawing.Graphics, clipBounds As System.Drawing.Rectangle, gridBounds As System.Drawing.Rectangle)
MyBase.PaintBackground(graphics, clipBounds, gridBounds)
Dim rectSource As New Rectangle(MyBase.Location, MyBase.Size)
Dim rectDest As New Rectangle(0, 0, rectSource.Width, rectSource.Height)
Dim b As New Bitmap(Parent.ClientRectangle.Width, Parent.ClientRectangle.Height)
Graphics.FromImage(b).DrawImage(MyBase.Parent.BackgroundImage, Parent.ClientRectangle)
graphics.DrawImage(b, rectDest, rectSource, GraphicsUnit.Pixel)
End Sub
Protected Overrides Sub OnColumnAdded(e As System.Windows.Forms.DataGridViewColumnEventArgs)
MyBase.OnColumnAdded(e)
SetCellStyle(Color.Transparent)
End Sub
Private Sub SetCellStyle(ByVal cellColour As Color)
For Each col As DataGridViewColumn In MyBase.Columns
col.DefaultCellStyle.BackColor = cellColour
col.DefaultCellStyle.SelectionBackColor = cellColour
Next
End Sub
End Class

It looks like I had to call DataGridView1.SelectAll() within the timer tick. Thanks everyone.

I assume you want an image behind data (datagridview).
If datagridview is transparent then just add an image in the background. Stick it on the form or on an item behind datagridview. It will no scroll since it would be outside datagridview
Change image alpha if data not clearly visible.

Related

How to stop a timer when mouse is scrolling or on top of scrollbar in listbox

I'm looking for a way to detect and switch off a timer when the mouse cursor is scrolling a listbox.
There is an easy way despite to create a new class like this one?link
Would be possible to check rectangle location of listbox 1 scroll bar and say: if mouse is in this range then timer1.stop?
EDIT1:
In order to create a rectangle I'm using
If e.X >= 364 AndAlso e.X <= 446 AndAlso e.Y >= 86 AndAlso e.Y <= 144 Then
MessageBox.Show("Clicked within the rectangle")
Else
MessageBox.Show("Clicked outside the rectangle")
End If
449-359 are the Top left corner location of the rectangle
while the rectangle size is x30 y156
The problem is I don't know in which event let it run!
Listbox click event doesn't recognize scrollbar as "inside of listbox"
Form_mouse click event doesn't recognize listbox scroll bar as a click in the form.
There is an event that despite the control you are on, it will let you play with this workaround?
Thanks
Here is what I posted on MSDN using this C# code. There is no code presented below that will restart the Timer.
Public Class BetterListBox
Inherits ListBox
' Event declaration
Public Delegate Sub BetterListBoxScrollDelegate(ByVal Sender As Object, ByVal e As BetterListBoxScrollArgs)
Public Event Scroll As BetterListBoxScrollDelegate
' WM_VSCROLL message constants
Private Const WM_VSCROLL As Integer = &H115
Private Const SB_THUMBTRACK As Integer = 5
Private Const SB_ENDSCROLL As Integer = 8
Protected Overrides Sub WndProc(ByRef m As Message)
' Trap the WM_VSCROLL message to generate the Scroll event
MyBase.WndProc(m)
If m.Msg = WM_VSCROLL Then
Dim nfy As Integer = m.WParam.ToInt32() And &HFFFF
If (nfy = SB_THUMBTRACK OrElse nfy = SB_ENDSCROLL) Then
RaiseEvent Scroll(Me, New BetterListBoxScrollArgs(Me.TopIndex, nfy = SB_THUMBTRACK))
End If
End If
End Sub
Public Class BetterListBoxScrollArgs
' Scroll event argument
Private mTop As Integer
Private mTracking As Boolean
Public Sub New(ByVal top As Integer, ByVal tracking As Boolean)
mTop = top
mTracking = tracking
End Sub
Public ReadOnly Property Top() As Integer
Get
Return mTop
End Get
End Property
Public ReadOnly Property Tracking() As Boolean
Get
Return mTracking
End Get
End Property
End Class
End Class
Then in your form subscribe to the Scroll event. Requires the ListBox above in your project, one Timer enabled and a Label.
Private Sub BetterListBox1_Scroll(Sender As Object, e As BetterListBox.BetterListBoxScrollArgs) _
Handles BetterListBox1.Scroll
Timer1.Enabled = False
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
Label1.Text = Now.ToString()
End Sub

How do I code out with numeric keypads with multi textboxes?

I'm trying to code out a programme where the user sees a form and in that form, there are 2 text boxes and 10 buttons.
Username:
Password:
1 2 3
4 5 6
7 8 9
0
I've tried this code
Private Sub Btn1_Click(sender As Object, e As EventArgs) Handles Btn1.Click
If UsernameTextbox.Focused = True Then
UsernameTextbox.Text = UsernameTextbox.Text + "1"
End If
End Sub
I understand that clicking on Btn1 will steal the focus from the text box. So how can I write the programme?
One option would be to declare a variable of type Control and, in the Leave event handler for each control, assign the sender to that variable. You can then use that variable in the Click event handler of your Button to determine which control had focus and possibly reassign back to that control and then update it appropriately. You can do the lot with two event handlers, e.g.
Private previouslyActiveTextBox As TextBox
Private Sub TextBoxes_Leave(sender As Object, e As EventArgs) Handles TextBox2.Leave,
TextBox1.Leave
previouslyActiveTextBox = DirectCast(sender, TextBox)
End Sub
Private Sub Buttons_Click(sender As Object, e As EventArgs) Handles Button3.Click,
Button2.Click,
Button1.Click
previouslyActiveTextBox.Select()
previouslyActiveTextBox.SelectedText = CStr(DirectCast(sender, Button).Tag)
End Sub
That code handles multiple events with a single method in both cases. It also requires that you assign the number for each Button to the Tag property of that control. Note that it also sets the SelectedText, rather than appending to the Text property. That is more correct because it will add the new text where the caret is actually located and replace text if it is selected.
An even better option might be to use a custom button control that doesn't take focus. Here's one I prepared earlier:
http://www.vbforums.com/showthread.php?459890-Building-Blocks-for-an-On-screen-Keyboard
Items within a ToolStrip do not grab focus when clicked. While the standard ToolStrip usage is as a menu bar, there is nothing that prevents you from using it as a container for buttons laid out in a grid. In fact, the class ToolStrip.LayoutStyle Property allows you select a table style.
The following is a proof-of-concept custom ToolStrip that is prepopulated with the buttons to create a number pad like control. The control has sufficient function to work as intended, but is not locked down to prevent misuse by manipulating the Items collection and other properties.
Public Class NumPadToolstrip : Inherits ToolStrip
Private _ButtonSize As Size = New Size(50, 50)
Private _ButtonMargin As Padding = New Padding(5)
Private _ButtonBackColor As Color = Color.Ivory
Public Sub New()
MyBase.New
LayoutStyle = ToolStripLayoutStyle.Table
Dim settings As TableLayoutSettings = CType(LayoutSettings, TableLayoutSettings)
settings.ColumnCount = 3
settings.RowCount = 4
AddButtons(7, 9)
AddButtons(4, 6)
AddButtons(1, 3)
AddButtons(0, 0)
Dock = DockStyle.None
AutoSize = True
BackColor = Color.LightGray
End Sub
Public Property ButtonSize As Size
Get
Return _ButtonSize
End Get
Set(value As Size)
If value <> _ButtonSize Then
_ButtonSize = value
UpdateButtonSizes()
End If
End Set
End Property
Public Property ButtonMargin As Padding
Get
Return _ButtonMargin
End Get
Set(value As Padding)
If value <> _ButtonMargin Then
_ButtonMargin = value
UpdateMargins()
End If
End Set
End Property
Public Property ButtonBackColor As Color
Get
Return _ButtonBackColor
End Get
Set(value As Color)
If value <> _ButtonBackColor Then
_ButtonBackColor = value
UpdateButtonBackColor()
End If
End Set
End Property
Private Sub AddButtons(start As Int32, [end] As Int32)
For num As Int32 = start To [end]
Dim b As New ToolStripButton With {.Text = num.ToString(),
.Size = ButtonSize,
.Margin = ButtonMargin,
.BackColor = ButtonBackColor,
.AutoSize = False}
AddHandler b.Paint, Sub(sender As Object, e As PaintEventArgs)
With e.Graphics
Dim r As Rectangle = e.ClipRectangle
r.Inflate(-1, -1)
r.Location = Point.Empty
.DrawRectangle(Pens.Black, r)
End With
End Sub
Items.Add(b)
Next
End Sub
Private Sub UpdateButtonSizes()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.Size = _ButtonSize
Next
ResumeLayout()
End Sub
Private Sub UpdateMargins()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.Margin = _ButtonMargin
Next
ResumeLayout()
End Sub
Private Sub UpdateButtonBackColor()
SuspendLayout()
For Each btn As ToolStripButton In Items.OfType(Of ToolStripButton)
btn.BackColor = _ButtonBackColor
Next
ResumeLayout()
End Sub
End Class
Add the above class to your project and perform a build operation. The NumPadToolstrip control should then be available in the ToolBox. Add the control to the form and then add a handler for its ItemClicked event to pass the proper text to the TextBox.
Private Sub NumPadToolstrip1_ItemClicked(sender As Object, e As ToolStripItemClickedEventArgs) Handles NumPadToolstrip1.ItemClicked
Dim tb As TextBoxBase = TryCast(ActiveControl, TextBoxBase)
If tb IsNot Nothing Then tb.SelectedText = e.ClickedItem.Text
End Sub

Changing a form opacity from a custom timer class

I created a class that inherits a timer class because I want to customize the Tick function, and I want to use this specific function in many classes without the need to change the function in all the timers every time.
Public Class FadeInTimer
Inherits Timer
Public Sub New()
MyBase.New()
Me.Enabled = False
Me.Interval = 75
End Sub
Private Sub FadeInTimer_Tick(sender As Object, e As EventArgs) Handles Me.Tick
Dim workingAreaWidth As Integer = Screen.PrimaryScreen.WorkingArea.Width - Me.Width
Me.Opacity += 0.1
If Not Me.Location.X <= workingAreaWidth Then
Me.Location = New Point(Me.Location.X - 30, Me.Location.Y)
End If
Me.Refresh()
If Me.Opacity = 1 Then
Me.Stop()
End If
End Sub
End Class
The purpose of this function is to make a simple fade in when the form is created. The problem is I can't use "Me." because I am in the Timer class, so, how can I make changes to the form from this class.
The first thing to do is to pass an instance of the form to be faded in inside the constructor of the custom timer, save that instance in a global class variable and add the tick handler with AddHandler like so
Public Class FadeInTimer
Inherits System.Windows.Forms.Timer
Dim parent As Form
Public Sub New(p As Form)
MyBase.New()
parent = p
AddHandler MyBase.Tick, AddressOf FadeInTimer_Tick
End Sub
Now, when you need to refer to the 'parent' form you use the parent variable and not the Me statement. Also, every time you need to refer to the timer, you should use MyBase statement
Private Sub FadeInTimer_Tick(sender As Object, e As EventArgs)
Dim workingAreaWidth As Integer = Screen.PrimaryScreen.WorkingArea.Width - Parent.Width
parent.Opacity += 0.1
If Not parent.Location.X <= workingAreaWidth Then
parent.Location = New Point(parent.Location.X - 30, parent.Location.Y)
End If
parent.Refresh()
If parent.Opacity = 1 Then
MyBase.Stop()
End If
End Sub
This could be tested in LinqPad using this code
Sub Main
Dim f As Form = New Form()
Dim t As FadeInTimer = New FadeInTimer(f)
f.Opacity = 0
t.Interval = 150
t.Start()
f.ShowDialog()
End Sub

Change datagridview cell background based on a external parameter

I should change the color to a cell which contains the parameter 'tarjeta_fam'. I tried to change the cell default property and then invalidate the row to refresh it, but (obviously) nothing happens. It's possible to change a cell color out of the cell formatting event?
Public Sub New(user As Usuario, ByVal tarjeta_fam As String)
InitializeComponent()
gridFamiliares.DataSource = BD.getTable(a query)
If Me.gridFamiliares.Rows.Count > 0 Then
For i As Integer = 0 To Me.gridFamiliares.Rows.Count - 1
If Me.gridFamiliares.Rows(i).Cells("tarjeta_fam").Value = tarjeta_fam Then
Me.gridFamiliares.Rows(i).DefaultCellStyle.BackColor = Color.Black
Me.gridFamiliares.InvalidateRow(i)
End If
Next
End If
End Sub
The DataGridView control really wants you to use the CellFormatting event for this, so declare a form level variable to be used by that event:
Private tarjeta_fam_Value As String = String.Empty
Public Sub New(user As Usuario, ByVal tarjeta_fam As String)
InitializeComponent()
gridFamiliares.DataSource = BD.getTable(a query)
tarjeta_fam_Value = tarjeta_fam
End Sub
Private Sub gridFamiliares_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles gridFamiliares.CellFormatting
If tarjeta_fam_Value <> String.Empty Then
With gridFamiliares.Rows(e.RowIndex)
If .Cells("tarjeta_fam").Value = tarjeta_fam_Value Then
.DefaultCellStyle.BackColor = Color.Black
End If
End With
End If
End Sub

How can I respond to events raised by programmatically created UI elements?

I'm creating a board game for a piece of coursework. For the board, I'm using some nested For loops running through a 2D array to generate a "Space" object at each square.
The Space object contains a picturebox and some data about that space.
How can I handle events caused by clicking on the generated picturebox without having to hard-code it for each space?
I noticed this question seems to address this, but it's in C# and I couldn't translate it to VB.Net.
Edit:
This is how the board is generated
Dim board(23, 24) As Space
Private Sub GenerateBoard()
Dim spaceSize As New Size(30, 30)
Dim spaceLocation As New Point
Dim validity As Boolean
For Y = 0 To 24
For X = 0 To 23
spaceLocation.X = 6 + (31 * X)
spaceLocation.Y = 6 + (31 * Y)
If validSpaces(Y).Contains(X + 1) Then
validity = True
Else
validity = False
End If
board(X, Y) = New Space(validity, spaceSize, spaceLocation)
Me.Controls.Add(board(X, Y).imageBox)
board(X, Y).imageBox.BackColor = Color.Transparent
board(X, Y).imageBox.BringToFront()
Next
Next
End Sub
Space Class:
Public Class Space
Dim _active As Boolean
Dim _imageBox As PictureBox
Public Sub New(ByVal activeInput As Boolean, ByVal size As Size, ByVal location As Point)
_active = activeInput
_imageBox = New PictureBox
With _imageBox
.Size = size
.Location = location
.Visible = False
End With
End Sub
Property active As Boolean
Get
Return _active
End Get
Set(value As Boolean)
_active = value
End Set
End Property
Property imageBox As PictureBox
Get
Return _imageBox
End Get
Set(value As PictureBox)
_imageBox = value
End Set
End Property
Public Sub highlight()
With _imageBox
.Image = My.Resources.Highlighted_slab
.Visible = True
End With
End Sub
End Class
First all controls created by designer(textbox, label...) a generated by code too, but VisualStudio write this for you. If you open Designer file(yourForm.Designer.vb), then you can see all code how to generate a controls.
If you want a create event handler for your pictureBox , then:
//Initialize control
Private WithEvents _imageBox as PictureBox
Then create a event handler method:
Private Sub imageBox_Click(sender as Object, e as EventArgs)
//Your code
End Sub
Then in VB.NET you can assign a Event handler to the Event in two ways
first: In class constructor after you created a pictureBox( New PictureBox()) add
AddHandler Me._imageBox, AddressOf Me.imageBox_Click
second: On line we you created a event handler add next:
Private Sub imageBox_Click(sender as Object, e as EventArgs) Handles _imageBox.Click
//Your code
End Sub
And remember add your pictureBox to form controls YourForm.Controls.Add(spaceInstance.ImageBox)