I have an Excel12v function using XLOPER to set some values on an Excel sheet. I can create XLLs fine as per Microsoft's XLL guide. I authored xladd-derive for Rust which enables this an allows returning scalars and ranges of values very simply.
However I would like, rather than return a value, to set a random cell to a value. There is xlSet function demonstrated below that does this and works fine.
short WINAPI xlSetExample()
{
XLOPER12 xRef, xValue;
xRef.xltype = xltypeSRef;
xRef.val.sref.count = 1;
xRef.val.sref.ref.rwFirst = 204;
xRef.val.sref.ref.rwLast = 205;
xRef.val.sref.ref.colFirst = 1;
xRef.val.sref.ref.colLast = 1;
xValue.xltype = xltypeInt;
xValue.val.w = 12345;
Excel12v(xlSet, 0, 2, (LPXLOPER12)&xRef, (LPXLOPER12)&xValue);
return 1;
}
but only works if it's called from a VBA macro
Sub test()
Application.Run("xlSetExample","12345")
End Sub
Is there an equivalent xlf* or xlc* function that allows one to set cell values but do not need to be called from a VBA macro
In general, Excel prevents spreadsheet functions from changing the values in cells. In effect, spreadsheet functions are given a read-only view of the values in the sheet.
This is the documentation for xlSet which states:
xlSet behaves as a Class 3 command-equivalent function; that is, it is
available only inside a DLL when the DLL is called from an object,
macro, menu, toolbar, shortcut key, or the Run button in the Macro
dialog box (accessed from View tab on the ribbon starting in Excel
2007, and the Tools menu in earlier versions).
The reason for this is to prevent circular references or other actions that would break or confuse the calculation tree. Excel would struggle to determine dependencies between cells if a function in one cell could change other cells' contents.
Consider the hypothetical function AddOne() which takes a number, adds one and uses this to set the cell immediately to the right via xlSet (or otherwise). What would happen if the formula in cell A1 were =AddOne(B1)?
This Excel SDK reference gives more information. Namely:
Different Types of Functions
Excel4 and Excel12 distinguish among three classes of functions. The
functions are classified according to the three states in which Excel
might call the DLL.
Class 1 applies when the DLL is called from a worksheet as a result of
recalculation.
Class 2 applies when the DLL is called from within a function macro or
from a worksheet where it was registered with a number sign (#) in the
type text.
Class 3 applies when a DLL is called from an object, macro, menu,
toolbar, shortcut key, ExecuteExcel4Macro method, or the
Tools/Macro/Run command. For more information, see Excel Commands,
Functions, and States.
Only Class 3 functions can call xlSet.
So, in summary, the Excel application really doesn't want users to change one cell from a function call in another. As always, if you work hard enough you could probably achieve this (eg get the COM application object pointer by some method and modify the cell that way, or set up a callback to modify the cell asynchronously), but you might have unpredictable results.
Related
I am looking for a way to determine inside my XLL whether the call is coming from the re-calculation process or from a new formula being entered for the cell. I have seen examples where the XLL can detect if it is being called from the Function Wizard (via checking the window class etc), but what if it is typed directly into the cell?
I can get the reference of the cell from the xlfCaller function:
XLOPER xlRef;
Excel(xlfCaller, &xlRef, 0);
but that doesn't get me very far. I am trying to mimic Excel's handling of the TODAY() function, which changes the cell number format if the formula is entered in the cell directly (rather than pasted or called from within another function).
It's possible to replicate this aspect of the TODAY() behaviour by hooking the SheetChange event - this will only fire when a formula is entered and not when it's recalculated (even with Ctrl-Alt-F9). I don't know if TODAY() uses this approach or perhaps it uses something not available to user-defined functions. In addition, replicating TODAY() would require parsing the formula and applying some logic to determine whether it applies the date format or not, this would be a bit tricky but there are some Excel formulas parsers out there.
In xlOil (disclaimer: I wrote it) it could be implemented as:
XLO_FUNC_START(testToday())
{
CallerInfo caller;
if (!caller.fullSheetName().empty()) // Check caller is worksheet
{
// Add a SheetChange handler
auto handle = xloil::Event::SheetChange().bind(
[=](const wchar_t* wsName, const Range& target)
{
// Need to check range here as well to avoid being triggered by another sheet change
if (wsName == caller.sheetName())
excelApp().Range[caller.writeAddress().c_str()]->NumberFormat = L"dd-mm-yyyy";
}
);
// Wait 0.5 sec then unbind the event handler by queuing a window message with Excel
auto milliSecsDelay = 500;
excelPost([=]() mutable
{
handle.reset(); // Removes the SheetChange handler
}, QueueType::WINDOW, 0, 0, milliSecsDelay);
}
// This is how to get the current date in C++
std::tm buf;
auto now = std::time(0);
localtime_s(&buf, &now);
return returnValue(buf); // xlOil will convert the std::tm to an Excel date
}
XLO_FUNC_END(testToday);
This is just a proof-of-concept and could do with some tidying for example the range should be checked and the overhead could be quite large if the function was called many times.
How can I select text in Gtk::TextView:
starting from where the cursor is
n number of characters backwards
The documentation from developer.gnome.org doesn't seem to help.
The selection isn't done in the Gtk::TextView itself but in the associated Gtk::TextBuffer. While I'm not sure why exactly this design choice was done I'm at least clear about the consequence: Selections may be shared between multiple Gtk::TextViews when they share the same buffer. This may be desirable or not but it's how “they” have done it.
The buffer of a Gtk::TextView can be obtained with
Glib::RefPtr< TextBuffer > get_buffer ()
Returns the Gtk::TextBuffer being displayed by this text view.
The reference count on the buffer is not incremented; the caller of this function won’t own a new reference.
Then, the Gtk::TextBuffer provides
void Gtk::TextBuffer::select_range (const iterator& ins, const iterator& bound)
This function moves the “insert” and “selection_bound” marks simultaneously.
If you move them in two steps with move_mark(), you will temporarily select a region in between their old and new locations, which can be pretty inefficient since the temporarily-selected region will force stuff to be recalculated. This function moves them as a unit, which can be optimized.
ins Where to put the “insert” mark.
bound Where to put the “selection_bound” mark.
The current cursor position can be obtained with
Glib::RefPtr Gtk::TextBuffer::get_insert()
Returns the mark that represents the cursor (insertion point).
Equivalent to calling get_mark() to get the mark named “insert”, but very slightly more efficient, and involves less typing.
The returned Gtk::TextMark can be “converted” to a Gtk::TextIter by using
TextIter Gtk::TextMark::get_iter().
Additionally, Gtk::TextBuffer provides a variety of get_iter_at functions to get the Gtk::TextBuffer::iterators for distinct parameters.
A note in general:
To learn a powerful widget API by the reference manual, is something I would consider as tedious.
In the case of gtkmm, there is a serious alternative:
Programming with gtkmm 3
(which is available in other languages as well).
Chapter 11 is about TextView and might help to get the “big picture”.
I have the following wxDialog parent window:
I have created that parent window by the following code:
settingsFrm settingsWindow(this, "Settings");
settingsWindow.ShowModal();
I have tried to use FindWindowByName to get the value of the first text ctrl as follow:
wxLogMessage(dynamic_cast<wxTextCtrl*>(settingsWindow->FindWindowByName("keywords_txt"))->GetValue());
But unfortunately, it doesn't work and gives me a runtime error.
I don't know if that method suitable to do what I want.
How to get the value/other of a control through its parent window?
From your comments, it seems like you expect the function to find the control from the name of the variable in your code which is not how it works and would be pretty much impossible.
FindWindowByName() uses the window name (and, as a fallback, label, but this is irrelevant here because text controls don't have labels anyhow), so for it to work you need to set the window name when creating the control, using the corresponding parameter of its ctor. This is very rarely useful in C++ code, however, as it's simpler to just store a pointer to the control in some variable and use this instead.
FindWindowByName() can often be useful when creating controls from XRC, however. If you do this, then you should specify names for your controls in XRC and pass the same name to this function.
How did you create the TextCtrl instance? You should have something like wxTextCtrl m_textCtrl1 = new wxTextCtrl(/// arguments); Accessing the value should be very easy, as wxString text = m_textCtrl1->GetValue(); You definitely don't need FindWindowByName just for what you are trying to do here.
I've got a pretty old MFC application that's been touched by many people over the years (most of them probably not even CS guys) and it follows, what I like to call the "anarchy design pattern."
Anyway, one of the dialogs has a series of 56 vertical sliders and check boxes. However, there are additional sliders and checkboxes on the dialog as shown below.
Now, the problem is that the additional sliders and checkboxes take on IDs that are in sequence with the slider/checkbox series of the dialog. My task is to add more sliders and checkboxes to the series (in the blank space in the Slider Control group box) Unfortunately, since IDC_SLIDER57 through IDC_SLIDER61 are already in the dialog (same goes for the checkboxes), existing code, such as the snippet below will break:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
Is there a better way to modify the resource file without doing it manually? I've seen a third party tool called ResOrg that looks like it'll help do what I want, but the software is a bit pricey, especially since I'll only use it once. I guess I can give the demo a try, but the limitations might restrict me.
FYI, I'm using Visual C++ 6.0 (yes...I know, don't laugh, it's being forced upon me).
Instead of writing:
pVSlider = (CSliderCtrl *)GetDlgItem(IDC_SLIDER1+i);
you could write:
pVSlider = (CSliderCtrl *)GetDlgItem(GetSliderID(i));
where GetSlider is a function that returns the id of slider number i.
GetSlider function
int GetSliderID(int nslider)
{
static int sliderids[] = {IDC_SLIDER1, IDC_SLIDER2, IDC_SLIDER3, .... IDC_SLIDERn};
ASSERT(nslider < _countof(sliderids));
return sliderids[nslider];
}
With this method the IDC_SLIDERn symbols dont need to have sequential values.
I have a MFC C++(not managed) program and I need to generate a xls.
I'm using xlslib(http://xlslib.sourceforge.net/) version 2.3.4 to generate the xls, but I can't resize excel columns.
The class "worksheet" has the method "colwidth":
void colwidth(unsigned32_t col, unsigned16_t width, xf_t* pxformat = NULL); // sets column widths to 1/256 x width of "0"
I invoked this method passing the parameters (0, 5), (0,20), (0,1000) and (1,5), no one worked :/.
I just need that the column fit the size necessary to display all the text.
Any help will be very useful, I'm lost.
Try the following code:
workbook WorkBook;
worksheet* WorkSheet = WorkBook.sheet(_T("Sheet1"));
WorkSheet->defaultColwidth(8);
WorkSheet->colwidth(0, 256*10);;
WorkSheet->colwidth(1, 256*16);
WorkSheet->rowheight(0, 256*1.0586);
WorkSheet->rowheight(1, 256*2);
I also meet with this problem,i try it many times and discover that before invoke "colwidth" you must firstly invoke "defaultColwidth",the parameter of method "defaultColwidth" must be "8".The codes already work fine on my computer.
I am Chinese,English not mother language,I wish you can understand it.