Return the line to its original position after making a Requery - vba

I apologize for my English is a Google translation.
This is a question that I have had a hard time with for a long time and in all the places that have been talked about it remains unanswered, so I am publishing my solution for the benefit of all.
Sometimes you are required to refresh the source of the form (in continuous form) and then you use let's say a bookmark to return to the record you were before the refresh, the problem is that if we say the form now shows you records 40-60 and you stand on record 45, when you return to 45 after refresh it is not The fifth will be displayed on the screen but it will be the first, which may cause confusion for the user, I have always looked for a way to return the same record that will be the fifth on the screen and the user will not see any change.
I found that it is possible to use the "CurrentSectionTop" property, it means where you are located in relation to the top edge of the form, you need to lower the height of the header from it.
Below is the code:
Const MaxRecordInViwe = 50
Const ValuePerLine = 564
MySelTop = Me.SelTop
CurrentRowInViwe = (Me.CurrentSectionTop - Me.FormHeader.Height) / ValuePerLine
Me.Requery
Me.SelTop = (MySelTop - MyCurrentRowInViwe) + MaxRecordInViwe
Me.SelTop = MySelTop - MyCurrentRowInViwe
Me.SelTop = MySelTop
If your screen has more than 50 entries, you will change the default "MaxRecordInViwe", if you enter less you can leave it unchanged.
The constant "ValuePerLine" fits my form, I did not find a formula to calculate it but you can find it manually:
Go to the first record
In the Immediate window, type the following code:
?Form_table1.CurrentSectionTop - Form_Table1.FormHeader.Height
In the form, go to the second entry
In the Immediate window, type the following code:
?(Form_table1.CurrentSectionTop- Form_Table1.FormHeader.Height)- {The previous result})
Enter the result to set "ValuePerLine"

Related

How to identify which monitor a winform is displayed on, in a multi monitor setup?

I have found a lot of answers researching this, but non address my question.
Assume that user has 2 monitors, say a laptop screen with 1600×1200 res, and external monitor of 2560×1440 res. Regardless how the 2 displays are set up, if a client moves the main-form of the program to the external monitor, I would like it to report that its on 2560×1440 res. When the main-form is moved on to the laptop it should report the 1600x1200.
Is this possible? I know how to report the res, I just do not know how to identify which monitor the main-form is sitting on.
You need to first identify what you mean by the form being on a screen, because it's possible for a single form to span multiple screens. You're going to be using the Screen class regardless, but the calculations will be different. The simplest option would be to use the Location property, e.g.
For Each scrn In Screen.AllScreens
If scrn.Bounds.Contains(Location) Then
MessageBox.Show($"Resolution: {scrn.Bounds.Width} x {scrn.Bounds.Height}")
Exit For
End If
Next
Another option would be to use the screen that contains the largest proportion of the form, e.g.
Dim maxArea = 0
Dim resolution = Size.Empty
For Each scrn In Screen.AllScreens
Dim intersection = Rectangle.Intersect(scrn.Bounds, Bounds)
Dim area = intersection.Width * intersection.Height
If area > maxArea Then
maxArea = area
resolution = scrn.Bounds.Size
End If
Next
MessageBox.Show($"Resolution: {resolution.Width} x {resolution.Height}")
Note that this code will display the resolution of the first encountered if the equal parts of the form are on multiple screens.
There may be other options too, although these seem the most likely.
EDIT:
It's also worth noting that the first code won't work for a maximised form because the actual Location value will be outside the bounds of the screen it's on, so you'd need a bit of jiggery-pokery to handle that. The second code will handle that without issue.

PCOMM gettext is pulling invisible information

I've had a randomly recurring issue where I can use gettext to pull information just fine from a page on a PCOMM (IBM Personal Communicator) screen, then when I go to the next screen it will pull that SAME information, despite appearing visually blank.
I can't paste screenshots for InfoSec reasons... But here's the gist:
Dim ps As New AutPS
Dim oia As New AutOIA
Page 1: ps.GetText(15,31,7) = 1800.00 (I can see this value on the screen.)
Go to next page, wait for oia.InputInhibited = 0 And ps.Ready
Page 2: ps.GetText(15,31,7) = 1800.00 (Screen in this position appears blank.)
This issue is not isolated, and is repeatable with a specific account number.
Found a solution!
The key lies with using the ps.autECLFieldList. This object can detect when a given field (located using FindFieldByRowCol) is displayed or not, so when used in tandem with our getText, we can make sure that we're only retrieving information from a visible field.
Dim fl As Object = ps.autECLFieldList
fl.refresh() 'Good practice to make sure the Field List is up to date
If fl.FindFieldByRowCol(15, 31).display Then
Amount = ps.GetText(15, 31, 7)
End If

Dataset is empty while it is not empty at first

