using sendkeys VBA to compress images in Visio as part of a sub process - vba

I routinely produce visio documents with images on each page that I paste in from another app. The files are large so need compressing, which isn't fun by hand. I want to be able to loop through each page and compress any images a set amount (75%). So far I've got a sub that selects all images on a page and I've got a sub that uses send keys to bring up the image compression window and run compression at 75%. The problem is the two won't run together. SendKeys compression works fine if I select all images first then run compression separately. But executing in the same sub doesn't work. Code I'm using below. All I can think is that something is breaking the sendkeys rhythm because instead of compressing I'll get mc 75 inserted as text below the image, which is the sendkeys keys. Or I'm stringing them together in the wrong way.
If I run the following separately they work. ie manually executing each one
'selects all images on a page
Sub SelectImagesOnPage()
Dim vsoSelection As Selection
'add all pictures to selection
Set vsoSelection = ActivePage.CreateSelection(visSelTypeByType, visSelModeSkipSuper, visTypeSelBitmap)
ActiveWindow.Selection = vsoSelection
End Sub
'uses sendkeys to bring up the compress image dialogue
Sub compressImageSelection()
'should check an image is selected.
SendKeys "%(jp)", True 'holds ALT while pressing JP
SendKeys "m", True
SendKeys "c"
SendKeys "{TAB}{TAB}"
SendKeys "75{ENTER}"
End Sub
But putting the two together like this doesn't work.
Sub compressPicturesOnPage()
'add all pictures to selection
Call SelectImagesOnPage
'compress
Call compressImageSelection
End Sub
Update: Turns out that for the context sensitive 'Compress Image' button and 'Picture Format' tab to appear on the ribbon menu all Sub's have to complete. ie. visio has to 'regain control'. Blows a hole in what I'm trying to do but at least I know now! Possible solution by Jon Fournier in the comments to try.

Related

Running macro in PowerPoint slideshow does not run unless done manually first

I'm creating a slideshow to display some stats from a sql table. The macro does not want to run unless I run it manually once so I created a simple test to see if it was something with the sql call. Doing this in PPT 2016.
New presentation with 3 slides, a "title page" and two for data. Created a text box on slides 2 & 3. Saved as .pptm
Sub OnSlideShowPageChange()
Dim i As Integer
i = ActivePresentation.SlideShowWindow.View.CurrentShowPosition
If i = 1 Then Call ChangeData
End Sub
Sub ChangeData()
If ActivePresentation.Slides(2).Shapes("TextBox 1").TextFrame.TextRange.Text = "Answer 1" Then
ActivePresentation.Slides(2).Shapes("TextBox 1").TextFrame.TextRange.Text = "Answer A"
ActivePresentation.Slides(3).Shapes("TextBox 1").TextFrame.TextRange.Text = "Answer B"
Else
ActivePresentation.Slides(2).Shapes("TextBox 1").TextFrame.TextRange.Text = "Answer 1"
ActivePresentation.Slides(3).Shapes("TextBox 1").TextFrame.TextRange.Text = "Answer 2"
End If
End Sub
Close the presentation. Open presentation and run the slideshow. It cycles through the 3 slides and repeats as I want but the "data" is not changing. Esc slideshow and manually run the ChangeData macro. Start slideshow again. Now it cycles through the slides and changes the data as desired.
Any ideas as to why it requires a macro to be run first? I would like to go straight to the slideshow or better yet use the ppt viewer.
Edit:
After looking around more I found this thread How do you run vba code when changing slides in powerpoint?
So, added an ActiveX TextBox and moved off slide with the following code for the control
Private Sub TextBox1_Initialize()
End Sub
Interestingly on the test presentation I have to click on the title slide to kick off the slideshow but when I include the control on my actual presentation it works just fine, without having to click on the first slide. I also tested saving my presentation as a ppsm and it still works. Can modify the sql data and it updates the slide table as desired.
I incorporated Sam's suggestion of Sub OnSlideShowPageChange(ByVal Wn As SlideShowWindow) and also tested as orig and both work. I also tested by adding an ActiveX Label but that did not work, had to be a TextBox or maybe other but not as a Label.

Pause VBA Word macro, allow user to make a selection, and restart where it left off

I have a requirement for VBA script in Microsoft Word to pause so that the user can select text that will be copied to the clipboard so that it can exported to an Excel file. The user will make a number of selections and finally indicate he/she is done when the contents of the clipboard will be copied to a template Excel file.
I have the code working to copy each selection to the clipboard and then all rows to the Excel file. But I need assistence in figuring out how to pause the code to allow the user to make the selection and then restart the code to copy the selection to the clipboard. I am able to get the userform with toggle switch to switch states and labels when pressed. But have not figured out how to pause the VBA code to allow the user to navigate to the next section of the Word document for the next selection.
The Stakeoverflow question/answer below appears to address this requirement but I have not been able to get it to work. It appears that the code is incomplete.
Pause VBA macro, allow user to make a selection, and restart where it left off
Can someone provide example VBA code that accomplishes this?
Your assistence is much appreciated as I have been beating my head against the wall and it is starting to hurt!
There's no way in VBA to "pause" a macro. Code must run to completion... Unless there's a command for user input.
Input can be requested via the InputBox and MsgBox methods, but those block access to the document because they're modal. A UserForm, however, can be set to display as non-modal, meaning it stays on top, but doesn't block access to the document or the application features. Since you're already working with a UserForm, this can be implemented relatively easily.
In the small example below, the Continue button runs the code to perform an action on the user selection. When Done is clicked the entire code is exited and the form unloaded.
Code behind the user form
Option Explicit
Private Sub cmdContinue_Click()
Debug.Print Selection.Range.Text
End Sub
Private Sub cmdDone_Click()
Me.Hide
End Sub
Private Sub UserForm_Activate()
'Position the form near the top-left of the window
'So that the user can work with the document
Me.Top = Application.ActiveWindow.Top + 50
Me.Left = Application.ActiveWindow.Left + 50
End Sub
Code in a regular module
Option Explicit
Sub DisplayModeless()
Dim frm As frmModelessForInput
Set frm = New frmModelessForInput
frm.Show False 'Display as non-modal
Set frm = Nothing
End Sub

