JavaFX: Cell renderer instance for a given row of a TableColumn - tableview

In JavaFX, how to get the cell renderer instance for a given cell of a given TableColumn?
In Swing, the way to do it would be to invoke getTableCellRendererComponent() on the TableCellRenderer for that column and pass it the row and column indices. But JavaFX seems to be very different. I tried searching and going through the TableColumn API but I don't seem to be able to figure this out. Maybe I have to do something with getCellFactory().
My goal is to query the preferred width for each cell renderer of a column and then calculate the width to set on the column so that the contents of all the cells of that column are fully visible.
A question was asked here - JavaFX 2 Automatic Column Width - where the goal of the original poster was the same as that of mine. But there hasn't been a satisfactory answer there yet.

There is resizeToFit() method in TableColumnHeader class. Unfortunately it is protected. How about just copy-paste the code to your application and change it a bit:
protected void resizeToFit(TableColumn col, int maxRows) {
List<?> items = tblView.getItems();
if (items == null || items.isEmpty()) return;
Callback cellFactory = col.getCellFactory();
if (cellFactory == null) return;
TableCell cell = (TableCell) cellFactory.call(col);
if (cell == null) return;
// set this property to tell the TableCell we want to know its actual
// preferred width, not the width of the associated TableColumn
cell.getProperties().put("deferToParentPrefWidth", Boolean.TRUE);//the change is here, only the first parameter, since the original constant is not accessible outside package
// determine cell padding
double padding = 10;
Node n = cell.getSkin() == null ? null : cell.getSkin().getNode();
if (n instanceof Region) {
Region r = (Region) n;
padding = r.getInsets().getLeft() + r.getInsets().getRight();
}
int rows = maxRows == -1 ? items.size() : Math.min(items.size(), maxRows);
double maxWidth = 0;
for (int row = 0; row < rows; row++) {
cell.updateTableColumn(col);
cell.updateTableView(tblView);
cell.updateIndex(row);
if ((cell.getText() != null && !cell.getText().isEmpty()) || cell.getGraphic() != null) {
getChildren().add(cell);
cell.impl_processCSS(false);
maxWidth = Math.max(maxWidth, cell.prefWidth(-1));
getChildren().remove(cell);
}
}
col.impl_setWidth(maxWidth + padding);
}
Then you can call the method after load data:
for (TableColumn clm : tblView.getColumns()) {
resizeToFit(clm, -1);
}

Related

Something strange with positioning text with custom font in Itext7

