=Count([qty_rec])/Count([sub]) is the control source for a text box. Format for the control is 'percentage'. I have also tried 'standard', fixed and leaving it blank. I suspect the evaluation is comparing apples to oranges.
Private Sub Form_Current()
If Me.txt_percent_received = 0.5 Then
Me.cbtn_shortage.Visible = False
Else
End If
End Sub
I put breakpoint at If and goto to immediate and type ?Me.txt_percent_received
It says 0.5
Why does system think this number is too big?
and why does it work if I step thru the code?
Updated
Dim intTemp As Integer
intTemp = Me.txt_percent_received
If intTemp = 0.5 Then
Me.cbtn_shortage.Visible = False
Else
End If
Now the error is on intTemp = Me.txt_percent_received
qty_rec and sub are for totaling populated fields.
I have reproduced the effect, and I think what happens here is:
Calculated controls are evaluated after the form has finished loading. If you remove the event code, and open the form, you will notice that the value of txt_percent_received is displayed with a slight delay.
You may even notice that at first it displays #Number!, and then calculates the value.
But the form events happen before that, so what you get is a division of 0/0, and this gets runtime error 6 "Overflow".
1/0 would get error 11 "Division by zero".
You need a different way either to calculate txt_percent_received, or to implement your cbtn_shortage logic.
Related
I'd like to add some extra space every 10 lines on each report page for readability.
I've tried counting lines and changing the height of the detail section in the Detail_Format event routine but that didn't seem to do anything.
Then I tried using a tall dummy field with just a space char that was made visible every 10 lines (along with the proper CanShrink settings), and the extra space was visible but not on the correct lines. Instrumentation showed that the event routine was calculating properly but the effect seemed to be out of sync.
But there must be a straightforward way to do this, right? Any suggestions?
Such a result is only possible at print layout as far as I know.
That's how I did it:
The sample counts the printed rows for each page and uses the Print event of the Detail section to add an empty row if necessary by setting PrintSection and NextRecord properties of the report.
To assure a resetting of the counter for each page and prevent that the first row of a page will be blank the Format event of the PageHeaderSection is used.
Use the constant INSERT_BLANK_ROW_EVERY to set when a blank row should be inserted.
Const INSERT_BLANK_ROW_EVERY As Integer = 10
Dim insertBlankRowNext As Integer
Dim pageLineCount As Integer
Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer)
If PrintCount = 1 Then pageLineCount = pageLineCount + 1
Me.PrintSection = Not insertBlankRowNext
Me.NextRecord = Not insertBlankRowNext
insertBlankRowNext = (pageLineCount Mod INSERT_BLANK_ROW_EVERY = 0)
End Sub
Private Sub PageHeaderSection_Format(Cancel As Integer, FormatCount As Integer)
pageLineCount = 0
insertBlankRowNext = False
End Sub
Regarding the PrintCount parameter Microsoft writes:
Microsoft Access increments the PrintCount property each time the OnPrint property setting is evaluated for the current section. As the next section is printed, Access resets the PrintCount property to 0.
See details here: Report.PrintCount property
You can also add dummy fake records that are blank.
Assuming your report is based on query e.g. Query1, instead of your using it as RecordSource for the report, you could use it as source for a table (Make Table) and create a table that holds the information you want but with the extra records (lines) for readability.
Just after the "dumping" of the Query1 to table..you load it on a RecordSet ...you iterate the records and according to your needs you .AddNew records.
Based on the information in UnhandledException's answer, this is how I did it, and it's it's actually very easy to do.
Step 1: Add a text box of the desired height on the detail line. I think CanShrink must be set for both the text box and the detail line.
Step 2: Add these to your event handling:
Private Sub Detail_Format(Cancel As Integer, FormatCount As Integer)
LineFormatEvents = LineFormatEvents + 1
Me.txtExtraSpace.Visible = (LineFormatEvents Mod 10 = 0)
End Sub
Private Sub PageHeaderSection_Paint()
LineFormatEvents = 0
End Sub
Note that I'm using Access 2016; I don't know how many versions back this will work.
What I'm trying to do is, whenever a user opens a form (and the sub-form that opens by default), I want to search through all the columns (controls?) on the form, check to see if they are currently set to aggregate (sum, count etc.) with Access' built-in Totals row, and if so, set them to not aggregate.
The reason for this is there are several millions records that are stored, so when someone queries it down to 3-4 and turns on Sum, then closes it, when the next person opens it, it tries to sum millions of numbers and freezes up. The form displays the queried results from a table which is populated via SQL (I think, if that sentence makes sense). Here's what I have so far:
Private Sub Form_Load()
'this form_load is in the UserApxSub sub-form, for reference
Call De_Aggregate
End Sub
Private Sub De_Aggregate()
Dim frm As Form, con As Control
Set frm = Forms!UserAPX!UserApxSub.Form!
For Each con In frm.Controls
If con.ControlType = acTextBox Then
If con.Properties("AggregateType").Value <> -1 Then
'crashes on following line
con.Properties("AggregateType").Value = -1
End If
End If
Next con
End Sub
I have not so much experience in Access VBA (usually work in Excel VBA) so please forgive me if I'm entirely off the mark here. The command con.Properties("AggregateType").Value = -1 doesn't throw an error, but Access just straight-up crashes when reaching that line specifically.
I've tried a number of variations in the syntax with no success, and I've also tried looping through other elements of the file (tabledefs, querydefs, recordsets, etc.) as well to see if I'm trying to change the wrong value, but the controls on this subform are the only things in the entire .mdb file that results when I search for elements with the AggregateType property.
I switched out the line that errors with Debug.Print con.Name & " - " & con.Properties("AggregateType").Value and I can check, have nothing return anything other than -1, turn on aggregation in some column manually, and have it return the correct result (0 for sum for example), so I think I'm looking in the right place, just missing some key factor.
I've been working on this for a couple weeks with no success. Any way to fix what I have or point me toward the right direction would be greatly appreciated!
This is not necessarily the answer but I don't have enough reputation
to give a "comment"...
I tried your scenario and verified can change the property value as you are however I did not iterate through all controls and simply used an onDoubleClick event on a column to simulate.
I would suggest trying to fire your sub with Form_Open or Form_Current to see if the property is getting reset after your code has been called for some reason.
UPDATE:
You are referencing the "Subform" Object of your main Form:
Set frm = Forms!UserAPX!UserApxSub.Form!
Try referencing the actual UserApxSub FORM explicitly.
Something like Set frm = Forms!UserApxSub! (assuming UserApxSub is the name of the form)
then stick in the Form_Open of your main form:
Private Sub Form_Open(Cancel As Integer)
'// the following would set a single control only. You can add your loop through all controls
Me!{your control name}.Properties("AggregateType").Value = -1 '// set control in your main form
Form_UserApxSub!{your control name}.Properties("AggregateType").Value = -1 '// set control in your "sub" form
End Sub
I am having a trouble while trying to conditionally format the exhibition of records in a report inside a MS Access 2007 form.
I have search the Internet and I have seen lots os fellows stating that it is possible to perform visual changes in a single record via code implementing the method Detail_Paint() for the event Paint of the Detail section in a Report. Those people say that something like this is going to work:
Private Sub Detail_Paint()
val = CStr(Me.someTextBox.Value)
If val = "constraint" Then
Me.lineStrikethrough.BorderStyle = 0
End If
End Sub
The problem is that although the reading statement Me.someTextBox.Value returns the value of each record when the Paint event is thrown, the writing statement Me.lineStrikethrough.BorderStyle = 0 writes the value of the property BorderStyle for every single line in my report, not only for the one respecting the single record whose value I read from someTextBox field.
Can anyone tell me why such is happening? If this is the correct behaviour (although it does not seem right to me), how can I achieve my goal?
Note: lineStrikethrough is used to perform a strikethrough effect over the record in a Report. If there is another way to do that I would be happy to know.
Two things:
1 - Use the Detail's On Print event and not On Paint event.
Private Sub Detail_Print(Cancel As Integer, PrintCount As Integer)
val = CStr(Me.someTextBox.Value)
If val = "constraint" Then
Me.lineStrikethrough.BorderStyle = 0
End If
End Sub
2 - To see the conditional formatting, always open your report in Print Preview and not Report View.
You are really close!! :-) In my testing, it appears that the Detail_Paint() event allows you to change the formatting of controls, but changes will continue in subsequent records until you change/reset them to something else.
In your code sample, you just need to add another line to turn the strikethrough BorderStyle back on when the condition is no longer met.
Private Sub Detail_Paint()
Val = CStr(Me.someTextBox.Value)
If Val = "constraint" Then
Me.lineStrikethrough.BorderStyle = 0
Else
Me.lineStrikethrough.BorderStyle = 1
End If
End Sub
I found this clue on a code sample on MSDN which demonstrates conditional formatting using the Detail_Paint() method.
I found that Select Case to work best in the detail paint over if statements for a continuous form.
'Private Sub Detail_Paint()
Select Case CStr(Me.someTextBox.Value)
Case "constraint"
Me.lineStrikethrough.BorderStyle = 0
Case Else
Me.lineStrikethrough.BorderStyle = 1 'or what the default value is
End Select
I have a report which is like an hourly schedule for a whole week. Each cell in the schedule is 1 day for 1 machine. Each column is one of 7 machines. Thus, a row consists of 7 day cells. So far so good, but each day needs 18 rows of text (a Memo field) and - each row needs to be colorized. I've created 18 labels numbered Label33 and up, for each of the 7 columns.
I'm setting their BackColor with a pretty large case statement of 7 cases and 18 x Labelnn.Backcolor=aColor in each case.
However, I'd like to replace this with something that forms the control_name="Label" & nn, and do something like Me.control_name.BackColor=aColor.
Possible? How? (No, considering how flexible VBA-Access is I haven't tried the above yet.)
Cody Gray is correct but this is not helpful if you do not know what a control array is.
The following is Excel VBA but I have done the same with Access VBA but not recently. I think the syntax is the same but I do not guarantee it.
I created a workbook, inserted a form, pulled a selection of controls onto it and then ran the following code:
Option Explicit
Sub TestControls()
Dim InxC As Long
Load UserForm1
With UserForm1
For InxC = 0 To .Controls.Count - 1
Debug.Print .Controls(InxC).Name
Next
End With
End Sub
The output to the immediate window was:
Label1
CommandButton1
ComboBox1
CommandButton2
OptionButton1
You can see that Label1.xxx is exactly the same as .Controls(0).xxx. I name my controls systematically so I can run code like:
With UserForm1
For InxC = 0 To .Controls.Count - 1
If Mid(.Controls(InxC).Name,1,5) = "lblXx" Then
' Code to set properties of all lblXx controls
End If
Next
End With
I use this functionality most when I do not know how many of a particularly type of control I need. I create 10, say, of them which is more than I will ever need and make them all invisible.
At run time, I make those I need visible and set their top and left properties as necessary.
I agree with Cody Gray. Use the Control Arrays.
Here is a link which will help you
http://www.siddharthrout.com/index.php/2018/01/15/vba-control-arrays/
Though Tony has given you a relatively easy way to do it but there are instances where you might add or delete a control or simply mess up on the sequence. Also there are instances when you simply cannot leave the label as Label1. You might be adding some text to it so that it signifies something...
In such a scenario use TypeOf instead of Name
For example
Option Compare Database
Private Sub Command1_Click()
Dim ctl As Control
For Each ctl In Me.Controls
If TypeOf ctl Is Label Then
Debug.Print ctl.Name
End If
Next ctl
End Sub
Is there a way to disable entering multi-line entries in a Text Box (i.e., I'd like to stop my users from doing ctrl-enter to get a newline)?
I was able to do it on using KeyPress event.
Here's the code example:
Private Sub SingleLineTextBox_ KeyPress(ByRef KeyAscii As Integer)
If KeyAscii = 10 _
or KeyAscii = 13 Then
'10 -> Ctrl-Enter. AKA ^J or ctrl-j
'13 -> Enter. AKA ^M or ctrl-m
KeyAscii = 0 'clear the the KeyPress
End If
End Sub
The way I did it before (and the last time I worked in Access was around '97 so my memory is not so hot) was raising a key-up event and executing a VBA function. It's a similar method to what you do with an AJAX suggest text box in a modern webform application, but as I recall it could get tripped up if your Access form has other events which tend to occur frequently such a onMouseMove over the entire form object.
Using the KeyPress event means that your code will fire every time the user types. This can lead to screen flickering and other problems (the OnChange event would be the same).
It seems to me that you should use a single event to strip out the CrLf's, and the correct event would be AfterUpdate. You'd simply do this:
If InStr(Me!MyMemoControl, vbCrLf) Then
Me!MyMemoControl = Replace(Me!MyMemoControl, vbCrLf, vbNullString)
End If
Note the use of the Access global constants, vbCrLf (for Chr(10) & Chr(13)) and vbNullString (for zero-length string).
Using a validation rule means that you're going to pop up an ugly error message to your user, but provide them with little in the way of tools to correct the problem. The AfterUpdate approach is much cleaner and easier for the users, seems to me.
Thanks Ian and BIBD. I created a public sub based on your answer that is reusable.
Public Sub PreventNewlines(ByRef KeyAscii As Integer)
If KeyAscii = 10 Or KeyAscii = 13 Then KeyAscii = 0
End Sub
Private Sub textbox_KeyPress(KeyAscii As Integer)
Call PreventNewlines(KeyAscii)
End Sub
Screen flicker should never be an issue, as these are handled events, not constant polling (and it's per control further limiting the scope). Seems to me like an invalid argument, as every text editor is executing some code per keystroke.
Thanks
not entirely sure about that one, you should be able to remove the line breaks when you render the content though, or even run a vbscript to clear it out, you just need to check for chr(13) or vbCrLf.
If you don't want an event interfering, you can set up the Validation Rule property for the textbox to be
NOT LIKE "*"+Chr(10)+"*" OR "*"+Chr(13)+"*"
You will probably also want to set the Validation Text to explain specifically why Access is throwing up an error box.
Jason's response works well. Just to add to it..
If you want to allow the user to leave the text box blank, you could use this:
Not Like ""+Chr(10)+"" Or ""+Chr(13)+"" Or Is Null