Error in saving minitab graphs and plots: "...collection is empty and contains no valid output object" - excel

I want to automate GageR&R study in minitab.
I found code but the line mtbProject.Commands.Item(1).Outputs.Item(1).Graph.SaveAs.
Gives
Run time error:"IOutput: IOutput collection is empty and contains no valid output object"
Sub msa_macro()
'
' msa_macro Macro
'
'
Dim MtbApp As Mtb.Application
Dim mtbProject As Mtb.Project
Dim mtbWorksheet As Mtb.Worksheet
Set MtbApp = New Mtb.Application
Set mtbProject = MtbApp.ActiveProject
Set mtbWorksheet = mtbProject.ActiveWorksheet
MtbApp.UserInterface.Visible = True
MtbApp.UserInterface.DisplayAlerts = True
mtbProject.ExecuteCommand "Execute 'C:\Amir\DataAnalysis2\MSA_FixtureMill_STC049\MSA_STC049_BSM\Results_Files\readfileMinitab_test.mtb' 1."
mtbProject.Commands.Item(1).Outputs.Item(1).Graph.SaveAs "C:\Result_Files\grph1.png", True, GFJPEG
End Sub

The problem is, that you want to save the Outputs.Item(1) from Commands.Item(1). So you address the first command that you called, which is "Excecute … ", and this has no Output-Item. Therefore the IOutputs Collection for this Command-Item is empty.
The Output-Collection is defined as the Items of Outputs for each command. What you would want to do, is to save the first Output-Item of the command with which you created the graph.
It would be very helpful, if you could provide some information about your readfileMinitab_test.mtb. What are you doing in this .mtb file, is it also a macro-enabled file? I would guess, that you create the graph in this file?
If you want to save your graph as a .png, I guess you might need the MtbGraphFiletype GFPNGColor instead of GFJPEG. You also don´t need to save the file as grph1.png (just grph1 will suffice), as this is done automatically, because you tell Minitab to save it in a specific filetype.
You could also use the digit-code for the Filetypes (which is a little bit shorter). This would mean GFPNGColor = 3 and GFJPEG = 1. For some further information about this I recommend you the Minitab-Automation-Guide.
An example code could look as following:
'This is the first Command Minitab is executing
mtbProject.ExectueCommand "Execute <something>"
'This is the second Command Minitab is executing
mtbProject.ExecuteCommand "Boxplot C" & CStr(i as Integer)
'We want to Save the Graph, which we created with Command 2. We created one graph with
'this Command, to we only have 1 Output.
mtbProject.Commands.Item(2).Outputs.Item(1).Graph.SaveAs <path as String>, True, 3

Thanks Florian. Yes you are right, I figured it out that I am trying to read the output of the wrong command.
I wanted to execute a sequence of 'Gage R&R' commands and to save an output graph. It is completed now.
Thanks again for the helping answer.

Related

HyperLink click runs function twice and give patch error