Word document not reflecting change visually after vba code is used to indent a paragraph

I have a simple vba code in Word 2010:
Sub IncreaseIndent()
For Each p In Selection.Paragraphs
p.LeftIndent = p.LeftIndent + InchesToPoints(0.25)
p.FirstLineIndent = InchesToPoints(-0.25)
Next
End Sub
It works great, does what I need, and I have it associated to a shortcut key. But I'm trying to figure out one last glitch it has. When I use it, the paragraph indents, but it's not visually refreshed properly in the document. I have to scroll so that the text goes out of view, and then scroll it back. (Any action that makes Word re-render works, like switching to another program whose window is on top of Word, and back again.) After that, the paragraph looks as it should.
I'm thinking I'm missing some kind of p.Refresh / Re-render / Recalc command, but don't know what that is. Anyone know how to cause the refresh in the vba code?
Thanks,
Sandra
I was not able to replicate what you describe, but there is a .ScreenRefresh method which might do the trick.
https://msdn.microsoft.com/en-us/library/office/ff193095(v=office.15).aspx
Note: in the example code provided at MSDN (and as modified slightly, below), when I test it the toggling ScreenUpdating property has no effect, it always appears to update for me when I run it, even when set explicitly to False
Sub t()
Dim rngTemp As Range
Application.ScreenUpdating = False
Set rngTemp = ActiveDocument.Range(Start:=0, End:=0)
rngTemp.InsertBefore "new"
Application.ScreenRefresh
Application.ScreenUpdating = True
End Sub

Can I display something while a macro is running?

I have a macro that takes roughly five seconds to execute and I'm using the code Application.ScreenUpdating = False so it looks like Word has locked up when it's running.
I use a message box at the end to tell them it's complete, but I'd like to display an image during its execution that tells the user the macro is running (primarily so they don't get worried, but also because it's nicer to look at).
There might be an easier way to go about this, but I decided to create an image, create a very basic user form, and simply set my image as its background. Then, I have that user form pop up as soon as the code starts to run.
The problem I'm having is that unless I close it, the rest of the code won't execute. It just hangs until I do something. Is there a way I can get the user form to be displayed without stopping the rest of the process? If not, is there another approach I can take to display an image while the macro is running?
You can show the userform as non-modal:
Userform1.Show False
'do more stuff (doesn't wait for form to close)
Userform1.Hide
I too have found that if you .show a userform at the beginning of the process, images contained within userform take a while to display and the result is less than smooth.
I have solved it by inserting a 1 second "wait" immediately after the userform.show instruction. In that split second, the image loads and displays successfully and the result is seamless.
Here the code. I have 2 macros: 1 to display and 1 to hide. I call the first macro at the beginning of the process just before freezing the screen and the second at the end of the process just before unfreezing the screen
Userform name is "myuserform"
Sub message_show()
userform.Show False
Application.Wait (Now + TimeValue("0:00:01"))
End Sub
Sub message_hide()
Application.Wait (Now + TimeValue("0:00:02"))
userform.Hide
End Sub

How do you prevent printing dialog when using Excel PrintOut method

When I use the PrintOut method to print a Worksheet object to a printer, the "Printing" dialog (showing filename, destination printer, pages printed and a Cancel button) is displayed even though I have set DisplayAlerts = False. The code below works in an Excel macro but the same thing happens if I use this code in a VB or VB.Net application (with the reference changes required to use the Excel object).
Public Sub TestPrint()
Dim vSheet As Worksheet
Application.ScreenUpdating = False
Application.DisplayAlerts = False
Set vSheet = ActiveSheet
vSheet.PrintOut Preview:=False
Application.DisplayAlerts = True
Application.ScreenUpdating = True
End Sub
EDIT: The answer below sheds more light on this (that it may be a Windows dialog and not an Excel dialog) but does not answer my question. Does anyone know how to prevent it from being displayed?
EDIT: Thank you for your extra research, Kevin. It looks very much like this is what I need. Just not sure I want to blindly accept API code like that. Does anyone else have any knowledge about these API calls and that they're doing what the author purports?
If you don't want to show the print dialogue, then simply make a macro test as follows; it won't show any print dialogue and will detect the default printer and immediately print.
sub test()
activesheet.printout preview:= false
end sub
Run this macro and it will print the currently active sheet without displaying the print dialogue.
When you say the "Printing" Dialog, I assume you mean the "Now printing xxx on " dialog rather than standard print dialog (select printer, number of copies, etc). Taking your example above & trying it out, that is the behaviour I saw - "Now printing..." was displayed briefly & then auto-closed.
What you're trying to control may not be tied to Excel, but instead be Windows-level behaviour. If it is controllable, you'd need to a) disable it, b) perform your print, c) re-enable. If your code fails, there is a risk this is not re-enabled for other applications.
EDIT: Try this solution: How do you prevent printing dialog when using Excel PrintOut method. It seems to describe exactly what you are after.
The API calls in the article linked by Kevin Haines hide the Printing dialog like so:
Get the handle of the Printing dialog window.
Send a message to the window to tell it not to redraw
Invalidate the window, which forces a redraw that never happens
Tell Windows to repaint the window, which causes it to disappear.
That's oversimplified to put it mildly.
The API calls are safe, but you will probably want to make sure that screen updating for the Printing dialog is set to True if your application fails.