I'm working on a program that creates several pdf docs and puts different text in the same location in them.
Text should be placed in a particular area and if it doesn't fit it in width it should wrap. It also has a custom font and may be differently aligned in that area. It should be Vertically aligned to Top because when the area is laid out for three lines and I has only one, it should appear on the top. Finally, I need to preserve leading on the level of font-size.
It is important to be precise in text positioning (e.g. I need an upper left corner of "H" from "Hello world" to appear definitely at 0, 100).
Now, I'm using
canvas.showTextAligned(paragraph, 0, 300,
TextAlignment.valueOf(alignment),
VerticalAlignment.TOP);
However, when I try to implement it with different fonts it has a various offset from desired y = 300. Moreover, offset differ from font to font. For Helvetica (everywhere 50 fontSize is used) offset is about 13 px, for Oswald about 17 px and for SedgwickAveDisplay it is massive 90 px.
I added borders to paragraph for debugging purpose and things become more strange.
Helvetica:
SedgwickAveDisplay:
The full snippet of my code to create pdf is below:
public byte[] createBadgeInMemory(int i) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
PdfDocument newPdf = new PdfDocument(new PdfWriter(out));
srcPdf.copyPagesTo(1,1,newPdf);
PdfPage page = newPdf.getFirstPage();
PdfCanvas pdfCanvas = new PdfCanvas(page);
Canvas canvas = new Canvas(pdfCanvas, newPdf, pageSize);
File defaultFont = new File("src/main/resources/fonts/Helvetica.otf");
PdfFont font = PdfFontFactory
.createFont(fontPath == null ? defaultFont.getAbsolutePath() : fontPath,
PdfEncodings.IDENTITY_H, true);
String value = "Example word";
Paragraph paragraph = new Paragraph(value);
float textWidth = font.getWidth("Example", 50);
paragraph.setWidth(textWidth);
switch (alignment) {
case("CENTER"):
textWidth /= 2;
break;
case("RIGHT"):
break;
default:
textWidth = 0;
break;
}
paragraph.setFont(font)
.setFontSize(fontSize)
.setFixedLeading(fontSize)
.setFontColor(new DeviceRgb(red, green, blue))
.setMargin(0)
.setPadding(0);
paragraph.setBorderTop(new DashedBorder(Color.BLACK, 0.5f))
.setBorderBottom(new DashedBorder(Color.BLACK, 0.5f))
.setBorderRight(new DashedBorder(Color.BLACK, 0.5f));
paragraph.setHyphenation(new HyphenationConfig(0,
"Example".length()));
canvas.showTextAligned(paragraph,
0 + textWidth,
300,
TextAlignment.valueOf(alignment),
VerticalAlignment.TOP);
newPdf.close();
return out.toByteArray();
}
I also tried variant from here, but for some reason text inside rectangle cuts out at some point (for instance, if I have area width 100px and text snippet I put in that I know occupies exactly 100 px (with the help of font.getWidth(value)), I have my text cut at nearly 80 px).
I also haven't found a way to align text inside a rectangle.
This is the result with Rectangle. A solid border is Rectangle border. As you can see it cuts letter "t" in "Redundant". It also should contain "word" on the second line, but it doesn't.
I copied code from an example.
I need your help. What am I doing wrong or may be there is another way to layout text in particular area with alignment and font?
Thank you in advance.
Update 21.09.17
Also tried variant from this question with SedgwickAveDisplay:
paragraph.setHorizontalAlignment(HorizontalAlignment.LEFT);
paragraph.setVerticalAlignment(VerticalAlignment.TOP);
paragraph.setFixedPosition( 0, 300 - textHeight, "Example".length());
doc.add(paragraph);
The result is the same as on the second screenshot.
This is a font-specific problem. iText guesses information about font glyphs, namely the bboxes incorrectly.
There is a quick and dirty method to adjust this behavior. You can create a custom renderer for text and adjust the calculated positions in it. An example of such a class would be as follows:
class CustomTextRenderer extends TextRenderer {
private CustomTextRenderer(Text text) {
super(text);
}
#Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
Rectangle oldBbox = this.occupiedArea.getBBox().clone();
// you can also make the height more than font size or less if needed
this.occupiedArea.setBBox(oldBbox.moveUp(oldBbox.getHeight() - fontSize).setHeight(fontSize));
yLineOffset = fontSize * 0.8f; // here you config the proportion of the ascender
return result;
}
#Override
public IRenderer getNextRenderer() {
return new CustomTextRenderer((Text) modelElement);
}
}
In order that new rendering logic to be applied, you have to use it in the following way:
Text text = new Text(value);
text.setNextRenderer(new CustomTextRenderer(text));
Paragraph paragraph = new Paragraph(text);
Please note that you have to be very careful with this kind of low-level layouting, be aware of you are doing and use this as seldom as possible.
Finally, I created a variant that worked for me.
pdfCanvas.beginText()
.setFontAndSize(font, fontSize)
.setLeading(fontSize)
.moveText(0, 300);
numberOfLines = 0;
sumOfShifts = 0;
float maxWidth = computeStringWidth("Exaxple");
String[] words = value.split("\\s");
StringBuilder line = new StringBuilder();
line.append(words[0]);
float spaceWidth = computeStringWidth(" ") ;
float lineWidth;
for (int index = 1; index < words.length; index++) {
String word = words[index];
float wordWidth = computeStringWidth(word) ;
lineWidth = computeStringWidth(line.toString()) ;
if (lineWidth + spaceWidth + wordWidth <= maxWidth) {
line.append(" ").append(word);
} else {
showTextAligned(alignment, pdfCanvas, line.toString(), lineWidth, maxWidth);
line.delete(0, line.length());
line.append(word);
}
}
if(line.length() != 0) {
lineWidth = computeStringWidth(line.toString()) ;
showTextAligned(alignment, pdfCanvas, line.toString(), lineWidth, maxWidth);
}
pdfCanvas.endText();
As computeStringWidth(String str) I used
Toolkit.getToolkit().getFontLoader().computeStringWidth(String str, Font font);
from import com.sun.javafx.tk.Toolkit with Font from javafx.scene.text.Font. I've chosen it because I use it in other parts of my app.
showTextAligned(...) is my own method that looks this way:
private void showTextAligned(String alignment,
PdfCanvas pdfCanvas,
String line,
float lineWidth,
float maxWidth) {
switch (alignment) {
case "CENTER": {
float shift = (maxWidth - lineWidth) / 2 - sumOfShifts;
pdfCanvas.moveText(shift, 0);
if(numberOfLines == 0) pdfCanvas.showText(line);
else pdfCanvas.newlineShowText(line);
numberOfLines++;
sumOfShifts += shift;
break;
}
case "RIGHT": {
float shift = maxWidth - lineWidth - sumOfShifts;
pdfCanvas.moveText(shift, 0);
if(numberOfLines == 0) pdfCanvas.showText(line);
else pdfCanvas.newlineShowText(line);
numberOfLines++;
sumOfShifts += shift;
break;
}
default:
pdfCanvas.moveText(0, 0);
if(numberOfLines == 0) pdfCanvas.showText(line);
else pdfCanvas.newlineShowText(line);
numberOfLines++;
break;
}
}
In my project, I used my variant, because it gives me an opportunity to work with hyphenation deeper (for instance, I can in future add functionality to avoid putting prepositions as a last word in the line).

