The Eng
The Eng

Reputation: 39

NumericUpDown that only allows a range of values of the power of two

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?

Upvotes: 1

Views: 323

Answers (2)

Jimi
Jimi

Reputation: 32223

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

Upvotes: 2

Andrew Morton
Andrew Morton

Reputation: 25013

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.

Upvotes: 0

Related Questions