I can create two tables easy enough but I am having trouble getting them to appear side by side like this:
I am unsure how to achieve this using the Open XML SDK. I'm guessing it will either be a TableProperty or a trick with paragraphs but using the Productivity Tool I couldn't work it out. Code snippet:
int LeftWidth = 2000;
int RightWidth = 2000;
int NumberOfCols = 2;
Table leftTable = StartTable(NumberOfCols, LeftWidth); // Create a basic table
Table rightTable = StartTable(NumberOfCols, RightWidth);
body.Append(leftTable);
/// Do something to right table properties here?
body.Append(rightTable);
I am open to different methods, although ideally the idea would be transferable to three tables side by side too.
In the end I realised there are two main ways to achieve this is Word - either click a table and drag it's top left crosshair to where you want it or split the page into two columns and place a column break between the tables.
Floating Tables Method
int LeftWidth = 2000;
int RightWidth = 2000;
int NumberOfCols = 2;
Table leftTable = StartTable(NumberOfCols, LeftWidth); // Create a basic table
Table rightTable = StartTable(NumberOfCols, RightWidth);
/// Add table position properties and place table in top left
TableProperties tblProps = leftTable.Descendants<TableProperties>().First();
TablePositionProperties tblPos = new TablePositionProperties() { VerticalAnchor = VerticalAnchorValues.Text, TablePositionY = 1 };
TableOverlap overlap = new TableOverlap() { Val = TableOverlapValues.Overlap };
tblProps.Append(tblPos, overlap);
body.Append(leftTable);
/// Add position property to right table, set 8700 and 2400 to where you want the table
TableProperties tblProps2 = rightTable.Descendants<TableProperties>().First();
TablePositionProperties tblPos2 = new TablePositionProperties() { HorizontalAnchor = HorizontalAnchorValues.Page, VerticalAnchor = VerticalAnchorValues.Page, TablePositionX = 8700, TablePositionY = 2400 };
TableOverlap overlap2 = new TableOverlap() { Val = TableOverlapValues.Overlap };
tblProps2.Append(tblPos2, overlap2);
body.Append(rightTable);
Columns Method
Before the tables place this code to keep the prior content in one column:
/// Make sure everything else stays at one column
Paragraph oneColPara = body.AppendChild(new Paragraph());
/// Adjust current doc properties to keep things like landscape
SectionProperties sectionOneProps = null;
if (body.Descendants<SectionProperties>().Count() > 0)
sectionOneProps = (SectionProperties)body.Descendants<SectionProperties>().First().CloneNode(true);
else
sectionOneProps = new SectionProperties();
sectionOneProps.RemoveAllChildren<Columns>();
sectionOneProps.RemoveAllChildren<DocGrid>();
sectionOneProps.Append(new Columns(){ Space = "708" }, new DocGrid(){ LinePitch = 360 }, new SectionType { Val = SectionMarkValues.Continuous } );
oneColPara.Append(new ParagraphProperties(sectionOneProps));
Then do this in the tables part:
int LeftWidth = 2000;
int RightWidth = 2000;
int NumberOfCols = 2;
Table leftTable = StartTable(NumberOfCols, LeftWidth); // Create a basic table
Table rightTable = StartTable(NumberOfCols, RightWidth);
/// Need this blank para to line tables up
body.Append(new Paragraph());
body.Append(leftTable);
/// Place the tables side by side
body.Append(new Paragraph(new Run(new Break() { Type = BreakValues.Column })));
body.Append(rightTable);
/// Make section have 2 columns
Paragraph twoColPara = body.AppendChild(new Paragraph());
/// Adjust current doc properties to keep things like landscape
SectionProperties sectionTwoProps = null;
if (body.Descendants<SectionProperties>().Count() > 0)
sectionTwoProps = (SectionProperties)body.Descendants<SectionProperties>().First().CloneNode(true);
else
sectionTwoProps = new SectionProperties();
sectionTwoProps.RemoveAllChildren<Columns>();
sectionTwoProps.RemoveAllChildren<DocGrid>();
sectionTwoProps.Append(new Columns() { Space = "284", ColumnCount = 2 }, new DocGrid() { LinePitch = 360 }, new SectionType { Val = SectionMarkValues.Continuous });
twoColPara.Append(new ParagraphProperties(sectionTwoProps));
Related
I know, that I can change color of all text in shape this way:
Shape.CellsU["Char.Color"].FormulaForceU = "RGB(255,255,255)";
There is also way to change color of certain characters in shape this way:
Characters.Begin = 2;
Characters.End = 5;
Characters.set_CharProps((short)MSVisio.VisCellIndices.visCharacterColor, (short)MSVisio.VisDefaultColors.visRed;);
But I can't find any way to pass custom RGB (or HEX or any type) value of color to just certain characters in shape. I don't want to cut shape into little shapes.
Can you please help? Thanks
The CharProps property allows you to set an index into the predefined document colors collection. For a custom RGB you can set the corresponding cell formula by first getting the row index with CharPropsRow like this:
var shp = vApp.ActiveWindow.Selection.PrimaryItem;
var shpChars = shp.Characters;
shpChars.Begin = 2;
shpChars.End = 5;
//shpChars.set_CharProps((short)Visio.VisCellIndices.visCharacterColor, (short)Visio.VisDefaultColors.visRed);
var targetRow = shpChars.CharPropsRow[0];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(40,220,40)";
and that should give you similar results to this:
[Update] The above assumes you're targeting existing formating and changing it. To add new runs you can use CharProps first to add the row and then the CharPropsRow to target that new run. So you can run this code against a new page:
var vPag = vApp.ActivePage;
var shp = vPag.DrawRectangle(3,3,5,4);
shp.Text = "GoodMorning";
var shpChars = shp.Characters;
shpChars.Begin = 0;
shpChars.End = 4;
var targetRow = shpChars.CharPropsRow[(short)Visio.VisCharsBias.visBiasLetVisioChoose];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(220,40,40)";
shpChars.Begin = 4;
shpChars.End = 11;
shpChars.set_CharProps((short)Visio.VisCellIndices.visCharacterColor, (short)Visio.VisDefaultColors.visBlack);
targetRow = shpChars.CharPropsRow[(short)Visio.VisCharsBias.visBiasLetVisioChoose];
shp.CellsSRC[(short)Visio.VisSectionIndices.visSectionCharacter,
targetRow,
(short)Visio.VisCellIndices.visCharacterColor].FormulaU = "RGB(40,200,40)";
...and this should result in the following:
I have a table with sensors data. There are sensors with long names that do not fit into a cell.
I want to add three points to end of the long sensor names (like text-overflow: ellipsis in css). I want to do it flexible without hardcoded values. Because in the future number of columns may be different.
How can I do it?
I create table like this:
var table = new PdfPTable(columns.Length);
var widths = new List<float>();
for (var i = 0; i < columns.Length; i++)
{
widths.Add(1f);
}
table.SetWidths(widths.ToArray());
And fill it:
for (var i = 0; i < columns.Length; i++)
{
var cell = new PdfPCell(new Phrase(columns[i], tableDataFont));
cell.UseAscender = true;
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
cell.BackgroundColor = new Color(204, 204, 204);
cell.MinimumHeight = 20f;
table.AddCell(cell);
}
Something like this should work...
var text = "testtesttesttesttest";
var maxLength = 7;
var displayname = text;
if (text.Length > maxLength)
{
displayname = text.Substring(0, maxLength) + "...";
}
Considering you didn't post any code of your own, I can only provide some logic.
What I do here is just take the real value (insert that into text).
Declare a maximum length you want the text in your fields to be (maxLength).
Create a storage variable to for manipulation of the name without losing the original data (in case you want to keep that).
Then check if the text is longer than the maximumlength and replace all that is too long with "...".
You can then return "displayname" to whatever field you want it to be in.
This most likely isn't what you're looking for, but it does answer your question as it is right now.
I have to create a document with tables and nested tables. When the nested table is added to a column with a fixed width (in my example this is the first column with a width of 150pt) the nested table looks as expected (first column auto, second 70pt). But If I add the same nested table to a column where the width should automatically be adapted the columns of the nested table seems to be changed to auto as well. Is there something I have missed?
nested table example
The code to generate this example looks as follow
public void Test(){
//using (var stream = new MemoryStream())
var file = string.Format(#"c:\sample{0}.pdf", Guid.NewGuid());
var rand = new Random();
using (var pdfDoc = new PdfDocument(new PdfWriter(file)))
using (var doc = new Document(pdfDoc))
{
var table = new Table(new[] { UnitValue.CreatePointValue(150), UnitValue.CreatePointValue(0), UnitValue.CreatePointValue(0), UnitValue.CreatePercentValue(25)});
//table.SetWidthPercent(100);
for (var i = 0; i < table.GetNumberOfColumns(); i ++ )
{
var column = table.GetColumnWidth(i);
table.AddHeaderCell(new Cell().SetBackgroundColor(Color.LIGHT_GRAY).SetMargin(0).Add(column.ToString()));
}
const string sampledata = "01234567";
for (var i = 0; i < table.GetNumberOfColumns() * 6; i++)
{
switch (i)
{
case 6:
table.AddCell(new Image(ImageDataFactory.Create(#"c:\demo.jpg")));
break;
case 4:
{
var subTable = CreateSubTable("subtable", rand);
table.AddCell(new Cell().SetMargin(0).SetPadding(0).Add(subTable));
break;
}
case 9:
{
var subTable = CreateSubTable("subtable", rand);
table.AddCell(new Cell().SetMargin(0).SetPadding(0).Add(subTable));
break;
}
default:
table.AddCell(sampledata.Substring(0, rand.Next(1, sampledata.Length)));
break;
}
}
doc.Add(table);
}
private static Table CreateSubTable(string sampledata, Random rand){
var subTable = new Table(new[] {UnitValue.CreatePointValue(0), UnitValue.CreatePointValue(70)});
for (var h = 0; h < subTable.GetNumberOfColumns(); h++)
{
var column = subTable.GetColumnWidth(h);
subTable.AddHeaderCell(new Cell().SetBackgroundColor(Color.LIGHT_GRAY).SetMargin(0).Add(column.ToString()));
}
for (var j = 0; j < subTable.GetNumberOfColumns() * 4; j++)
{
subTable.AddCell(sampledata.Substring(0, rand.Next(1, sampledata.Length)));
}
return subTable;
}
Yes, you've missed something.
First of all, you can check the latest itext7 snapshot version and find your code working as you expect. See the result pdf
The difference is that in 7.0.2 auto layout itext do not consider column width in max width calculations. That has been changed and that's why now your code will work as you expect.
However, in certain conditions the same nested table will be processed differently. It depends on available width (in your case for second column - column with width to be calculated automatically). So generally speaking with certain cell content that will be impossible to place nested table as it should be (0 pt, 70 pt), and itext will squeeze the second column.
The good news is that we received too many questions about auto layout algorithm and decided to write some detailed documentation. I believe that will be finished in a week. And then everybody will be happy =)
I am trying to show x axis value in the form of date(MMM-yy) but it is always begin with jan-01. So please provide solution to display other then jan-01, I mean instead of Jan-01 show oct-01.
Please find the simulated function :
private static void drawGraph()
{
List<GraphPoints> listGP = new List<GraphPoints>();
listGP.Add(new GraphPoints()
{
RecordDate = "01/10/1984",
benchmark = "10000.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "29/06/1987",
benchmark = "30396.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "31/05/1989",
benchmark = "10000.00"
});
listGP.Add(new GraphPoints()
{
RecordDate = "30/09/1993",
benchmark = "310137.88"
});
listGP.Add(new GraphPoints()
{
RecordDate = "31/12/2015",
benchmark = "440037.28"
});
Graph.Chart chart;
chart = new Graph.Chart();
chart.Location = new System.Drawing.Point(10, 10);
chart.Size = new System.Drawing.Size(800, 300);
chart.ChartAreas.Add("draw");
chart.ChartAreas["draw"].AxisX.IntervalType = Graph.DateTimeIntervalType.Years;
chart.ChartAreas["draw"].AxisX.LabelStyle.Format = "MMM-yyyy";
chart.ChartAreas["draw"].AxisX.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisX.MajorGrid.LineDashStyle = Graph.ChartDashStyle.NotSet;
chart.ChartAreas["draw"].AxisY.IntervalAutoMode = Graph.IntervalAutoMode.VariableCount;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineColor = Color.Black;
chart.ChartAreas["draw"].AxisY.MajorGrid.LineDashStyle = Graph.ChartDashStyle.NotSet;
chart.ChartAreas["draw"].BackColor = Color.White;
chart.Series.Add("Bench-Mark");
chart.Series["Bench-Mark"].XValueType = Graph.ChartValueType.Date;
chart.Series["Bench-Mark"].ChartType = Graph.SeriesChartType.Line;
chart.Series["Bench-Mark"].Color = Color.Red;
chart.Series["Bench-Mark"].BorderWidth = 1;
foreach (var item in listGP)
{
chart.Series["Bench-Mark"].Points.AddXY(Convert.ToDateTime(item.RecordDate).ToOADate(), item.benchmark);
}
chart.SaveImage("MyImage.jpg", Graph.ChartImageFormat.Jpeg);
}
See Graph axis points are showing from jan 1988.
There is a nice page on MSDN on various types of labels.
It explains three types of labelling:
Using the Label of the AxisX.LabelStyle.Format and Axis.Interval property to create a regular grid of labels not really connected to the data points
Using the DataPoint.AxisLabel property to label each DataPoint individually
Using CustomLabels to set labels at arbitrary points on an axis.
You are using the first option but this will put a Label at the beginning of one unit of the AxisX.IntervalType which in your case will be years even if you switch to Months because there simply are too few points.
This really should be simple to correct; since you do not want the IntervalType units labelled but the individual DataPoints, you should add AxisLabels to each DataPoint and all ought to be well:
Series S1 = chart.Series["Bench-Mark"];
foreach (var item in listGP)
{
DateTime dt = Convert.ToDateTime(item);
int p = S1.Points.AddXY(dt, listGP[item]);
string l = dt.ToString("MMM-yyyy");
S1.Points[p].AxisLabel = l;
}
Unfortunately with your data, the Chart control's built-in 'intelligence' makes this a bit harder; the issue is that no matter which combination of Interval and IntervalType you choose it just never will show each AxisLabel. In fact I only managed to display those that actually hit the Interval, i.e. DataPoints the fall the 1st of a month. But your data are randomly spread out over several years.
But you can use CustomLabels as a workaround. After adding the AxisLabels in the code above call this little helper function to add CustomLabels; we need to tell the Chart for which range each is to be displayed, and with a large enough range they all show up where they should (according to my data):
void addCustomLabels(Chart chart)
{
Series S1 = chart.Series[0];
ChartArea CA = chart.ChartAreas[0];
CA.AxisX.CustomLabels.Clear();
for (int i = 0; i < S1.Points.Count; i++)
{
CustomLabel cl = new CustomLabel();
cl.FromPosition = S1.Points[i].XValue - 10; // 10 day back and ahead..
cl.ToPosition = S1.Points[i].XValue + 10; //..will be enough space for one label
cl.Text = S1.Points[i].AxisLabel;
CA.AxisX.CustomLabels.Add(cl);
}
}
Note that such a solution will only work well if your data points are as sparse as in the example; for many points the labels would clutter the axis.
I'm entering data from a CSV file into a OpenOffice spreadsheet.
This code gets the a new sheet in a spreadsheet:
Public Spreadsheet getSpreadsheet(int sheetIndex, XComponent xComp)
{
XSpreadsheet xSheets = ((XSpreadsheetDocument)xComp).getSheets();
XIndexAccess xSheetIA = (XIndexAccess)xSheets;
XSpreadsheet XSheet = (XSpreadsheet)xSheetsA.getByIndex(sheetIndex).Value;
return XSheet;
}
I then have method that enters a list into a cell range one cell at a time. I want to be able to automatically set the column size for these cells. which is something like
string final DataCell;
Xspreadsheet newSheet = getSpreadsheet(sheetIndex, xComp);
int numberOfRecords = ( int numberOfColumns * int numberOfRows);
for(cellNumber = 0; cellNumber < numberOfrecords; cellNumber++)
{
XCell tableData = newSheet.getCellbyPosition(columnValue, rowValue);
((XText)tableData).setString(finalDataCell);
column Value++;
if(columnValue > = numberOfColumns)
{
rowVal++ column = 0;
}
}
After googling i have found the function:
columns.OptimalWidth = True on http://forum.openoffice.org/en/forum/viewtopic.php?f=20&t=31292
but im unsure on how to use this. Could anyone explain this further or think of another way to have the cell autofit?
I understand the comments in the code are in Spanish I think, but the code is in English. I ran the comments through Google translate so now they are in English. I copied it from here:
//Auto Enlarge col width
private void largeurAuto(string NomCol)
{
XCellRange Range = null;
Range = Sheet.getCellRangeByName(NomCol + "1"); //Recover the range, a cell is
XColumnRowRange RCol = (XColumnRowRange)Range; //Creates a collar ranks
XTableColumns LCol = RCol.getColumns(); // Retrieves the list of passes
uno.Any Col = LCol.getByIndex(0); //Extract the first Col
XPropertySet xPropSet = (XPropertySet)Col.Value;
xPropSet.setPropertyValue("OptimalWidth", new one.Any((bool)true));
}
What this does it this: First it gets the range name and then gets the first column. The real code, though, is XpropertySet being used, which is explained REALLY well here.
public void optimalWidth(XSpreadsheet newSheet)
{
// gets the used range of the sheet
XSheetCellCursor XCursor = newSheet.createCursor();
XUsedAreaCursor xUsedCursor = (XUsedAreaCursor)XCursor;
xUsedCursor.gotoStartOfUsedArea(true);
xUsedCursor.gotoEndOfUsedArea(true);
XCellRangeAddressable nomCol = (XCellRangeAddressable)xUsedCursor;
XColumnRowRange RCol = (XColumnRowRange)nomCol;
XTableColumns LCol = RCol.getColumns();
// loops round all of the columns
for (int i = 0; i < nomCol.getRangeAddress().EndColumn;i++)
{
XPropertySet xPropSet = (XPropertySet)LCol.getByIndex(i).Value;
xPropSet.setPropertyValue("OptimalWidth", new uno.Any(true));
}
}