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
Related
I have created a class to use as a notification window (similar to toast notifications, which are disabled on our system).
I use a timer object to timeout the closing the form, and a backgroundworker to handle the animation of it sliding in from the bottom of the screen. For debugging purposes the form just outputs it's own size and the screen bounds.
Imports System.ComponentModel
Public Class ASNotify
Public Sub New(ByVal title As String, ByVal msg As String, ByVal Optional timeout As Integer = 5000)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.Text = title
Me.NotifyMessage.Text = $"{Me.Width}x{Me.Height}{vbCrLf}{My.Computer.Screen.WorkingArea.Size.Width}x{My.Computer.Screen.WorkingArea.Size.Height}"
TimeoutTimer.Interval = timeout
TimeoutTimer.Enabled = True
AnimationWorker.RunWorkerAsync()
End Sub
Private Sub AnimationWorker_DoWork(sender As Object, e As DoWorkEventArgs) Handles AnimationWorker.DoWork
Dim xloc As Integer = My.Computer.Screen.WorkingArea.Size.Width - Me.Width
Dim yloc As Integer = My.Computer.Screen.WorkingArea.Size.Height
For x As Integer = 0 To Me.Height
MoveWindow(xloc, yloc - x)
Threading.Thread.Sleep(2)
Next
End Sub
Private Sub MoveWindow(xloc As Integer, yloc As Integer)
If InvokeRequired Then
Invoke(Sub() MoveWindow(xloc, yloc))
Else
Location = New Drawing.Point(xloc, yloc)
End If
End Sub
Private Sub TimeoutTimer_Tick(sender As Object, e As EventArgs) Handles TimeoutTimer.Tick
Me.Close()
End Sub
End Class
I call this from another form by calling
Private Sub NotifyUser(ByRef a As Alert.Alert)
Dim notify As New ASNotify(a.Location, a.Comment, 5000)
notify.Show()
End Sub
I call that sub by pressing a button on the form, and it works perfectly.....Sometimes.
repeatedly triggering the notify window makes it pops up as one of 2 different sizes on the screen, although the contents showing the size always state 264x81 and screenbounds 1920x1040
and occasionally I get an exception that the line saying 'Location = new Drawing.Point(xloc,yloc) is being called from a thread other than that which it was created on, despite the Invoke call.
Moved the timer-start and animationworker start to the Load method of the form, rather than New.
Private Sub ASNotify_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TimeoutTimer.Enabled = True
AnimationWorker.RunWorkerAsync()
End Sub
When I moves window on screen, user control is not moving.Is there any way we can add the control to the window except we create control at run time in form window. I have shared the code below.
I've created a custom CustomBox using links link1 and link2
User Control Code
Private mList As CustomBox
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
mList = New CustomBox(Me)
mList.Location = New Point(5, 10)
mList.Size = New Size(50, Me.ClientSize.Height + 50)
For ix As Integer = 0 To 100 - 1
mList.Items.Add(ix)
Next
End Sub
EDITED:
Instead of passing Me (i.e. user control instance) as parent, pass the Me.ParentForm as the parent. In case you still require the user control instance for any other purpose, just pass it as another parameter.
The other thing you need to manage is the offset. For that you can simply add the user control's location to wherever you want to place it.
Here is the updated code:
Public Class UserControl1
Private mList As CustomBox
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
mList = New CustomBox(Me.ParentForm)
mList.Location = Me.Location + (New Point(5, 10))
mList.Size = New Size(50, Me.ClientSize.Height + 50)
For ix As Integer = 0 To 100 - 1
mList.Items.Add(ix)
Next
End Sub
End Class
Here's how it looks with above code changes.
https://imgur.com/8lbAfjU
Have a question. I think it must be quite easy to implement but for some reason I can't do it. Right now the charts are updated if I click on them. I wish that they were updated every time I change a value (just like in Excel), for must be easier to implement a timer.
For some reason I can't implement it and I have already tried a few things that I have found online.
I have two charts and I want the charts to update the values every second (or the interval suitable for the program).
I am working on a Windows form and have the following VB code:
Private Sub Chart1_Click(sender As Object, e As EventArgs) Handles Chart1.MouseClick
AutoSize = False
Chart1.ChartAreas(0).AxisX.Interval = 0.05
Chart1.ChartAreas(0).AxisY.Interval = 200
With Chart1
.Series(0).Points.Clear()
.Series(1).Points.Clear()
.Series(2).Points.Clear()
End With
With Chart1
.Series(0).Points.AddXY(TOCGLong, TOSumMassValues)
.Series(1).Points.AddXY(LandCGLong, LandSumMassValues)
.Series(2).Points.AddXY(ZFWCGLong, ZFWSumMassValues)
End With
With Chart1.ChartAreas
With .Max
.AxisX.Maximum = 3.55
.AxisY.Maximum = 2300
End With
With .Min
.AxisX.Minimum = 3.15
.AxisY.Minimum = 1200
End With
End With
Chart1.Series(3).Points.Clear()
For i As Integer = 0 To 5
Chart1.Series(3).Points.AddXY(CGLimitX(i), CGLimitY(i))
Next
End Sub
Private Sub Chart3_Click(sender As Object, e As EventArgs) Handles Chart3.MouseClick
Dim FuelX() As Integer = {80, 90, 100, 110, 120, 130, 140, 150, 160, 170, 180}
Dim ISA() As Double = {27171.16, 24053.39, 21011, 18043.99, 15152.36, 12336.11, 9595.24, 6929.75, 4339.64, 1824.91, -614.44}
Dim ISA20() As Double = {25421.84, 21987.56, 18644, 15409.16, 12277.04, 9247.64, 6320.96, 3497, 775.76, -1842.76, -4358.56}
Dim ISA35() As Double = {23726.04, 19793.81, 16041, 12467.61, 9073.64, 5859.09, 2823.96, -31.75, -2708.04, -5204.91, -7522.36}
AutoSize = False
Chart3.ChartAreas(0).AxisX.Interval = 10
Chart3.ChartAreas(0).AxisY.Interval = 5000
With Chart3
.Series(0).Points.Clear()
'.Series(1).Points.Clear()
'.Series(2).Points.Clear()
End With
With Chart3
.Series(0).Points.AddXY(FuelConsuption, SDaltitude.Value)
For i As Integer = 0 To 10
.Series(1).Points.AddXY(FuelX(i), ISA(i))
.Series(2).Points.AddXY(FuelX(i), ISA20(i))
.Series(3).Points.AddXY(FuelX(i), ISA35(i))
Next
End With
With Chart3.ChartAreas
With .Max
.AxisX.Maximum = 180
.AxisY.Maximum = 23000
End With
With .Min
.AxisX.Minimum = 80
.AxisY.Minimum = 0
End With
End With
End Sub
Take the code out of the Chart1.MouseClick handler and put it in a Sub of its own with a descriptive name. Do the same for the Chart3.MouseClick handler.
In the Chart1.MouseClick handler, call that first Sub.
In the Chart3.MouseClick handler, call that second method.
For the question in the question:
I wish that they were updated everytime I change a value
In the appropriate textbox leave handlers, call the appropriate method(s), something like this:
Private Sub TextBox1_Leave(sender As Object, e As EventArgs) Handles TextBox1.Leave
UpdateChart1()
UpdateChart2()
End Sub
I suggest using the Leave event so that it doesn't keep changing while the user is in the middle of typing.
For the question in the title:
You should put the chart updating code in its own methods, as written above. Then you can easily call it from a timer's tick event. The essential parts of the code are like this:
Public Class Form1
Dim tim As Timer
Sub UpdateMpgChart()
' ... code here to update the chart
End Sub
Sub UpdateOtherChart()
' ... code here to update the other chart
End Sub
Sub TimerTickHandler(sender As Object, e As EventArgs)
UpdateMpgChart()
UpdateOtherChart()
End Sub
Sub InitialiseTimer()
tim = New Timer With {.Interval = 1000}
AddHandler tim.Tick, AddressOf TimerTickHandler
tim.Start()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
InitialiseTimer()
End Sub
Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If tim IsNot Nothing Then
tim.Dispose()
End If
End Sub
End Class
I wish that they were updated every time I change a value (just like in Excel), for must be easier to implement a timer.
You can use the ReactiveProperty nuget.
You declare a ReactiveProperty for each value you want to "react":
public ReactiveProperty<int> Prop1 = new ReactiveProperty(0);
public ReactiveProperty<int> Prop2 = new ReactiveProperty(0);
In the constructor (or load event) just tell the property to update the chart:
Prop1.Subscribe(value => Chart1_Click(this, null));
Here I'm telling to Prop1 to execute the Chart1_Click method, but you can create an specific method for updating the charts and put this in the subscribe method instead the Chart1_Click.
And for change the Prop1 or Prop2 values just:
Prop1.Value = 5; // this line will run the specified method
Prop2.Value = 10;
I want to specify in a text field how many timers I want to add to my form and specify the code that should be into the timer.
For instance: My textbox says "2" and then I click a button and it creates two timers and adds a specific source code for both timers.
I have tried different codes and while they worked, I wasn't able to specify the number of controls on a form to create.
How can I achieve this efficiently?
Thanks
Just to create one timer
Public Class Form1
private _timer as Windows.Forms.Timer
...
Public Sub New()
...
_timer = New Timer(Me)
_timer.Interval = 1000 'Timer will trigger one second after start
AddHandler _timer.tick, AddressOf Timer_tick 'Timer will call this sub when done
End Sub
Sub Button_click(sender as Object, e as EventArgs)
_timer.Start() 'Start the timer
...
End Sub
Private Sub Timer_tick(sender as Object, e as EventArgs)
MessageBox.Show("Timerrr!!")
End Sub
...
End Class
Now if you want to create more than one timer, you can use an array of Timer.
In this case, I used a form conatining a NumericUpDown controll element, a button and a label, plus two labels which only contain text.See this picture
To create the timers, I use the function add_timers(timercount), which looks like this:
Function add_timers(timercount As Integer)
'Using a loop to creat <timercount> timers
For g As Integer = 1 To timercount
'Creating new timer 't'
Dim t As New Timer()
'setting interval of t
t.Interval = 1000
'Enabling timer
t.Enabled = True
'Code which runs when t ticks
AddHandler t.Tick, AddressOf TimerTick
Next
End Function
This function gets called when Button1, the start button gets pressed. It uses NumericUpDown1.Value as the parameter for the function. The function uses a loop to create new timers t, sets their intervals and the code to run when they tick.
Unfourtunately, I didn't find a way to dynamically create code, so every timer performs the same action. Using arrays and loops in a clever way might enable you to use different value for each timer. To create code for the timer use a Sub:
Sub TimerTick(ByVal sender As Object, e As EventArgs)
'Add your code here
Label1.Text += 1
End Sub
The complete code I use is:
Public Class Form1
Function add_timers(timercount As Integer)
'Using a loop to creat <timercount> timers
For g As Integer = 1 To timercount
'Creating new timer 't'
Dim t As New Timer()
'setting interval of t
t.Interval = 1000
'Enabling timer
t.Enabled = True
'Code which runs when t ticks
AddHandler t.Tick, AddressOf TimerTick
Next
End Function
Sub TimerTick(ByVal sender As Object, e As EventArgs)
'Add your code here
Label1.Text += 1
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
add_timers(NumericUpDown1.Value)
End Sub
End Class
Packing the timers into an array is possible, that way you can easily access each timer with its index. Serach for it on the internet, and if you then have no idea of how to do it, tell me in the comments.
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)