I'm looking for a way to detect if the user has been idle for 5 min then do something, and if and when he comes back that thing will stop, for example a timer.
This is what i have tried (but this will only detect if form1 has been inactive / not clicked or anything):
Public Class Form1
Private Sub form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'You should have already set the interval in the designer...
Timer1.Start()
End Sub
Private Sub form1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles Me.KeyPress
Timer1.Stop()
Timer1.Start()
End Sub
Private Sub form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
Timer1.Stop()
Timer1.Start()
End Sub
Private Sub form1_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
Timer1.Stop()
Timer1.Start()
End Sub
Private Sub Timer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
MsgBox("Been idle for to long") 'I just have the program exiting, though you could have it do whatever you want.
End Sub
End Class
This is done easiest by implementing the IMessageFilter interface in your main form. It lets you sniff at input messages before they are dispatched. Restart a timer when you see the user operating the mouse or keyboard.
Drop a timer on the main form and set the Interval property to the timeout. Start with 2000 so you can see it work. Then make the code in your main form look like this:
Public Class Form1
Implements IMessageFilter
Public Sub New()
InitializeComponent()
Application.AddMessageFilter(Me)
Timer1.Enabled = True
End Sub
Public Function PreFilterMessage(ByRef m As Message) As Boolean Implements IMessageFilter.PreFilterMessage
'' Retrigger timer on keyboard and mouse messages
If (m.Msg >= &H100 And m.Msg <= &H109) Or (m.Msg >= &H200 And m.Msg <= &H20E) Then
Timer1.Stop()
Timer1.Start()
End If
End Function
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Timer1.Stop()
MessageBox.Show("Time is up!")
End Sub
End Class
You may have to add code that disables the timer temporarily if you display any modal dialogs that are not implemented in .NET code.
This might work by setting it to just call the Reset idk i just want it work all over the program idk how to do it, i just created this code :
Public Class test
Dim IdleTimer As String
Dim testsave As String
Dim idle_TimerSet As String = 60 '<---- Here You choose The timer (1 per Sec)
Private Sub test_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
IdleTimer = idle_TimerSet
End Sub
Private Sub Idle_Tick(sender As Object, e As EventArgs) Handles Idle.Tick
If IdleTimer <= 1 Then
MsgBox("[ Idle Screen ]")
Else
IdleTimer = IdleTimer - 1 '<--- The Counter
IdleTracker.Text = IdleTimer
End If
End Sub
Private Sub test_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
Call Reset_Idle() 'This is on the main Form
End Sub
Private Sub test_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
Call Reset_Idle() 'This is on the main Form
End Sub
Public Sub Reset_Idle() '<-- The Reset Action
'Idle.Enabled = False
IdleTimer = idle_TimerSet
'Idle.Enabled = True
End Sub
End Class
Related
I'm facing a big problem here, I'm developing a app to read data from a Weight.
Everything is working perfectly, but the result is not what I expected: when reading the data from the scale, it keeps printing the data without stopping and I would like it to read a single line and whenever there is any change in the scale, just change the value and not add a new line...
The way it's printed:
My code:
Public Class Form1
Dim Q As Queue(Of String) = New Queue(Of String)
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
For Each s In System.IO.Ports.SerialPort.GetPortNames()
ComboBox1.Items.Add(s)
Next s
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Try
If ComboBox1.SelectedIndex = -1 Then
MsgBox("Please select a port")
Exit Sub
Else
SerialPort1.BaudRate = 9600
SerialPort1.DataBits = 8
SerialPort1.Parity = IO.Ports.Parity.None
SerialPort1.StopBits = IO.Ports.StopBits.One
SerialPort1.PortName = ComboBox1.SelectedItem.ToString
SerialPort1.Open()
Timer1.Start()
End If
Catch ex As Exception
MsgBox(ex.Message)
End Try
End Sub
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, _
ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) _
Handles SerialPort1.DataReceived
Q.Enqueue(SerialPort1.ReadExisting())
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick
SyncLock Q
While Q.Count > 0
TextBox1.Text &= Q.Dequeue
End While
End SyncLock
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
SerialPort1.Close()
Timer1.Stop()
End Sub
End Class
Here's a simple example using Control.BeginInvoke() to set a Control's property with some data coming from a secondary Thread.
You can use this method since you have all your code in a Form and you use
a SerialPort Component.
Otherwise, build a class to handle the SerialPort and pass a delegate to its Constructor, capture SynchronizationContext.Current and Post() to the delegate.
Or use an IProgress<T> delegate (Progress(Of String) here) and pass this delegate to the class, then just call its Report() method from the event handler.
Assuming ReadExisting() works for you and the Encoding is set correctly (it appears to be, from the results shown in the OP), you could change the code in the DataReceived handler to:
It's required to check whether the handles of the Controls involved (the Form, mainly) are created before calling Invoke() / BeginInvoke(), otherwise you may (will, at some point) get an exception that may kill the application (the IProgress<T> pattern is preferable).
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim comPort = DirectCast(sender, SerialPort)
UpdateUI(comPort.ReadExisting())
End Sub
' [...]
Private lastWeight As String = String.Empty
Private Sub UpdateUI(weight As String)
If IsHandleCreated Then
BeginInvoke(New Action(
Sub()
If Not lastWeight.Equals(weight) Then
lastWeight = weight
If TextBox1.IsHandleCreated Then TextBox1.Text = lastWeight
End If
End Sub))
End If
End Sub
Make a test with a threaded Timer, setting the Interval to a low value (e.g., 50ms).
You can also try to close the Form without stopping the Timer.
Found the soluction:
Public Class Form5
Delegate Sub SetTextCallback(ByVal data As String)
Private Delegate Sub UpdateLabelDelegate(theText As String)
Private Sub UpdateLabel(theText As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateLabelDelegate(AddressOf UpdateLabel), theText)
Else
TextBox1.Text = theText
End If
End Sub
Private Sub SerialPort1_DataReceived(ByVal sender As System.Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort1.DataReceived
Dim returnStr As String
returnStr = SerialPort1.ReadExisting
Me.BeginInvoke(Sub()
UpdateLabel(returnStr)
End Sub)
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SerialPort1.Open()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
SerialPort1.Close()
End Sub
End Class
I have two buttons Start button and Stop button .I run my program by clicking on start button. I want to stop the program during the start button . But the program will not responde until the start buttun finish its job. How i can do check the stop buttun during the start. i heard about threading but i do not know how i can do it.
Private Sub Button_Start (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
//my code
//check always if the user push stop if no continue if yes go to this sub
//my code
end sub
Private Sub Button_Stop (ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
stopClick = True
Dim Response As Integer
Response = MessageBox.Show("Do you really want to exit?", "", MessageBoxButtons.YesNo, MessageBoxIcon.Question)
If Response = vbYes Then
Me.Close()
End If
End Sub
you can use threading put button1 code in a function and use the thread .
you can refer to this example
'Thread created to handle the Background process for start_function
Dim t As System.Threading.Thread
Private Sub start_function()
While True
'your code here for Eg:
Dim i As Integer
i = i + 1
End While
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
t = New System.Threading.Thread(AddressOf Me.start_function)
t.Start()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
t.Abort()
End Sub
Drag a backgroundworker component onto your form.
Imports System.ComponentModel
Public Class Form1
Private Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
Me.Text = "Busy Doing Work"
BackgroundWorker1.WorkerSupportsCancellation = True
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub btnStop_Click(sender As Object, e As EventArgs) Handles btnStop.Click
Me.Text = "Asking to Cancel"
BackgroundWorker1.CancelAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
While Not BackgroundWorker1.CancellationPending
System.Threading.Thread.Sleep(1000)
End While
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
Me.Text = "Cancelled"
End Sub
End Class
Public Class Form1
Private _zkouska1 As New Bitmap("C:\Users\w\Desktop\zkouska1.gif")
Private _zkouska2 As New Bitmap("C:\Users\w\Desktop\zkouska2.gif")
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
e.Graphics.DrawImageUnscaled(New Bitmap(_zkouska1), 0, 0)
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
MyNewSub()
End Sub
Sub MyNewSub()
BackColor = Color.Red
TransparencyKey = BackColor
End Sub
Private Sub Example_ControlAdded(ByVal sender As Object, ByVal e As System.Windows.Forms.ControlEventArgs) Handles Me.ControlAdded
AddHandler e.Control.MouseClick, AddressOf Example_MouseClick
End Sub
Private Sub Example_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
If True Then e.Graphics.DrawImageUnscaled(New Bitmap(_zkouska2), 0, 0) = True
End Sub
End Class
You haven't indicated specifically which lines are causing the issue, but the issue with this line:
If True Then e.Graphics.DrawImageUnscaled(New Bitmap(_zkouska2), 0, 0) = True
is that MouseEventArgs doesn't have a Graphics member. Perhaps the thing to do here is to use the Mouse_Clicked event to set a variable that keeps tracks of whether the mouse was clicked (and where), and use the Paint event to do the actual drawing.
So you would add a boolean variable to the class:
Private _clicked As Boolean
Change the MouseClicked event to something like this:
Private Sub Example_MouseClick(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseClick
_clicked = True
End Sub
Add a Paint event and make that event so it's something like this:
Private Sub Form1_Paint(sender As System.Object, e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
If _clicked Then
e.Graphics.DrawImageUnscaled(New Bitmap(_zkouska2), 0, 0)
End If
End Sub
why does the FileSystemWatcher fire twice? Is there an easy way to fix it? Surely if I update or edit the text file it should only fire once?
this link here http://weblogs.asp.net/ashben/archive/2003/10/14/31773.aspx says
Events being raised twice - An event will be raised twice if an event handler (AddHander FSW.Created, AddressOf FSW_Created) is
explicitly specified. This is because, by default, the public events
automatically call the respective protected methods (OnChanged,
OnCreated, OnDeleted, OnRenamed). To correct this problem, simply
remove the explicit event handler (AddHandler ...).
What does "remove the explicit event handler" mean?
Imports System.IO
Public Class Form2
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
'this fires twice
MessageBox.Show("test")
End Sub
Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test\"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastAccess Or NotifyFilters.LastWrite Or NotifyFilters.FileName Or NotifyFilters.DirectoryName Or NotifyFilters.CreationTime
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "text.txt"
End Sub
End Class
Update:
I have come up with 2 solutions. One uses Threads, and the other doesn't. Take your pick :-).
Without threading:
Imports System.IO
Public Class Form1
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
Dim watcher As System.IO.FileSystemWatcher = sender
watcher.EnableRaisingEvents = False
'Do work here while new events are not being raised.
MessageBox.Show("Test")
watcher.EnableRaisingEvents = True 'Now we can begin watching for new events.
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "test.txt"
End Sub
Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class
This solution (without threading), sets the watcher.EnableRaisingEvents to False. It is after this point where you would normally process whatever files are affected (or changed). It then sets the EnableRaisingEvents back to True after your work is done.
With threading:
Imports System.IO
Public Class Form1
Private Sub FileSystemWatcher1_Changed(ByVal sender As System.Object, ByVal e As System.IO.FileSystemEventArgs) Handles FileSystemWatcher1.Changed
FileSystemWatcher1.EnableRaisingEvents = False
Threading.Thread.Sleep(250)
FileSystemWatcher1.EnableRaisingEvents = True
MessageBox.Show("test")
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
FileSystemWatcher1.Path = "C:\Users\c\Desktop\test"
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Filter = "test.txt"
End Sub
Private Sub FileSystemWatcher_OnChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
End Sub
End Class
This solution, although a bit hacky, does work. It disables checking for new changes/events for 250ms and then re-enables checking, based on the assumption that you won't been needing to check for a change every 250ms. I have tried almost everything that I could think of to get a real solution for you but this will work in the meantime.
Check e.ChangeType. I imagine you're getting two different notifications. Perhaps LastAccess and LastModified. In which case, that's the expected behavior.
Today i crashed in FileSystemWatcher and found this site. Suggested Thread.Sleep cannot completely eliminate problem. Tested with fast counter-integer. And is blocking UI. Most problematic is startup, it sliped trough at 5s. Then i set FileSystemWatcher1.EnableRaisingEvents = False immediately in TimerWatcherChanged.Tick and never enabled again... But surprisingly counter still catch up-to 4 events! I would like to share my solution, non-blocking, with adjustable Timer. Feedback is welcome.
Imports System.IO
Imports System.Diagnostics
Public Class Form1
Dim fileName As String
Dim Fsw_counter As Integer
WithEvents TimerWatcherChanged As New Windows.Forms.Timer
WithEvents TimerTest As New Windows.Forms.Timer
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TimerWatcherChanged.Interval = 100
TimerTest.Interval = 100 : TimerTest.Start()
TextBox1.Text = "C:\Downloads\New Text Document.txt"
TextBox1.SelectionStart = TextBox1.Text.Length
WatcherSetup()
End Sub
Sub WatcherSetup()
fileName = TextBox1.Text
FileSystemWatcher1.IncludeSubdirectories = False
FileSystemWatcher1.Path = Path.GetDirectoryName(fileName)
FileSystemWatcher1.Filter = Path.GetFileName(fileName)
FileSystemWatcher1.NotifyFilter = NotifyFilters.LastWrite
FileSystemWatcher1.EnableRaisingEvents = True
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
WatcherSetup()
End Sub
Private Sub FileSystemWatcher1_Changed(sender As Object, e As FileSystemEventArgs) Handles FileSystemWatcher1.Changed
If TimerWatcherChanged.Enabled = False Then
TimerWatcherChanged.Enabled = True
Fsw_counter += 1
' ***** Your WATCH Code put here... *****
End If
End Sub
Private Sub TimerWatcherChanged_Tick(sender As Object, e As EventArgs) Handles TimerWatcherChanged.Tick
TimerWatcherChanged.Enabled = False
End Sub
Private Sub TimerTest_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles TimerTest.Tick
TextBox2.Text = "Changed: " & Fsw_counter
If TimerWatcherChanged.Enabled = True Then
TextBox2.BackColor = Color.Red
Else
TextBox2.BackColor = Color.LawnGreen
End If
End Sub
End Class
A few weeks ago I wrote a wrapper for the ServiceController control to enhance and streamline the base ServiceController. One of the changes I made was to add a monitoring component using the System.Threading.Timer object. On any change of status, an event is raised to the parent class. The actual monitoring works fine, but when the event is handled in the main form, my program abruptly ends - no exceptions, no warning, it just quits. Here's a skeleton version of the control:
Public Class EnhancedServiceController
Inherits ServiceController
Public Event Stopped(ByVal sender As Object, ByVal e As System.EventArgs)
Public Event Started(ByVal sender As Object, ByVal e As System.EventArgs)
Private _LastStatus As System.ServiceProcess.ServiceControllerStatus
Private serviceCheckTimer as System.Threading.Timer
Private serviceCheckTimerDelegate as System.Threading.TimerCallback
...
Private Sub StartMonitor()
MyBase.Refresh()
_LastStatus = MyBase.Status
serviceCheckTimerDelegate = New System.Threading.TimerCallback(AddressOf CheckStatus)
serviceCheckTimer = New System.Threading.Timer(serviceCheckTimerDelegate, Nothing, 0, 60*1000)
End Sub
Private Sub CheckStatus()
MyBase.Refresh()
Dim s As Integer = MyBase.Status
Select Case s
Case ServiceControllerStatus.Stopped
If Not s = _LastStatus Then
RaiseEvent Stopped(Me, New System.EventArgs)
End If
Case ServiceControllerStatus.Running
If Not s = _LastStatus Then
RaiseEvent Started(Me, New System.EventArgs)
End If
End Select
_LastStatus = s
End Sub
End Class
And the form:
Public Class Form1
Private Sub ServiceStarted(ByVal sender As Object, ByVal e As System.EventArgs) Handles ESC.Started
Me.TextBox1.Text = "STARTED"
End Sub
Private Sub ServiceStopped(ByVal sender As Object, ByVal e As System.EventArgs) Handles ESC.Stopped
Me.TextBox1.Text = "STOPPED"
End Sub
End Class
If I had to guess, I'd say that there's some sort of thread problem, but I'm not sure how to handle that in the form. Any ideas?
IF it is a threading issue then you are probably trying to update the UI from a non-UI thread.
So something like this should solve that...
Private Delegate Sub UpdateTextBoxDelegate(byval tText as String)
Private Sub UpdateTextBox(byval tText As String)
If Me.InvokeRequired Then
Me.Invoke(New UpdateTextBoxDelegate(AddressOf UpdateTextBox), tText)
Exit Sub
End If
TextBox1.Text = tText
End Sub
Private Sub ServiceStarted(ByVal sender As Object, ByVal e As System.EventArgs) Handles ESC.Started
UpdateTextBox ("STARTED")
End Sub
Private Sub ServiceStopped(ByVal sender As Object, ByVal e As System.EventArgs) Handles ESC.Stopped
UpdateTextBox("STOPPED")
End Sub