-
Jun 14th, 2015, 10:51 AM
#1
Thread Starter
Hyperactive Member
[RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
I've a mdiparent form where I load multiple mdichild forms. These mdichild forms are the same form with different data (the program is based on data analysis, so I can open multiple files and create a new form in runtime). The code I use to open the new form is the next
Code:
Dim MyNewForm As New frmChildForm
Load MyNewForm
MyNewForm.Show
So each time I open a file, a new form is shown.
The problem I've is that I want to draw a line in MyNewForm from another form when I press a command button (the command button is not in the MyNewForm) a new MyNewForm is opened instead of drawing the line in the active MyNewForm.
In MyNewForm I've a Public Sub:
Code:
Public Sub DrawALine()
MyPictureBox.Line (10,50) - (30, 80)
End Sub
In the other form I've
Code:
frmChildForm.DrawALine
And the result is that a new mdichild form is created with the line, instead of drawing in the active form.
What do I should change to draw the line in the active form instead of creating a new form?
-
Jun 14th, 2015, 10:57 AM
#2
Re: How to prevent to open a new dynamical form in runtime in this case?
The active MDI child is a property of the MDI form: ActiveForm
Is that what you want? MDIform.ActiveForm.DrawALine ?
-
Jun 14th, 2015, 11:03 AM
#3
Thread Starter
Hyperactive Member
Re: How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
The active MDI child is a property of the MDI form: ActiveForm
Is that what you want? MDIform.ActiveForm.DrawALine ?
I'm looking something like that but I cannot find .ActiveForm property. I'm looking for it.
-
Jun 14th, 2015, 11:04 AM
#4
Re: How to prevent to open a new dynamical form in runtime in this case?
It's a property on the MDI parent: Me.ActiveForm or [MDIparentFormName].AcitveForm
-
Jun 14th, 2015, 11:10 AM
#5
Thread Starter
Hyperactive Member
Re: How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
It's a property on the MDI parent: Me.ActiveForm or [MDIparentFormName].AcitveForm
I've found it. Thank you. It works ok.
I've another question. In this case I don't have any problem because the secondary form where I press the button 'Draw a line' is not an mdichild. But imagine that the activeform is the mdichild form where I press 'draw a line'. The program would try to draw a line in the same form where I press the button.
So I think I should have to use another method to draw a line in a non-active mdichild form and it must be done where there are maybe 4 or 5 non-active mdichild forms. How to approach the problem in that scenario?
-
Jun 14th, 2015, 11:27 AM
#6
Re: How to prevent to open a new dynamical form in runtime in this case?
Good question. How will your form know which sibling is to draw the line? Will the active form have to know which sibling form to call or will the user have to tell it which sibling?
If it is user-directed, you will likely want to show some menu or popup window for the user to choose from.
If is is not user-directed, you will likely need to keep some sort of list. If it decided by ZOrder of the child forms, you can get the current ZOrder via APIs. But those APIs use hWnds and since all your child forms are of the same class (frmChildForm), you'll want to loop thru the Forms collection to find the form that has the appropriate hWnd, i.e.,
Code:
For f = 0 To Forms.Count - 1
If Forms(f).hWnd = targetHwnd Then
Forms(f).DrawALine
Exit For
End If
Next
The above questions are rhetorical, to be answered by you. I didn't ask them, for you to post the answers here.
Bottom line Jose, this requires a bit of forethought on your part. First think it through and then the best option will likely stand out
-
Jun 14th, 2015, 11:40 AM
#7
Thread Starter
Hyperactive Member
Re: How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
Good question. How will your form know which sibling is to draw the line? Will the active form have to know which sibling form to call or will the user have to tell it which sibling?
If it is user-directed, you will likely want to show some menu or popup window for the user to choose from.
If is is not user-directed, you will likely need to keep some sort of list. If it decided by ZOrder of the child forms, you can get the current ZOrder via APIs. But those APIs use hWnds and since all your child forms are of the same class (frmChildForm), you'll want to loop thru the Forms collection to find the form that has the appropriate hWnd, i.e.,
Code:
For f = 0 To Forms.Count - 1
If Forms(f).hWnd = targetHwnd Then
Forms(f).DrawALine
Exit For
End If
Next
The above questions are rhetorical, to be answered by you. I didn't ask them, for you to post the answers here.
Bottom line Jose, this requires a bit of forethought on your part. First think it through and then the best option will likely stand out
I'm carefully reading your answer. The line has to be drawn in the last active frmChildForm and it's not user-directed. I think the program will need to select the form via ZOrder, because the intention is to use the last active frmChildForm.
I don't know how to identify the target hWnd. I think about monitoring the frmChildForms and each time that the frmChildForm is activated, the value of a variable LastActivefrmChildForm can be updated with the hWnd of the active frmChildForm. Would be this a good solution?
-
Jun 14th, 2015, 11:46 AM
#8
Re: How to prevent to open a new dynamical form in runtime in this case?
Think that should work for you and honestly, should be easier than calling some function to determine which sibling form is directly lower in the ZOrder, via APIs, than the current one. But you'll need to think this thru. If you click on the child whose button will be clicked, that child will have set itself as the LastActiveChildForm, correct? So, sounds like you to need to know at least the last 2 active child forms?
-
Jun 14th, 2015, 11:54 AM
#9
Thread Starter
Hyperactive Member
Re: How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
Think that should work for you and honestly, should be easier than calling some function to determine which sibling form is directly lower in the ZOrder, via APIs, than the current one. But you'll need to think this thru. If you click on the child whose button will be clicked, that child will have set itself as the LastActiveChildForm, correct? So, sounds like you to need to know at least the last 2 active child forms?
Well, I don't explained the mechanism very well sorry. I tried to explain that only the frmChildForms can modify the LastActiveChildForm. You've correct when you say that the other form would update the LastActiveChildForm variable. But I forgot to mention that only the frmChildForms can update that value.
-
Jun 14th, 2015, 12:01 PM
#10
Re: How to prevent to open a new dynamical form in runtime in this case?
If it doesn't work or becomes a pain to keep your references up to date, the API approach is quite simple to return the hWnd of the sibling window directly below, in ZOrder, of the active window
Code:
' Declarations
Private Declare Function GetNextWindow Lib "user32.dll" Alias "GetWindow" (ByVal hWnd As Long, ByVal wFlag As Long) As Long
Private Const GW_HWNDNEXT As Long = 2
' sample call from the child form whose button is being clicked
tgtHwnd = GetNextWindow(Me.hWnd, GW_HWNDNEXT)
' if tgtHwnd = 0 then there is only 1 child form loaded
-
Jun 14th, 2015, 12:07 PM
#11
Thread Starter
Hyperactive Member
Re: How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
If it doesn't work or becomes a pain to keep your references up to date, the API approach is quite simple to return the hWnd of the sibling window directly below, in ZOrder, of the active window
Code:
' Declarations
Private Declare Function GetNextWindow Lib "user32.dll" Alias "GetWindow" (ByVal hWnd As Long, ByVal wFlag As Long) As Long
Private Const GW_HWNDNEXT As Long = 2
' sample call from the child form whose button is being clicked
tgtHwnd = GetNextWindow(Me.hWnd, GW_HWNDNEXT)
' if tgtHwnd = 0 then there is only 1 child form loaded
thank you very much LaVolpe. That information is high enought to solve the problem.
-
Jun 14th, 2015, 12:37 PM
#12
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Here's an example that demonstrates another simple approach that doesn't require APIs. Instead, it relies on the Deactivate event of a Form. Start a new Standard EXE project, make the default Form an MDIChild, add an MDIForm and a standard module and then copy & paste the following:
Code:
Option Explicit 'In MDIChild Form
Private Const GW_HWNDNEXT As Long = 2
Private Declare Function GetWindow Lib "user32.dll" (ByVal hWnd As Long, ByVal uCmd As Long) As Long
Private WithEvents cmdNewForm As VB.CommandButton
Private WithEvents cmdPrintTimer As VB.CommandButton
Private Sub cmdNewForm_Click()
#If OneLiner Then
Forms.Add(Name).Show
#Else
With New Form1
.Show
End With
#End If
End Sub
Private Sub cmdPrintTimer_Click()
If Not LastActiveChildForm Is Nothing Then LastActiveChildForm.Print Timer
End Sub
Private Sub Form_Deactivate()
Set LastActiveChildForm = Me
End Sub
Private Sub Form_Load()
AutoRedraw = True
Caption = hWnd
Set cmdNewForm = Controls.Add("VB.CommandButton", "cmdNewForm")
cmdNewForm.Caption = "New &Form"
cmdNewForm.Visible = True
Set cmdPrintTimer = Controls.Add("VB.CommandButton", "cmdPrintTimer")
cmdPrintTimer.Caption = "Print &Timer"
cmdPrintTimer.Visible = True
End Sub
Private Sub Form_Resize()
On Error Resume Next
cmdNewForm.Move ScaleWidth / 2! - cmdNewForm.Width, (ScaleHeight - cmdNewForm.Height) / 2!
cmdPrintTimer.Move ScaleWidth / 2!, (ScaleHeight - cmdPrintTimer.Height) / 2!
End Sub
Private Sub Form_Unload(Cancel As Integer)
Dim hWndNext As Long, Form As VB.Form
If Not LastActiveChildForm Is Nothing Then
DoEvents 'Let the new LastActiveChildForm's Deactivate event finish first (this won't happen though when stepping thru in IDE)
hWndNext = GetWindow(LastActiveChildForm.hWnd, GW_HWNDNEXT)
If hWndNext Then
For Each Form In Forms
If Form.hWnd = hWndNext Then
Set LastActiveChildForm = Form
Exit For
End If
Next
Else
Set LastActiveChildForm = Nothing
End If
End If
End Sub
Code:
Option Explicit 'In a standard (.BAS) module
Public LastActiveChildForm As VB.Form
EDIT
The amended code above now incorporates LaVolpe's API suggestion which solves the issue he pointed out in post #17.
Last edited by Bonnie West; Jun 15th, 2015 at 04:34 AM.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jun 14th, 2015, 01:31 PM
#13
Thread Starter
Hyperactive Member
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by Bonnie West
Here's an example that demonstrates another simple approach that doesn't require APIs. Instead, it relies on the Deactivate event of a Form. Start a new Standard EXE project, make the default Form an MDIChild, add an MDIForm and a standard module and then copy & paste the following:
Code:
Option Explicit 'In MDIChild Form
Private WithEvents cmdNewForm As VB.CommandButton
Private WithEvents cmdPrintTimer As VB.CommandButton
Private Sub cmdNewForm_Click()
#If OneLiner Then
Forms.Add(Name).Show
#Else
With New Form1
.Show
End With
#End If
End Sub
Private Sub cmdPrintTimer_Click()
If Not LastActiveChildForm Is Nothing Then LastActiveChildForm.Print Timer
End Sub
Private Sub Form_Deactivate()
Set LastActiveChildForm = Me
End Sub
Private Sub Form_Load()
AutoRedraw = True
Set cmdNewForm = Controls.Add("VB.CommandButton", "cmdNewForm")
cmdNewForm.Caption = "New &Form"
cmdNewForm.Visible = True
Set cmdPrintTimer = Controls.Add("VB.CommandButton", "cmdPrintTimer")
cmdPrintTimer.Caption = "Print &Timer"
cmdPrintTimer.Visible = True
End Sub
Private Sub Form_Resize()
On Error Resume Next
cmdNewForm.Move ScaleWidth / 2! - cmdNewForm.Width, (ScaleHeight - cmdNewForm.Height) / 2!
cmdPrintTimer.Move ScaleWidth / 2!, (ScaleHeight - cmdPrintTimer.Height) / 2!
End Sub
Code:
Option Explicit 'In a standard (.BAS) module
Public LastActiveChildForm As VB.Form
Thank you very much for the information. I really appreciate it.
-
Jun 14th, 2015, 01:36 PM
#14
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
@Bonnie
What's it supposed to do
If I put the code in the MDIChild (Form1) like you say I get nothing but a blank Form
If I put the code in the MDIForm (Form2) I get error
No MDI Form available to load (by clicking on the cmdNewForm button)
Last edited by jmsrickland; Jun 14th, 2015 at 01:39 PM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
-
Jun 14th, 2015, 01:55 PM
#15
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by jmsrickland
@Bonnie
What's it supposed to do
If I put the code in the MDIChild (Form1) like you say I get nothing but a blank Form
If I put the code in the MDIForm (Form2) I get error
No MDI Form available to load (by clicking on the cmdNewForm button)
Did you perform the following steps exactly as I wrote above?
- Start a new Standard EXE project.
- Make the default Form an MDIChild.
- Add an MDIForm and a standard Module.
- Copy & paste the codes in post #12 to their respective modules.
If you've done it correctly, the cmdNewForm button will load and show a new instance of the MDIChild while the cmdPrintTimer button will print the output of the Timer function to the last active MDIChild Form.
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jun 14th, 2015, 02:51 PM
#16
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
I started a new Standard EXE
When the default Form (Form1) appears I made MDIChild = True
I added Form2 and left it as is (MDIChild = False)
I put the code in Form1, the MDIChild Form
I added a .BAS module
I put the module code in the module
I set the project to start on Form2
All that happen is I get Form2 show as a blank Form
If you've done it correctly, the cmdNewForm button will load and show a new instance of the MDIChild while the cmdPrintTimer button will print the output of the Timer function to the last active MDIChild Form.
How can that happen when Form2 has no code and Form1(with the code to show cmdNewForm) is never executed.
If I set the project to start on Form1 I get error
Are you sure you stated everything to do?
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
-
Jun 14th, 2015, 02:57 PM
#17
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Getting Bonnie's sample project running is one thing, but her logic to determine 2nd to last form that had focus is pretty good. I do see at least one pitfall.
Let's say there are 3 child forms currently displayed
1. User clicks on the middle one, the one that happens to be LastActiveChildForm
2. This forces what was just the top level form to deactivate & changes LastActiveChildForm to itself
3. User closes the now top level form (does it trigger a deactivate event?)
-- if yes, then LastActiveChildForm points to an unloaded form -- incorrect
-- if not, then LastActiveChildForm now points to the top level form -- incorrect
-
Jun 14th, 2015, 03:57 PM
#18
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by jmsrickland
I added Form2 and left it as is (MDIChild = False)
. . .
I set the project to start on Form2
All that happen is I get Form2 show as a blank Form
The second Form (Form2) is supposed to be an MDIForm. A VB6 project cannot have MDIChild(s) without their parent MDIForm. The project's Startup Object should be the first Form (Form1).
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
-
Jun 14th, 2015, 04:11 PM
#19
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
So how to make Form2 a MDIForm
Last edited by jmsrickland; Jun 14th, 2015 at 04:14 PM.
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
-
Jun 14th, 2015, 04:16 PM
#20
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by jmsrickland
So how to make Form2 a MDIForm
Menu: Project|Add MDI Form
Change the form name if desired
-
Jun 14th, 2015, 04:19 PM
#21
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Duh
Anything I post is an example only and is not intended to be the only solution, the total solution nor the final solution to your request nor do I claim that it is. If you find it useful then it is entirely up to you to make whatever changes necessary you feel are adequate for your purposes.
-
Jun 15th, 2015, 04:34 AM
#22
Re: [RESOLVED] How to prevent to open a new dynamical form in runtime in this case?
Originally Posted by LaVolpe
I do see at least one pitfall.
Great catch!
The best way, it seems, to fix that issue is by combining both of our approaches. The revised code in post #12 now has the best of both worlds and with none of the disadvantages!
On Local Error Resume Next: If Not Empty Is Nothing Then Do While Null: ReDim i(True To False) As Currency: Loop: Else Debug.Assert CCur(CLng(CInt(CBool(False Imp True Xor False Eqv True)))): Stop: On Local Error GoTo 0
Declare Sub CrashVB Lib "msvbvm60" (Optional DontPassMe As Any)
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|