I'm working on a complex grid layout, and UltimateGrid is my choice.
I have set a multi-row heading, then I have joined some cells in heading vertically.
Now, I'm looking for a way to set multi-line text in heading cells which I have joined.
Here's an explanatory screenshot.
I already have tried by writing:
void MyCug::OnSetup(){
int rows = 5;
int cols = 20;
// setup rows and columns
SetNumberRows(rows);
SetNumberCols(cols);
// create 3 row top heading
SetTH_NumberRows(2);
...
JoinCells (16, -2, 16, -1); // Here I joins - in heading - two cells : row 16, columns -2 and -1
...
// Then I retrieve merged cell
CUGCell m_cell;
GetCell(16, -2, &m_cell);
// I need to show multi-line content in heading cells: I tried to set multi-row property.
int result = m_cell.SetPropertyFlags(m_cell.GetPropertyFlags() | UGCELL_MULTIROWCELL);
if (result == UG_SUCCESS) {
bool ok = true; // all seems to be ok...
}
m_cell.SetText("string\r\nstring\r\nstring"); // Despite my attempt, this will be always show on a single line!
SetCell(16, -3, &m_cell);
...
}
Without success: cell text is always shown on a single line, that is exactly what I don't want.
How can I get the cell text on multiple lines?
I tell how I have solved my problem, hoping it will be useful to someone.
To set multi-line cells, member function CUGCell::SetCellTypeEx() should be used.
This function allow you to set extended properties for single cells.
The example below works perfectly:
void MyCug::OnSetup(){
int rows = 5;
int cols = 20;
// setup rows and columns
SetNumberRows(rows);
SetNumberCols(cols);
// create 3 row top heading
SetTH_NumberRows(2);
...
JoinCells (16, -2, 16, -1); // Here i joins - in heading - two cells : row 16, columns -2 and -1
...
// I retrieve merged cell
CUGCell m_cell;
GetCell(16, -2, &m_cell);
cell.SetCellTypeEx(UGCT_NORMALMULTILINE); // set multiline cell
m_cell.SetText("string\r\nstring\r\nstring");
SetCell(16, -3, &m_cell);
}
Inside the OnSetup() method:
Set the number of rows in the top heading.
SetTH_NumberRows(2); // Set 2 rows
Join the range of cells together
JoinCells(1,-2, 1,-1); // Join row -1 and -2 in column 1
Add multiline feature to the cell
QuickSetCellTypeEx(1, -2, UGCT_NORMALMULTILINE); // Column 1, row -2 is a multiline
Add text
CString title = _T("New\r\nline");
QuickSetText(1, -2, title); SetColWidth(1, 200); // Set text in the preferred cell
Related
How do i fit values in those horizontally splitted cells ? I am cloning each row dynamically. The values being populated currently is a merge field as i was using this approach but i couldn't make the report dynamic with it.
Any help would be appreciated.
Well, you cannot input two values in a single cell in MS Excel. I think You may achieve your task by merging/ un-merging some cells and input values into relevant cells accordingly. See the sample code below for your reference, it covers and design some part of your attached table/matrix. Please refer to it and you may write your own code (via Aspose.Cells APIs) to accomplish your task accordingly:
var workbook = new Workbook();
var worksheet = workbook.Worksheets[0];
//Input header value to B1 cell (later we will merge it: B1:C1 --> B1
worksheet.Cells[0, 1].PutValue("header2");
//Input value to B2 cell that would be merged with B3 to become B2.
worksheet.Cells[1, 1].PutValue(1);
//Input value to C2 cell.
worksheet.Cells[1, 2].PutValue(2);
//Input value to C3 cell.
worksheet.Cells[2, 2].PutValue(3);
//Set row heights for 2nd and third rows for the cells accordingly.
worksheet.Cells.SetRowHeight(1, 25);
worksheet.Cells.SetRowHeight(2, 25);
//Merging cells.
//Merge B1:C1 --> B1
worksheet.Cells.Merge(0, 1, 1, 2);
//Merge B2:B3 --> B2
worksheet.Cells.Merge(1, 1, 2, 1);
//Formatting cells and ranges.
//Creating a range that spans over the all data cells of a worksheet
var range = worksheet.Cells.CreateRange("B1", "C3");
//Create a Style object.
Style colstyle = workbook.CreateStyle();
colstyle.Borders[BorderType.LeftBorder].LineStyle = CellBorderType.Thin;
colstyle.Borders[BorderType.RightBorder].LineStyle = CellBorderType.Thin;
colstyle.Borders[BorderType.TopBorder].LineStyle = CellBorderType.Thin;
colstyle.Borders[BorderType.BottomBorder].LineStyle = CellBorderType.Thin;
colstyle.HorizontalAlignment = TextAlignmentType.Center;
StyleFlag flag = new StyleFlag();
flag.Borders = true;
flag.HorizontalAlignment = true;
//Apply the style to the range
range.ApplyStyle(colstyle, flag);
workbook.Save("e:\\test2\\output__mergedcells.xlsx");
See the screen shot of the output Excel file taken in Ms Excel for your reference:
http://prntscr.com/8rbc0i
I am a developer/evangelist at Aspose.
I am creating a command-line minesweeper game which has a save and continue capability. My code generates a file called "save.txt" which stores the position of the mines and the cells that the player has opened. It is separated into two columns delimited by a space where the left column represents the row of the cell and the right column represents the column of the cell in the matrix generated by my code. The following is the contents of save.txt after a sample run:
3 7
3 9
5 7
6 7
8 4
Mine end
2 9
1 10
3 5
1 1
Cell open end
You may have noticed Mine end and Cell open end. These two basically separate the numbers into two groups where the first one is for the position of the mines and the latter is for the position of the cells opened by the player. I have created a code which generates an array for each column provided that the text file contains integers:
int arrayRow[9];
int arrayCol[9];
ifstream infile("save.txt");
int a, b;
while(infile >> a >> b){
for(int i = 0; i < 9; i++){
arrayRow[i] = a;
arrayCol[i] = b;
}
}
As you can see, this won't quite work with my text file since it contains non-integer text. Basically, I want to create four arrays: mineRow, mineCol, openedRow, and openedCol as per described by the first paragraph.
Aside from parsing the string yourself and doing string operations, you can probably redefine the file format to have a header. Then you can parse the once and keep everything in numbers. Namely:
Let the Header be the first two rows
Row 1 = mineRowLen mineColLen
Row 2 = openedRowLen openedColLen
Row 3...N = data
save.txt:
40 30
20 10
// rest of the entries
Then you just read 40 for the mineRow, 30 for mineCol, 20 for openedRow, 10 for openedCol since you know their lengths. This will be potentially harder to debug, but would allow you to hide the save state better to disallow easy modification of it.
You can read the file line by line.
If the line matches "Mine end" or "Cell open end", continue;
Else, split the line by space (" "), and fill the array.
I'm trying to implement an undo function for inserting a new line for a simple text editor program.
When I call a new line, I increment the row of a vector of strings, and insert an empty string into it. This pushes everything below the new row down by one. It looks something like this (where | is the cursor):
Before
1: Hello
2: |World
After inserting a new line between hello and world
1: Hello
2:
3: |World
When I call my undo function I want it to delete the line (the empty one in this case), and then push every row up by one. I know insert() handles shifting elements, but is there some sort of equivalent for erase()? Here is my code for insertNewLine()
void Editor::insertNewLine()
{
std::string currLine = lines[row];
size_t tempSize = currLine.size();
int lengthOffset = getSubstringOffset(tempSize, column);
std::string cutTemp = currLine.substr(column, lengthOffset);
// Insert a new line
lines[row].erase(column);
// after incrementing, row and amount of lines, initialize the new row
numberOfLines++;
lines.insert(lines.begin() + row, ""); // initialize and shift other rows
row++;
column = 1;
lines[row] += cutTemp; // insert substring into new line
}
My attempt at undoing this works if I don't have any rows underneath the thing I'm about to undo.
Here is my current code for undo:
void Editor::undoNewLine()
{
size_t updateCol = lines[row - 1].size(); // holds size of our old string
lines[row - 1] += lines[row];
lines[row].erase(column);
row--;
numberOfLines--;
column = updateCol; // update to point back to where we were
}
And here is what it looks like when I erase something that has rows underneath it:
Before (we insert new lines, and end up creating a new line after row 1, which we want to undo)
1. Hello
2. |
3. asdf
4. rld
After user hits undo key
1. |Hello
2.
3. asdf
Here is what it should look like though:
Before
1. Hello
2. |
3. asdf
4. rld
After
1. |Hello
2. asdf
3. rld
So how can I erase an element and have it shift everything up one line like insert() does?
You should delete the row instead of deleting in the string:
void Editor::undoNewLine()
{
size_t updateCol = lines[row - 1].size(); // holds size of our old string
lines[row - 1] += lines[row];
lines.erase(lines.begin() + row);
row--;
numberOfLines--;
column = updateCol; // update to point back to where we were
}
Third line was lines[row].erase(column); who -- from what I understand -- erase in your string.
BTW you should avoid having numberOfLines because it needs to reflect exactly lines.size() and here the bug would have been obvious, I think, if you had use lines.size(), which was still 4.
I have a problem understanding how Scintilla markers are bound to a margin.
Lets say I want 3 margins. 1st for linenumbers (no problem here), 2nd for arrow markers only and 3rd for circle makers only. I know from the documentation that I have to specify marginmasks to bind a marker to a margin, but I don't get how to specify the mask. I tried around a little but never got the wanted result. (Either arrows were displayed on both margings (2nd and 3rd) or no symbol was highlighted and instead the line was highlighed). Hope someone can enlighten me how to set the marginmasks.
/* 2nd marker margin -> only arrows */
Call(SCI_SETMARGINTYPEN, 1, SC_MARGIN_SYMBOL);
Call(SCI_SETMARGINWIDTHN, 1, 20);
Call(SCI_SETMARGINSENSITIVEN, 1, 1);
Call(SCI_SETMARGINMASKN, 1, SC_MARK_ARROW); // <=== ???
DefineMarker(1, SC_MARK_ARROW, 0xffffff, 0x0000ff);
/* 3rd marker margin -> only circles */
Call(SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL);
Call(SCI_SETMARGINWIDTHN, 2, 50);
Call(SCI_SETMARGINSENSITIVEN, 2, 1);
DefineMarker(2, SC_MARK_CIRCLE, 0xffffff, 0x00ff00);
Call(SCI_SETMARGINMASKN, 2, SC_MARK_CIRCLE); // <=== ???
Call(SCI_MARKERADD, 1, 1);
Call(SCI_MARKERADD, 1, 2);
That way I get an arrow marker on margin 1 but only a highlighted line and no circle marker for margin 2. I would be glad if someone can explain how the masks have to be set.
There are 32 markers available, and numbers 0 to 24 have no pre-defined use. The numbers 25 to 31 are used for folding, but if you don't need that, you could use those numbers as well.
The first step is to choose a number for each of the markers you want to set up: let's say 4 for arrows, and 5 for circles (probably some constants should be defined for these).
The margin mask is a 32-bit value. To set it, you need to flip the bit that corresponds with each of the marker numbers that should be enabled for that margin:
Call(SCI_SETMARGINMASKN, 1, 1 << 4); // 2nd margin, arrow marker
Call(SCI_SETMARGINMASKN, 2, 1 << 5); // 3rd margin, circle marker
Then you need to define the markers themselves:
DefineMarker(4, SC_MARK_ARROW, 0xffffff, 0x0000ff);
DefineMarker(5, SC_MARK_CIRCLE, 0xffffff, 0x00ff00);
So you can finally add them to a specific line:
Call(SCI_MARKERADD, 1, 4);
Call(SCI_MARKERADD, 1, 5);
This is a programming question, but I'll give you a little of the stats background first. This question refers to part of a data sim for a mixed-effects location scale model (i.e., heterogeneous variances). I'm trying to simulate two MVN variance components using the RANDNORMAL function in IML. Because both variance components are heterogeneous, the variances used by RANDNORMAL will differ across people. Thus, I need IML to select the specific row (e.g., row 1 = person 1) and use the RANDNORMAL function before moving onto the next row, and so on.
My example code below is for 2 people. I use DO to loop through each person's specific variance components (VC1 and VC2). I get the error: "Module RANDNORMAL called again before exit from prior call." I am assuming I need some kind of BREAK or EXIT function in the DO loop, but none I have tried work.
PROC IML;
ColNames = {"ID" "VC1" "VC2"};
A = {1 2 3,
2 8 9};
PRINT A[COLNAME=ColNames];
/*Set men of each variance component to 0*/
MeanVector = {0, 0};
/*Loop through each person's data using THEIR OWN variances*/
DO i = 1 TO 2;
VC1 = A[i,2];
VC2 = A[i,3];
CovMatrix = {VC1 0,
0 VC2};
CALL RANDSEED(1);
U = RANDNORMAL(2, MeanVector, CovMatrix);
END;
QUIT;
Any help is appreciated. Oh, and I'm using SAS 9.4.
You want to move some things around, but mostly you don't want to rewrite U twice: you need to write U's 1st row, then U's 2nd row, if I understand what you're trying to do. The below is a bit more efficient also, since I j() the U and _cv matrices rather than constructing then de novo every time through the loop (which is slow).
proc iml;
a = {1 2 3,2 8 9};
print(a);
_mv = {0,0};
U = J(2,2);
_cv = J(2,2,0);
CALL RANDSEED(1);
do i = 1 to 2;
_cv[1,1] = a[i,2];
_cv[2,2] = a[i,3];
U[i,] = randnormal(1,_mv, _cv);
end;
print(u);
quit;
Your mistake is the line
CovMatrix = {VC1 0, 0 VC2}; /* wrong */
which is not valid SAS/IML syntax. Instead, use #Joe's approach or use
CovMatrix = (VC1 || 0) // (0 || VC2);
For details, see the article "How to build matrices from expressions."
You might also be interested in this article that describes how to carry out this simulation with a block-diagonal matrix: "Constructing block matrices with applications to mixed models."