tlfeet
asked on
Redraw controls after Resizing Form is done?
Hi,
Probably been asked before ... and I know there is an answer out there ... just not able to find it (looking for wrong term?)
Anyway, have VB.NET Windows app and users can resize the main form.
And, of course, resizing the form requires resizing, re-positioning of controls.
The issue is when resizing by moving the handles (on border) or the grip (as opposed to hitting min or max buttons) - just a tiny bit of movement (1 px horizontal or vertical) triggers the resize event.
As there are a fair number of controls (some requiring a fair amount of code for redrawing) ... it becomes very slow to re-size the form.
e.g. as user changes width from say 800 to 600 ... that is 200 times the Resize event is triggered.
Is there a way to supress redrawing everything until the user is done resizing? I am not sure ... but say on MouseUp? or such .... as opposed to it redrawing everything for each little, tiny change in size?
Thanks,
Mike
Probably been asked before ... and I know there is an answer out there ... just not able to find it (looking for wrong term?)
Anyway, have VB.NET Windows app and users can resize the main form.
And, of course, resizing the form requires resizing, re-positioning of controls.
The issue is when resizing by moving the handles (on border) or the grip (as opposed to hitting min or max buttons) - just a tiny bit of movement (1 px horizontal or vertical) triggers the resize event.
As there are a fair number of controls (some requiring a fair amount of code for redrawing) ... it becomes very slow to re-size the form.
e.g. as user changes width from say 800 to 600 ... that is 200 times the Resize event is triggered.
Is there a way to supress redrawing everything until the user is done resizing? I am not sure ... but say on MouseUp? or such .... as opposed to it redrawing everything for each little, tiny change in size?
Thanks,
Mike
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Ok, I'm stumped ...
Where does one find the constant values?
Yes, VS help and MSDN Library say
"Actual constant values can be found in the windows.h header file included in the Platform SDK (Core SDK) download, which is also available on MSDN."
Well, have download, and installed.
Even found windows.h file, but constant values ain't there - at least not those that might be of interest or use.
Did find references to Winuser.h ... and it appears to have the values ... but given documentation says I should find the values in windows.h but they are not, ... well sort of confused as to what is where.
Is there a handy spot the defines the constants, what they are/do and their values?
Mike
Where does one find the constant values?
Yes, VS help and MSDN Library say
"Actual constant values can be found in the windows.h header file included in the Platform SDK (Core SDK) download, which is also available on MSDN."
Well, have download, and installed.
Even found windows.h file, but constant values ain't there - at least not those that might be of interest or use.
Did find references to Winuser.h ... and it appears to have the values ... but given documentation says I should find the values in windows.h but they are not, ... well sort of confused as to what is where.
Is there a handy spot the defines the constants, what they are/do and their values?
Mike
I wish a had a GOOD answer for that question.
Personally I browse MSDN online and find the message I need. For example:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowmessages/wm_exitsizemove.asp
Then I come here to EE and do a search for that constant name. It is pretty rare that I can't find the constants value here somewhere. When I can't find it here, I google it along with "const".
I've never looked up the values in the C header files.
Sorry...
Personally I browse MSDN online and find the message I need. For example:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowmessages/wm_exitsizemove.asp
Then I come here to EE and do a search for that constant name. It is pretty rare that I can't find the constants value here somewhere. When I can't find it here, I google it along with "const".
I've never looked up the values in the C header files.
Sorry...
ASKER
Hi Idle Mind,
Yes, I understand what you are saying ... but:
Can, does, will WndProc deal with, handle, have something to do with say "X" ?
- "X" beings something going on with app or OS ...
Stumble around find out "Yes, WndProc does somehow interact with "X" - but what constant does it use? What is its name?
If you don't know the name, can't search for it?
So, 2 parter really ... Looking to see what/if WndProc might deal with, handle, have something to do ... does it get/process a message for "X" and then ... find the name ... which one does not know beforehand ... else one would not be looking for the name.
I did not know WndProc would somehow catch/deal with Reszing ... so did not even bother searching for "something ... who knows what" in WndProc
But, then you clued me in ... OK, so next q one would have is "Gee I wonder what constant or constants are involved ... might ne of use?" Again, as the one does not know the name(s) ... hard to search for them. ;-)
Anyway ... going to tak eyour code bit, above and see what happens ... worse that happens ... I crash the internet ... ;-)
Thanks,
Mike
Yes, I understand what you are saying ... but:
Can, does, will WndProc deal with, handle, have something to do with say "X" ?
- "X" beings something going on with app or OS ...
Stumble around find out "Yes, WndProc does somehow interact with "X" - but what constant does it use? What is its name?
If you don't know the name, can't search for it?
So, 2 parter really ... Looking to see what/if WndProc might deal with, handle, have something to do ... does it get/process a message for "X" and then ... find the name ... which one does not know beforehand ... else one would not be looking for the name.
I did not know WndProc would somehow catch/deal with Reszing ... so did not even bother searching for "something ... who knows what" in WndProc
But, then you clued me in ... OK, so next q one would have is "Gee I wonder what constant or constants are involved ... might ne of use?" Again, as the one does not know the name(s) ... hard to search for them. ;-)
Anyway ... going to tak eyour code bit, above and see what happens ... worse that happens ... I crash the internet ... ;-)
Thanks,
Mike
I understand what your saying...
Unfortunately I'm a self-taught programmer from the school of hard-knocks.
The majority of my knowledge comes from figuring out what doesn't work and from observing other peoples code (as in EE for example).
Unfortunately I'm a self-taught programmer from the school of hard-knocks.
The majority of my knowledge comes from figuring out what doesn't work and from observing other peoples code (as in EE for example).
ASKER
Hi Idle Mind,
Tried your code, and several variations on it ...
You'll see why in a minute .... but set up following methods/events handlers on my Form
Private Sub Form1_Resize (....) Handles MyBase.Resize
Private Sub Form1_Paint (...) Handles MyBase.Paint
Private Sub Form1_Layout (...) Handles MyBase.Layout
Protected Overrides Sub WndProc(ByRef m as Message)
... as with yours above.
The problem?
WndProc is the last Method/Handle called during the process of resizing, redrawing, layout.
Windows App calls, goes through the Methods/Handlers in this order:
Resize
Layout
Paint
and last WndProc
Thus setting the SIZING flag in WndProc is too late.
When resizing the form, WndProc is last method called and it never gets back to Resize handle (or Paint, or Layout)
No, big deal per se ... I guess I hope ... I did have the code to control/trigger resizing various parts of the app in the Form's Resize event handler ... just going to have to move it to the WndProc method ... I guess.
Is there some reason I shouldn't do that?
Tried your code, and several variations on it ...
You'll see why in a minute .... but set up following methods/events handlers on my Form
Private Sub Form1_Resize (....) Handles MyBase.Resize
Private Sub Form1_Paint (...) Handles MyBase.Paint
Private Sub Form1_Layout (...) Handles MyBase.Layout
Protected Overrides Sub WndProc(ByRef m as Message)
... as with yours above.
The problem?
WndProc is the last Method/Handle called during the process of resizing, redrawing, layout.
Windows App calls, goes through the Methods/Handlers in this order:
Resize
Layout
Paint
and last WndProc
Thus setting the SIZING flag in WndProc is too late.
When resizing the form, WndProc is last method called and it never gets back to Resize handle (or Paint, or Layout)
No, big deal per se ... I guess I hope ... I did have the code to control/trigger resizing various parts of the app in the Form's Resize event handler ... just going to have to move it to the WndProc method ... I guess.
Is there some reason I shouldn't do that?
This looks like it contains a pretty extensive list of constants.
http://de.pastebin.ca/23663
It doesn't say which is used for what, but a lot of the names give decent clues. And that might give a more focussed starting point for further searches. And it appears to be up to date.
Another source is this
http://www.mcfedries.com/books/vba2000unleashed/Win32API.txt
Although it is vba, rather than VB.NET, and somewhat old, again it might provide a starting point. I don't mess much with Windows Messaging but I have a version of this file that was originally supplied with VB5 so is even older. But I've been able to use some stuff from it directly, and other with only slight modification, under VB.NET
Roger
http://de.pastebin.ca/23663
It doesn't say which is used for what, but a lot of the names give decent clues. And that might give a more focussed starting point for further searches. And it appears to be up to date.
Another source is this
http://www.mcfedries.com/books/vba2000unleashed/Win32API.txt
Although it is vba, rather than VB.NET, and somewhat old, again it might provide a starting point. I don't mess much with Windows Messaging but I have a version of this file that was originally supplied with VB5 so is even older. But I've been able to use some stuff from it directly, and other with only slight modification, under VB.NET
Roger
Oops, cross-post, I see. And in view of the latest message, probably irrelevant. Never mind.
Roger
Roger
ASKER
Hi Roger ... thanks for the list.
Anyway, q boils down to this ...
Is there, would there be something wrong with (I mean besides the world ending ;-) )
By doing this:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa ge)
Select Case m.Msg
Case WM_ENTERSIZEMOVE
Debug.WriteLine("WM_ENTERS IZEMOVE... ")
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI ZEMOVE..." )
... insert
all my resizing, moving code
End Select
MyBase.WndProc(m)
End Sub
As opposed to setting the SIZING flag and trying to catch that in some normal VB.NET, windows event handler?
I suppose not?
Thanks,
Mike
Anyway, q boils down to this ...
Is there, would there be something wrong with (I mean besides the world ending ;-) )
By doing this:
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Messa
Select Case m.Msg
Case WM_ENTERSIZEMOVE
Debug.WriteLine("WM_ENTERS
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI
... insert
all my resizing, moving code
End Select
MyBase.WndProc(m)
End Sub
As opposed to setting the SIZING flag and trying to catch that in some normal VB.NET, windows event handler?
I suppose not?
Thanks,
Mike
Before you do that, try running this
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.ICon tainer
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.Debugg erStepThro ugh()> Private Sub InitializeComponent()
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Name = "Form1"
Me.Text = "Form1"
End Sub
#End Region
Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
Static i As Integer
Debug.WriteLine("resize " & i)
i += 1
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.Paint EventArgs) Handles MyBase.Paint
Static i As Integer
Debug.WriteLine("paint " & i)
i += 1
End Sub
Private Sub Form1_Layout(ByVal sender As Object, ByVal e As System.Windows.Forms.Layou tEventArgs ) Handles MyBase.Layout
Static i As Integer
Debug.WriteLine("layout " & i)
i += 1
End Sub
Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
Static i As Integer
Debug.WriteLine("move " & i)
i += 1
End Sub
End Class
For me, each of those events only fires once if the form is resized "by moving the handles (on border) or the grip (as opposed to hitting min or max buttons)" or if it is moved. That is, the form's own event only seems to fire, anyway, when the Windows Message is WM_EXITSIZEMOVE.
So I wonder why, in your case, "as user changes width from say 800 to 600 ... that is 200 times the Resize event is triggered." And whether, if that is indeed the case with you, making the alteration you propose will make any difference.
Roger
Public Class Form1
Inherits System.Windows.Forms.Form
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
'This call is required by the Windows Form Designer.
InitializeComponent()
'Add any initialization after the InitializeComponent() call
End Sub
'Form overrides dispose to clean up the component list.
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing Then
If Not (components Is Nothing) Then
components.Dispose()
End If
End If
MyBase.Dispose(disposing)
End Sub
'Required by the Windows Form Designer
Private components As System.ComponentModel.ICon
'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
<System.Diagnostics.Debugg
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 266)
Me.Name = "Form1"
Me.Text = "Form1"
End Sub
#End Region
Private Sub Form1_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Resize
Static i As Integer
Debug.WriteLine("resize " & i)
i += 1
End Sub
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.Paint
Static i As Integer
Debug.WriteLine("paint " & i)
i += 1
End Sub
Private Sub Form1_Layout(ByVal sender As Object, ByVal e As System.Windows.Forms.Layou
Static i As Integer
Debug.WriteLine("layout " & i)
i += 1
End Sub
Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Move
Static i As Integer
Debug.WriteLine("move " & i)
i += 1
End Sub
End Class
For me, each of those events only fires once if the form is resized "by moving the handles (on border) or the grip (as opposed to hitting min or max buttons)" or if it is moved. That is, the form's own event only seems to fire, anyway, when the Windows Message is WM_EXITSIZEMOVE.
So I wonder why, in your case, "as user changes width from say 800 to 600 ... that is 200 times the Resize event is triggered." And whether, if that is indeed the case with you, making the alteration you propose will make any difference.
Roger
ASKER
Hi Roger,
I tried that ... well not worried about moving, per se, at this point ... and the Resize, Layout and Paint events are triggerred several times as I resize (using handles, as opposed to Max, Restore, Min.
I am going to double check firing sequence though ... one more time.
And, worse than them being triggerred several times (afterall, could put in code to ignore all but last) is that the WndProc method is not hit until after Resize, Layout, Paint handlers.
Mike
I tried that ... well not worried about moving, per se, at this point ... and the Resize, Layout and Paint events are triggerred several times as I resize (using handles, as opposed to Max, Restore, Min.
I am going to double check firing sequence though ... one more time.
And, worse than them being triggerred several times (afterall, could put in code to ignore all but last) is that the WndProc method is not hit until after Resize, Layout, Paint handlers.
Mike
The WndProc() is ALWAYS hit first.
You should get WM_ENTERSIZEMOVE, followed by a series of resize/layout/paint..., followed by WM_EXITSIZEMOVE.
You can handle it all from inside WndProc() but then you need to find the constants for WM_PAINT, etc.....
You should get WM_ENTERSIZEMOVE, followed by a series of resize/layout/paint..., followed by WM_EXITSIZEMOVE.
You can handle it all from inside WndProc() but then you need to find the constants for WM_PAINT, etc.....
ASKER
Hi again,
Here is ouput in from debug Output window:
Last line of usual loading/startup output:
'WhatIsBlue.exe': Loaded 'c:\windows\assembly\gac\s ystem.xml\ 1.0.5000.0 __b77a5c56 1934e089\s ystem.xml. dll', No symbols loaded.
Counter: 1 Form1_Resize SIZING: False
Counter: 2 Form1_Resize IN SIZING FALSE SIZING: False
'WhatIsBlue.exe': Loaded 'c:\windows\assembly\gac\m icrosoft.v isualbasic \7.0.5000. 0__b03f5f7 f11d50a3a\ microsoft. visualbasi c.dll', No symbols loaded.
Counter: 3 Form1_Layout SIZING: False
Counter: 4 Form1_Resize SIZING: False
Counter: 5 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 6 Form1_Layout SIZING: False
'WhatIsBlue.exe': Loaded 'xuylumb1', No symbols loaded.
Counter: 7 Form1_Resize SIZING: False
Counter: 8 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 9 Form1_Resize SIZING: False
Counter: 10 Form1_Resize IN SIZING FALSE SIZING: False
'WhatIsBlue.exe': Loaded 'r1sk8dpk', No symbols loaded.
Counter: 11 Form1_Resize SIZING: False
Counter: 12 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 13 Form1_Layout SIZING: False
Counter: 14 End MyBase.Load
'Have code in a MyBase.Load method, so slapped in an output line at the end of it.
Counter: 15 Form1_Layout SIZING: False
Counter: 16 Form1_Paint SIZING: False
Counter: 17 Form1_Paint SIZING: False
'This next line is where, really I started resizing ... using handles on form border
'I resized it once, in a smooth move ;-) to about 1 inch smaller on the screen, maybe a little more
Counter: 18 WM_ENTERSIZEMOVE SIZING: True
Counter: 19 Form1_Layout SIZING: True
Counter: 20 Form1_Resize SIZING: True
Counter: 21 Form1_Paint SIZING: True
Counter: 22 Form1_Layout SIZING: True
Counter: 23 Form1_Resize SIZING: True
Counter: 24 Form1_Paint SIZING: True
[...]
Counter: 82 Form1_Layout SIZING: True
Counter: 83 Form1_Resize SIZING: True
Counter: 84 Form1_Paint SIZING: True
Counter: 85 Form1_Layout SIZING: True
Counter: 86 Form1_Resize SIZING: True
Counter: 87 Form1_Paint SIZING: True
Counter: 107 WM_EXITSIZEMOVE SIZING: False
The last line, being where I stopped resizing, let go of boder resize handle.
Here is ouput in from debug Output window:
Last line of usual loading/startup output:
'WhatIsBlue.exe': Loaded 'c:\windows\assembly\gac\s
Counter: 1 Form1_Resize SIZING: False
Counter: 2 Form1_Resize IN SIZING FALSE SIZING: False
'WhatIsBlue.exe': Loaded 'c:\windows\assembly\gac\m
Counter: 3 Form1_Layout SIZING: False
Counter: 4 Form1_Resize SIZING: False
Counter: 5 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 6 Form1_Layout SIZING: False
'WhatIsBlue.exe': Loaded 'xuylumb1', No symbols loaded.
Counter: 7 Form1_Resize SIZING: False
Counter: 8 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 9 Form1_Resize SIZING: False
Counter: 10 Form1_Resize IN SIZING FALSE SIZING: False
'WhatIsBlue.exe': Loaded 'r1sk8dpk', No symbols loaded.
Counter: 11 Form1_Resize SIZING: False
Counter: 12 Form1_Resize IN SIZING FALSE SIZING: False
Counter: 13 Form1_Layout SIZING: False
Counter: 14 End MyBase.Load
'Have code in a MyBase.Load method, so slapped in an output line at the end of it.
Counter: 15 Form1_Layout SIZING: False
Counter: 16 Form1_Paint SIZING: False
Counter: 17 Form1_Paint SIZING: False
'This next line is where, really I started resizing ... using handles on form border
'I resized it once, in a smooth move ;-) to about 1 inch smaller on the screen, maybe a little more
Counter: 18 WM_ENTERSIZEMOVE SIZING: True
Counter: 19 Form1_Layout SIZING: True
Counter: 20 Form1_Resize SIZING: True
Counter: 21 Form1_Paint SIZING: True
Counter: 22 Form1_Layout SIZING: True
Counter: 23 Form1_Resize SIZING: True
Counter: 24 Form1_Paint SIZING: True
[...]
Counter: 82 Form1_Layout SIZING: True
Counter: 83 Form1_Resize SIZING: True
Counter: 84 Form1_Paint SIZING: True
Counter: 85 Form1_Layout SIZING: True
Counter: 86 Form1_Resize SIZING: True
Counter: 87 Form1_Paint SIZING: True
Counter: 107 WM_EXITSIZEMOVE SIZING: False
The last line, being where I stopped resizing, let go of boder resize handle.
ASKER
The last output line above, should read:
Counter 88: WM_EXITSIZEMOVE SIZING: False
Counter 88: WM_EXITSIZEMOVE SIZING: False
Your output confirms what I said...
The initial Layout/Resize hits are from the form loading.
When you actually resized with the mouse, WndProc() was hit first and last. Furthermore, during the resizing, the Sizing variable was true in the Layout/Resize/Paint events.
The initial Layout/Resize hits are from the form loading.
When you actually resized with the mouse, WndProc() was hit first and last. Furthermore, during the resizing, the Sizing variable was true in the Layout/Resize/Paint events.
ASKER
Just got your post Idle Mind;
Re:
"The WndProc() is ALWAYS hit first.
You should get WM_ENTERSIZEMOVE, followed by a series of resize/layout/paint..., followed by WM_EXITSIZEMOVE.
You can handle it all from inside WndProc() but then you need to find the constants for WM_PAINT, etc....."
As you can see, in my case yes, the WM_ENTERMOVESIZE is hit first, then it does the whole bunch of resize, pain, layout calls, then when I stop resizing it then hits WndProc one more time for WM_EXITSIZEMOVE
But, for the "thing" to work, once stopping reszing I need it to hit one (or more) of the Resize (best), Paint or Layout handles one more time.
So, yes, WndProc does get hit first - sets flag to true
Hits Resize handle several times as I resize.
During those resizing, do not want it to actually go through all the code to repostion/resize parts (as well, that puts me back to the beginning ... it owuld go through all that code several, dozens, hundreds of times during resizing)
Want to to go through the code when user is done resizing ... which occurs at the point it hits WM_EXITMOVESIZE
So, something "after" WM_EXITMOVESIZE needs to be the trigger for my code to reposition/resize my parts.
Indeed, surprised MS VB.NET does not have a Handle MyBase.DoneResizing or similar for DoneDidFinishedMoving
Sure explains why a lot of apps are funky if moving it/stuff about or resizing manually ...
Right now ... I do not have all the repositioning/resizing code hooked up (it is all not being called) so right now users' would not notice a slow-down or weirdness ... but thinking ahead to when I do get it all hooked up ...
... resize by one pixel, wait a half-hour while it redraws ... resize the next pixel ... wait another half-hour .... ;-)
Re:
"The WndProc() is ALWAYS hit first.
You should get WM_ENTERSIZEMOVE, followed by a series of resize/layout/paint..., followed by WM_EXITSIZEMOVE.
You can handle it all from inside WndProc() but then you need to find the constants for WM_PAINT, etc....."
As you can see, in my case yes, the WM_ENTERMOVESIZE is hit first, then it does the whole bunch of resize, pain, layout calls, then when I stop resizing it then hits WndProc one more time for WM_EXITSIZEMOVE
But, for the "thing" to work, once stopping reszing I need it to hit one (or more) of the Resize (best), Paint or Layout handles one more time.
So, yes, WndProc does get hit first - sets flag to true
Hits Resize handle several times as I resize.
During those resizing, do not want it to actually go through all the code to repostion/resize parts (as well, that puts me back to the beginning ... it owuld go through all that code several, dozens, hundreds of times during resizing)
Want to to go through the code when user is done resizing ... which occurs at the point it hits WM_EXITMOVESIZE
So, something "after" WM_EXITMOVESIZE needs to be the trigger for my code to reposition/resize my parts.
Indeed, surprised MS VB.NET does not have a Handle MyBase.DoneResizing or similar for DoneDidFinishedMoving
Sure explains why a lot of apps are funky if moving it/stuff about or resizing manually ...
Right now ... I do not have all the repositioning/resizing code hooked up (it is all not being called) so right now users' would not notice a slow-down or weirdness ... but thinking ahead to when I do get it all hooked up ...
... resize by one pixel, wait a half-hour while it redraws ... resize the next pixel ... wait another half-hour .... ;-)
Issue a refresh command after setting SIZING to false:
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI ZEMOVE..." )
SIZING = False
Me.Refresh()
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI
SIZING = False
Me.Refresh()
ASKER
Hi Idle Mind,
Re: Me.Refresh()
I think I am going to need to setup a delegate for that (or something)
A little lost on the Method.
When, during, after Resizing, my Main Form is not the issue, or problem.
I have User Controls, classes, etc .... parts if you will and they are the ones that have to have their sizes, contents, bounds, positions, etc. etc. recalculated, redrawn, and resized.
e.g. I have a Label, part of a user control ... when form loads, it calculates how big to make the usercontrol and its label (and other bits) and for the label, it calculates how/what to display ... based in part on on the size allocated/available for the label.
Similarly, I have, an imaage gallery of a sorts, and say the whole gallery contains 50 images ... and the app is sized ... to say display 10 images per "page" then user resizes app ... say smaller, then it may only be able to display 5 images per "page", so it must re-page the gallery and relayout the images based upon the new size.
Anyway, calling Me.Refresh does a fine job of doing the Main form, but does nothing about all the bits, parts "attached" to the form ...
I did some reading on the Refresh method ... looks like another one of those things that are going to require a bit of study, error, error, trial and error ... ;-)
I'll be Bach
Mike
Re: Me.Refresh()
I think I am going to need to setup a delegate for that (or something)
A little lost on the Method.
When, during, after Resizing, my Main Form is not the issue, or problem.
I have User Controls, classes, etc .... parts if you will and they are the ones that have to have their sizes, contents, bounds, positions, etc. etc. recalculated, redrawn, and resized.
e.g. I have a Label, part of a user control ... when form loads, it calculates how big to make the usercontrol and its label (and other bits) and for the label, it calculates how/what to display ... based in part on on the size allocated/available for the label.
Similarly, I have, an imaage gallery of a sorts, and say the whole gallery contains 50 images ... and the app is sized ... to say display 10 images per "page" then user resizes app ... say smaller, then it may only be able to display 5 images per "page", so it must re-page the gallery and relayout the images based upon the new size.
Anyway, calling Me.Refresh does a fine job of doing the Main form, but does nothing about all the bits, parts "attached" to the form ...
I did some reading on the Refresh method ... looks like another one of those things that are going to require a bit of study, error, error, trial and error ... ;-)
I'll be Bach
Mike
The Refresh() call is supposed to be propogated down to all the controls on the form causing them to redraw as well.
You could try calling Invalidate() before refresh:
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI ZEMOVE..." )
SIZING = False
Me.Invalidate()
Me.Refresh() ' or use Me.Update()
If that doesn't work then we could always use a recursive routine to visit all the controls on your form and tell each one to repaint itself using the Refresh() method (or a combination of Invalidate()/Refresh()).
You could try calling Invalidate() before refresh:
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI
SIZING = False
Me.Invalidate()
Me.Refresh() ' or use Me.Update()
If that doesn't work then we could always use a recursive routine to visit all the controls on your form and tell each one to repaint itself using the Refresh() method (or a combination of Invalidate()/Refresh()).
ASKER
Hi Idle Mind,
Re: "The Refresh() call is supposed to be propogated down to all the controls on the form causing them to redraw as well."
Well, that is the thing ... the stuff, bits, parts aren't "controls" ON the form, per se, directly.
e.g. take my label, ... please
I have a UserControl, MyUserControl, which is on the form.
The Control as a label, MyLabel
So, yes, MyUserControl and MyLabel do get redrawn, regenerated, but they do NOT:
1. get resized, nor
2. does the content of the label change
By calling Me.Refresh on the main form.
What happens, absent specfici code to handle resizing MyUserControl and MyLabel is:
say I am reszing, by making the app narrower ... as I make the app narrower, the right hand edges of MyUserControl and MyLabel get chopped off.
And of course the contents of MyLabel do not change.
Similarly if I make app wider ... then well, if wide enough there is then a gap between the right edge of MyUserControl and the right edge of the app window.
But I need MyUserControl to fill the width of the app ... so it needs to have its width change along with the size of the app's width.
In addition, the content of MyLabel needs to change as the width of the app, hence, the width of MyUserControl, hence, the width of MyLabel and its text need to change in a corresponding manner.
Now, if all MyUserControl had on it was MyLabel, well, not much point of doing it that way ... so it does have more "stuff" on it.
But in addition, essentially what I am doing is pulling everything, out of, away from the main Form directly.
I am doing a re-write, if you will
I had MyLabel directly on the Form ... along with the code to change the contents.
If my Main Form only had that ... well I would not be doing the re-write, but my app literally has/had thousands of controls on it ... and having all the other code for them, also directly on the Form, worked to be sure
But its was a nightmare, picking through thousands of controls, their various methods, etc. all sitting on the Main Form ... "Let's see, where did I stick the handler for TextChanged on Label90123?" ... "Where did I stick the code to recalculate number of images per page? ... Oh, yea that's right it calls this Method, then that Method, then this other one to do its thing ...?"
I am sure if I had my main form very well organized, sectioned, regioned out, it would not be such a hassle ... but I didn't (or rather I tired, but as I added stuff, took stuff off, rearranged this part for one control, well ended up with tons of extraneous code, disorganized parts, etc. etc.)
Smart or not, right or not ... decided to pull almost everything out of the main Form itself, create User Controls and classes for the stuff, and for a given control/class, but all its methods, handles, etc. together in the UserControl (some are UserControls, consisting of other UserControls, which in turn are made up of other UserControls) ... and the main Form, basically just provides the means to hook them together and display them.
Long winded way of saying:
Yes, Refresh would work fine (for most part) if the stuff I was trying to deal with was/were controls directly on the form itself ... but they aren't.
But, your ideas and Roger's have been a big help and I think I have puzzled it out .... and will post back with what I came up with, shortly
Thanks a ton,
Mike
Re: "The Refresh() call is supposed to be propogated down to all the controls on the form causing them to redraw as well."
Well, that is the thing ... the stuff, bits, parts aren't "controls" ON the form, per se, directly.
e.g. take my label, ... please
I have a UserControl, MyUserControl, which is on the form.
The Control as a label, MyLabel
So, yes, MyUserControl and MyLabel do get redrawn, regenerated, but they do NOT:
1. get resized, nor
2. does the content of the label change
By calling Me.Refresh on the main form.
What happens, absent specfici code to handle resizing MyUserControl and MyLabel is:
say I am reszing, by making the app narrower ... as I make the app narrower, the right hand edges of MyUserControl and MyLabel get chopped off.
And of course the contents of MyLabel do not change.
Similarly if I make app wider ... then well, if wide enough there is then a gap between the right edge of MyUserControl and the right edge of the app window.
But I need MyUserControl to fill the width of the app ... so it needs to have its width change along with the size of the app's width.
In addition, the content of MyLabel needs to change as the width of the app, hence, the width of MyUserControl, hence, the width of MyLabel and its text need to change in a corresponding manner.
Now, if all MyUserControl had on it was MyLabel, well, not much point of doing it that way ... so it does have more "stuff" on it.
But in addition, essentially what I am doing is pulling everything, out of, away from the main Form directly.
I am doing a re-write, if you will
I had MyLabel directly on the Form ... along with the code to change the contents.
If my Main Form only had that ... well I would not be doing the re-write, but my app literally has/had thousands of controls on it ... and having all the other code for them, also directly on the Form, worked to be sure
But its was a nightmare, picking through thousands of controls, their various methods, etc. all sitting on the Main Form ... "Let's see, where did I stick the handler for TextChanged on Label90123?" ... "Where did I stick the code to recalculate number of images per page? ... Oh, yea that's right it calls this Method, then that Method, then this other one to do its thing ...?"
I am sure if I had my main form very well organized, sectioned, regioned out, it would not be such a hassle ... but I didn't (or rather I tired, but as I added stuff, took stuff off, rearranged this part for one control, well ended up with tons of extraneous code, disorganized parts, etc. etc.)
Smart or not, right or not ... decided to pull almost everything out of the main Form itself, create User Controls and classes for the stuff, and for a given control/class, but all its methods, handles, etc. together in the UserControl (some are UserControls, consisting of other UserControls, which in turn are made up of other UserControls) ... and the main Form, basically just provides the means to hook them together and display them.
Long winded way of saying:
Yes, Refresh would work fine (for most part) if the stuff I was trying to deal with was/were controls directly on the form itself ... but they aren't.
But, your ideas and Roger's have been a big help and I think I have puzzled it out .... and will post back with what I came up with, shortly
Thanks a ton,
Mike
So are you manually resizing the usercontrols from within your Resize event on your form based on the current size of the app?
You can call those events directly after the WM_EXITSIZEMOVE messgage:
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI ZEMOVE..." )
SIZING = False
Me.Refresh()
Me.Form1_Resize(Nothing, Nothing) ' replace with the name of your sub that handles this event...
You can call those events directly after the WM_EXITSIZEMOVE messgage:
Case WM_EXITSIZEMOVE
Debug.WriteLine("WM_EXITSI
SIZING = False
Me.Refresh()
Me.Form1_Resize(Nothing, Nothing) ' replace with the name of your sub that handles this event...
ASKER
Hi again Mind,
Re: "So are you manually resizing the usercontrols from within your Resize event on your form based on the current size of the app?"
Sort of ... similar ... working out a few things ... as the resizing of one of my "things" can trigger the need to resize another one of my "things" ... which triggers the resizing of yet another "thing" ... wanna make sure ... what needs to be resized is resized, what does not need to be resized, does not ... and avoiding some sort of loop, where A->resizes B-> which resizes C-> ... etc. etc. which triggers the resizing of A ... leading to some sort of never ending resizing loop ;-).
And need to work out some of the "when" issues ... e.g. if a "thing" is not visible ... do I need to, our should I, resize it anyway ... or wait until/if it become visible again to bother.
But that all means, I may need to get at some resizing Methods individually, out-of-the-mainstream, sort of thing, as well as being called from within WndProc or Me.Refresh or not, both, either, or .... more of just matter of picking through the logic of what, when, how, if ...
Mike
Re: "So are you manually resizing the usercontrols from within your Resize event on your form based on the current size of the app?"
Sort of ... similar ... working out a few things ... as the resizing of one of my "things" can trigger the need to resize another one of my "things" ... which triggers the resizing of yet another "thing" ... wanna make sure ... what needs to be resized is resized, what does not need to be resized, does not ... and avoiding some sort of loop, where A->resizes B-> which resizes C-> ... etc. etc. which triggers the resizing of A ... leading to some sort of never ending resizing loop ;-).
And need to work out some of the "when" issues ... e.g. if a "thing" is not visible ... do I need to, our should I, resize it anyway ... or wait until/if it become visible again to bother.
But that all means, I may need to get at some resizing Methods individually, out-of-the-mainstream, sort of thing, as well as being called from within WndProc or Me.Refresh or not, both, either, or .... more of just matter of picking through the logic of what, when, how, if ...
Mike
ASKER
Hi again,
What I ended up doing?
My code
Form has usual Methods, for which I just do opening line/outline
Public Class Form1
Inherits System.Windows.Forms.Form
Private SIZING As Boolean = False
Private WM_ENTERSIZEMOVE As Integer = &H231 ' right now, not actually using this
Private WM_EXITSIZEMOVE As Integer = &H232
Private WM_SIZE As Integer = &H5
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
Private components As System.ComponentModel.ICon tainer
[etc ...]
<System.Diagnostics.Debugg ingStepThr ough()> Private Sub Initialize Component()
[etc ...]
#End Region
I added:
Private Overloads Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'actually added this sub for reasons not directly related to this question
'namely to handle loading in saved window size from an xml file, from last time app was quit
'if I had code to apply that size to in MyBase.New, after "Add any initialization ...."
' the app/window would actually render with some "random" size and position ... wierd ... so moved calling
' calling that code into this method.
'
' works out well with this question
code to load the xml file and apply settings, preferences, saved values, etc. stored in the xml file
'added this to do the resizing thing
SIZING = False 'see below, but the initial loading, start of app, resets from False to True and need it to be
'False at this point
RefreshMyStuff()
End Sub 'Form1_Load
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case (m.Msg)
Case WM_EXITSIZEMOVE
If (SIZING) Then Me.Refresh()
SIZING = False
Case WM_SIZE
SIZING = True
' working with WM_SIZE and not WM_ENTERSIZEMOVE as WM_ENTERSIZEMOVE is triggered with both
' moving and resizing the Form ... and issue is only when I need to resize things/stuff and do not need, nor
' want to trigger resizing code if the form is simply moved.
' Right now, don't see how, if moving owuld create an issue - but if it does, well I'll burn that bridge when I cross it. ;-)
End Select
MyBase.WndProc(m)
End Sub 'WndProc
Protected Overloads Sub Refresh()
' similar to WndProc ... overload the base Method with own method
MyBase.Refresh()
' need to call the Base class refresh method so the form itself is still refreshed
RefreshMyStuff()
End Sub 'Refresh()
Private Sub RefreshMyStuff()
'my code to handle resizing, positioning and content of my "stuff" user controls, their controls, classes, etc.
MyGallery.Repage()
MyLabel.ResizeContent()
MyListBox.ReloadContents()
etc.
End 'RefreshMyStuff()
The Sub New() and Form1_Load methods, automatically construct, refresh, the apps main window/form - so at that pont do not need to do a Form1.Refresh()
But do need to RefreshMyStuff() ' partially as the loading of stuff from xml changes what/how/behavior of my stuff, and need to "initialize" them, and thus redraw them to match the size of main app/form.
After loading app/form and doing intial rendering, user could, may resize the form, so the WndProc WM_SIZING part catches that resizing has started/is going on.
Once user is done resizing then WndProc() with the WM_EXITSIZEMOVE catches the end of sizing (and moving for that matter), and if it was sizing that was happening (as opposed to moving) then need to Refresh form and then resize, position and/or change content of various stuff. ;-)
I've tested it out, several times ... with several parts of MyStuff hooked in and it seems to work well ( ... er well, well I actually do some math and logic properly ;-) in my methods)
Does not seem to throw any fatal errors, get stuck in some sort of loop ... and best of all, allows me to:
1. move a huge amount of code off the main form -
2. even eliminate large chuncks
3. and better seperate it all out - so I can work with bits, parts, pices of my stuff w/o my intermediate work/re-working mucking up something else.
By judicious use of docking and/or anchoring of controls, on UserControlA, which in turn is anchored/docked on UserControlB, ... etc. etc. which finally ends up on the form ... a lot of it does end up being auotmatically handled anyway.
It is just that some of it can't be handled via docking or anchoring (or I do not like how those automatic "type" features do it, so well now can write in some code to handle what needs to be handled.
Thanks Roger and Idle Mind
What I ended up doing?
My code
Form has usual Methods, for which I just do opening line/outline
Public Class Form1
Inherits System.Windows.Forms.Form
Private SIZING As Boolean = False
Private WM_ENTERSIZEMOVE As Integer = &H231 ' right now, not actually using this
Private WM_EXITSIZEMOVE As Integer = &H232
Private WM_SIZE As Integer = &H5
#Region " Windows Form Designer generated code "
Public Sub New()
MyBase.New()
Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
Private components As System.ComponentModel.ICon
[etc ...]
<System.Diagnostics.Debugg
[etc ...]
#End Region
I added:
Private Overloads Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'actually added this sub for reasons not directly related to this question
'namely to handle loading in saved window size from an xml file, from last time app was quit
'if I had code to apply that size to in MyBase.New, after "Add any initialization ...."
' the app/window would actually render with some "random" size and position ... wierd ... so moved calling
' calling that code into this method.
'
' works out well with this question
code to load the xml file and apply settings, preferences, saved values, etc. stored in the xml file
'added this to do the resizing thing
SIZING = False 'see below, but the initial loading, start of app, resets from False to True and need it to be
'False at this point
RefreshMyStuff()
End Sub 'Form1_Load
Protected Overrides Sub WndProc(ByRef m As Message)
Select Case (m.Msg)
Case WM_EXITSIZEMOVE
If (SIZING) Then Me.Refresh()
SIZING = False
Case WM_SIZE
SIZING = True
' working with WM_SIZE and not WM_ENTERSIZEMOVE as WM_ENTERSIZEMOVE is triggered with both
' moving and resizing the Form ... and issue is only when I need to resize things/stuff and do not need, nor
' want to trigger resizing code if the form is simply moved.
' Right now, don't see how, if moving owuld create an issue - but if it does, well I'll burn that bridge when I cross it. ;-)
End Select
MyBase.WndProc(m)
End Sub 'WndProc
Protected Overloads Sub Refresh()
' similar to WndProc ... overload the base Method with own method
MyBase.Refresh()
' need to call the Base class refresh method so the form itself is still refreshed
RefreshMyStuff()
End Sub 'Refresh()
Private Sub RefreshMyStuff()
'my code to handle resizing, positioning and content of my "stuff" user controls, their controls, classes, etc.
MyGallery.Repage()
MyLabel.ResizeContent()
MyListBox.ReloadContents()
etc.
End 'RefreshMyStuff()
The Sub New() and Form1_Load methods, automatically construct, refresh, the apps main window/form - so at that pont do not need to do a Form1.Refresh()
But do need to RefreshMyStuff() ' partially as the loading of stuff from xml changes what/how/behavior of my stuff, and need to "initialize" them, and thus redraw them to match the size of main app/form.
After loading app/form and doing intial rendering, user could, may resize the form, so the WndProc WM_SIZING part catches that resizing has started/is going on.
Once user is done resizing then WndProc() with the WM_EXITSIZEMOVE catches the end of sizing (and moving for that matter), and if it was sizing that was happening (as opposed to moving) then need to Refresh form and then resize, position and/or change content of various stuff. ;-)
I've tested it out, several times ... with several parts of MyStuff hooked in and it seems to work well ( ... er well, well I actually do some math and logic properly ;-) in my methods)
Does not seem to throw any fatal errors, get stuck in some sort of loop ... and best of all, allows me to:
1. move a huge amount of code off the main form -
2. even eliminate large chuncks
3. and better seperate it all out - so I can work with bits, parts, pices of my stuff w/o my intermediate work/re-working mucking up something else.
By judicious use of docking and/or anchoring of controls, on UserControlA, which in turn is anchored/docked on UserControlB, ... etc. etc. which finally ends up on the form ... a lot of it does end up being auotmatically handled anyway.
It is just that some of it can't be handled via docking or anchoring (or I do not like how those automatic "type" features do it, so well now can write in some code to handle what needs to be handled.
Thanks Roger and Idle Mind
ASKER
Yes, I think I could generalize that, or specialize that ;-) , as the case maybe to work with my project.
I need to dig into the WndProc method a bit ... er a fair amount ... er, well seems quite dense ... off to pick my way through it ...