-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmodScaleForm.bas
922 lines (789 loc) · 38.9 KB
/
modScaleForm.bas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
Attribute VB_Name = "modScaleForm"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' If you can read "Attribute VB_Name = "modScaleForm"" on the line above when already in the
' Access VBA editor, please remove this line or the module will not compile.
' When importing the .bas-file the the "import from file" function, this line never appears
' and the module is already correctly named "modScaleForm"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GENERAL INFORMATION
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Module : modScaleForm
' Version : 2024-12-18
' Usable : From Access 2002 (XP) and up, maybe from Access 2000 and up
' Author : Markus Gruber (markus.gruber@gruber.cc)
' Purpose : Resize Access forms and scale the controls within according to screen resolution
' and DPI.
' Usage : 1) Add "ScaleFormWindow Me" to the OnOpen-Event of all your forms. When setting
' the optional parameter "DoNotScaleFormProportionally" to true, the window
' does not scale to the same ratio horizontally and vertically, but strict to
' the ratios between design resolution and current resolution. This may lead to
' unproportionally scaled forms and controls.
' 2) Add "ScaleFormControls Me" to the OnResize-Event of all your forms.
' 1+2) (You can also use the function "InitialInsertCodeIntoForms" to do this initially.
' Watch the "immediate window".)
' 3) Set the following constants in the module to match your design environment:
' DefaultDesignWidth (default is 1280)
' DefaultDesignHeight (default is 1024)
' DefaultDesignDPI (default is 120)
' 4) If one form was designed at another resolution, add the following to the
' form's tag field (do not forget all the ":"):
' DesignRes:<width>x<height>x<DPI>: - for example:
' DesignRes:1024x768x96:
' Credits : .) Thanks to Jamie Czernik for his module modResizeForm, it was much inspiration!
' .) Thanks to Myke Mayers for his function AdjustColumnWidths, it helped me a lot!
' Requires : :) This module needs the class module clFormWindow:
' Visit http://www.mvps.org/access/forms/frm0042.htm
' and download http://www.mvps.org/access/downloads/clFormWindow.bas
' Remarks : .) I am pretty sure that there are many errors in this module. Feel free
' to correct them yourself or simply inform me about them.
' .) This module is provided "as is", I do not take responsability for usage.
' .) This module is licensed under the GPL.
' .) Thanks to all other Access developers posting solutions and code helping me
' over the last years!
' Remarks 2 : .) Resizing (sub)forms with many controls takes long (I know of a case, where it
' takes 15 seconds).
' .) Fonts are sized using the smaller value of either horizontal or vertical scale
' factor - if this would not be the case, fonts would not fit any more into
' their controls.
' .) Windows are centered after rescaling, so that they can not "disappear" to
' non-visible areas. Therefore, I use the class module "clFormWindow". If you only
' want the module to set the new size but not center the form, set the optional
' parameter "DoNotCenterForm" to "true".
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' CHANGELOG
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 2024-12-18: .) modScaleForm and clFormWindow are now compatible with 64 bit systems.
'
' 2008-03-10: .) New function PreScale: Can scale forms one time only in design mode to a desired
' target resolution, could also be called "static scaling"
' .) New function mSFOpenForm: Similar to docmd.openform with following addition: Opens
' a given form not directly, but searches for a statically scaled form and opens this
' one. Returns the name of the finally opened form as string. Same parameters usage as
' docmd.openform, but no error handling implemented yet.
' .) Cosmetic changes to the code (no added/changed functionality)
'
' 2008-02-08: .) Corrected version info in the "General Information" header. Thanks to anonymous!
'
' 2008-02-02: .) Added a comment about a possible caveat with the line
' "Attribute VB_Name = "modScaleForm"". Thanks to Tony D'Ambra from
' www.accessextra.net for the information!
' .) Added description about optional parameter "DoNotScaleFormProportionally".
' .) Added description about font sizing behavior.
' .) Added description why I use clFormWindow for setting a form's position.
' .) New optional parameter "DoNotCenterForm".
'
' 2008-01-21: .) Fixed a bug at scaling column widths
'
' 2008-01-18: .) First control element returned from Access has been been included in array (missing
' "ReDim Preserve" added)
'
' 2008-01-07: .) DPI changes are reflected in scale factors
' .) Added function "InitialInsertCodeIntoForms"
'
' 2007-12-01: .) Split ModScaleForm in several functions
'
' 2007-11-01: .) First thoughts and research
' .) Decision to create modScaleForm
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Compare Database
Option Explicit
Private Type tRect 'for window sizes
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Type tControl 'for control properties
FormName As String
NAME As String
Height As Long
Width As Long
Top As Long
Left As Long
FontSize As Long
ColumnWidths As String
ListWidth As Long
TabFixedWidth As Long
TabFixedHeight As Long
End Type
Private Type tDisplay
Height As Long
Width As Long
DPI As Long
End Type
Private Const DefaultDesignWidth As Long = 1920
Private Const DefaultDesignHeight As Long = 1080
Private Const DefaultDesignDPI As Long = 120
Private Const WM_HORZRES As Long = 8
Private Const WM_VERTRES As Long = 10
Private Const WM_LOGPIXELSX As Long = 88
#If VBA7 Then
Private Declare PtrSafe Function WM_apiGetDC Lib "user32" Alias "GetDC" (ByVal hWnd As LongPtr) As LongPtr
Private Declare PtrSafe Function WM_apiReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hWnd As LongPtr, ByVal hdc As LongPtr) As Long
Private Declare PtrSafe Function WM_apiGetDeviceCaps Lib "gdi32" Alias "GetDeviceCaps" (ByVal hdc As LongPtr, ByVal nIndex As Long) As Long
Private Declare PtrSafe Function WM_apiGetWindowRect Lib "user32.dll" Alias "GetWindowRect" (ByVal hWnd As LongPtr, lpRect As tRect) As Long
#Else
Private Declare Function WM_apiGetDC Lib "user32" Alias "GetDC" (ByVal hWnd As Long) As Long
Private Declare Function WM_apiReleaseDC Lib "user32" Alias "ReleaseDC" (ByVal hWnd As Long, ByVal hdc As Long) As Long
Private Declare Function WM_apiGetDeviceCaps Lib "gdi32" Alias "GetDeviceCaps" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function WM_apiGetWindowRect Lib "user32.dll" Alias "GetWindowRect" (ByVal hWnd As Long, lpRect As tRect) As Long
#End If
Public arrCtlsScaleForm() As tControl 'public array for control properties, available for all forms
Public Sub ScaleFormWindow( _
ByVal frm As Access.Form, _
Optional DoNotScaleFormProportionally As Boolean, _
Optional DoNotCenterForm As Boolean)
Dim CurrentFormHeight As Long
Dim CurrentFormName As String
Dim CurrentFormWidth As Long
Dim CurrentScreenDPI As Long
Dim CurrentScreenHeight As Long
Dim CurrentScreenWidth As Long
Dim DesignResDPI As Long
Dim DesignResHeight As Long
Dim DesignResWidth As Long
Dim GetScreenResolution As tDisplay
#If VBA7 Then
Dim hDCcaps As LongPtr
#Else
Dim hDCcaps As Long
#End If
Dim lngRtn As Long
Dim MonitorResHeightRatio As Single
Dim MonitorResWidthRatio As Single
Dim NewForm As New clFormWindow
Dim NewFormHeight As Long
Dim NewFormWidth As Long
Dim OnOpenWindowHeight As Long
Dim OnOpenWindowWidth As Long
Dim rectWindow As tRect
Dim ScaledFormString As String
Dim TagString As String
Dim TagStringArray() As String
Dim TagStringPosition As Long
On Error Resume Next
CurrentFormName = frm.NAME
'Call API to get current resolution
hDCcaps = WM_apiGetDC(0) 'Get display context for desktop (hwnd = 0).
With GetScreenResolution
.Height = WM_apiGetDeviceCaps(hDCcaps, WM_VERTRES)
.Width = WM_apiGetDeviceCaps(hDCcaps, WM_HORZRES)
.DPI = WM_apiGetDeviceCaps(hDCcaps, WM_LOGPIXELSX)
End With
lngRtn = WM_apiReleaseDC(0, hDCcaps) 'Release display context.
CurrentScreenWidth = GetScreenResolution.Width
CurrentScreenHeight = GetScreenResolution.Height
CurrentScreenDPI = GetScreenResolution.DPI
ScaledFormString = ("_mSF" & CurrentScreenWidth & "x" & CurrentScreenHeight & "x" & CurrentScreenDPI)
If isSubform(frm) Then
Exit Sub
Else
If Right(CurrentFormName, Len(ScaledFormString)) = ScaledFormString Then
Exit Sub 'this form is statically scaled for the current resolution
Else
'go go go
End If
End If
'Set size to fit form
DoCmd.RunCommand acCmdSizeToFitForm
'Extract "DesignRes:*:" from Tag-Option of Form
TagString = LCase(frm.Tag) 'lower case tag-field
TagStringPosition = InStr(TagString, "designres:") 'get left position of resolution
If TagStringPosition > 0 Then
TagString = Mid(TagString, TagStringPosition + 10) 'get string starting with resolution (the "+10" is the char count of "DesignRes:"
TagStringPosition = InStr(TagString, ":") 'Get Position of ":" behind resolution
TagString = Left(TagString, TagStringPosition - 1) 'remove everything behind ":" - the variable now contains the design resolution
ReDim TagStringArray(1)
TagStringArray = Split(TagString, "x") '"x" is the delimiter
If UBound(TagStringArray) >= 0 Then DesignResWidth = TagStringArray(0)
If UBound(TagStringArray) >= 1 Then DesignResHeight = TagStringArray(1)
If UBound(TagStringArray) >= 2 Then DesignResDPI = TagStringArray(2)
If (DesignResWidth <= 0) Or (DesignResHeight <= 0) Or (DesignResDPI <= 0) Then
DesignResWidth = DefaultDesignWidth
DesignResHeight = DefaultDesignHeight
DesignResDPI = DefaultDesignDPI
End If
Erase TagStringArray
Else
'DesignRes is not specified in the form so we use default values for scaling
DesignResWidth = DefaultDesignWidth
DesignResHeight = DefaultDesignHeight
DesignResDPI = DefaultDesignDPI
End If
'Extract "OnOpenRes:*:" from Tag-Option of Form
TagString = LCase(frm.Tag) 'lower case tag-field
TagStringPosition = InStr(TagString, "onopenres:") 'get left position of resolution
If TagStringPosition > 0 Then
TagString = Mid(TagString, TagStringPosition + 10) 'get string starting with resolution (the "+10" is the char count of "OnOpenRes:"
TagStringPosition = InStr(TagString, ":") 'Get Position of ":" behind resolution
TagString = Left(TagString, TagStringPosition - 1) 'remove everything behind ":" - the variable now contains the OnOpen resolution
ReDim TagStringArray(1)
TagStringArray = Split(TagString, "x") '"x" is the delimiter
OnOpenWindowWidth = TagStringArray(0)
OnOpenWindowHeight = TagStringArray(1)
Erase TagStringArray
Else
Call WM_apiGetWindowRect(frm.hWnd, rectWindow) 'prepare for getting size of current window on screen
OnOpenWindowWidth = rectWindow.Right - rectWindow.Left
OnOpenWindowHeight = rectWindow.Bottom - rectWindow.Top
frm.Tag = frm.Tag & ", OnOpenRes:" & OnOpenWindowWidth & "x" & OnOpenWindowHeight & ":"
End If
If (DesignResDPI = CurrentScreenDPI) And (DesignResWidth = CurrentScreenWidth) And (DesignResHeight = CurrentScreenHeight) Then
'design values match current values, no need for scaling
Exit Sub
Else
'design values and current values are not equal - go on
End If
'Calculate Ratios
MonitorResHeightRatio = (CurrentScreenHeight / DesignResHeight) * (DesignResDPI / CurrentScreenDPI)
MonitorResWidthRatio = (CurrentScreenWidth / DesignResWidth) * (DesignResDPI / CurrentScreenDPI)
'If DoNotScaleFormProportionally is True, then the ratios remain the same. Else, the smaller value is chosen for both
If DoNotScaleFormProportionally = False Then
If MonitorResHeightRatio < MonitorResWidthRatio Then MonitorResWidthRatio = MonitorResHeightRatio
If MonitorResWidthRatio < MonitorResHeightRatio Then MonitorResHeightRatio = MonitorResWidthRatio
Else
'leave ratios as they are and scale unproportionally, strictly as display resolution ratios are.
End If
'Get width and heights of form
Call WM_apiGetWindowRect(frm.hWnd, rectWindow) 'prepare for getting size of current window on screen
CurrentFormWidth = rectWindow.Right - rectWindow.Left
CurrentFormHeight = rectWindow.Bottom - rectWindow.Top
'Calculate new width and height (add 1 pixel for safety reasons), including percentage relative to whole desktop
NewFormHeight = Round(CurrentFormHeight * MonitorResHeightRatio, 0) '+ 1
NewFormWidth = Round(CurrentFormWidth * MonitorResWidthRatio, 0) '+ 1
'Set form's new size and position
NewForm.hWnd = frm.hWnd
With NewForm
.Height = NewFormHeight
.Width = NewFormWidth
End With
'If DoNotCenterForm is True, then the form is not centered
If DoNotCenterForm = False Then
With NewForm
.Top = (.Parent.Height - NewFormHeight) / 2
.Left = (.Parent.Width - NewFormWidth) / 2
End With
Else
'form should not be centered
End If
Set NewForm = Nothing
End Sub
Public Sub ScaleFormControls( _
ByVal frm As Access.Form, _
Optional NoScalingWhenSubform As Boolean)
Dim ArrayCount As Long
Dim ctl As Control
Dim CurrentWindowHeight As Long
Dim CurrentWindowWidth As Long
Dim FormExists As Boolean
Dim LastScaleHorzFactor As Single
Dim LastScaleVertFactor As Single
Dim OnOpenWindowHeight As Long
Dim OnOpenWindowWidth As Long
Dim rectWindow As tRect
Dim ScaleFontFactor As Single
Dim ScaleHorzFactor As Single
Dim ScaleVertFactor As Single
Dim TagString As String
Dim TagStringArray() As String
Dim TagStringPosition As Long
On Error Resume Next 'no error messages, no debugger will start
'prepare array holding initial control sizes
If (Not arrCtlsScaleForm) = -1 Then
'array empty, so create one
ReDim arrCtlsScaleForm(1) 'create array
Else
'array exists, do nothing
End If
If isSubform(frm) And (NoScalingWhenSubform = True) Then
Exit Sub
Else
'go go go
End If
'Extract "OnOpenRes:*:" from Tag-Option of Form
TagString = LCase(frm.Tag) 'lower case tag-field
TagStringPosition = InStr(TagString, "onopenres:") 'get left position of resolution
If TagStringPosition > 0 Then
TagString = Mid(TagString, TagStringPosition + 10) 'get string starting with resolution (the "+10" is the char count of "OnOpenRes:"
TagStringPosition = InStr(TagString, ":") 'Get Position of ":" behind resolution
TagString = Left(TagString, TagStringPosition - 1) 'remove everything behind ":" - the variable now contains the OnOpen resolution
ReDim TagStringArray(1)
TagStringArray = Split(TagString, "x") '"x" is the delimiter
OnOpenWindowWidth = TagStringArray(0)
OnOpenWindowHeight = TagStringArray(1)
Erase TagStringArray
Else
Call WM_apiGetWindowRect(frm.hWnd, rectWindow) 'prepare for getting size of current window on screen
OnOpenWindowWidth = rectWindow.Right - rectWindow.Left
OnOpenWindowHeight = rectWindow.Bottom - rectWindow.Top
frm.Tag = frm.Tag & ", OnOpenRes:" & OnOpenWindowWidth & "x" & OnOpenWindowHeight & ":"
End If
'check if form has already been opened and is part of the array
'if not, write the properties to the array
FormExists = 0 'means name of form is not in the array, initially
For ArrayCount = LBound(arrCtlsScaleForm) To UBound(arrCtlsScaleForm)
If arrCtlsScaleForm(ArrayCount).FormName = frm.NAME Then FormExists = 1 'form name is already in the array, no need to write array
Next ArrayCount
If FormExists = 0 Then
ArrayCount = UBound(arrCtlsScaleForm) + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount) 'Increase the size of the array.
For Each ctl In frm.Controls
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = ctl.NAME
.Height = ctl.Height
.Width = ctl.Width
.Top = ctl.Top
.Left = ctl.Left
.FontSize = ctl.FontSize
.ColumnWidths = ctl.ColumnWidths
.ListWidth = ctl.ListWidth
.TabFixedWidth = ctl.TabFixedWidth
.TabFixedHeight = ctl.TabFixedHeight
End With
ArrayCount = ArrayCount + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount) 'Increase the size of the array.
Next ctl
'save initial heights for header, detail, footer
ArrayCount = UBound(arrCtlsScaleForm) + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount)
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = "xxxHeaderxxx"
.Height = frm.Section(Access.acHeader).Height
End With
ArrayCount = ArrayCount + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount)
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = "xxxDetailxxx"
.Height = frm.Section(Access.acDetail).Height
End With
ArrayCount = ArrayCount + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount)
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = "xxxFooterxxx"
.Height = frm.Section(Access.acFooter).Height
End With
ArrayCount = ArrayCount + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount)
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = "xxxLastScaleVertFactorxxx"
.Height = 1
End With
ArrayCount = ArrayCount + 1
ReDim Preserve arrCtlsScaleForm(ArrayCount)
With arrCtlsScaleForm(ArrayCount)
.FormName = frm.NAME
.NAME = "xxxLastScaleHorzFactorxxx"
.Height = 1
End With
End If
Call WM_apiGetWindowRect(frm.hWnd, rectWindow) 'prepare for getting size of current window on screen
CurrentWindowWidth = rectWindow.Right - rectWindow.Left
CurrentWindowHeight = rectWindow.Bottom - rectWindow.Top
For ArrayCount = LBound(arrCtlsScaleForm) To UBound(arrCtlsScaleForm)
If arrCtlsScaleForm(ArrayCount).FormName = frm.NAME Then
Select Case arrCtlsScaleForm(ArrayCount).NAME
Case "xxxLastScaleHorzFactorxxx"
LastScaleHorzFactor = arrCtlsScaleForm(ArrayCount).Height
Case "xxxLastScaleVertFactorxxx"
LastScaleVertFactor = arrCtlsScaleForm(ArrayCount).Height
End Select
End If
Next
'Calculate the scaling factors and round them to 2 decimal places.
'This ensures that changes happen only in the area of 1% relative to the original size
ScaleVertFactor = Round((CurrentWindowHeight / OnOpenWindowHeight), 2)
ScaleHorzFactor = Round((CurrentWindowWidth / OnOpenWindowWidth), 2)
ScaleFontFactor = VBA.IIf(ScaleHorzFactor < ScaleVertFactor, ScaleHorzFactor, ScaleVertFactor)
If (ScaleVertFactor = LastScaleVertFactor) And (ScaleHorzFactor = LastScaleHorzFactor) Then
'nothing to rescale
Exit Sub
Else
'there is something to rescale, so we update the array
For ArrayCount = LBound(arrCtlsScaleForm) To UBound(arrCtlsScaleForm)
If arrCtlsScaleForm(ArrayCount).FormName = frm.NAME Then
Select Case arrCtlsScaleForm(ArrayCount).NAME
Case "xxxLastScaleHorzFactorxxx"
arrCtlsScaleForm(ArrayCount).Height = ScaleHorzFactor
Case "xxxLastScaleVertFactorxxx"
arrCtlsScaleForm(ArrayCount).Height = ScaleVertFactor
End Select
End If
Next
End If
frm.Painting = False 'Turn off painting
For ArrayCount = LBound(arrCtlsScaleForm) To UBound(arrCtlsScaleForm)
If arrCtlsScaleForm(ArrayCount).FormName = frm.NAME Then
Select Case arrCtlsScaleForm(ArrayCount).NAME
Case "xxxHeaderxxx"
frm.Section(Access.acHeader).Height = arrCtlsScaleForm(ArrayCount).Height * ScaleVertFactor
Case "xxxDetailxxx"
frm.Section(Access.acDetail).Height = arrCtlsScaleForm(ArrayCount).Height * ScaleVertFactor
Case "xxxFooterxxx"
frm.Section(Access.acFooter).Height = arrCtlsScaleForm(ArrayCount).Height * ScaleVertFactor
End Select
End If
Next ArrayCount
For ArrayCount = LBound(arrCtlsScaleForm) To UBound(arrCtlsScaleForm)
If (arrCtlsScaleForm(ArrayCount).FormName = frm.NAME) And (arrCtlsScaleForm(ArrayCount).NAME <> "") Then
'On Error GoTo err
If frm.Controls.Item(arrCtlsScaleForm(ArrayCount).NAME).ControlType <> Access.acPage Then 'Ignore pages in Tab controls.
With frm.Controls.Item(arrCtlsScaleForm(ArrayCount).NAME)
If ScaleVertFactor <> LastScaleVertFactor Then
.Height = arrCtlsScaleForm(ArrayCount).Height * ScaleVertFactor
.Top = arrCtlsScaleForm(ArrayCount).Top * ScaleVertFactor
End If
If ScaleHorzFactor <> LastScaleHorzFactor Then
.Left = arrCtlsScaleForm(ArrayCount).Left * ScaleHorzFactor
.Width = arrCtlsScaleForm(ArrayCount).Width * ScaleHorzFactor
End If
If .FontSize > 0 Then
.FontSize = arrCtlsScaleForm(ArrayCount).FontSize * ScaleFontFactor
End If
Select Case frm.Controls.Item(arrCtlsScaleForm(ArrayCount).NAME).ControlType
Case Access.acListBox
.ColumnWidths = ScaleColumnWidths(arrCtlsScaleForm(ArrayCount).ColumnWidths, ScaleHorzFactor)
Case Access.acComboBox
.ColumnWidths = ScaleColumnWidths(arrCtlsScaleForm(ArrayCount).ColumnWidths, ScaleHorzFactor)
.ListWidth = arrCtlsScaleForm(ArrayCount).ListWidth * ScaleHorzFactor
Case Access.acTabCtl
.TabFixedWidth = arrCtlsScaleForm(ArrayCount).TabFixedWidth * ScaleHorzFactor
.TabFixedHeight = arrCtlsScaleForm(ArrayCount).TabFixedHeight * ScaleVertFactor
End Select
End With
End If
End If
Next
frm.Painting = True
'Keep this comments for debugging reasons
frm.txtOnOpenwindowWidth = OnOpenWindowWidth
frm.txtOnOpenwindowHeight = OnOpenWindowHeight
frm.txtCurrentwindowWidth = CurrentWindowWidth
frm.txtCurrentwindowHeight = CurrentWindowHeight
frm.txtscalevertfactor = ScaleVertFactor
frm.txtscalehorzfactor = ScaleHorzFactor
'Free up resources
Set ctl = Nothing 'Free up resources.
Set frm = Nothing 'Free up resources.
End Sub
Function isSubform(frmIn As Form) As Boolean
Dim strX As String
On Error Resume Next
strX = frmIn.Parent.NAME
isSubform = Err.Number = 0
End Function
Private Function ScaleColumnWidths(DesignColumnWidths As String, ScaleColumnWidthFactor As Single) As String
On Error Resume Next
Dim DesignColumnWidthsArray() As String
Dim NewColumnWidths As String
Dim TempVar As Long
ReDim DesignColumnWidthsArray(0)
DesignColumnWidthsArray = Split(DesignColumnWidths, ";")
NewColumnWidths = vbNullString
For TempVar = LBound(DesignColumnWidthsArray) To UBound(DesignColumnWidthsArray)
If Not IsNull(DesignColumnWidthsArray(TempVar)) And DesignColumnWidthsArray(TempVar) <> "" Then
NewColumnWidths = NewColumnWidths & CSng(DesignColumnWidthsArray(TempVar)) * ScaleColumnWidthFactor & ";"
End If
Next
ScaleColumnWidths = NewColumnWidths
Erase DesignColumnWidthsArray
End Function
Function InitialInsertCodeIntoForms()
Dim lngProcCountLines As Long
Dim lngProcStartLine As Long
Dim loCont As Container
Dim loDb As Database
Dim loDoc As Document
Dim loForm As Form
Dim loMod As Module
Dim pkType As Long
Dim strCode As String
Dim strName As String
Set loDb = CurrentDb
Set loCont = loDb.Containers("Forms")
For Each loDoc In loCont.Documents
strName = loDoc.NAME
DoCmd.OpenForm strName, acDesign
Set loForm = Forms(strName)
Debug.Print loForm.NAME; ".HasModule = "; loForm.HasModule
If loForm.HasModule = True Then
Set loMod = loForm.Module
On Error Resume Next
lngProcStartLine = loMod.ProcStartLine("Form_Open", pkType)
If Err > 0 Then
Debug.Print vbTab; "FormOpen Added"
loForm.OnOpen = "[Event Procedure]"
lngProcStartLine = loMod.CountOfLines
strCode = "Private Sub Form_Open(Cancel As Integer)" _
& vbCrLf _
& "ScaleFormWindow Me" _
& vbCrLf _
& "End Sub"
loMod.InsertLines lngProcStartLine + 1, strCode
Else
Debug.Print vbTab; "FormOpen Edited"
lngProcCountLines = loMod.ProcCountLines("Form_Open", pkType)
loMod.InsertLines lngProcStartLine + lngProcCountLines - 1, "ScaleFormWindow Me"
End If
If loForm.OnOpen <> "[Event Procedure]" Then Debug.Print vbTab; "Check OnOpen Event, it is not set to [Event Procedure]."
Err.Clear
End If
If loForm.HasModule = True Then
Set loMod = loForm.Module
On Error Resume Next
lngProcStartLine = loMod.ProcStartLine("Form_Resize", pkType)
If Err > 0 Then
Debug.Print vbTab; "FormResize Added"
loForm.OnOpen = "[Event Procedure]"
lngProcStartLine = loMod.CountOfLines
strCode = "Private Sub Form_Resize()" _
& vbCrLf _
& "ScaleFormControls Me" _
& vbCrLf _
& "End Sub"
loMod.InsertLines lngProcStartLine + 1, strCode
Else
Debug.Print vbTab; "FormResize Edited"
lngProcCountLines = loMod.ProcCountLines("Form_Resize", pkType)
loMod.InsertLines lngProcStartLine + lngProcCountLines - 1, "ScaleFormControls Me"
End If
If loForm.OnResize <> "[Event Procedure]" Then Debug.Print vbTab; "Check OnResize Event, it is not set to [Event Procedure]."
Err.Clear
End If
DoCmd.Close acForm, strName, acSaveYes
Next
Set loMod = Nothing
Set loForm = Nothing
Set loDoc = Nothing
Set loCont = Nothing
Set loDb = Nothing
End Function
Function PreScale()
Dim ArrayCount As Long
Dim ctl As Control
Dim DesignResDPI As Long
Dim DesignResHeight As Long
Dim DesignResWidth As Long
Dim FormHasToBeScaled As Boolean
Dim FormNameArray() As String
Dim frm As Object
Dim frm2 As Form
Dim KeepOriginalFormNames As Boolean
Dim NewFormName As String
Dim ScaleFontFactor As Single
Dim ScaleHorzFactor As Single
Dim ScaleVertFactor As Single
Dim TagString As String
Dim TagStringArray() As String
Dim TagStringPosition As Long
Dim TagStringPosition2 As Long
Dim TagStringPosition3 As Long
Dim TagStringTemp As String
Dim TargetResDPI As Long
Dim TargetResHeight As Long
Dim TargetResString As String
Dim TargetResWidth As Long
Dim TempString As String
'Define options here
TargetResWidth = 1400
TargetResHeight = 1050
TargetResDPI = 96
KeepOriginalFormNames = False
Debug.Print "==========================================="
Debug.Print "Starting"
Debug.Print "==========================================="
'Write the names of all forms to an array
ReDim FormNameArray(0)
ArrayCount = UBound(FormNameArray)
Debug.Print
Debug.Print "Writing form names to array"
Debug.Print "==========================================="
Debug.Print
For Each frm In CurrentProject.AllForms
ReDim Preserve FormNameArray(ArrayCount)
FormNameArray(ArrayCount) = frm.NAME
Debug.Print frm.NAME
ArrayCount = ArrayCount + 1
Next
TargetResString = "_mSF" & TargetResWidth & "x" & TargetResHeight & "x" & TargetResDPI
'delete all existing prescaled forms for target resolution
Debug.Print
Debug.Print "Deleting existing forms for " & TargetResWidth & "x" & TargetResHeight & "x" & TargetResDPI
Debug.Print "==========================================="
Debug.Print
For ArrayCount = LBound(FormNameArray) To UBound(FormNameArray)
If Right(FormNameArray(ArrayCount), Len(TargetResString)) = TargetResString Then 'this form can be deleted
On Error Resume Next
DoCmd.DeleteObject acForm, FormNameArray(ArrayCount)
Debug.Print FormNameArray(ArrayCount)
End If
Next
Debug.Print
Debug.Print "Starting form manipulation"
Debug.Print "==========================================="
Debug.Print
For ArrayCount = LBound(FormNameArray) To UBound(FormNameArray)
Debug.Print FormNameArray(ArrayCount)
If InStr(1, FormNameArray(ArrayCount), "_msf", vbTextCompare) > 0 Then
'form has "_msf" in the name, so it has already been scaled for another resolution
Debug.Print " skipped, it has already been scaled for another resolution"
Else
If Len(FormNameArray(ArrayCount) & TargetResString) <= 64 Then
FormHasToBeScaled = True
DoCmd.OpenForm FormNameArray(ArrayCount), acDesign
Set frm2 = Forms(FormNameArray(ArrayCount))
'Extract "DesignRes:*:" from Tag-Option of Form
TagString = LCase(frm2.Tag) 'lower case tag-field
TagStringPosition = InStr(TagString, "designres:") 'get left position of resolution
If TagStringPosition > 0 Then
TagString = Mid(TagString, TagStringPosition + 10) 'get string starting with resolution (the "+10" is the char count of "DesignRes:"
TagStringPosition = InStr(TagString, ":") 'Get Position of ":" behind resolution
TagString = Left(TagString, TagStringPosition - 1) 'remove everything behind ":" - the variable now contains the design resolution
ReDim TagStringArray(1)
TagStringArray = Split(TagString, "x") '"x" is the delimiter
If UBound(TagStringArray) >= 0 Then DesignResWidth = TagStringArray(0)
If UBound(TagStringArray) >= 1 Then DesignResHeight = TagStringArray(1)
If UBound(TagStringArray) >= 2 Then DesignResDPI = TagStringArray(2)
If (DesignResWidth <= 0) Or (DesignResHeight <= 0) Or (DesignResDPI <= 0) Then
DesignResWidth = 0
DesignResHeight = 0
DesignResDPI = 0
End If
Erase TagStringArray
Else
'DesignRes is not specified in the form so we use default values for scaling
DesignResWidth = 0
DesignResHeight = 0
DesignResDPI = 0
End If
If (DesignResWidth > 0) And (DesignResHeight > 0) And (DesignResDPI > 0) Then
If (DesignResWidth = TargetResWidth) And (DesignResHeight = TargetResHeight) And (DesignResDPI = TargetResDPI) Then
Debug.Print " Forms DesignRes is equal to the TargetRes, so it does not have to be scaled"
FormHasToBeScaled = False
End If
Else
If (DefaultDesignWidth = TargetResWidth) And (DefaultDesignHeight = TargetResHeight) And (DefaultDesignDPI = TargetResDPI) Then
Debug.Print " Forms DesignRes is not set, TargetRes is equal to DefaultDesignRes, so it does not have to be scaled"
FormHasToBeScaled = False
End If
End If
DoCmd.Close acForm, FormNameArray(ArrayCount), acSaveNo
If FormHasToBeScaled = True Then
On Error Resume Next
If KeepOriginalFormNames = True Then
NewFormName = FormNameArray(ArrayCount)
Else
NewFormName = FormNameArray(ArrayCount) & TargetResString
DoCmd.CopyObject , NewFormName, acForm, FormNameArray(ArrayCount)
Debug.Print " copying to " & NewFormName
Debug.Print " changing subform names"
End If
DoCmd.OpenForm NewFormName, acDesign
If KeepOriginalFormNames = False Then
For Each ctl In Screen.ActiveForm.Controls
TempString = ctl.SourceObject & TargetResString
ctl.SourceObject = TempString
Next
End If
Debug.Print " scaling controls"
If (DesignResWidth > 0) And (DesignResHeight > 0) And (DesignResDPI > 0) Then
ScaleVertFactor = (TargetResHeight / DesignResHeight) * (TargetResDPI / DesignResDPI)
ScaleHorzFactor = (TargetResWidth / DesignResWidth) * (TargetResDPI / DesignResDPI)
ScaleFontFactor = VBA.IIf(ScaleHorzFactor < ScaleVertFactor, ScaleHorzFactor, ScaleVertFactor)
Else
ScaleVertFactor = (TargetResHeight / DefaultDesignHeight) * (TargetResDPI / DefaultDesignDPI)
ScaleHorzFactor = (TargetResWidth / DefaultDesignWidth) * (TargetResDPI / DefaultDesignDPI)
ScaleFontFactor = VBA.IIf(ScaleHorzFactor < ScaleVertFactor, ScaleHorzFactor, ScaleVertFactor)
End If
Screen.ActiveForm.Width = Screen.ActiveForm.Width * ScaleHorzFactor
Screen.ActiveForm.Section(Access.acHeader).Height = Screen.ActiveForm.Section(Access.acHeader).Height * ScaleVertFactor
Screen.ActiveForm.Section(Access.acDetail).Height = Screen.ActiveForm.Section(Access.acDetail).Height * ScaleVertFactor
Screen.ActiveForm.Section(Access.acFooter).Height = Screen.ActiveForm.Section(Access.acFooter).Height * ScaleVertFactor
For Each ctl In Screen.ActiveForm.Controls
If ctl.ControlType <> Access.acPage Then 'Ignore pages in Tab controls.
With ctl
.Height = ctl.Height * ScaleVertFactor
.Top = ctl.Top * ScaleVertFactor
.Left = ctl.Left * ScaleHorzFactor
.Width = ctl.Width * ScaleHorzFactor
If .FontSize > 0 Then
.FontSize = ctl.FontSize * ScaleFontFactor
End If
Select Case ctl.ControlType
Case Access.acListBox
.ColumnWidths = ScaleColumnWidths(ctl.ColumnWidths, ScaleHorzFactor)
Case Access.acComboBox
.ColumnWidths = ScaleColumnWidths(ctl.ColumnWidths, ScaleHorzFactor)
.ListWidth = ctl.ListWidth * ScaleHorzFactor
Case Access.acTabCtl
.TabFixedWidth = ctl.TabFixedWidth * ScaleHorzFactor
.TabFixedHeight = ctl.TabFixedHeight * ScaleVertFactor
End Select
End With
End If
Next
frm.Painting = True
'remove temporary OnOpenRes from Tag
Set frm2 = Forms(NewFormName)
frm2.Tag = Left(frm2.Tag, (InStr(LCase(frm2.Tag), LCase("onopenres:")) - 3))
'Update DesignRes
If InStr(LCase(frm2.Tag), LCase("designres:")) > 0 Then 'designres is set in the form, so remove it
TagStringPosition2 = InStr(LCase(frm2.Tag), LCase("designres:"))
TagStringPosition3 = InStr(TagStringPosition2 + Len("designres:"), frm2.Tag, ":")
TagStringPosition3 = Len(frm2.Tag) - TagStringPosition3
TagStringTemp = Left(frm2.Tag, TagStringPosition2 - 1) & Right(frm2.Tag, TagStringPosition3)
frm2.Tag = TagStringTemp
End If
frm2.Tag = frm2.Tag & ", DesignRes:" & TargetResWidth & "x" & TargetResHeight & "x" & TargetResDPI & ":"
'Save scaled form
DoCmd.Close acForm, NewFormName, acSaveYes
End If
Else
Debug.Print NewFormName & " would have more than 64 characters - form was not created."
End If
End If
Next
Debug.Print
Debug.Print "==========================================="
Debug.Print "Finished!"
Debug.Print "==========================================="
End Function
Public Function mSFOpenForm( _
FormName As String, _
Optional View As AcFormView = acNormal, _
Optional FilterName As String, _
Optional WhereCondition As String, _
Optional DataMode As AcFormOpenDataMode = acFormPropertySettings, _
Optional WindowMode As AcWindowMode = acWindowNormal, _
Optional OpenArgs As String) As String
'this function returns the name of the opened form as String
Dim frm As Object
Dim GetScreenResolution As tDisplay
Dim hDCcaps As Long
Dim lngRtn As Long
Dim ScaledFormName As String
hDCcaps = WM_apiGetDC(0) 'Get display context for desktop (hwnd = 0).
With GetScreenResolution
.Height = WM_apiGetDeviceCaps(hDCcaps, WM_VERTRES)
.Width = WM_apiGetDeviceCaps(hDCcaps, WM_HORZRES)
.DPI = WM_apiGetDeviceCaps(hDCcaps, WM_LOGPIXELSX)
End With
lngRtn = WM_apiReleaseDC(0, hDCcaps) 'Release display context.
ScaledFormName = FormName & "_mSF" & GetScreenResolution.Width & "x" & GetScreenResolution.Height & "x" & GetScreenResolution.DPI
For Each frm In CurrentProject.AllForms
If LCase(frm.NAME) = LCase(ScaledFormName) Then
FormName = frm.NAME
End If
Next
DoCmd.OpenForm FormName, View, FilterName, WhereCondition, DataMode, WindowMode, OpenArgs
mSFOpenForm = FormName
End Function