How do I prevent mouse wheel from incrementing numericupdown without over loading?
I had previously inherited numericupdwon to overload the MouseWheel event with an empty event. This worked for a while, but something happened when I switched to x64 that made the whole inherited class periodically show not found. Not sure because even if I switched back to x86 it was still a problem.
This worked for me..
Private Sub NumericUpDown1_MouseWheel(sender As Object, e As MouseEventArgs) Handles NumericUpDown1.MouseWheel
Dim MW As HandledMouseEventArgs = CType(e, HandledMouseEventArgs)
MW.Handled = True
End Sub
That HandledMouseEventArgs usage does look weird though.. but it works.
https://msdn.microsoft.com/en-us/library/system.windows.forms.handledmouseeventargs(v=vs.110).aspx
I came up with a different solution, using the following code to prevent the increment
Private Sub nup_cores_MouseWheel(sender As Object, e As MouseEventArgs) Handles nup_cores.MouseWheel
nup_cores.Increment = 0
End Sub
And then change it back. In the specific case of a numericupdown, the cursor blinking seems to trigger gotfocus. The same principle could be applied with a short duration timer
Private Sub nup_cores_GotFocus(sender As Object, e As EventArgs) Handles nup_cores.GotFocus
nup_cores.Increment = 1
End Sub
For C#:
For some reason the MouseWheel doesn't show up in the list of events from the GUI. So I had to programmatically add the event in my form load. In the MouseWheel event I do something similar as the above selected answer (but a little different).
private void Form1_Load(object sender, EventArgs e)
{
numericUpDownX.MouseWheel += new MouseEventHandler(handle_MouseWheel);
}
void handle_MouseWheel(object sender, MouseEventArgs e)
{
((HandledMouseEventArgs)e).Handled = true;
}
Related
I am trying to create a VB.net form where the user can click on a button and it is associated with a specific image and when the user clicks the image and then clicks select it will add it to a variable.
If you need more information please let me know (this is the image of my form)
I wanted to know:
how to assign an image to a button ( so when you click it, it means that the user wants that image) I am not sure if my method is correct
how to assign the image that was selected to a variable (so that once the variable is called it will output the image)
and how to end the form once the image is selected. (once use clicks the select button it should end the form, or if the user clicks cancel it should end the form).
Public Class Form1
Private Property SelectedPictureBox() As Image
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Controls.OfType(Of ButtonPictureBox).ToList().ForEach(
Sub(box)
AddHandler box.Click, AddressOf AllButton_Click
End Sub)
End Sub
Private Sub AllButton_Click(sender As Object, e As EventArgs)
SelectedPictureBox = CType(sender, ButtonPictureBox).PictureBox
End Sub
Private Sub GetBtnSelect_Click(sender As Object, e As EventArgs) Handles GetBtnSelect.Click
If SelectedPictureBox IsNot Nothing Then
MessageBox.Show(SelectedPictureBox.Name)
Else
MessageBox.Show("Please select an image")
End If
End Sub
Private Sub BtnTropicalFloral_Click(sender As Object, e As EventArgs) Handles BtnTropicalFloral.Click
SelectedPictureBox = PictureBoxTropicalFloral.Image
End Sub
Private Sub BtnLightGeode_Click(sender As Object, e As EventArgs) Handles BtnLightGeode.Click
SelectedPictureBox = PictureBoxLightGeode.Image
End Sub
Private Sub BtnStripes_Click(sender As Object, e As EventArgs) Handles BtnStripes.Click
SelectedPictureBox = PictureBoxStripes.Image
End Sub
Private Sub BtnAuroraBorealis_Click(sender As Object, e As EventArgs) Handles BtnAuroraBorealis.Click
SelectedPictureBox = PictureBoxAuroraBorealis.Image
End Sub
Private Sub BtnDiagonals_Click(sender As Object, e As EventArgs) Handles BtnDiagonals.Click
SelectedPictureBox = PictureBoxDiagonals.Image
End Sub
Private Sub BtnComb_Click(sender As Object, e As EventArgs) Handles BtnComb.Click
SelectedPictureBox = PictureBoxComb.Image
End Sub
Private Sub BtnMountain_Click(sender As Object, e As EventArgs) Handles BtnMountain.Click
SelectedPictureBox = PictureBoxMountain.Image
End Sub
Private Sub BtnLandscape_Click(sender As Object, e As EventArgs) Handles BtnLandscape.Click
SelectedPictureBox = PictureBoxLandscape.Image
End Sub
Private Sub BtnGradient_Click(sender As Object, e As EventArgs) Handles BtnGradient.Click
SelectedPictureBox = PictureBoxGradient.Image
End Sub
Private Sub BtnAbstract_Click(sender As Object, e As EventArgs) Handles BtnAbstract.Click
SelectedPictureBox = PictureBoxAbstract.Image
End Sub
Private Sub BtnGeode_Click(sender As Object, e As EventArgs) Handles BtnGeode.Click
SelectedPictureBox = PictureBoxGeode.Image
End Sub
End Class
My VB is a bit rusty, so I'll have to give the answer in C#. I'm sure you'll get the gist, and will be able to translate it into VB.
First of all: whenever you see that you are repeating things, for instance by copy-paste, you should stop, and rethink your design: maybe it would be better to create a method for this, or an object.
All your PictureBox/Button combinations have some common behavior. This means that you should think of creating a class for it.
In your case, you have the combination of a Button and a PictureBox. You want to be able to set and get an Image. The PictureBox will show this image. Finally you want to be notified if the operator clicks the Button.
In the event handler of this Notification you want to know which pictureBox/Button combination sent the event. You get the image from this combination and close the form.
In WinForms, whenever you want to have a class that is a combination of several controls, you make a UserControl.
In Visual Studio, in the solution control, right click on the project (not the solution!) and select: Add new Item. Select to add a new User Control. Think of a proper name, I'll call this ImageSelectionControl
Use the visual studio designer to give ImageSelectionControl the proper size. Add a PictureBox and a Button. Also use the visual studio designer to add an EventHandler for if the operator clicks the button.
In the code of the User Control add the property to Set / Get an Image. The Image that you set will be displayed in the PictureBox; the Image that you get is the image that is displayed in the PictureBox.
Here comes the first chunk of C#:
public Image Image
{
get => this.pictureBox1.Image;
set => this.pictureBox1.Image = value;
}
I think in VB this will be very similar.
Now you want that users of your control (= software, not humanoids) get notified that the operator selects an image. Officially, you even want to hide how the operator selected this image: all you want to say: "Hey, the operator selected my image!"
Normally you would do this using an event:
The 2nd piece of C#:
public event EventHandler ImageSelected;
The event won't have any data. It will only say: "Hey, the operator selected my image!". The event event handler will have to find out which user control raised the event, and fetch the image.
Ok, raise the event:
private void OnImageSelected()
{
this.ImageSelected?.Invoke(this, EventArgs.Empty);
}
It will be a bit more difficult to translate this into VB. What it does, it checks if there is at least one person who wants my events. If so it raises the event. with two parameters: the sender (which is me), and no parameters. Later we will see how the receiver of the event works.
Finally: if the operator clicks the button, he indicates that he wants to select the image in the user control, and thus OnImageSelected needs to be called
private void ButtonSelect_Clicked(object sender, EventArgs e)
{
this.OnImageSelected();
}
We've finished creating the UserControl. After Compilation you will find it in visual studio designer toolbox.
So we'll go to the form that will have to display the eleven PictureBox-Button combinations. Let's call this form: ImageSelectionForm.
Using Visual Studio Designer, add 11 ImageSelectionControls. If you know already at design time which control will show which image, you can do this in the designer, similarly to how you set the text or the background of a button.
If you only know at run-time which control should show which image, consider to add a method, for instance if you want to load it from file:
void ShowImage(ImageSelectionControl imageSelectionControl, string imageFileName)
{
Image image = this.LoadImageFromFile(imageFileName);
this.imageSelectionControl.Image = image;
}
Or maybe you have a different method to decide which ImageSelectionControl should displaye which image. I guess you get the gist.
Almost done. ImageSelectionForm needs to be notified about the selected image, so just like you would do with a button, you need to subscribe to event ImageSelected.
In the constructor or ImageSelectionForm, subscribe to the events:
private ImageSelectionForm()
{
InitializeComponent();
// subscribe to events
this.controlBlueGeod.ImageSelected += this.ImageSelected;
this.controlAbstract.ImageSelected += this.ImageSelected;
...
}
Of course, you can put all ImageSelectionControls in one list and use foreach to subscribe (that is too much VB for me, no idea how to do this)
The event handler:
void ImageSelected(object sender, EventArgs e)
{
// we know that the sender is the one that holds the selected images:
ImageSelectionControl imageSelectionControl = (ImageSelectionControl)sender;
We will be closiing the form very soon, so we will have to remember this selected image somewhere in a property:
public Image SelectedImage {get; set;}
So continuing the event handler:
this.SelectedImage = imageSelectionControl.Image;
this.DialogResult = DialogResult.OK;
this.Close();
}
So the selected image is saved. The dialog result is set to indicate that an image was selected, not cancel clicked. And the form is closed.
Showing the form and process the selected image
The form that has to show ImageSelectionForm has a procedure:
private void ShowImageSelectionForm()
{
using (ImageSelectionForm dialog = new ImageSelectionForm())
{
// show the dialog and process the result:
DialogResult dlgResult = dialog.ShowDialog(this);
if (dlgResult == DialogResult.OK)
{
this.ProcessSelectedImage(dialog.SelectedImage);
}
else
{
// TODO: process cancel
}
}
}
There is one memory leak: if you created a lot of images, all images need to be Disposed after usage. Best is to by overriding Component.Dispos(bool)
ImageSelectionControl:
protected override Dispose (bool disposing)
{
if (disposing && this.Image != null)
{
this.Image.Dispose();
}
}
ImageSelectionForm:
protected override Dispose (bool disposing)
{
if (disposing)
{
this.controlBlueGeod.Dispose();
this.controlAbstract.Dispose();
...
}
}
This is quite a nuisance for 11 controls. Therefore quite often a Form or a UserControl has a System.ComponentModel.IContainer components. If you add your ImageSelectionControls to this container, then the ImageSelectionControls will be automatically disposed when ImageSelectionForm is disposed.
You have two Controls that work together to allow users to preview and select one or more Images in the UI. When you have this kind of scenario, build a UserControl that contains all the required UI elements and the logic used perform this action.
To build this UserControl:
Open the Project menu and select Add User Control...
Right away, set (in this order):
AutoScaleMode = Dpi
Font = Segoe UI, 9pt
BackColor = Color.Transparent
Set a Size that you think is the minimum required to show an Image and a Button
When you have found the right size, set also the MinimumSize to this value
Add a Button to the UC, configure it as needed, set its Width as the Width of the UC minus 4 pixels. Position the Button at the bottom of UC, 2 pixels to the left and set Anchor = Bottom, Left, Right
Add a PictureBox, same Width and Left location as the Button. Set the Height as required, then Anchor = Top, Bottom, Left, Right
Design completed. Build the Project.
Now, your UserControl needs to provide means to set an Image to the PictureBox and the Text of the Button.
You can add two Public Properties of Type Image and String that, when a value is assigned, set the PicureBox.Image property and the Button.Text property.
Also, when the Button is clicked, the UserControl needs to notify that the User has performed a selection, so whatever other code needs to do something with this information, will be able to act on it.
In an event-driven UI, you make your UC raise a public event that interested parties can subscribed to, to receive a notification that something happened.
You just need to define a Field of Type Event and give it a name. In this case, e.g.:
Public Event ImageSelection As EventHandler
When the Button is clicked, you raise the event:
RaiseEvent ImageSelection(Me, EventArgs.Empty)
The sample UserControl is named ImagePicker, the PictureBox is named picImage and the Button is btnSelectImage
Public Class ImagePicker
Public Event ImageSelection As EventHandler
Private m_Picture As Image = Nothing
Private m_Title As String
Public Property Picture As Image
Get
Return m_Picture
End Get
Set
m_Picture = Value
picImage.Image = m_Picture
End Set
End Property
Public Property Title As String
Get
Return m_Title
End Get
Set
m_Title = Value
btnSelectImage.Text = m_Title
End Set
End Property
Private Sub btnSelectImage_Click(sender As Object, e As EventArgs) Handles btnSelectImage.Click
RaiseEvent ImageSelection(Me, EventArgs.Empty)
End Sub
End Sub
In your Form (for example), you can the subscribe to this event to receive a notification that the User has selected the Image of one of your UserControls.
When the event is raised, the sender object is the UserControl that raised the event. You can then cast sender to your UserControl Type and read the Public Property that references the Image you have assigned to it.
In a Form, you can add some of your UserControls to a FlowLayoutPanel (in the example, named flpPreviews), which will take care of the layout of these Controls.
While adding the UserControls, you set their Public Properties and also subscribe to the Public event.
When the event is raised, cast sender to ImagePicker and read its public Picture property to get the reference of the Image selected:
Public Class SomeForm
Public Sub New()
InitializeComponent()
' Add three ImagePicker UserControls to a FlowLayoutPanel
For i As Integer = 0 To 2
Dim picker = New ImagePicker()
picker.Picture = [Some Image]
picker.Title = "Some Title"
' Subscribe to the event
AddHandler picker.ImageSelection, AddressOf ImageSelectionChanged
flpPreviews.Controls.Add(picker)
Next
End Sub
Private Property SelectedImage As Image
Private Sub ImageSelectionChanged(sender As Object, e As EventArgs)
SelectedImage = DirectCast(sender, ImagePicker).Picture
' Show the selected Image in a PictureBox, child of the Form
picSelected.Image = SelectedImage
End Sub
End Class
I am reworking old application built in VB6, with VB.NET and Visual Studio 2005.
It has one large form with like 50-60 text boxes, each with 2-3 event handlers, click, validating, keydown, enter etc...
The person who built this application didn't pay attention to keep good structure, so now the code file for the form is almost 2900 lines of code.
It has 3-4 important functions, other functions are just event handlers.
The problem is, each of those event handlers are defined as private and refer to objects/textboxes which exist only in the form code file.
What would be the right approach to move those event handlers to separate files?
Here is a sample code which I failed to move to separate file since I am noob VB.NET programmer:
Imports System.Windows.Forms
Public Class Pol
Private cboPol As MaskedTextBox = New MaskedTextBox()
Private Sub cboPol_Enter(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) 'Handles cboPol.Enter
' TODO ova beshe zakomentirano. Da se proveri
'meGodrag.SelStart = 0
' meGodrag.SelLength = 4
'grstar = meGodrag.Text
End Sub
Private Sub cboPol_KeyDown(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyEventArgs) 'Handles cboPol.KeyDown
Dim KeyCode As Short = eventArgs.KeyCode
Dim Shift As Short = eventArgs.KeyData \ &H10000
If KeyCode = Constants.LEFT_ARROW_KEY Then
'meNasmes.Focus()
End If
End Sub
Private Sub cboPol_KeyPress(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyPressEventArgs) 'Handles cboPol.KeyPress
Dim KeyAscii As Short = Asc(eventArgs.KeyChar)
'If KeyAscii = Constants.ENTER_KEY Then
System.Windows.Forms.SendKeys.Send(Constants.TAB_KEY)
'End If
eventArgs.KeyChar = Chr(KeyAscii)
If KeyAscii = 0 Then
eventArgs.Handled = True
End If
End Sub
End Class
The simplest approach to divide your mega-class in small parts is through the use of the concept of Partial class
Just create a new class file and name it as your big form class but add the keyword Partial before both classes. Now you can move all your event handlers to the second file freeing your main form from this stuff
See MSDN on How to split a class into partial classes
On a more structural solution you can check if it is possibile to create an unique event handler for the same event and force your controls to use the same event handler.
For example, if the action on the KeyDown event is the same for all controls then you can write a single event handler and tell your controls to use it
Private Sub allControls_KeyDown(ByVal eventSender As System.Object, ByVal eventArgs As System.Windows.Forms.KeyEventArgs)
Handles cboPol.KeyDown, cboXXXX.KeyDown, cboYYYY.KeyDown etc.....
Or, if you find this approach too 'verbose', just use the Winforms designer to select the same event handler for all controls
If the sample code you posted is indicative, it is possible a lot of the code is just for navigating the form.
You might be able to remove most of it by setting your tab order correctly.
For special navigation keys (e.g. left arrow key does something special, or you want the ENTER key to move to the next control like the TAB key), try setting Form.KeyPreview = True and having form-wide KeyUp/KeyDown/KeyPress routines.
I want to make a public sub in my module to to store a repeating procedure. Specifically key press events.
Private Sub txtPass_KeyPress(sender As Object, e As KeyPressEventArgs) _
Handles txtPass.KeyPress
FunctionKeys(Me, sender, e)
End Sub
Public Sub FunctionKeys(form as object, sender as object, _
e as KeyPressEventArgs)
With form
If e.KeyChar = ChrW(Keys.Enter) Then .btnOk_Click(sender, e)
If e.KeyChar = ChrW(Keys.Escape) Then .btnClose_Click(sender, e)
end with
End sub
I guess it would look something like this. Unfortunately, this tells me it can't find a public sub for formname.btnok_click etc. I want to know if there's a way around this. Looking around the net I found I can use the AcceptButton and CancelButton property. But only if i actually have a button to press. My MDI does not have buttons. Just menu. Also, I'm aware I can use formname.close() for the Keys.Escape. But I'd still have a problem with the OK button.
You can make btnOk_Click and btnClose_Click public on all your forms and that'll work.
i have a couple of questions about my basic project
if i have a check box and when its checked, it is going to a text box which is displaying the price, when i uncheck it my price still says in that text box, how can i make it dissapear as i uncheck the box?
Dim total As Double
If rb_s1.Checked = True Then
total += 650.0
txt_1.Text = total
thats my code.
and i have many combo boxes, how can i make them all add up as i check/uncheck them.
I would add this functionality into the CheckBox_Changed event handler. This way you can tell if it is unchecked or checked and add or subtract the value from price.
Private Sub CheckBox1_CheckedChanged(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
If CheckBox1.Checked Then
total += 650.00
Else
total -= 650.00
End If
TextBox1.Text = total.ToString()
End Sub
You have to use Checked_Changed event of checkbox.
SHARED void CheckBox1_CheckedChanged(object sender, EventArgs e)
IF ChkBx.Checked = true then
textBox1.text = "1500"
else
textBox1.text = ""
END IF
END SUB
To get your displayed text to change when the state of your checkbox changes, you'll need to handle the CheckedChanged event. In Visual Studio while in Desginer mode for your form/control, you can select the check box control, and then in the Properties window, select the Events tab (the one with the little lightingbolt icon), and double click the CheckChanged event to stub in an event handler method AND attach the event to the handler.
ETA: I re-reading this, I'm not sure how clear I was. When I mentioned stubbing in the event handler and attaching the event to the handler, I meant that going the route of double-clicking the event in the designer will do this for you.
As an aside, it sounds like you want the text to be a sum of only the checked items, so from an architechtueral sense, I would recommend creating a single method to determine the sum, and have all check-box check events invoke that method rather than trying to make the event handler method itself do too much directly (maybe that was already clear to you).
So you might do something like this:
Public Class Form1
Private Sub DisplayTotal()
Dim total As Decimal = 0
If (CheckBox1.Checked) Then
total += Decimal.Parse(txtItem1.Text)
End If
'Add other items
txtTotal.Text = total
End If
End Sub
Private Sub CheckBox1_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBox1.CheckedChanged
DisplayTotal()
End Sub
Private Sub CheckBox2_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBox1.CheckedChanged
DisplayTotal()
End Sub
End Class
I got this timer tick function:
Private Sub controlTick(ByVal sender As Object, ByVal e As EventArgs)
Label2.Text = (Control.ModifierKeys = Keys.Control)
End Sub
That is supposed to make my label say "True" if I am currently holding down the Control key, and "False" if I am not.
But, how come my label is always "False"? What is interesting is that if I press the Control key at lighting speed a bunch of times I can see for a fraction of a second "True", but immediately turns to "False".
Timer ticks every 50ms.
I do not understand.... any ideas?
I can't reproduce the behavior you describe... I tried creating a new WinForms project, placed a Label control on the middle of the form, and added a Timer control.
Whenever I press the Ctrl key, the label reads True. Otherwise, it reads False. Exactly the behavior you would expect to see. I don't have to press anything at lightning speed.
(Edit: It doesn't break when more controls are placed on the form either. What are you doing differently?)
My code looks like this:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
' Start the timer
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' Update the label
Label1.Text = (Control.ModifierKeys = Keys.Control).ToString
End Sub
Only difference is that you're apparently compiling without type checking enabled (Option Strict Off).
I always prefer to code in VB.NET with this turned on (check your project's Properties window), in which case you have to explicitly convert the boolean type to a string type using ToString.
I have created a winform application to prove this.. I am using the form and I have set the "KeyPreview" property to true and for every key pressed I get the code correctly.
Please check again using the way I mentioned and let me know if it resolves.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
MessageBox.Show(e.KeyCode.ToString());
}
Also for Control key the code is (e.KeyCode == Keys.ControlKey)....
I'm not sure this will help, but try using HasFlag, because maybe there is some other flag in ModifierKeys which is also on:
http://msdn.microsoft.com/en-us/library/system.enum.hasflag.aspx