How would I set focus in a LibreOffice macro (for use in a Base form)? Or set up a "Position-To" field that DOESN'T filter? - libreoffice-basic

In a LibreOffice Base form, I have a button set to call .uno:RecSearch, in order to bring up the record search dialog.
The problem with that is that if no field in the form has focus, the record search dialog comes up with the third of seven date fields in the form as the search target (which is pretty much useless), rather than the desired "Name" field. (And even more puzzling, the listbox to select which field to search seems to have the fields in more-or-less random order).
I would like to create a macro for a LibreOffice Base form, that would first set focus to the "Name" field, then call .uno:RecSearch.
Can that be done, and if so, how?

I never did find a way to do that (although I found that the sequence of fields as seen by macros bears no resemblance to the nominal sequence of the fields in the record or on the screen, which is a puzzle in itself), but I found something that, for my purposes, is better: how to implement a "Position To" field (as contrasted with a filter, which is precisely what I don't want!) with a macro, attached to the "Changed" event of a "Position To" field added to the form.
option explicit
sub PositionTo (e as object)
dim c as object
dim oDoc, oDrawpage, oForm, oName, oConnection as object
oDoc = thisComponent
oDrawpage = oDoc.drawpage
oForm = oDrawPage.forms.getByName("MainForm")
oName = oForm.getByName("txtName")
if ucase(e.source.text) < ucase(oName.text) then
do until (ucase(e.source.text) > ucase(oName.text)) or (oForm.isBeforeFirst)
oForm.previous
loop
oForm.next
else
do until (ucase(e.source.text) <= ucase(oName.text)) or (oForm.isAfterLast)
oForm.next
loop
if oForm.isAfterLast then oform.previous
endif
end sub
It is, of course, a brute-force approach, that would have serious performance problems in a database with more than a few thousand records, but then again, a database with more than a few thousand records would call for something more sophisticated than LibreOffice Base over its own built-in (and rather out-of-date) HSQLDB.
The situation is a table, in which the unique primary key is a non-case-sensitive text field.
First, we define our variables, and get hold of the form and the keyfield's presence on the form. Then, we check whether the value of the "Position To" field ("e.source.text") comes before the current record's key value ("oName.text"), ignoring case.
If we're after the Position To value, then we step backwards through the records until we get to a record before our "Position To" value, or we're at the top of the file, then step forward one record.
If we're before the Position To value, then we step forward until we reach the first record that's at least a match, or we hit EOF; if the latter, we back up to the last record.
Performance could of course be improved for long sweeps by doing it in two stages, with longer steps for the first stage, but that would be more trouble than it's worth, given the size of the database.
But of course, I would welcome any viable, practical, suggestions for improvements. And if there's an existing "position to" function I don't know about, that would help.

Related

MS ACCESS: VBA too fast leading to field updating only if Toggle Breakpoint in code, need timer?

I am currently doing a Purchase Order "software" under Access and I am having issue with calculating the amount after a item quantity (qty) update.
When I have Toggle breakpoints in my VBA code on the "after update" event, after updating qty = 5 and going through the lines of code, I have the parent text field correctly updated from the subform one (which is the sum of the 'Total Price' fields).
The code contains a Refresh in order to add the right value rather than the old one:
.
.
However, when I remove the toggle breakpoint, I think that the VBA code does not have enough time fully process the refresh command, which update the parent text field with the wrong (old) value.
This issue leads to have a discrepancy between the actual subform calculated total, and the value added to the parent table (here I removed the toggle breakpoint, and added 1 on the second line item, but the calculation gave a 250 rather than a 251):
When I look at the values in the code, when the breakpoint is on the updating line, you can see that the value of the field is the right one, but the 'watch' field shows the old value:
.
.
Do you guys have a solution to make sure all the fields are updated before going to the next line?
I was thinking using some sort of delay, or an "application wait until processing done" type of command but I cannot find anything that is actually working;
Let me know,
Cheers!
EDIT 1:
The "Expected Total Cost" is bound to a table field called "curPOExpectedTotalCost", which is why I use VBA code to populate the data into its dedicated textbox (called "txtcurPOExpectedTotalCost").
The main goal is simply to have this bound field being correctly updated; I want to be able to change the qty or the unit price and automatically populate the right total PO price into "Expected Total Cost" which is bound to a table; the issue is that it works well when I am running each lines one by one using the breakpoints in my code, but does not work when I remove them; this tells me it is probably too fast, hence a way of delaying the next command or a command to wait for processing to be done.
EDIT 2:
I found a workaround, but it seems overpowered for this simple task I was trying to achieve; good side is that it removes the middle man (the subform textbox that sum all the total prices):
I open a recordset and iterate a variable until I can populate the result into the dedicated "Expected Total Cost" bound textbox:
DoCmd.RunCommand (acCmdRefresh)
Dim RS As DAO.Recordset
Dim SQL As String
SQL = "SELECT numPONumberAndRevID, numPOContentQtyOrdered, numPOContentPrice FROM tblPOSCONTENT WHERE numPONumberAndRevID = " & Nz(Me.Parent.MasterPOID.Value)
Set RS = CurrentDb.OpenRecordset(SQL)
Do While Not RS.EOF
ExpectedCalculatedCost = ExpectedCalculatedCost + RS("numPOContentQtyOrdered") * RS("numPOContentPrice")
RS.MoveNext
Loop
RS.Close
Set RS = Nothing
Me.Parent.txtcurPOExpectedTotalCost.Value = ExpectedCalculatedCost
We could arrange in a simple way.
We name the detail input subform control as sfrmDetail, the main total control can be assigned with a .ControlSource like:
Me.txtcurPOExpectedTotalCost.ControlSource="=[sfrmDetail].[Form].[txtSubFormExpectedTotalCost]"
When txtnumPOContentQtyOrdered updates, your main form changes instanteneously without any VBA code.
In the subform, say sfrmDetail, that will be embedded in the main form as subformcontrol sfrmDetail (yes with the same name), we assign a .ControlSouce=Sum(Qty*UnitPrice) for the control txtSubFormExpectedTotalCost, at the footer of the subform.
Solution II:
As #June7 pointed out in comments, the Total cost, that can be calculated dynamically, should be better only for display only (form input display, report printing, but not saved in disk).
OK, now we want at any cost to stock in field tblMain.curPOExpectedTotalCost the total cost with a slight data redundancy, so in the main form we have Me.txtcurPOExpectedTotalCost.ControlSource="curPOExpectedTotalCost"
In the subform sfrmDetail, we can update with:
Option Compare Database
Option Explicit
Private Sub txtnumPOContentQtyOrdered_AfterUpdate()
Me.Recalc
Me.Parent.txtcurPOExpectedTotalCost.Value = Me.txtSubformExpectedTotalCost.Value
End Sub
Me.Recalc() updates all calculated fields of sfrmDetail before we change the target main table field.
Please consult also Is storing counts of database record redundant? for data redundancy.

Why did I have to manually set the .value from the .text on losing focus in an unbound textbox

I have an unbound textbox to accept the delete older than: number of days. It is in the report header. I set it to 30 days but I want the user to be able to change it. I was banging my head trying to figure out why entering 40 was not being accepted and it reverted back to 30 every time. I finally decided on using the lost_focus event to set .value to .text. That worked.
Further research showed that when the textbox get's focus text and value are both the same, 30 in my case. Changing the number in the text box to 40 shows the values of text at 40 and value at 30. Unless I specifically set Value to the value of text Access changes text to the value of value. This is different behavior than other places in Access such as forms.
Can anyone tell me why this might be? I can't find any setting that might do this. Is it because it's in a report header? what is the difference between this and every other text box I've ever used?
From a "best practices" viewpoint, Access Reports are not intended to be used interactively despite the ability to manipulate some unbound controls. Although workarounds can be implemented that function sufficiently well, such solutions are often incomplete and buggy and function differently depending on the active view: Report View vs. Print Preview. Appropriate design patterns include using Access Forms for specifying report options which then open the Report in a static configuration.
This may not satisfy the question "Why?" if seeking a deeper answer as to why Microsoft implemented inconsistent binding behavior in Access, or why they allowed interactive controls in reports at all if they don't behave the same way as in forms. But Access has plenty of other quirky behaviors that have no known/published explanation.
Regarding the priority of the Value property updating the Text property (and not vice versa): Value is the key field because it contains the actual data for the control (bound or unbound). Although it is natural to have a single control for both display and input (uh, that's how almost all controls work), the processes of displaying data and parsing user input are two distinct functions. The visual representation returned by the Text property can be manipulated using the various formatting properties, and technically could display an incomplete representation of the underlying Value data. If there are any conflicts between the stored Value property and the Text property, it is natural that the existing Value property has precedent.
My guess is that the automatic binding behavior was "relaxed" for reports to allow more flexible custom reporting output. First consider an Access Form in Datasheet view: An unbound Form control shows the same value for all records. Even if the control is edited while on a particular row, the updated value is displayed for all rows. The same control object is essentially repainted for each row and there is no concept of individual instances of the control that can hold different values. Bound controls have built-in code that repaint the control with data from the particular row, but there are still not multiple instances each "holding" the individual values. The visual output differs from an intuitive object-oriented paradigm where our minds what to assign each visual row its own in-memory instance of the controls--it just doesn't work like that in Access.
Unlike the Form behavior just described, the Report's Print Preview (and actual printed output) allows unbound controls to display different data per row using the Detail_Format() event. Within the Detail_Format() event, one can set the Value property of a control at which time the Text property is automatically updated according to various formatting properties. This update Text is then output for the current row. Perhaps (just guessing) that this behavior would not function properly if the Text property updated the value property. I suspect it would cause recursive events during report generation. Because reports are not meant to be interactive, relevant text-input parsing code was "disconnected" so that it doesn't behave like on a form.
All that explanation doesn't make Access any less frustrating nor remove its limitations, but at least learn to adapt and design things in the "Access-esque" way rather than fighting it.
your best bet is to design a form with the unbound combo boxes and have your data displayed in a subreport. I like to design my reports so that when values are updated the query for the recordsource of the report is generated doing this requires 2 queries to exist, one with all data possible and a filtered one as subreport recordsource. This will control the data for printing and also allow users to close or navigate away from the report and return to the data later.
Private Sub ComboBox1_AfterUpdate()
Dim Query1 as Object
Dim Temp_Name as Variant
Temp_Name = SubReport.SourceObject
SubReport.SourceObject = Empty
Set Query1 = Me.Form.Application.DBEngine.Workspaces(0).Databases(0).QueryDefs ("SubReport_Query")
Query1.SQL = "Select * Unfiltered_Query WHERE Field1 <= " ComboBox1 & ";"
SubReport.SourceObject = Temp_Name
End Sub

Is AutoComplete Possible in a Combo Box?

I have created a Userform with a ComboBox for purposes of entering client names and information about their children, their names addresses, etc. The data entered will be used to populate various legal documents, and in many cases the clients will select their children (and the children's information) repeatedly. Understanding this to be the case, I have each entry .AddItem'd to the ComboBox List as I enter the data. So far so good.
But I am now trying to set the MatchEntry property (or something else in a manner which will allow me to "find" a former entry in the list and then select it or override it). The MatchEntryFirstLetter property, if active and nothing matches it, won't allow a new entry, it just flashes-back with the letters I type. MatchEntryComplete forces me to use a former entry (for instance if I have earlier entered the client name in Lower Case, MatchEntryComplete finds the Lower Case name but won't let me override it with an UPPER CASE version. Ho-hum.
So before I struggle further (and abandon this to MatchEntryNone), is there a way to structure the ComboBox (or is there a form of VBA code) such that as I enter text in the ComboBox it will simply "search" for a match, and then release me to either select the match or override it with a new entry?
Thanks in advance for your answers.
Mike
AFAIK, ComboBox already have that feature.
You just need to:
set MatchEntry to 1 - fmMatchEntryComplete
set Style to 0 - fmStyleDropDownCombo which are actually the defaults.
Consider below:
Private Sub UserForm_Initialize()
Me.ComboBox1.List = Array("Entry1", "Option1", "Item3")
End Sub
Say we have a UserForm1 with 1 ComboBox named ComboBox1.
If we run the form, it will look like below after typing O and p.
If you type another letter say y, it will automatically be overwritten.
If the searched match already satisfies your search, the just move on to next control either by using mouse or Tab key. Is this what you're trying to do or did I misunderstood your question?

How to work around Access VBA error 3188

Having converted a number of fields in a table tblSource to Rich Text memos, I'm getting an error 3188 in the following circumstances.
Main form has a subform open (frmSource) bound to qrySource. qrySource pulls in some fields from tblSource and adds a calculated field which concatenates the (newly-minted) rich-text memo fields (SD1 to SD20) so that the result can be displayed in a single text box on frmSource called Citation.
If the user wishes to edit SD1 to SD20, they double-click on the Citation field and a modal form frmCitation opens up displaying the SD fields for editing. frmCitation is bound to qryCitation which pulls the SD fields and a couple of others out of tblSource. When finished, they close frmCitation. When SD1 etc were text fields, the tblSource record was updated successfully. However, now they're memo fields, I'm hitting VBA error 3188 ("Could not update; currently locked by another session on this machine.").
Searching on the Internet suggests that this is a common issue with Rich Text memos when a memo size exceeds 2k (limitation possibly due to Access edit buffer size?), so I'm looking for ways to work around it.
One option would be be to split tblSource into two tables tblSource and tblCItation with a one-to-one relationship between them, then base qrySource on tblSource and qryCitation on tblCitation, but that's fairly major surgery with knock-on effects in a number of other places in the application.
Another option is to limit the size of all the memo fields on this form (as per Rich text input into limited length text field in Access 2010), but there's one field for which that wouldn't be acceptable to the users.
Is there another technique I could explore?
Per the following MS Link: http://answers.microsoft.com/en-us/office/forum/office_2007-access/memo-field-could-not-update-currently-locked-by/d5c8163a-7ce5-484f-80d4-98c1a8c92160
near the bottom, they suggest the limit is 2,000 characters.
Not that it helps, but could you add code to the 'before update' to display what the new size should be wnen concatenated? May help to figure a solution...
Be sure to save the form before making any changes with:
If Me.Dirty Then Me.Dirty = False
Workaround 1: Try to update not a field of an underlaying query or table, but a field of the form's Recordset. For example:
With Me.Recordset
.Edit
!MemoField = "TEXT ADDED HERE <- " & !MemoField
.Update
End With
Workaround 2: If you need to update not form's Recordset, but any other Recordset, try to unbind the TexBox, make the update and then make the TextBox binded back again.
I had the same issue and I closed all other open tabs (tables, etc...) and tried again. That worked fine.
I had this problem years ago & was revisiting in case it as not an issue anymore, but seems it is.
I had a list/column form of emails inc a field with a large rft memo.
I wanted to click on a record to bring up the one email in single form
The only way I could get it to work was Open the Single form & immediately close the multi row form, on exiting the single had to load the list again using bookmarks etc. to return to where I wanted to be, a real pain.
Especially as like now I would like to be able to access the the list whilst still on the single form, hence the revisit, instead looks like I will have to save all the list'id somehow. Dooable but a lot more programming that I think should be necessary.

VBA for taking information from text boxes and inserting into table

So I have an input form that I want to use to update a table with certain fields of information. I have the ID of the record automatically coming up in a text box. I have three text boxes that I need to add to the table (excluding the ID) on a button click.
Name
Date
Method
are the field names.
As_Name
As_Date
As_Method
are the text box names
The table name is POC, and the ID is POC_ID (its an autonumber).
So I do not want these objects (text boxes) to be bound to the table because this is a little separate "pop-up" form that comes from a form that the table, and I only want the input to be relative to the POC_ID that is already selected via the original form.
So how do I write the vba for this to 1)check to make sure that records do not already exist....2)update the fields (listed above) with data input from the text boxes(listed above). I want to be able to use this with a button click....
EDIT:
actually it is one table not two; i have two forms that I want to be able to send information to the same table (different information though). this db was already built by someone else and know I have been deamed to take it over.
I need to add a second little pop up form for additional information to be added based on new requirements (there is literally no where for me to place this on the other one). I have already done that, and used a suggested object approach to reference the first forms (from which this second "pop-up" form springs from) to add the relative id fields. Now I have this second little pop up form that just asked three values to be inputted (which are the ones listed above).
I just simply do not know how to link the text box, with a field so that once a user enters in the information, clicks "save" it saves the information to the table relative to the TripID that is there (one mentioned above). the only way I know how to get the text boxes to save data to the table is to use the builder/wizard when I create a new one.
I would like to learn how to link an object (text box, cmb, list) etc on a form, to a table with an "On Click" method so that I can use a save button. Basically that is it!
The OpenForm method of DoCmd allows for several arguments, including Where and Openargs. You can take advantage of these.
However, something seems to be quite wrong with your table design in that you appear to be holding the same information in two tables and for no stated reason. Have you read http://www.r937.com/relational.html?
I would suggest that the design you need probably only includes a numeric field POC_ID that is a foreign key to the main table.
Still not sure I understand your situation, but let me offer the outline of an answer. If my outline is not close enough, please explain where I went astray.
Your parent form, frmParent, has a command button (cmdMoreFields) which opens the child form (frmChild) where you will enter values for 3 additional fields in the record currently displayed in frmParent. After the user enters those values in frmChild (in text box controls named As_Name, As_Date, and As_Method), she will click a command button (cmdSave) to store those values to fields (Name, Date, and Method) in table POC, and close frmChild. Also, frmParent includes a text box (txtPk_field) which holds the value for the primary key (field pk_field in table POC) of the current record.
However, I'm not sure which field/control you're using for txtPk_field, and doubt that value is available if the the current record has not yet been saved. So, I'll suggest this code for the cmdMoreFields "on click" event:
If Me.Dirty Then Me.Dirty = False
DoCmd.OpenForm "frmChild"
In the "on click" event of cmdSave (on frmChild), try code similar to:
Dim strSql As String
strSQL = "UPDATE POC SET [Name] = """ & Me.As_Name & """, [Date] =#" _
& Me.As_Date & "#, Method = """ & Me.As_Method & """ WHERE pk_field = " _
& Forms!frmParent.txtPk_field & ";"
Debug.Print strSql
CurrentDb.Execute strSql, dbFailOnError
DoCmd.Close
If that approach works, consider passing the pk_field value to frmChild with Openargs, as Remou suggested.
Note: I assumed the data type for Name is text, Date is date/time, and Method is text. You will have to change the UPDATE statement delimiters for any fields whose data types differ from my guesses.