When we work with controls in VBA. (For simplicity, let sht represent a worksheet object)
We normally do sht.Shapes(xxx) or sht.OLEObjects(xxx) to access controls. Shapes() and OLEObjects() are well defined in the documentation. They are properties of the worksheet object.
However, sht.Buttons(xxx), sht.CheckBoxes(xxx) actually also work. But they are not defined in the document. If you check the object library in the VBE, you still can't find them. And if you type things in VBE, no IntelliSense for .Buttons of .CheckBoxes, but there're IntelliSense for .Shapes()
Even though you can access a button using sht.Buttons() and sht.Shapes(), however, I find sht.Buttons() return an object with a much cleaner interface.
So where are the .Buttons method from? Is it just an extension method defined somewhere for the worksheet object?
Related
I wrote a macro that saves an image from CATIA, using the CaptureToFile method in the Viewer object. The macro works great, but only when the Render Style is "Parallel". Some of the designers in my company do not have the Render Style to "Parallel", so I want to change the Render Style to "Parallel" with the macro.
There is a property in the TreeTabSettingAtt object, called RenderStyle. The documentation says that the property "Returns or sets the value to signify
whether the 3D Render Style is Parallel or Perspective". It seems to be exactly what I need. To get to that property, I need to get to the TreeTabSettingAtt object, which seems to be a SettingController in the SettingControllers collection, but I can't get to it because I don't know its object type. The latter is needed to be passed as an argument of the Item method of the setting controller collection object. Unfortunately, the Item method only takes a string, which I don't know.
sub CATMain()
Dim catia as INFITF.Application
Dim att as PROCESSITF.TreeTabSettingAtt
Set catia = GetObject(, "catia.Application")
Set att = catia.SettingControllers.Item("I dont know the object type of
TreeTabSettingAtt")
att.RenderStyle "Parallel"
End Sub
In the documentation, seen in the following link, the setting controller object type of many setting controller objects are listed, but some are missing including the object type for the TreeTabSettingAtt setting controller object.
https://www.maruf.ca/files/caadoc/CAAScdInfTechArticles/CAAInfTabPageList.htm
The property you've located seems bound to the application settings (i.e. the ones you change from Tools>Options..). I don't know how good they are exposed to automation but from a quick debug session, it was evident that with
Set att = CATIA.SettingControllers
one actually gets the collection, Count property is 70 in my case, but no Item method was available! This is inconsistent with the documentation. Note that the documentation reports that the argument must be an index in long format, but passed as a string.
Answer:
I have instead located the "live setting" which is bound to the Viewpoint3D object as follows. Note that either in CATScript or CATVBA you don't need to assign the Application object (CATIA object of class Application is always available):
Set view = CATIA.ActiveWindow.ActiveViewer.Viewpoint3D
view.ProjectionMode = catProjectionCylindric
'or
view.ProjectionMode = catProjectionConic
Images in the office ribbon can be large (32x32) or small (16x16). If they are specified as large, but the window is too narrow to fit them, then they are automatically made small. By default, these are just a condensed version of the larger image.
There was an office design document (since disappeared) that suggested that one should properly design the small icons, and that they should not just be small versions of the big ones because condensing to 16x16 does not always work very well. Very sensible.
But does one actually do it in the XML? Elements like Button only seem to have one image attribute. I would expect two, largeImage and smallImage (say).
Is this something that really needs horrible call backs? In which case, how does one catch the event that the ribbon has decided to resize the image? (Ribbon call backs are a mess with VBA for several reasons.)
The Ribbon XML does not have an option to specify large and small icons as part of its defintion. If you use the image attribute then you can provide only one picture.
There's also no way to catch whether/when Office reduces the size of the Ribbon. You'd have to do some research, checking which window width triggers the resize, then you could use the WindowResize event of the Application object to invalidate the control(s), changing the picture (and possibly the control size).
In order to provide more than one icon you'd need to use the callback attribute getImage to tell the Ribbon which picture to use. This isn't as simple as passing the string value of a file stored in the Office document as the callback function expects an IPictureDisp object; the image would need to be stored outside the Office document, as a file.
The intricacies of using getImage are described in Customizing the 2007 Office Fluent Ribbon for Developers (Part 1 of 3), near the end of the article, but the code provided there is for the .NET Framework.
It's actually a bit easier to code using VBA since the stdOle library that provides IPictureDisp is an office library. You need to set a reference to the library - in the VBA Editor's Tools/References it's labelled as OLE Automation. Note that this does not work with the graphic png file format - the library is a bit old...
Public Sub GetIconImage(control As IRibbonControl, ByRef image)
Dim sPicPath As String
Dim stdPic As StdPicture
sPicPath = "C:\Users\[userName]\Pictures\test.jpg" 'Schweiz.png"
Set stdPic = stdole.StdFunctions.LoadPicture(sPicPath)
Set image = stdPic
End Sub
I'm trying to do some practices on a MDI application in Microsoft Visual Studio 2012 but it seems that I'm doing something wrong.
I made a new Windows Forms Application project and changed the IsMdiContainer property of the first form to True. Then I add a new form by right clicking the project in solution explorer and selecting Add - New Item - Windows Form.
I'm trying to set MdiParent property of form2 to the MDI Container form, but it seems that form2 has no MdiParent property.
Here's the properties of form2 sorted alphabetically.
Of course I can open form2 as a child form this way:
form2 newMDIChild = new form2();
newMDIChild.MdiParent = this;
newMDIChild.Show();
I just wondered why the forms has no MDIParent property.
According to this page the child forms have a MdiParent property.
Any kind of help is much appreciated.
You're doing it right, instantiating the new form and assigning MdiParent there. Really there IS such a property, and in your code you're using it:
newMDIChild.MdiParent = this;
This is perfectly fine and the normal way of doing it.
Now, what you're pointing is that the designer doesn't shows it, which is also true. That don't means that the property don't exist (it does, and you're using it in fact!). Why it isn't in the designer property sheet is another history, totally irrelevant, but I suppose that it has to do with the fact that it's difficult, if not impossible to properly set MdiParent at design time. If you think about it, it must contain an instance of another form (with it's IsMdiContainer set to true). At design time, you don't have any instances of anything, as they're created as your program runs. There is no way that you can set it beforehand, as you must normally pass another form to it, which you can't know while designing.
I cannot figure out what the deal is with this code. "command" = Park, and the Park method exists in the interface. "method", however, just equals null, so it throws an exception when I hit invoke. The debugger kicks in, and so I was able to make sure that everything looks OK. Why does method not get set?
The scope object is defined. It is a com object. I expanded the dynamic view of the scope object and all it shows is properties or something (blue 3d boxes, not hand and paper), no methods. Is that the problem? But why, since I am referring to ITelescope and don't do anything with scope until I try to invoke the method, which was not set.
I got the Activator code from this question.
ITelescope scope = (ITelescope)Activator.CreateInstance(Type.GetTypeFromProgID(scopeProgID));
var method = typeof(ITelescope).GetMethod(command);
method.Invoke( scope, new object[0]{ } );
I remembered that I had asked another question about interfaces and reflection. The problem has something to do with interop types. To fix it you right click on the offending reference in the reference list of the project, click properties, and set "embed interop types" to false.
This is a vba question. I found the question:
"Adding controls to a frame in an Excel userform with VBA"
and used its method to add commandbuttons to my frame in my user form. Since I added four commandbuttons, I ran the code in a loop, and used the
With ...
.Name = "commandbutton" & x
to give each command button its own name. I included in my code macros for each commandbutton (since I renamed them I know what the name of each cb is) but when I click on the button, nothing happens.
Alternatively, if someone could explain to me how use code to place controls on a form into a frame, I could solve my problem a different way.
Thanks,
Michael
It seems that events are only handled for object variables which were declared when the VBA program is compiled (i.e. at design time.) If you dynamically create objects in the program (i.e. at run-time) then you need to assign references to those objects to appropriate object variables which have already been declared.
As per your example, in the module which relates to your UserForm, you would need to have:
Public WithEvents btn1 As MSForms.CommandButton
Public WithEvents btn2 As MSForms.CommandButton
Public WithEvents btn3 As MSForms.CommandButton
Public WithEvents btn4 As MSForms.CommandButton
(The MSForms prefix to the variable type might not be strictly necessary)
then in your With statement to create the controls you would need to assign each control to one of the variables which ends up being fairly messy.
Better solutions:
create the maximum number of possible buttons at design time and just toggle the Visible property to show the correct ones
if the function of each button would be determined at run-time then use some property of the CommandButton object to determine this (e.g. Caption property, Tag property) and then have the event handler for that button call the appropriate function based on that property
change the UI and use a ListBox or ComboBox instead of buttons