I use the following code in my form:
Public Class Form1
Private Sub Form1_ResizeEnd(sender As Object, e As EventArgs) Handles MyBase.ResizeEnd
MsgBox("Resized")
End Sub
End Class
When I move my form, it also seems to trigger MyBase.ResizeEnd. Why is that? A move of the panel doesn't change the size, so I don't understand why.
Why does a form move trigger ResizeEnd?
Because this is the documented behavior. From the documentation:
The ResizeEnd event is also generated after the user moves a form, typically by clicking and dragging on the caption bar.
If you want an event that doesn't get triggered when the form is moved, you should use either Resize or SizeChanged. The problem with those two events is that they will be triggered while the form is being resized by the user. To work around that, you may use it with both ResizeBegin and ResizeEnd with a couple of flags to signal when the user actually finishes resizing the form.
Here's a complete example:
Private _resizeBegin As Boolean
Private _sizeChanged As Boolean
Private Sub Form1_ResizeBegin(sender As Object, e As EventArgs) Handles MyBase.ResizeBegin
_resizeBegin = True
End Sub
Private Sub Form1_SizeChanged(sender As Object, e As EventArgs) Handles MyBase.SizeChanged
' This is to avoid registering this as a resize event if it was triggered
' by another action (e.g., when the form is first initialized).
If Not _resizeBegin Then Exit Sub
_sizeChanged = True
End Sub
Private Sub Form1_ResizeEnd(sender As Object, e As EventArgs) Handles MyBase.ResizeEnd
_resizeBegin = False
If _sizeChanged Then
_sizeChanged = False
MessageBox.Show("The form has been resized.")
End If
End Sub
One thing to note is that both ResizeBegin and ResizeEnd are only triggered when the user manually resizes* the form. It does not, however, handle other situations like when the form is resized via code, when the form is maximized, or restored.
* or moves the form, which is the part that we're trying to avoid here.
Related
I am currently working on a project and decided to create a user interface for it using visual studio with a windows forms application(Visual Basic).
The problem I'm facing is that the user interface doesn't respond as quickly and smoothly as I'd like it to.
Mainly, I am using pictures as buttons to make the user form look more modern.
However, when I hover my mouse over a "button" it takes a while until the "highlighted button" appears.
P1 is the picture of the "normal button" and P2 is the picture of the "highlighted button".
Here is the short code I have for now:
Public Class Main
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub PictureBox1_MouseHover(sender As Object, e As EventArgs) Handles P1.MouseHover
P1.Visible = False
P2.Visible = True
End Sub
Private Sub P2_MouseClick(sender As Object, e As MouseEventArgs) Handles P2.MouseClick
'Call cmdInit()
'Call cmdConnectRobot()
'Call cmdUnlock()
End Sub
Private Sub Main_MouseHover(sender As Object, e As EventArgs) Handles Me.MouseHover
If P2.Visible = True Then
P2.Visible = False
P1.Visible = True
End If
End Sub
Private Sub P4_Click(sender As Object, e As EventArgs) Handles P4.Click
End Sub
End Class
Another problem I'm facing is that when I call other subs, the user form becomes unresponsive while the sub is running.
I researched and found that I could implement multi threading or async tasks but I'm a bit lost and would be extremely grateful if someone could guide me or point me in the right direction.
Thanks in advance!!
In this case your UI is responsive, however the MouseHover event is only raised once the mouse cursor has hovered over the control for a certain amount of time (default is 400 ms), which is what is causing the delay.
What you are looking for is the MouseEnter event, which is raised as soon as the cursor enters ("touches") the control:
Private Sub P1_MouseEnter(sender As Object, e As EventArgs) Handles P1.MouseEnter
P1.Visible = False
P2.Visible = True
End Sub
You can then use that together with the MouseLeave event on the second picture box to switch back to the non-highlighted image:
Private Sub P2_MouseLeave(sender As Object, e As EventArgs) Handles P2.MouseLeave
P1.Visible = True
P2.Visible = False
End Sub
However switching picture boxes like this is not optimal. I recommend you to look into how you can use Application Resources, then modify your code to only switch the image that one picture box displays.
Here are the basic steps:
Right-click your project in the Solution Explorer and press Properties.
Select the Resources tab.
To add an image either:
a. Drag and drop the image onto the resource pane.
b. Click the arrow next to the Add Resource... button and press Add Existing File....
Now, in your code add this right below Public Class Form1:
Dim ButtonNormal As Image = My.Resources.<first image name>
Dim ButtonHighlighted As Image = My.Resources.<second image name>
Replace <first image name> and <second image name> with the names of your button images.
Now you only need one picture box for the button:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
P1.Image = ButtonNormal
End Sub
Private Sub P1_MouseEnter(sender As System.Object, e As System.EventArgs) Handles P1.MouseEnter
P1.Image = ButtonHighlighted
End Sub
Private Sub P1_MouseLeave(sender As System.Object, e As System.EventArgs) Handles P1.MouseLeave
P1.Image = ButtonNormal
End Sub
I'll start by saying i'm not a programmer by trade, and i'm sure someone will point out better ways of doing these things, but in regards to the threading question it's fairly simple to implement.
Imports System.Threading
Public Class Form1
Dim WorkerThread As New Thread(AddressOf DoWork)
'WorkerThread' can be any name you like, and 'DoWork' is the name of the sub you want to run in the new thread, and is launched by calling:
WorkerThread.start()
However there is a catch, the new thread is not able to interact directly with the GUI, so you cannot change textbox text etc... I find the easiest way to get changes made to the GUI is to drag a timer onto your form, and have the new thread change variables (pre-defined just below Public Class Form1), then use the Timer1 Tick event to monitor the variables and update the GUI if there are any changes.
I am making a custom control that looks like this (there is a label on the right of the button):
I want the user to be able to define what the button does in his code, but still execute some code on the click event on top of the user's code.
What I want to execute :
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Button1.Enabled = False
Label1.ForeColor = Color.Gray
Label1.Text = "In Progress"
End Sub
then after this is executed the user's on click event would trigger.
How can I achieve this?
With "the user" you mean a developer which uses that user control, right? Well, the most common thing is to raise an event which the next developer can use to implement his own logic. This is exactly the same as you do - you use the Click-Event of the button.
So basically, take your code and add the RaiseEvent below:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Me.Button1.Enabled = False
Label1.ForeColor = Color.Gray
Label1.Text = "In Progress"
' this does not affect your code but provides a "hook" for
' other developers
RaiseEvent OnButtonClick(Button1)
End Sub
Now you need to define the event itself like this ...
Public Event OnButtonClick(ByVal sender As Control)
... btw, you can pass other stuff (or nothing at all) as arguments. Sending the button as sender is just a habit.
A developer using your user control can attach a so called "Handler" to implement code as soon as the button was clicked, for example:
AddHandler UserControl1.OnButtonClick, AddressOf OnUserControlButtonClick
This code line should only be executed once, so typically it is placed in the Form_Load event.
Now, in this case the button click is routed to a method called OnUserControlButtonClick() which meets the signature of the event: that means it has one argument which is the sender.
Private Sub OnUserControlButtonClick(ByVal sender as Control)
' custom logic here ...
End Sub
There are so many examples on the web, you could start here.
I have a form (frmwizard) which I am using to create a wizard like interface. The form contains a usercontrol and a button (for testing). There is also a function on the form called "NextPage"
The form loads a usercontrol (ucpage1) on load and the usercontrol has a button on it that when clicked attempts to call a function on the main form as per below:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
frmWizard.Nextpage(me.name)
End Sub
Within my function called "NextPage" have the following for testing.
Public Sub NextPage(ByVal CurrentPage As String)
MessageBox.Show(UserControl1.Controls.Count)
End Sub
When I call the function from the form itself (via the button) I get the result of 1, when i call the function via the User Control, I get the result as 0
I'm sure there is something simple I need to do, but i'm unsure what i've overlooked.
I am trying to make the button on the user-control Save the data within the control and then to browse to the next wizard page. Hopefully this is enough information
Codependance is a bad idea, as it locks the two types together for the future. If your user control really needs to invoke the form, you should instead have it raise an event and handle the event in your form.
Public Class MyUserControl
Public Event OnNextPage(ByVal sender As Object, ByVal e As EventArgs)
Private Sub btnNextPage_Click(sender As Object, e As EventArgs) Handles btnNextPage.Click
RaiseEvent OnNextPage(Me, New EventArgs)
End Sub
End Class
Public Class Form1
Private Sub MyUserControl_OnNextPage(sender As Object, e As EventArgs) Handles MyUserControl1.OnNextPage ' , MyUserControl2.OnNextPage, etc...
MessageBox.Show(DirectCast(sender, MyUserControl).Controls.Count)
End Sub
End Class
I have created a form that allow users to close a form by clicking anywhere on the enlarged picture form (There are 3 objects to consider) and go back to the other form, which is called: "frmPhone". There's an actual picture on the form: "frmPhonePics" which is what I'm using to accomplish what I'm trying to do (was unable to insert an image on here. Sorry.) What I want to do is write a single click event to close the large picture form to allow the user to close it absolutely anywhere in the form, but I don't know how to do that. Here's the code I have so far:
Private Sub frmPhonePics_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Click
frmPhone.Show()
Me.Hide()
End Sub
It sounds as though you have a picture on your frmPhonePics form. If you double click that (from the VBA editor), you should be taken to the code - for example, you might see
Private Sub Image1_Click()
End Sub
Now all you have to do is add your code there:
Private Sub Image1_Click()
Me.Hide
frmPhone.Show()
End Sub
Note - the order matters, since frmPhone.Show() will "hijack" the code flow until it's dismissed, and in your code Me.Hide will not execute (so the form will not close) until frmPhone has been dismissed.
You can map the click handler for various object to one thing, if that is what you are asking:
Private Sub frmPhonePics_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles MyBase.Click, Handles picLarge.Click, Handles otherThing.Click
frmPhone.Show()
Me.Hide() ' should be Me.Close?
End Sub
Not sure why it is MyBase.Click in your code instead of Me.Click. Is this a subclassed form?
I'd strongly suggest using a DoubleClick instead of a single Click. The chances of an errant click doing the wrong thing is very great.
The easiest way is right from the designer. Write the sub routine, then for each control, in the properties window, click the events icon(thunderbolt) and assign the sub routine to the double-click event.
Alternatively, dispense with the Handles clause completely and use a series of Addhandler statements in the Load event handler. If you put a unique string in the names of the controls or if it's all the controls, you can iterate through the controls and use one addhandler statement for all of them
For Each c As Control In Me.Controls
AddHandler c.DoubleClick, AddressOf Ctrl_DoubleClick
Next
Private Sub Ctrl_DoubleClick(sender As Object, e As EventArgs)
'Do stuff
End Sub
I have a NumericUpDown Control on a form. In the Application Settings / Properties Binding, for the value parameter, i can't select my USER setting called : Heures (Integer / User).
I tried to save the value by this way :
Private Sub NumericUpDownHeures_Leave(sender As System.Object, e As System.EventArgs) Handles NumericUpDownHeures.Leave
My.Settings.Heures = NumericUpDownHeures.Value
My.Settings.Save()
End Sub
But it's not saved.
No problem for other settings (String / User). But i don't understand why the settings (Integer / User) are not saved.
Please help, Thanks.
As you are putting "NumericUpDown1.Value" you have to set the value at My.Settings.Heures to decimal.
In Form1_Load add:
NumericUpDownHeures.Value = My.Settings.Heures
and add to the event listener for your button or other widget:
My.Settings.Heures = NumericUpDownHeures.Value
I would guess the issue is that the Leave event is not being fired as you expect it to be, especially if the user just clicks the up/down arrows. I suspect that it is only fired when the user actually clicks into the value area, then leaves. You could verify this by debugging to see if your code is ever hit or by showing a simple msgbox from that event.
I think that you will have better luck if you hook the LostFocus or ValueChanged event.
I want to add to this as well for anyone looking at this in the future.
Save your settings as shown already by putting
My.Settings.Heures = NumericUpDownHeures.Value into your ValueChanged event, and then doing reverse in the form load event.
The problem is, this value changed event fires before the form load when you first initialize, so it will keep defaulting to whatever value you have set in the designer because you're overwriting the setting value with the designer value.
To get around this, you need a private/public boolean at the top of your code that is only set to true once your form has loaded (set to true at the bottom of your form_load event), then you can add the condition to the ValueChanged event checking if the form is loaded yet or not. If it is, then change the setting value, if not, then don't.
An example:
Private IsFormLoaded As Boolean = False
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
NumericUpDown1.Value = My.Settings.SavedNumValue
IsFormLoaded = True
End Sub
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
If IsFormLoaded = False Then Exit Sub
My.Settings.SavedNumValue = NumericUpDown1.Value
End Sub
OR
Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
If IsFormLoaded Then
My.Settings.SavedNumValue = NumericUpDown1.Value
End If
End Sub