How to get the XPath of a grid cell using Firebug?

I am working on a UI. My job is to automate it. I came across the following grid.
When you click on any cell under the Rule column, a browse button appears.
I am supposed to automate this scenario. So, using Firebug I am trying to extract the XPath of that cell.
I used Firebug's inspector to locate that particular cell, so that I can write the XPath for it, but I am unable to locate that cell. Instead, the entire row is getting selected, as shown in next images.
How should I approach this problem?
below code might help you to verify the grid values,
public void verifyTableValues(String expectedValue
) {
try {
//List of Fields values which you want to verify
List<String> expectedValues = Arrays.asList(expectedValue.split("#"));
// you will get the number of rows in Table Select the xpath to /tr
String tableRow = driver.findElements(By.xpath(//table row constant));
int tableRwCnt = getCount(tableRow);
// you will get the number of Columns in Table Select the xpath to /td
String tableColumn = driver.findElements(By.xpath(//table Column constant));
int tableColumnCnt = getCount(tableColumn);
for (int cnt = 1; cnt <= tableRwCnt; cnt++) {
for (int listCount = 1; listCount <= tableColumnCnt; listCount++) {
String actualVal = findElement(By.xpath(tableColumn + "[" + cnt + "]/td["
+ expectedValues.get(listCount) + "]").getText();
String expectdVal = expectedValues.get(listCount);
Assert.assertEquals("Value from table doent Match", expectdVal, actualVal);
}
}
} catch (Exception e) {
// code for exception
}
}
Parameter: expectedValue = test1#test2#test4#test4 (Grid values)

Table in Word looks different if halted on breakpoint

I have stumbled on a very annoying problem when setting column widths on a table in Word (using Microsoft Office 15.0 Object Library, VS 2013). If I run the code below without having any breakpoints, the result becomes incorrect (first column width should be 30%), but if I put a breakpoint (e.g.) on line 47, the generated Word file becomes as I want it to be.
The conclusion I make is that when the debugger stops execution, the given column size values are flushed into the data model and the output will be as I want it to be. Without the breakpoint, the merging of cells changes the widths (e.g. the first column becomes 12,5%).
I have searched for some sort of method/function to make the data model adjust to my programmatically given column sizes before the cell merging, with no luck. Anyone out there that can explain why halting on the breakpoint will change the output?
Regards,
Ola
using System;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Word;
namespace ShowWordProblem
{
class Program
{
private const string WordFileName = #"C:\temp\test.doc";
static void Main(string[] args)
{
var wordApplication = new Application();
wordApplication.Visible = false;
var wordDocument = wordApplication.Documents.Add();
FillDocument(wordDocument);
wordDocument.SaveAs2(WordFileName);
wordDocument.Close();
wordApplication.Quit(Type.Missing, Type.Missing);
Marshal.FinalReleaseComObject(wordApplication);
wordApplication = null;
wordApplication = new Microsoft.Office.Interop.Word.Application();
wordApplication.Visible = true;
wordApplication.Documents.Open(WordFileName);
}
private static void FillDocument(Document wordDocument)
{
Range range = wordDocument.Content.Paragraphs.Add().Range;
var table = range.Tables.Add(range, 5, 8);
table.PreferredWidthType = WdPreferredWidthType.wdPreferredWidthPercent;
table.PreferredWidth = (float)100.0;
table.Columns.PreferredWidthType = WdPreferredWidthType.wdPreferredWidthPercent;
table.Columns.PreferredWidthType = WdPreferredWidthType.wdPreferredWidthPercent;
table.Columns[1].PreferredWidth = 30;
for (int i = 2; i <= 8; i++) table.Columns[i].PreferredWidth = 10;
var widths = table.Columns.OfType<Column>().Select(c => c.Width).ToArray();
MergeGroupHeaderCells(table.Rows[1], 5, 9);
MergeGroupHeaderCells(table.Rows[1], 2, 5);
}
private static void MergeGroupHeaderCells(Row row, int startIndex, int lastIndex)
{
var r = row.Cells[startIndex].Range;
Object cell = WdUnits.wdCell;
Object count = lastIndex - startIndex - 1;
r.MoveEnd(ref cell, ref count);
r.Cells.Merge();
}
}
}
Finally I found a way to force the code to apply the given percentage values to the columns before the merging of the cells, and thereby having the correct widths on all columns.
By adding the following line of code after the last PreferredWidth-assignment:
var info = table.Range.Information[WdInformation.wdWithInTable];
it seems that the given PreferredWidth values are propagated to the columns, and the final rendered word document looks exactly as I want it.
/Ola

Why doesn't my OpenSCAD model render correctly in thingiverse?

I created a parametric OpenSCAD model, and tried importing it into thingiverse customizer. However, it is supposed to look like this:http://i.stack.imgur.com/BXFsQ.jpg, but it looks closer to this: http://i.stack.imgur.com/rOF5b.png
Does thingiverse simply not render anything correctly, or is there a problem with the model (code reproduced below)
//Do Nothing = 0
//Increment = 1
//Decrement = 2
//Increment + Zerocheck = 3
//Decrement + Zerocheck = 4
//Text position:
//Top left: 0
//Left side inwards: 1
//Left side outwards: 2
/* [Instructions] */
//Instructions for the Left Counter
Left_counter = 0; // [0:Do Nothing,1:Increment,2:Decrement,3:Increment and Check Zero,4:Decrement and Check Zero]
//Instructions for the Middle Counter
Middle_counter = 0; // [0:Do Nothing,1:Increment,2:Decrement,3:Increment and Check Zero,4:Decrement and Check Zero]
//Instructions for the Right Counter
Right_counter = 0; // [0:Do Nothing,1:Increment,2:Decrement,3:Increment and Check Zero,4:Decrement and Check Zero]
//Hole that currently has no purpose
No_Purpose_Hole = 0; // [0:Don't create hole,1:Create hole]
/* [Text] */
//Text to show
Text="";
//Can be used for card number, description, etc.
Text_position=0;// [0:Top left corner (1-3 chars),1:Left side facing inwards (1-12 chars),2:Left side facing outwards (1-12 chars)]
/* [Hidden] */
$fn=30;
include <write/Write.scad>;
punchcard();
module punchcard(){
scale([25.4,25.4,25.4])
difference(){
card(Text);
union(){
if (Left_counter == 1)
hole(3);
if (Left_counter == 2)
hole(1);
if (Left_counter == 3){
hole(3);
hole(5);}
if (Left_counter == 4){
hole(1);
hole(5);}
if (Middle_counter == 1)
hole(2);
if (Middle_counter == 2)
hole(8);
if (Middle_counter == 3){
hole(2);
hole(4);}
if (Middle_counter == 4){
hole(8);
hole(4);}
if (Right_counter == 1)
hole(10);
if (Right_counter == 2)
hole(7);
if (Right_counter == 3){
hole(10);
hole(9);}
if (Right_counter == 4){
hole(7);
hole(9);}
if (No_Purpose_Hole == 1)
hole(6);
}}}
module card(text){
difference(){
cube([3.3,1.8,.1]);
translate([0,0,-.5])union(){
//positioning holes
translate([1.65,.25,0])
cylinder(d=.25,h=1);
translate([1.65, 1.55,0])
cylinder(d=.25,h=1);
//threading holes
for(x=[.125,3.175])
for(y=[.125,1.675])
translate([x,y,0])
cylinder(d=.125,h=1);
}
if (Text_position == 0)
translate([.4,1.675,.1])
scale([.04,.04,.1])
writecube(text = Text, face = "top", size = .01);
if (Text_position == 1)
translate([.1,.9,.1])
scale([.04,.04,.1])
rotate([0,0,90])
writecube(text = Text, face = "top", size = .01);
if (Text_position == 2)
translate([.1,.9,.1])
scale([.04,.04,.1])
rotate([0,0,-90])
writecube(text = Text, face = "top", size = .01);
}
}
module hole (position){
translate([.3*position,0.7,-.5])
union(){
cylinder(d=.2, h=1);
translate([-.1,0,0])
cube([.2,.3,1]);
translate([0,.3,0])
cylinder(d=.2, h=1);
}}
Can you please specify how the rendering of thing-verse is off? The second image simply looks like the rendering of OpenSCAD. If you have already found an answer to your question, please let me know about the answer.

BIRT Palette scripting: How to access dataset row

If I want to change the color of circles in scatter chart based on a field not being used in the chart, then how do i use that column in script. I mean how can i get the that data...for example
If (row[v_count])>2
fill red color...
The exact code is below
function beforeDrawDataPoint(dph, fill, icsc)
{
//Fill implements Fill interface
//ImageImpl
//ColorDefinitionImpl
//GradientImpl
//MultipleFillImpl
//EmbeddedImageImpl
//PatternImageImpl
importPackage( Packages.org.eclipse.birt.chart.model.attribute.impl );
val = dph.getOrthogonalValue();
if( fill.getClass().isAssignableFrom(ColorDefinitionImpl)){
if (row[v_count]>2){
fill.set(255, 0, 0);
}
}
}
but i dont know do i get that v_count column in the script. is there some function to get that column ?
I mean if we are making some calculations based on a column from databinding columns..that is not being used in x or y axis, then how do we access that column in the script..is there some kind of function for that.. I tried row["v_count"], but it is not working.
Arif
You could use "persistent global variables". In any place of your report you can write the following to store and load a global variable. Note that you cannot store Integers but only Strings (but after loading you can cast your Strings back to other types). You could store the Value of your column in the Script of an invisible data field located above your chart, so inside your chart you can read the value.
//store a value
reportContext.setPersistentGlobalVariable("varName", "value");
//load the value
var load = reportContext.getPersistentGlobalVariable("varName");
I spend my day look but I did not find the solution, this is my colleague who give me :)
So I share.
in my example I had to create a vertical marker for every new year
function beforeGeneration(chart, icsc)
{
importPackage(Packages.org.eclipse.birt.chart.model.component.impl);
importPackage(Packages.org.eclipse.birt.chart.model.data.impl);
importPackage(Packages.org.eclipse.birt.chart.model.attribute);
importPackage(Packages.org.eclipse.birt.chart.model.attribute.impl);
var chart = icsc.getChartInstance();
var yAxis = chart.getBaseAxes()[0];
//get date series for my case
series = yAxis.getRuntimeSeries();
// but if you have multiple series ... (for exemple xaxis)
for (i = 0; i < series.length; i++){
var values = series[i].getDataSet().getValues();
for (j = 0; j < values.length; j++){
if(j > 1){
var date1 = values[j-1];
var date2 = values[j];
if(date1.getYear() < date2.getYear()){
min_ml = MarkerLineImpl.create(yAxis, NumberDataElementImpl.create(j));
min_ml.getLabel().getCaption().setValue("Nouveau boitier");
min_ml.getLineAttributes().getColor().set(255,0,0);
}
}
}
}
}

Resources