I have the following piece of code
_Foo = String.Concat(_Foo, " Var = '", _varValue, "' ")
_Bar = DsInvoice.viewInvoice.Select(_Foo, _Order)
If _Bar.Count > 0 Then
When I place the debug lines, the Dataset is actually returning rows, and _Bar has a count of 116. Yet when it is at the 3rd line (the if statement) _Bar is empty and the count returns 0. Without any reason I just lost my data.
Let me know if you need more information (I'm actually a PHP programmer and I had to fix a legacy bit of code :(. I lack VB experience to give more background information on this code.
_Bar has no rows because there is no value equal to the _varValue in the "Column" (a.k.a "Property") in the datatable.
*Even if the Property is numeric I doubt wrapping it with single quotes will matter. *
Tip: F8 (VB.Net) or F11 (C#) to step the code control (Yellow Line) onto the second line of code. Then hover your mouse over the viewInvoice word on the second line shown in your question, you'll see the ObjectBrowser Tooltip appear and in it will be a Magnifying Glass with a dropdown. Click it (the dropdown) and select the DataTable View to help you debug this problem.
You can change the Select(...) criteria in run/debug time and then (by dragging the yellow arrow in the line number margin up a line) see the effect of the different Select criteria to work out what is going wrong.

Multiple Text Box and Lookups

I am currently trying to improve on an Access Database VBA that I have inherited from my predecessor at work. I have come unstuck on a particular form.
I have a form that at the moment is just a large form containing 32 individual textbox, with the same code behind each but it is the same code repeated for each textbox with just the references to the text box changing in each.
Private Sub Cand_No2_AfterUpdate()
Cand_Name2 = DLookup("[Name]", "[qryExamAbsences]", "[Cand_No] = Cand_No2")
End Sub
Then once the button is pressed
If Not IsNull([Cand_Name1]) Then
Rope = Rope & " Or Cand_No = " & [Cand_No1]
End If
(The If statement is contained in the button mousedown event.)
Occurs for each text box which then filters a report that is printed for office use. There are many problems with this but the major one I am trying to solve is that there is an upper limit to the number of entries, if I need to filter more than 32 I would need to delete the text and start again as it were.
Is there a way of combining all this into a single section of code which will create text boxes when needed?
EDIT.
I have found a way to give the impression to the user that the text boxes are being created after each entry which has improved the form from a user standpoint (no longer having 32 textboxes or having to scroll down to the Print Button.) however this still hasn't solved the issue of messy code as I have had to repeat the extra code for each box again, it also leaves me with the maximum of 32 entries still.
The new code is as follows:
If Not IsNull(Cand_Name1.value) Then
Cand_No2.Visible = True
Cand_Name2.Visible = True
cmdPrint.Top = 2500
cmdPrint.Left = 2500
DoCmd.MoveSize 1440, 2201, , 4000
Else
Cand_No2.Visible = False
Cand_Name2.Visible = False
cmdPrint.Top = 2000
DoCmd.MoveSize 1440, 2201, , 3500
End If
Essentially makes the next text box visible and moves the print button down to make room for the new text boxes. It also expands the window.
Could you not just have 2 text boxes, one for CAND_NO and another for CAND_NAME and then beside those two boxes place an ADD CAND_NO button.
Create a list box that would list every CAND_NO / CAND_NAME after they press the add button so they can see what they've added so far. Then loop through your list box to build your rope string or have your rope string either a global variable on the form and build it as they add numbers or stored in a hidden text box storing the value as they add numbers if you don't like global.

MS Access 2003 - Automatically show last records in list box on a form rather than first

So I have a form that has a listbox that shows like a ledger. My question is how can I make it display the last records (or have the scroll bar default to the bottom instead of the top), instead of the first few as the default.
Now I don't mean reversing the order from bottom to top instead of top to bottom (though that would be a cool thing to learn how to do), just simply having the bottom of the list (in terms of the scroll bar) shown and the default, so that it is always showing the last 10 or so records (based on the size that I made the list box).
So i think this is simple, but then again, I obviously do not know?!?!
Thanks!
In a suitable event, such as the current event:
Me.ListX.Selected(Me.ListX.ListCount - 1) = True
You could add some code to the form load event so that it will do this:
YourListBox.SetFocus
YourListBox.ListIndex = YourListBox.ListCount - 1
YourListBox.Selected(YourListBox.ListCount - 1) = False
It basically selects the last item in the list box so it will scroll down to it, and then unselects it.
I know this is later but maybe this will help someone in the future who comes upon this thread. This is the code I used to go to the last record then unselect the last record.
YourListBox.SetFocus
YourListBox.Selected(YourListBox.ListCount - 1) = True
YourListBox.Selected(YourListBox.ListCount - 1) = False
How did you set the listbox items? Are they from a database? If yes, then you need to update the SQL statement with an "order by columnName".