From title you can already tell what is my problem.
Somethink from my side:
I know there is for sure work around to run the macro once with creating boolean or check and hadling the error (with I still dont know how).
I want to know why the macro runs twice. My guess is that it takes mouse movement or somethink like that.
How to fix it?
Or use better alternative of capturing click on text (I want to evoid selection change/change and I am not big fan of using FollowHyperlink with linking on same cell).
Function I am using : =HYPERTEXTOVÝ.ODKAZ("#LinkClick()";"CLICK")
Eng version : =HYPERLINK("#LinkClick()";"CLICK")
Function LinkClick()
Range("A1").Value = Range("A1").Value + 1
End Function
It should be the same function. It is just different in my language :
https://support.office.com/cs-cz/article/hypertextov%C3%BD-odkaz-funkce-333c7ce6-c5ae-4164-9c47-7de9b76f577f
https://support.office.com/en-us/article/hyperlink-function-333c7ce6-c5ae-4164-9c47-7de9b76f577f?omkt=en-US&ui=en-US&rs=en-US&ad=US
PS: My first post and my english isn't best. Thanks for any answers.
You need to Set LinkClick = Selection so you return a cell with your function otherwise the link is invalid.
According to the documentation your formula =HYPERLINK("#LinkClick()";"CLICK") needs a link_location as first parameter HYPERLINK(link_location, [friendly_name]). But because you have a function call there "#LinkClick()" the function needs to return a valid link location, and that is what Set LinkClick = Selection does, it returns the actual selection as link location, so the hyperlink selects what is already selected (means it does nothing at all, but it doesn't complain about an invalid link location).
Option Explicit
Public Function LinkClick() As Range
Set LinkClick = Selection 'make sure a valid link location is returned in the function
ActiveSheet.Range("A1").Value = ActiveSheet.Range("A1").Value + 1
End Function

Search txt and csv files for string using Excel VBA without opening files

I have a text file that is automatically generated from a machine. The machine writes the txt file in "chunks" (sorry I don't know the exact terminology). I need to pull data from this txt file, but I need the txt file to be finished before pulling data from it. I found a solution to verify that the machine has finished writing to the file... It is not as elegant as i had hoped, but seems to do the trick. Excel VBA opens a command prompt, the command prompt uses a Find command to find the string "End of Report"... This is basically one of the last lines of the txt file and pretty safe to assume the txt file is finished after this is found. This code runs in a loop 1000 times, every 10 seconds, until it finds this string or reaches 1000 tries...
The issue is that "result" returns some other characters besides just "End of Report" this is further complicated by the fact that I am attempting to run this on some csv files too... and "result" returns some additional characters also, but different from the ones returned from the txt files. For example, if I check the length of "result"... The length comes back as 43 on one file and 48 on another file... I think it is counting the file path + "End of Report" + a few more characters?
Anyways, I don't really need the "result"... I really only need a "true" / "false" if "Find" found "End of Report" or not... How can I accomplish this? Is there a different better way to do this? I am not familiar with command prompt programming.
Note: It is important that I search these files without opening them.
Sub test()
Dim SearchStr As String
Dim cmdLine As Object
Dim result As String
Dim FilePath As String
FilePath = "D:\test2.txt"
SearchStr = """End of Report"""
Set cmdLine = CreateObject("WScript.Shell")
result = cmdLine.Exec("%comspec% /C Find " & SearchStr & " " & Chr(34) & FilePath & Chr(34)).STDOut.ReadAll
Debug.Print (result)
End Sub
I am not really an expert in command line, but what I would do is export the result of the FIND command to a file, like here
Then I would check in your VBA code how many rows are in the file (either clean the file before, or check the number of rows before the export is done).
If the number of rows meets the criteria (probably 2 or more rows instead of 1), then you can set the flag to True.

How to get data from Excel and merge it into Word using MailMerge?

Trying to get data from Excel and merge it into Word using MailMerge (just like how it is done in this video).
However, fields aren't getting updated after running this code. VBA isn't throwing any error so looks like code is fine. Can you please help?
Sub getdata()
Dim numRecord As Integer
Dim myName As String
myName = InputBox("Enter the field name and relax!")
Set dsMain = ActiveDocument.MailMerge.DataSource
If dsMain.FindRecord(FindText:=myName, Field:="Fields") = True Then
numRecord = dsMain.ActiveRecord
End If
End Sub
Note: Data in Excel looks like this:
Fields First Layer Second Layer
CC 5 3
So when someone enters CC in Input box I want first_layer and Second_layer fields in word to get updated to 5 and 3 respectiely.
If you're running the mailmerge from Word, you don't actually need any VBA for this - it can all be done with a SKIPIF field. For example the following field code does the same as the macro in the video is supposed to:
{SKIPIF{FILLIN "Name to merge" \o}<> {MERGEFIELD Name}}
or:
{SKIPIF{FILLIN "Name to merge" \o}<> «Name»}
Note: The field brace pairs (i.e. '{ }') for the above example are all created in the document itself, via Ctrl-F9 (Cmd-F9 on a Mac or, if you’re using a laptop, you might need to use Ctrl-Fn-F9); you can't simply type them or copy & paste them from this message. Nor is it practical to add them via any of the standard Word dialogues. Likewise, the chevrons (i.e. '« »') are part of the actual mergefields - which you can insert from the 'Insert Merge Field' dropdown (i.e. you can't type or copy & paste them from this message, either). The spaces represented in the field constructions are all required.

Hide and unhide series in a chart based on their name and i have error 1104

I am trying to hide and unhide series in a chart based on their name using excel vba and I have a error 1004 invalid parameter after the first run of the for cycle.
Sub macroChart3()
'
' macroChart3 Macro test
'
Dim i, n As Integer
For i = 1 To 96 Step 1
If ActiveChart.SeriesCollection(i).Name = "*contracted*" Then
ActiveChart.SeriesCollection(i).IsFiltered = False
Else
ActiveChart.SeriesCollection(i).IsFiltered = True
End If
Next i
End Sub
SeriesCollection.IsFiltered method seemed to toggle this check box:
I couldn't use that. I wanted to record macro and see if any other method is used but the checkbox is gone in 2010:
So it might be not possible to use that anymore. If you are using a different version where this method exists you might have a problem that the series is not listed in in seriesCollection anymore:
Remarks from MSDN
When a user filters out a series, the series IsFiltered property switches to True, and the series is transferred out of its parent SeriesCollection.
See if you can use FullSeriesCollection instead when you change the visibility of series:
ActiveChart.FullSeriesCollection(2).IsFiltered = True
If that doesn't work you might add and remove ranges instead of hiding them.
UPDATE:
Run your macro in step mode (F8) so you have full visibility of the execution steps. Add your evaluated expressions (ones that are used within IFs) to see their result and you will find out if they are incorrect or are evaluated as FALSE and try to figure out why.
And don't forget to up vote the answer if you find it helpful.
thanks for the quick reply, the error is fixed, but still not all the series are processed by the if clauses in the for cycle, for example this statement:
Else
ActiveChart.SeriesCollection(i).IsFiltered = True
End If
Isn't executed and I don't understand why.

How can I delete an object which is the subject of a loop?

The problem I have is that the user is copying from one content control and pasting it into another accidentally. When extracting the data from this form, it then picks up that extra CC and therefore the value twice over.
When pulling the data I'm trying to see if a CC has a ParentCC and then delete it, but I keep getting
Run time error 5825: Object has been deleted.
I can understand why but I'm unsure as to how get around it, nothing I've searched seems to work.
'With Word document Statement precedes this
For Each CCtrl In .ContentControls
CCtrlText = CCtrl.Range.Text
If Not CCtrl.ParentContentControl Is Nothing Then
CCtrl.ParentContentControl.Range.Text = CCtrlText
CCtrl.Delete
End If
Next
How can I remove this content control which is duplicated inside the other and retain the input information?
So after some messing around and looking into how the local variables properties changed as a stepped through the code I have found that the line:
CCtrl.ParentContentControl.Range.Text = CCtrlText
Was in effect replacing the Content Control (CC) in it's ParentCC range property with the input text, and therefore deleting the duplicated CC.
CCtrl.Delete was trying to delete an object that had already been deleted and that swhy it was throwing an error.
I think with a foreach loop you can't alter the contents of the list/array without impacting the function of the loop. If you instead use the indexers, it should allow you to alter the collection, since you are not impacting the loop (number to number):
Dim i As Integer
Dim c As ContentControl
For i = 1 To d.ContentControls.Count
Set c = d.ContentControls(i)
c.Delete
Next i

Resources