I want to force the focus onto a particular cell, which I have a reference for via XlCall.Excel(XlCall.xlfCaller). I know how to do this in VSTO, but is there a way to do it with ExcelDNA?
One way would be to use the COM Automation interface, as you would from VBA or VSTO. Just be sure to use the Application object you get from ExcelDnaUtil.Application as your root. To convert from the ExcelReference that you received from xlfCaller to a COM Range object, you might try (this is the VB.NET version):
Private Function ReferenceToRange(ByVal xlRef As ExcelReference) As Object
Dim strAddress As String = XlCall.Excel(XlCall.xlfReftext, xlRef, True)
ReferenceToRange = ExcelDnaUtil.Application.Range(strAddress)
End Function
If you want to stick with the C API, you'd first have to select the right sheet, then the actual cell. So you might have:
string myCellSheet = (string)XlCall.Excel(XlCall.xlSheetNm, myCell);
XlCall.Excel(XlCall.xlcWorkbookSelect, new object[] { myCellSheet });
XlCall.Excel(XlCall.xlcFormulaGoto, myCell);
You won't be able to change the selection in a worksheet function, so I presume you are calling this from a macro or ribbon handler.
It's possible to do with ExcelDNA:
var activeCell = new ExcelReference(5, 5);
ExcelAsyncUtil.QueueAsMacro(() => XlCall.Excel(XlCall.xlcSelect, activeCell));
"ExcelAsyncUtil.QueueAsMacro" could be skipped, it's depends on context from which you call Excel command. If you call it from another Excel function - you should wrap it up with QueueAsMacro
Related
i have made a program, which include a lot of controls. The controls would be showed and hided according to the choice of the user. That means that controls overlapped on each other at design time. now i want to change the forecolor and backcolor of all controls at design time. but i founded so hard to accomplish this task, because all the control overlapping each other. so I decided to make a for loop method to iterate the controls in the form and then check each control in turn whether it has controls. when the control has also controls in it, I call the same method and pass the control to it to change the properties for the subcontrols too. The method like so:
void setColor(ref Control con)
{
con.BackColor= System.Drawing.Color.Black;
con.ForeColor=System.Drawing.Color.Yellow;
if (con.Controls.Count > 0) { setColor(ref con); }
}
so my Form include tabControl with multiple tabPages. I iterate the tabPages and wanted to pass it to this method, but I become error "Indexer may not be passed as an out or ref parameter"
I pass it so: setColor(ref tabControl1.Controls[i]);
can you please help me to solve this problem?
I have resolved the problem.
I have removed the "ref" from method and wrote the method simply like the following:
void SetColor(Control con)
{
con.BackColor = System.Drawing.Color.Black;
con.ForeColor = System.Drawing.Color.Yellow;
if (con.Controls.Count > 0)
{
for (int i=0; i<con.Controls.Count;i++)
SetColor(con.Controls[i]);
}
}
and call it so: setColor(this.Controls[i]);
I want to use JXA to automate some updating of Numbers spreadsheets. For example, copying a range of cells from one spreadsheet to another one with a different structure.
At this point, I'm just testing a simple program to set or read the value of a cell and I can't get this to work.
When I try to set a value I get "Error -1700: Can't convert types." and when I try to read a value I get back a [object ObjectSpecifier] rather than a text or number value.
Here's an example of the code:
Numbers = Application('Numbers')
Numbers.activate()
delay(1)
doc = Numbers.open(Path('/Users/username/Desktop/Test.numbers'))
currentSheet = doc.Sheets[0]
currentTable = currentSheet.Tables[0]
console.log(currentTable['name'])
console.log(currentTable.cell[1][1])
currentTable.cell[1][1].set(77)
When I run this, I get and output of [object ObjectSpecifier] for the two console.logs and then an error -1700: Can't convert types when it tries to set a cell.
I've tried several other variations of accessing or setting properties but can't get it to work.
Thanks in advance,
Dave
Here is a script that sets and gets a cell's value and then sets a different cell's value in the same table:
// Open Numbers document (no activate or delay is needed)
var Numbers = Application("Numbers")
var path = Path("/path/to/spreadsheet.numbers")
var doc = Numbers.open(path)
// Access the first table of the first sheet of the document
// Note:
// .sheets and .tables (lowercase plural) are used when accessing elements
// .Sheet and .Table (capitalized singular) are used when creating new elements
var sheet = doc.sheets[0]
var table = sheet.tables[0]
// Access the cell named "A1"
var cell = table.cells["A1"]
// Set the cell's value
cell.value = 20
// Get the cell's value
var cellValue = cell.value()
// Set that value in a different cell
table.cells["B2"].value = cellValue
Check out the Numbers scripting dictionary (with JavaScript selected as the language) to see classes and their properties and elements. The elements section will show you the names of elements (e.g. the Document class contains sheets, the Sheet class contains tables, and so on). To open the scripting dictionary, in Script Editor's menu bar, choose Window > Library, and then select Numbers in the library window.
In regards to the logging you were seeing - I recommend using a function similar to this:
function prettyLog(object) {
console.log(Automation.getDisplayString(object))
}
Automation.getDisplayString gives you a "pretty print" version of any object you pass to it. You can then use that for better diagnostic logging.
I have two form in my application i am calling two form together from master page.i wrote code in my master page
in top i declared like this
Dim form As New FrmDelivary
Dim frm1 As New FrmrecievedDelivaryRequest
in toolstrip menu event like this:
Dim frm1 As New FrmrecievedDelivaryRequest
frm1.Location = New Point(625, 225)
frm1.MdiParent = Me
frm1.Show()
Dim frm2 As New FrmDelivary
frm2.Location = New Point(965, 0)
frm2.MdiParent = Me
frm.show()
if i press R i want to go my cursor the particular textbox of FrmrecievedDelivaryRequest
if i press D i want to go my cursor the particular textbox of FrmDelivary
How can I do this? i trey something like this in frmMaster_KeyDown event: but same page is showing again. I have already open instance of FrmDelivary, so I don't want to show same page again. I want to just get cursor position to particular textbox of this form
If e.KeyCode = Keys.A Then
form.Show()
form.txtTicket.Focus()
Cursor.Position = form.txtTicket.Location
end if
I am working on vb.net windows application
After
frm1.Show()
place
frm1.txtTicket.Focus()
I don't think you need the Cursor.Position call
Set your frm1 and frm2 variables at the top of the code window so they are accessible from all of the Subs. In your KeyDown event, put
If e.KeyCode = Keys.A Then
frm1.Show()
frm1.txtTicket.Focus()
Cursor.Position = frm1.txtTicket.Location
end if
The problem is that you are instantiating a new copy of the form with the "AS NEW frmDelivery" statement.
I admittedly know little about the inner workings of javascript, but need to make a library and would like to learn (hence asking here). I understand using the closure and exporting to window to not pollute the global namespace, but beyond that it confuses me a bit.
(function() {
var Drop = window.Drop = function() {
var files = [];
var add = function(word) {
files.push(word);
return files;
}
return {
files: files,
add: add
}
}
})()
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
// Each has their own state which is what I want.
a.add("file1");
b.add("file2");
c.add("file3");
Why are all three ways of "initializing" Drop the same?
What exactly gives them the ability to have their own state?
Is there an alternative to the return syntax to export those functions on Drop?
Is there just a flat out better best practice way of creating a self contained library like this?
I have searched around the net, but have found very little consistency on this subject.
The first way (Drop()) just calls the function as normal, so this is the global object (window in browser environments). It does its stuff and then returns an object, as you'd expect.
The second way (new Drop()) creates a new Drop object and executes the constructor with this set to that object. You do not, however, use this anywhere and return an object created from an object literal, so the Drop object is discarded and the object literal returned instead.
The third way (new Drop) is semantically the same as the second; it is only a syntactic difference.
They all have their own state because each time you call Drop, it has its own set of local variables distinct from the local variables of any other call to Drop.
You could transform your code to use the normal new syntax and prototypes. This has a few advantages: namely, you only create the add function once rather than one for each Drop call. Your modified code might look like this:
function Drop() {
this.files = [];
}
Drop.prototype.add = function(word) {
this.files.push(word);
return this.files;
};
By doing this, though, you lose being able to call it without new. There is, however, a workaround: You can add this as the first line inside function Drop:
if(!(this instanceof Drop)) {
return new Drop();
}
Since when you call it with new, this will be a Drop, and when you call it without new, this will be something other than a Drop, you can see if this is a Drop, and if it is, continue initializing; otherwise, reinvoke it with new.
There is also another semantic difference. Consider the following code:
var drop = new Drop();
var adder = drop.add;
adder(someFile);
Your code will work here. The prototype-based code will not, since this will be the global object, not drop. This, too, has a workaround: somewhere in your constructor, you can do this:
this.add = this.add.bind(this);
Of course, if your library's consumers are not going to pull the function out of the object, you won't need to do this. Furthermore, you might need to shim Function.prototype.bind for browsers that don't have it.
No. It's all a matter of taste.
Why are all three ways of "initializing" Drop the same?
// All of these seem to be the same?
var a = Drop();
var b = new Drop();
var c = new Drop;
When you use new in JavaScript to invoke a function, the value of this inside the function becomes the new object.
But the reason they're the same in your case is that you're not using this at all. You're making a separate object using object literal syntax, and returning it instead, so the new has no impact.
What exactly gives them the ability to have their own state?
Because each function invocation makes a new object, each object is entirely different for each invocation.
The functions assigned to the object are recreated in each Drop invocation, and therefore create a closure over the enclosing variable scope. As such, the files array of each invocation is continuously accessible to the functions made in each respective invocation.
Is there an alternative to the return syntax to export those functions on Drop?
Yes. Assign the functions and array to this, and remove the return statement. But that will require the use of new. Alternatively, put the functions on the .prototype object of Drop, and they'll be shared among all instances made using new, but keep the array assigned to this in the constructor so that it's not shared.
For the prototyped functions to reference the array, they would use this.files.
Is there just a flat out better best practice way of creating a self contained library like this?
JavaScript is very flexible. There are many ways to approach a single problem, each with its own advantages/disadvantages. Generally it'll boil down to taking advantage of closures, of prototypal inheritance, or some combination of both.
Here's a full prototypal inheritance version. Also, the outer (function() {})() isn't being used, so I'm going to add a variable to take advantage of it.
(function() {
var totalObjects = 0; // visible only to functions created in this scope
var Drop = window.Drop = function() {
this.files = [];
this.serialNumber = totalObjects++;
}
Drop.prototype.add = function(word) {
this.files.push(word);
return this.files;
};
})();
i have written some Macros for Visio. Now I copied these to a Stencil called Macros.vss
How can I call my Macros now?
It all depends on what the macros do and how you'd like to call them. I'm going to assume they're simply macros that will execute something within the active Visio page.
By default in Visio VBA, any public subs with no arguments get added to the Visio Tools->Macros menu, in a folder named by the document holding the macros (in this case Macros) and then separated into folders by module name. If you're the only person using the macros then you probably don't need to do anything else.
However, since you put them in a vss file I'll assume you'd like to distribute them to other people.
There's something funny (and by funny I mean irritating) about Visio and how toolbars and buttons work, when added programmatically. Unfortunately, when you create a toolbar using the UIObject and Toolbar and ToolbarItem classes, Visio is going to assume the code you're calling resides in the active drawing, and cannot be in a stencil. So I can give you a little guidance on using those classes, but basically it consists of distributing a .vst template along with your .vss files, with just a single required sub in the .vst file.
So, instead of using a custom toolbar, you can attach code to shape masters in your .vss file that execute the code when they get dropped on a drawing document (using CALLTHIS and the EventDrop event in the shapesheet). With this method I just have a sub that gets called using callthis that takes a shape object as an argument, executes some code, then deletes the shape (if I don't want it around anymore).
And lastly, you can manipulate the Visio UI programmatically to add a toolbar and buttons for your macros. Below is some sample code, basically the way I do it with a solution I developed. As I mentioned above, the most important part of using this method is to have a document template (.vst) that holds a sub (with the below code it must be named RunStencilMacro) that takes a string as an argument. This string should be the "DocumentName.ModuleName.SubName". This sub must take the DocumentName out of the string, and get a Document object handle to that document. Then it must do ExecuteLine on that document with the ModuleName.SubName portion. You'll have to step through the code and figure some things out, but once you get the hang of what's going on it should make sense.
I'm not sure of any other ways to execute the macros interactively with VBA. I think exe and COM addons may not have this issue with toolbars...
Private Sub ExampleUI()
Dim UI As Visio.UIObject
Dim ToolbarSet As Visio.ToolbarSet
Dim Toolbars As Visio.Toolbars
Dim Toolbar As Visio.Toolbar
Dim ToolbarItems As Visio.ToolbarItems
Dim ToolbarItem As Visio.ToolbarItem
Dim TotalToolBars As Integer
Dim Toolbarpos As Integer
Const ToolbarName = "My Toolbar"
' Get the UIObject object for the toolbars.
If Visio.Application.CustomToolbars Is Nothing Then
If Visio.ActiveDocument.CustomToolbars Is Nothing Then
Set UI = Visio.Application.BuiltInToolbars(0)
Else
Set UI = Visio.ActiveDocument.CustomToolbars
End If
Else
Set UI = Visio.Application.CustomToolbars
End If
Set ToolbarSet = UI.ToolbarSets.ItemAtID(visUIObjSetDrawing)
' Delete toolbar if it exists already
TotalToolBars = ToolbarSet.Toolbars.Count
For i = 1 To TotalToolBars
Set Toolbar = ToolbarSet.Toolbars.Item(i - 1)
If Toolbar.Caption = ToolbarName Then
Toolbar.Visible = False
Toolbar.Delete
Exit For
End If
Next
' create toolbar
Set Toolbar = ToolbarSet.Toolbars.Add
Toolbar.Caption = ToolbarName
Dim IconPos As Long ' counter to determine where to put a button in the toolbar
IconPos = IconPos + 1
Dim IconFunction As String
IconFunction = """Macros.Module1.SubName"""
Set ToolbarItem = Toolbar.ToolbarItems.AddAt(IconPos)
With ToolbarItem
.AddOnName = "RunStencilMacro """ & IconFunction & """"
.Caption = "Button 1"
.CntrlType = Visio.visCtrlTypeBUTTON
.Enabled = True
.state = Visio.visButtonUp
.Style = Visio.visButtonIcon
.Visible = True
.IconFileName ("16x16IconFullFilePath.ico")
End With
' Now establish the position of this toolbar
With Toolbar
.Position = visBarTop 'Top overall docking area
.Left = 0 'Puts it x pixels from the left
.RowIndex = 13
.Protection = visBarNoCustomize
Toolbar.Enabled = True
.Visible = True
End With
Visio.Application.SetCustomToolbars UI
Visio.ActiveDocument.SetCustomToolbars UI
End Sub