I have a small media player application I've programmed which works really well.
I've even managed an on screen remote control (obviously just a Form with Buttons made to look like a virtual remote control) and yes I've also integrated an Arduino to be able to use a real remote control, but forget the Arduino remote control just for now my question is about the Virtual remote control I'm trying to build.
Programming a Button is quite elementary: it's one of the first things we learn in Vb.net, but that's just in a single click scenario.
If I look at a real TV remote, I can either click (most common with volume buttons) the volume up or down and the response is either that the volume goes up or down by one unit, or I can hold the same button down and it repeats the process changing the unit several times up or down depending on how long before I release the button again.
How would I achieve this?
I have tried googling this but everything I get back as a search result talks about a physical mouse button as apposed to what I need which is a Button control.
An example of an UserControl that provides the functionality of Up/Down spin buttons.
It uses two standard Buttons, a Label and a Timer.
To set it up, add a new UserControl to the Project:
Set its BackColor to Color.Transparent
Add two Buttons, select both and add event handlers to the MouseDown, MouseUp, KeyDown and KeyUp events (selecting both, you'll add 4 method)
Two Unicode chars (U+25B2 and U+25BC) are used to show the arrows. Setup the Buttons' Font size and Color as required (the sample UC uses Segoe UI as Font).
Anchor the upper Button to Left/Top/Right
Anchor the lower Button to Left/Bottom/Right
Anchor the Label to Left/Right
A Timer is created in the UC constructor, its Interval value set to 300. This value represents the initial speed of the increment when a mouse Button or keyboard key is held down. It's decremented each time the Timer ticks until it reaches a threshold defined by the UC's Speed public property (which is internally limited to the (1:10) range).
The maximum and minimum increment are defined by the UC's Min and Max public properties
The Value public property gets or sets the current increment.
The Timer is started when a Mouse Button or a Keyboard key are pressed and stopped when they're released. When the Timer.Tick event is raised, the Timer.Interval is decreased by 25ms until the max Speed value is reached. Since the initial value is set to 300ms and the maximum Speed is limited to 10, the minimum Interval value is 50ms, which is close to the System.Windows.Form.Timer official resolution.
The minimum Interval needs to be considered if these values are changed, to avoid overlapping Tick events.
This is how it works:
Imports System.Windows.Forms
Public Class SpinButtons
Private buttonsTimer As Timer = Nothing
Private timerThrottle As Integer = 0
Private timerIncrement As Integer = 0
Private m_Speed As Integer = 10
Private m_Value As Integer = 0
Public Sub New()
InitializeComponent()
Me.components = New System.ComponentModel.Container()
buttonsTimer = New Timer With {.Interval = 300}
Me.components.Add(buttonsTimer)
End Sub
Public Property Max As Integer = 100
Public Property Min As Integer = 0
Public Property Speed As Integer
Get
Return m_Speed
End Get
Set
m_Speed = Math.Max(Math.Min(Value, 10), 1)
End Set
End Property
Public Property Value As Integer
Get
Return m_Value
End Get
Set
m_Value = Value
SetIncrementValue()
End Set
End Property
Private Sub buttonsTimer_Tick(sender As Object, e As EventArgs)
SetIncrementValue()
If timerThrottle <= m_Speed Then
timerThrottle += 1
buttonsTimer.Interval -= 25
End If
End Sub
Private Sub btnUp_MouseDown(sender As Object, e As MouseEventArgs) Handles btnUp.MouseDown, btnDown.MouseDown
ButtonPressed(DirectCast(sender, Button))
SetIncrementValue()
End Sub
Private Sub btnUp_MouseUp(sender As Object, e As MouseEventArgs) Handles btnUp.MouseUp, btnDown.MouseUp
ButtonReleased(DirectCast(sender, Button))
End Sub
Private Sub btnUp_KeyDown(sender As Object, e As KeyEventArgs) Handles btnUp.KeyDown, btnDown.KeyDown
ButtonPressed(DirectCast(sender, Button))
SetIncrementValue()
End Sub
Private Sub btnUp_KeyUp(sender As Object, e As KeyEventArgs) Handles btnUp.KeyUp, btnDown.KeyUp
ButtonReleased(DirectCast(sender, Button))
End Sub
Private Sub SetIncrementValue()
m_Value += timerIncrement
m_Value = Math.Max(Math.Min(m_Value, Max), Min)
lblCounter.Text = m_Value.ToString()
End Sub
Private Sub ButtonPressed(btn As Button)
btn.ForeColor = Color.LawnGreen
timerIncrement = If(btn Is btnUp, 1, -1)
buttonsTimer.Enabled = True
End Sub
Private Sub ButtonReleased(btn As Button)
buttonsTimer.Enabled = False
buttonsTimer.Interval = 300
timerThrottle = 0
timerIncrement = 0
btn.ForeColor = Color.White
End Sub
Protected Overrides Sub OnFontChanged(e As EventArgs)
MyBase.OnFontChanged(e)
Me.btnUp.Font = Me.Font
Me.btnDown.Font = Me.Font
End Sub
Protected Overrides Sub OnResize(e As EventArgs)
MyBase.OnResize(e)
Me.MinimumSize = New Size(CInt(Me.Font.Size * 2), Me.btnUp.Height + Me.btnDown.Height + lblCounter.Height)
End Sub
End Class
Related
I have a NumericUpDown whose minimum value is set to 1 and its maximum is 64. I have to increment it, from 1 to 64, using the values of the power of 2, so it must be 1, 2, 4, 8, 16, 32, 64.
I've tried several ways to change the NUD increment but with no satisfying results.
How could I solve this issue?
I suggest to use a Custom Control derived from NumericUpDown, so you can handle internally the value changed events that are generated by different possible actions: click the Up/Down Buttons, spin the MouseWheel, enter a number manually, data bindings etc.
The OnValueChanged method override has the last word: if a value submitted doesn't meet the criteria (being a power of two in the specified range), the number is changed to the nearest (higher) valid value.
The OnMouseWheel override just calls the corresponding method based on the positive or negative value of the Delta.
► Requires Option Infer On or small changes
Imports System.ComponentModel
Imports System.Windows.Forms
<DesignerCategory("Code")>
Public Class NumericUpDownPow2
Inherits NumericUpDown
Public Sub New()
Me.Maximum = 64
Me.Minimum = 1
End Sub
Public Overrides Sub UpButton()
Value = Math.Min(Value * 2, Maximum)
End Sub
Public Overrides Sub DownButton()
Value = Math.Max((Value / 2), Minimum)
End Sub
Protected Overrides Sub OnMouseWheel(e As MouseEventArgs)
Call If(e.Delta > 0, Sub() UpButton(), Sub() DownButton())
DirectCast(e, HandledMouseEventArgs).Handled = True
MyBase.OnMouseWheel(e)
End Sub
Protected Overrides Sub OnValueChanged(e As EventArgs)
Dim nearest = CDec(Math.Round(2 ^ Math.Ceiling(Math.Log(Value, 2))))
Value = Math.Max(Math.Min(nearest, Maximum), Minimum)
MyBase.OnValueChanged(e)
End Sub
End Class
If you reduce the size of the text portion of the NumericUpDown control so it is not visible, you can put a read-only TextBox right next to it so it looks like it is part of it, then...
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
Dim nud = DirectCast(sender, NumericUpDown)
tbForNud1.Text = (2 ^ nud.Value).ToString()
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
tbForNud1.ReadOnly = True
tbForNud1.Text = "1"
End Sub
You might want to change the colour of the border of the TextBox: Change the borderColor of the TextBox.
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
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
I am trying to create a timer that will countdown from the specified time.
The user enters a time and clicks a button.
The button click opens a second form that has a timer in it.
Every time the timer ticks, the time decreases and the time left is displayed in a textbox on form2 (textbox.text = timeLeft).
However, the textbox will never actually update. It remains blank, and the only time that assigning a new value to the .text property will actually work is if I raise an event (for example clicking a button that will change the .text property of the textbox)
*Here is the code for the timer class
Public Class CountdownTimer
Private timeAtStart As Integer
Private timeLeft As Integer
Public Sub StartTimer(ByVal time As Integer)
timeAtStart = time
timeLeft = timeAtStart
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
If timeLeft > 0 Then
timeLeft = timeLeft - 1
txtTimeLeft.Text = timeLeft.ToString
Else
Timer1.Stop()
txtTimeRemaining.Text = "Time!"
txtTimeRemaining.ForeColor = Color.Red
End If
End Sub
End Class
And here is how I call it:
Dim timer As New CountdownTimer
timer.Show()
CountdownTimer.StartTimer(CInt(txtSetTime.Text))
Your code is calling the (form) class not the instance, and I cant see where Timer1 is properly referenced for an independant reusable class. Here is one way to implement a CountDown class that will work with other forms....
Friend Class CountdownTimer
Private timeAtStart As Integer
Private timeLeft As Integer
Private WithEvents Timer1 As New Timer
Private txtTimeLeft as TextBox
Public Sub New(TargetTB as TextBox)
txtTimeLeft= TargetTB
End Sub
Public Sub StartTimer(ByVal time As Integer, timeLength as Integer)
timeAtStart = time
timeLeft = timeLength
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs)_
Handles Timer1.Tick
' just dislaying time left
If timeLeft > 0 Then
timeLeft = timeLeft - 1
txtTimeLeft.Text = timeLeft.ToString
Else
Timer1.Stop()
txtTimeLeft.Text = "Time!"
txtTimeLeft.ForeColor = Color.Red
End If
End Sub
End Class
How to use it:
Dim CountDn As New CountdownTimer(frm.TextBoxToUse)
' use the INSTANCE name not the class name!!!!
'CountdownTimer.StartTimer(CInt(txtSetTime.Text))
CountDn.StartTimer(CInt(txtSetTime.Text))
If it displays the result after the timer has completed, i think you should use the
Application.DoEvents()
method to see the update immediately. It actually works with Windows Forms. What have you tried, so i can help further
You do realize that when you are counting down you are setting a different textbox than when it is complete, right?
txtTimeLeft.Text
VS
txtTimeRemaining.Text
Note: Timers run on the same thread as the UI so if you computer (or program) gets busy, the timer will NOT tick at exact intervals. If you are worried about small variances in your timer, you should compare the difference of your computer time during each tick event to determine how much time had passed.
Dim TS = TimeSpan = Now.Subtract(StartingTime)
Try refreshing the text boxes after each update:
So after
txtTimeLeft.Text = timeLeft.ToString
Add
txtTimeLeft.Refresh
This is your problem:
Dim timer As New CountdownTimer
timer.Show()
CountdownTimer.StartTimer(CInt(txtSetTime.Text))
You instantiate a new object called timer, but then start the timer on the CountdownTimer object
You need to change your code to this:
Dim timer As New CountdownTimer
timer.Show()
timer.StartTimer(CInt(txtSetTime.Text))
If I have a winform, may I know how can I control the zoom level of the font in the application (as well as the application window itself obviously) by using Ctrl + Mouse Scroll Wheel? I see there is a Delta in the Scroll Wheel event, but not sure how that works. Is there any code sample that I can look into?
I suspect that you can just test:
(VB.NET):
If (ModifierKeys And Keys.Control) = Keys.Control Then
(C#):
if( (ModifierKeys & Keys.Control) == Keys.Control )
to check if the control key is down.
You'll have to handle the KeyDown and KeyUp event in order to determine whether or not Ctrl key is being held down. This value should be stored at class-level because it will be used by other subroutines besides the KeyDown and KeyUp events.
You then write code to handle the form's MouseWheel event. Scrolling downwards (towards you) causes a negative value for the Delta property of the MouseEventArgs. Scrolling upwards is obviously the reverse. The value of the Delta property is always currently 120.
Microsoft's reason for this value is as follows:
Currently, a value of 120 is the standard for one detent. If higher resolution mice are introduced, the definition of WHEEL_DELTA might become smaller. Most applications should check for a positive or negative value rather than an aggregate total.
In your context you'll just check for the sign of the Delta and perform an action.
Here is a sample code implementing basic 'zoom' functionality:
Public Class Form1
Enum ZoomDirection
None
Up
Down
End Enum
Dim CtrlIsDown As Boolean
Dim ZoomValue As Integer
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
ZoomValue = 100
End Sub
Private Sub Form1_KeyDown_KeyUp(ByVal sender As Object, _
ByVal e As KeyEventArgs) _
Handles Me.KeyDown, Me.KeyUp
CtrlIsDown = e.Control
End Sub
Private Sub Form1_MouseWheel(ByVal sender As Object,
ByVal e As MouseEventArgs) _
Handles Me.MouseWheel
'check if control is being held down
If CtrlIsDown Then
'evaluate the delta's sign and call the appropriate zoom command
Select Case Math.Sign(e.Delta)
Case Is < 0
Zoom(ZoomDirection.Down)
Case Is > 0
Zoom(ZoomDirection.Up)
Case Else
Zoom(ZoomDirection.None)
End Select
End If
End Sub
Private Sub Zoom(ByVal direction As ZoomDirection)
'change the zoom value based on the direction passed
Select Case direction
Case ZoomDirection.Up
ZoomValue += 1
Case ZoomDirection.Down
ZoomValue -= 1
Case Else
'do nothing
End Select
Me.Text = ZoomValue.ToString()
End Sub
End Class
Read on the following for more information about your question:
MSDN: Control.KeyDown Event
MSDN: Control.KeyUp Event
MSDN: Control.MouseWheel Event
MSDN: MouseEventArgs Class
For CrystalReportViewer1
Just put CrystalReportViewer1.Zoom(ZoomValue)
instead of the line Me.Text = ZoomValue.ToString() in the Sub Zoom