In Microsoft Publisher VBA, how to access selected page? - vba

In Publisher, not VBA, I use the navigation pane to select page 5. Now, the work I do manually will apply to page 5. However, now I want to run a macro I wrote which will import, resize, label, etc. a batch of images. How do I make my macro recognize that I want those images imported onto page 5 (my current working page)?
I wrote my macro hardwired to page 2 (because I couldn't answer the above question):
set pg = activedocument.pages(2)
I envisioned something like (but this doesn't work, of course):
set pg = activedocument.selected.page
Similarly, after my macro runs, and it adds three new pages, I want the selected/active page to be the last page I added (e.g., page 9). How to do that? Again, I envisioned something like:
activedocument.pages(9).select
Much thanks.

The property that you found (helping me out, so thanks!) is for both getting and setting, but the trick is that you have to set it to a page, rather than trying to set it to a PageIndex ("ActivePage = 2")
ActiveDocument.ActiveView.ActivePage = yourPage;
For instance, you could go to the next page with:
pubApp.ActiveDocument.ActiveView.ActivePage = pubApp.ActiveDocument.Pages[pubApp.ActiveDocument.ActiveView.ActivePage.PageIndex+1];
...Just realised that you're asking about VBA rather than C#, so here are some VBA examples just for you:
GoToNextPage()
ActiveDocument.ActiveView.ActivePage = ActiveDocument.Pages(ActiveDocument.ActiveView.ActivePage.PageIndex + 1)
End Sub
GoToPageTwo()
ActiveDocument.ActiveView.ActivePage = ActiveDocument.Pages(2)
End Sub

Question 1 is answered:
Set p = ActiveDocument.ActiveView.ActivePage
Question 2 remains:
How do I use vba to make active a new particular page?
(i.e., i could use VBA such that the above would return to me a different page for "p"?)
For a shape, I can say: "my_shape.select"; how do I do that for a page?

Related

How can I make a form instance open a specific record on creation?

I'm trying to optimize the performance of my access frontend. One of the problems I'm stumbling on is how to set a multi-window form to open immediately to a specific record, because at the moment it queries everything twice.
Essentially, I allow my users to open multiple instances of a form. That way, a user can compare multiple records by placing the windows of those forms side by side.
At the moment, my code looks like this:
Set frm = New Form_Name
frm.RecordSource = "select * from Table where id = " & ID 'ID is a variable passed to the method
I'm pretty sure back then this question was one of the building blocks I relied on.
The problem is that on the first line, access already entirely opens the form and does everything the form does when opening, such as Form_Open, Form_Current, and loading subforms. Then, when I set the recordsource, it does all (or most) of that again, which significantly slows down the process of opening the form.
Here are some of the things I've tried:
Changing the Form_Current to recognize that it's being "used" twice and only actually run the code once. The problem is that the code is already very optimized and doesn't seem to be the bottleneck, so this doesn't seem to do much. Actually opening the form seems to be the bottleneck.
Trying to change the properties of the original form so that it opens the specific record I need, but I can't seem to change the properties without it opening the form.
Looking for a way to supply arguments to the form. That doesn't seem to be supported in VBA.
One other idea that popped into my mind was creating a variable in vba with the ID of the record, setting recordsource in the form properties to fetch that variable, but then, when I would open another form and change that ID, the form
I realize that I can do this with DoCmd.OpenForm, but that doesn't give me the option to open multiple instances of the same form.
How can I achieve this? This would mean a significant performance improvement.
OK, so I actually wanted to ask this question. But just before I hit the submit button, I had an idea...
Here's the idea: you set a global variable in VBA, which you then access in the form filter command. In my case I just added Public OpeningID As Long at the top of my VBA module. Then I create a function to get that value:
Public Function getFormID() As Long
getFormID = OpeningID
End Function
Then, in the form, you can set the filter criteria as ID = getFormID(). And then when you open the form instance, you do it like this:
OpeningID = ID
Set frm = New Form_Name
OpenindID = 0 'reset this to make sure that if it's being accessed when it shouldn't, it generates a clear error
The only problem is what happens when you refresh the form, as that will call the method again. When you refresh the form via VBA, you can set the OpeningID beforehand, and to avoid users refreshing the form, you can add this to your form (don't forget to turn on Key Previews in the form settings):
Private Sub Form_KeyDown(KeyCode As Integer, Shift As Integer)
If KeyCode = vbKeyF5 Then KeyCode = 0
End Sub
Bang. Forms open almost twice as fast. Awesome.

How to copy and paste a clicked shape from one slide to another

I am new to VBA in PowerPoint and I am trying to develop an interactive program for my class where a text box grouped with a bubble shape floats across the screen and they have to click it if they notice it contains a certain grapheme. I want the clicked text boxes to copy to another slide so that I can assess if the children have been successful or just clicked anything they saw.
I've pieced together this code from other sites:
Sub copyobject()
With ActivePresentation
Set myshape1 = ActivePresentation.Slides(2).Shapes(group5)
myshape1.ActionSettings(ppMouseClick).Action = myshape1.Copy
.Slides(3).myshape1.Paste
End With
End Sub
It doesn't appear to be working though. Can anybody help me out?
The error message I receive is 'compile error: method or data member not found' with .myshape1 highlighted.
If anybody could give me a completed code for this or correct what I have created I would greatly appreciate it.
Many thanks
Since the name of the object is "group5", I assume it's a group. But you can't apply an Action Setting to a group, only to a single object. This works for a single shape:
Sub copyobject()
With ActivePresentation
Set myshape1 = .Slides(2).Shapes("Rectangle 1")
myshape1.ActionSettings(ppMouseClick).Action = myshape1.Copy
.Slides(3).Shapes.Paste
End With
End Sub
BTW, an excellent VBA book for what you're doing is David Markovitz's Powerful PowerPoint for Educators. His support site for the book also has lots of free code and samples.

How to show the progress of the "Fields.Update"-Method in VBA (Word)

I'm trying to update all the fields in a Word document using the "Fields.Update"-Method. This is the code I use:
Sub UpdateFields()
Dim varRange As Range
'Update fields in the first section of the main text
set varRange = ThisDocument.StoryRanges(wdMainTextStory)
varRange.Fields.Update
'Update fields in subsequent sections (of the main text)
While Not (varRange.NextStoryRange Is Nothing)
Set varRange = varRange.NextStoryRange
varRange.Fields.Update
Wend
End Sub
There are over 750 fields in the document (linking to cell content in an/one Excelfile) so the update takes a while so for the user it looks like the application "freezes". When I update "manually" (selecting via Crtl+A and updating via F9), I get a progress bar like this within the status bar at the bottom of the word application window:
However it does not appear using the "Fields.Update"-Methode. Is there a way to show this Bar using the Filds.Update-Method or any other Method?
I suppose I could make my own "progress"-bar via a userform. But this would require to update each field individually (e.g. through cycling through all fields indevidually rngCurrentRange.Fields(i).Update) but I would rather avoid that. It makes the code more complex, slower and it's a pain in the ass to make sure Word keeps the userform updated in real time. But if there's no other solution I'll take that as well.
EDIT:
I found a workaround, but it's not working 100%, please see my answer...
Please Note: I also posted two other questions within this context:
Update multiple fields with Excel links very slow
VBA: force user form to update in real time
I found a workaround using Fields.Update in combination with selection:
'Do Field Updates
Dim rngCurrentRange As Range
set varRange = ThisDocument.StoryRanges(wdMainTextStory)
rngCurrentRange.Select
Selection.Fields.Update
But there is still a problem with this workaround: At first it doesn't seem to show a progress bar either, but when you run it a second time it does! I'm not sure why this is, but it made it possible to make a workaround: First I update some insignificant StoryRange, which will initialize the progress bar for the following Fields.Update-methods. Unfortunately this does not work for the "first approach" (without using selection).

Showing MsgBox() with nowait (no user input) is not the real issue

I had searched a lot how to display a Msgbox that will not wait the user input (pressing ok or cancel).
I found 3 solutiuons to this.
1- Display the MsgBox() in another thread or using BackgroundWorker()
2- Create a form that display the message, then closed the form by a timer and use it instead of Msgbox()
3- Using the API MessageBoxA()
Let say I have a loop from 1 to 100, and I want display a message for the i(counter)
When I test above 3 ways, I found that this is not the right way of doing it, I don't need a msgbox() to close by it self after showing the message, because that will display 100 dialog.
What I realy want is to display ONLY 1 MsgBox() and change the text accordingly.
I managed to do this using a a Form() as class and I did it using Application.DoEvents
I know it can be done using BackgroundWorker or Threading since alot of people advice against using Application.Doevents
Here is my code
Dim oWW As New WaitWindow With {.TopLevel = True,.TopMost = True,.StartPosition = FormStartPosition.CenterScreen}
oWW.Show(Me)
For i = 1 to 100
Threading.Thread.Sleep(500) ' Just to slowdown execution
oWW.SetMessage("Counter = " + i.ToString)
Next
oWW.Dispose()
Public Class WaitWindow
Sub SetMessage(ByVal Message As string)
lbl_message.Text = Message
Application.DoEvents
End Sub
End Class
WaitWindow is not more than a Form base class with a label (lbl_message)
That code works fine (display WaitWindowForm on center of currently displayed form only once, then I change the text)
I have 3 questions :
1- How to display the WaitWindowForm in the top right corner of my working form?
2- Is it possible to display the normal MsgBox() or MessageBox.Show() only once, then capture the text displayed and change it?
3- Which one is suitable for my issue (BackGroundWorker or Threading) and what the code in WaitWindow class I post will be if I decided to use Backgroundworker or Threading instead of Application.DoEvents (Changing the label text not showing new form with new text) ?
3 questions in one post.. humm.. who cares, I am not the one who will answer lol :)
Thanks in advance.
I think the issue that you're really encountering is that you're trying to use a message box for something it's not suited for. If you want to have text that constantly changes just add a text box in the upper right corner of your application and adjust it every time a new message needs to be shown.
You can also look up dialogu windows (search ".showdialog() vb.net" in google) might help as well.

How to select dropdown lists with no id

I've been researching this for the last couple days but haven't found a solution yet. Any help would be greatly appreciated.
I'm using VBA to put a push button on an Excel spreadsheet which will open an Internet Explorer window, log people into a particular site, search for a particular "case" (webform) on the site, fill in the values the way the user specified on the sheet, and then submit the form. Everything works except the form fields that are drop down lists. When I run it, it fills in the values I want in those fields but it seems like it's not actually selecting them from the list, just overwriting what's displayed there, because when it clicks submit an error window pops up saying to fill in those drop down fields.
From my research I've seen various solutions for how to search a drop down list and set it to the selected index once it's located the text I want, but my problem is that I haven't had luck selecting the drop down list at all. If you look at the screenshot below, that shows one of the fields as it looks in Internet Explorer's dev tools:
The highlighted portion is the id number I use to paste in my text (what I'm doing right now that isn't working) but the line below it with class ns-dropdown seems like it might be what I really want to access, but that line doesn't have an id.
Here's the relevant portion of my code:
Dim IE As Object
Dim IEForm As HTMLDocument
Set IEForm = IE.Document
With IEForm
.getElementById("custevent_crc_code_fs").innerText = Sheet1.Cells(9, 3) 'CRC Code
.getElementById("inpt_status4").innerText = Sheet1.Cells(8, 3) 'Status
.getElementById("inpt_custevent95").innerText = Sheet1.Cells(11, 3) 'Department
.getElementById("inpt_custevent426").innerText = Sheet1.Cells(10, 3) 'Case Origin
.getElementById("inpt_custevent447").innerText = Sheet1.Cells(6, 3) 'Created By
.getElementById("inpt_custevent1188").innerText = Sheet1.Cells(7, 3) 'Contact Reason
.getElementById("btn_multibutton_submitter").Click
End With
Let me know if you need any more information. I've been wrestling with this for a while and am trying not to flood you with too much extraneous info about things I've tried.