I have create a table with bars which shows frequency of the words in a text.I show the number of special word which user click on them or frequency of whole words in the text. I fetch my list of list and send it to the fill table function. All thing is OK but when I select a special word and then click to show whole words I get indexoutofbounds exception. I guess it is because I change my datasource. It is really strange but simple. However, I could not solve it.
public void fill_count_table(List<RootWordSet> source){
final List<RootWordSet> mysource=source;
if(source!=null){
for(int i=0;i<source.size();i++){
TableItem ti=new TableItem(count_table, SWT.NONE);
ti.setText(source.get(i).getRoot());
}
count_table.addListener(SWT.PaintItem, new Listener() {
public void handleEvent(Event event) {
if (event.index == 1) {
try{
GC gc = event.gc;
TableItem item = (TableItem)event.item;
int index = count_table.indexOf(item);
System.out.println(mysource.size());
int percent = mysource.get(index).getWordNumber();
org.eclipse.swt.graphics.Color foreground = gc.getForeground();
org.eclipse.swt.graphics.Color background = gc.getBackground();
gc.setForeground(Display_1.getSystemColor(SWT.COLOR_BLUE));
gc.setBackground(Display_1.getSystemColor(SWT.COLOR_DARK_BLUE));
int width = (tc2.getWidth() - 1) * percent / 100;
gc.fillGradientRectangle(event.x, event.y, width, event.height, true);
Rectangle rect2 = new Rectangle(event.x, event.y, width-1, event.height-1);
gc.drawRectangle(rect2);
gc.setForeground(Display_1.getSystemColor(SWT.COLOR_RED));
String text = Integer.toString(percent) ;
Point size = event.gc.textExtent(text);
int offset = Math.max(0, (event.height - size.y) / 2);
gc.drawText(text, event.x+2, event.y+offset, true);
gc.setForeground(background);
gc.setBackground(foreground);
}
catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
}
}
});
}
else{
count_table.removeAll();
count_table.redraw();
}
}
this is the line that make error: int percent = mysource.get(index).getWordNumber();
I really do not know what happens when I change datasources. when I shift to each other it stuck. Even I put a println to check the size of datasource but it was quite strange it had two size. One belong to former datasource and one belong to newwr. Anyway If I remove this graphic part table fill correctly. What do you think?
change this line:
int percent = mysource.get(index).getWordNumber();
to
int percent = mysource.get(index-1).getWordNumber();
Related
I would like to use column percentage sizing to force the table to take on the width of the parent.
This does not work when I hide column(s) by default because the setColumnPercentageSizing() method does not seem to exclude hidden columns and does not correctly calculate the width.
Is there an easy way to adjust this in my code?
Example:
public void example(){
createGlazedListsGridLayer();
autoResizeColumns();
nattable.configure();
}
public GlazedListsGridLayer createGlazedListsGridLayer(){
SortedList<T> sortedList = new SortedList<>(eventList, null);
this.bodyDataProvider = new ListDataProvider<>(sortedList,
columnPropertyAccessor);
this.bodyDataLayer = new DataLayer(this.bodyDataProvider);
ColumnHideShowLayer columnHideShowLayer = new
ColumnHideShowLayer(bodyDataLayer);
// In this example, hide the first column
columnHideShowLayer.hideColumnPositions(Lists.newArrayList(0));
this.bodyLayerStack = new DefaultBodyLayerStack(new
GlazedListsEventLayer<>(columnHideShowLayer, eventList));
//...etc
}
protected void autoResizeColumns() {
glazedListsGridLayer.getBodyDataLayer().setColumnPercentageSizing(true);
nattable.addConfiguration(new DefaultNatTableStyleConfiguration() {
{
cellPainter = new LineBorderDecorator(new TextPainter(false,
true, 5, true));
}
});
}
UPDATE
It's not ideal but this is the closest I could get to it
public void adjustColumnWidth() {
getBodyDataLayer().setColumnPercentageSizing(false);
// Avoid the first column since it's hidden
for (int x = 1; x <= numColumns; x++) {
getBodyDataLayer().setColumnWidthByPosition(x,
getParent().getSize().x / numColumns, true);
}
}
UPDATE 2
Here are a couple of different things I tried in various combinations. None of them seem to keep the column hidden after a table is dynamically populated with data.
protected void enableAutoResizeColumns() {
getBodyDataLayer().setColumnPercentageSizing(true);
getBodyDataLayer().setDefaultColumnWidthByPosition(0, 0);
getBodyDataLayer().setColumnWidthByPosition(0, 0);
getBodyDataLayer().setColumnWidthPercentageByPosition(0, 0);
getNatTable().addConfiguration(new
DefaultNatTableStyleConfiguration() {
{
cellPainter = new LineBorderDecorator(new TextPainter
(false, true, 5, true));
}
});
}
Currently there is no solution for that. The reason for this is that the column widths are calculated in the DataLayer. The ColumnHideShowLayer sits on top of it and simply hides columns. It doesn't communicate back to the DataLayer that something is hidden.
In the end the ColumnHideShowLayer would need to re-trigger percentage size calculation based on the hidden state. But there is currently no API for that.
Feel free to create an enhancement ticket and provide a patch if you have an idea how to solve it.
I'm trying to make a simple 3-column TableView:
One icon column containing a fixed size icon. This column must not be resizable, and must have a fixed size.
One text column with a predefined prefered size, which can be resized if needed.
One last column taking all available space.
Unfortunatly, this simple use case seems to be really complicated with Java FX 8. I tried the following, which should work according to my understanding of the documentation:
TableColumn<DebuggerItem, ImageView> iconColumn = new TableColumn<>("ICON");
TableColumn<DebuggerItem, String> typeColumn = new TableColumn<>("TEXT");
TableColumn<DebuggerItem, String> textColumn = new TableColumn<>("DATA");
setColumnResizePolicy(CONSTRAINED_RESIZE_POLICY);
// Fixed size column
iconColumn.setPrefWidth(40);
iconColumn.setMinWidth(40);
iconColumn.setMaxWidth(40);
iconColumn.setResizable(false);
// Predefined preferred size of 100px
typeColumn.setPrefWidth(100);
getColumns().addAll(iconColumn, typeColumn, textColumn);
This results in the following TableView:
We can see that if the first column has a correct size, the second and the hird have the same size, which is not what I expected. The second column should be 100px wide, and the last one take the rest of the space.
What did I miss ?
According to #kleopatra link, the solution is to use properties to compute last column width, and NOT use CONSTRAINED_RESIZE_POLICY :
LastColumnWidth = TableViewWidth - SUM(Other Columns Widths)
Which, according to my example give the following Java code:
TableColumn<DebuggerItem, ImageView> iconColumn = new TableColumn<>("ICON");
TableColumn<DebuggerItem, String> typeColumn = new TableColumn<>("TEXT");
TableColumn<DebuggerItem, String> textColumn = new TableColumn<>("DATA");
// Fixed size column
iconColumn.setPrefWidth(40);
iconColumn.setMinWidth(40);
iconColumn.setMaxWidth(40);
iconColumn.setResizable(false);
// Predefined preferred size of 100px
typeColumn.setPrefWidth(100);
// Automatic width for last column
textColumn.prefWidthProperty().bind(
widthProperty().subtract(
iconColumn.widthProperty()).subtract(
typeColumn.widthProperty()).subtract(2)
);
getColumns().addAll(iconColumn, typeColumn, textColumn);
Please note that we need to substract 2 pixels to get the exact width, it's not clear why.
I created a more general solution, that pixel-perfectly calculates width of last column for TableViews that:
have any number of columns
possibly hide or show columns at runtime
possibly have custom insets
possibly have scrollbar, possibly showing and hiding at runtime.
Usage:
bindLastColumnWidth(tableView);
Source:
public static <T> void bindLastColumnWidth (TableView<T> tableView) {
List<TableColumn<T,?>> columns = tableView.getColumns();
List<TableColumn<T,?>> columnsWithoutLast = columns.subList(0, columns.size() - 1);
TableColumn lastColumn = columns.get(columns.size() - 1);
NumberExpression expression = tableView.widthProperty();
Insets insets = tableView.getInsets();
expression = expression.subtract(insets.getLeft() + insets.getRight());
for (TableColumn column : columnsWithoutLast) {
NumberExpression columnWidth = Bindings.when(column.visibleProperty())
.then(column.widthProperty())
.otherwise(0);
expression = expression.subtract(columnWidth);
}
ScrollBar verticalScrollBar = getScrollBar(tableView, Orientation.VERTICAL);
if (verticalScrollBar != null) {
NumberExpression scrollBarWidth = Bindings.when(verticalScrollBar.visibleProperty())
.then(verticalScrollBar.widthProperty())
.otherwise(0);
expression = expression.subtract(scrollBarWidth);
}
expression = Bindings.max(lastColumn.getPrefWidth(), expression);
lastColumn.prefWidthProperty().bind(expression);
}
private static ScrollBar getScrollBar (Node control, Orientation orientation) {
for (Node node : control.lookupAll(".scroll-bar")) {
if (node instanceof ScrollBar) {
ScrollBar scrollBar = (ScrollBar)node;
if (scrollBar.getOrientation().equals(orientation)) {
return scrollBar;
}
}
}
return null;
}
You can call this below code after you add all columns to table.
This is nice when the code that resizes does not have a explicit list of columns.
public static void makeLastColumnGrow(TableView<?> items) {
var last = items.getColumns().get(items.getColumns().size() - 1);
var aBinding = Bindings.createDoubleBinding(() ->{
double width = items.getWidth();
for (int i = 0; i < items.getColumns().size() - 1 ; i++) {
width = width - items.getColumns().get(i).getWidth();
}
return width - 2; // minus -2 to account for border i think
}, items.widthProperty());
last.prefWidthProperty().bind(aBinding);
}
I am trying to find a way to programmatically set page breaks for printing out a JTable.
E.g., I have a table with approx 150 rows like this:
Line Number Data1 Data2 Data3 …etc
1 a b c d
1 a b c d
1 a b c d
2 a b c d
2 a b c d
3 a b c d
3 a b c d
3 a b c d
3 a b c d
4 a b c d
5 a b c d
5 a b c d
5 a b c d
…etc …etc …etc …etc …etc
I need to find a way to start printing a new page when the line number changes.
I found a method for printing selected rows, and so far have modified it to loop through my table adding rows to a temporary print model and then calling print() method to print before resetting the temporary variables. However, this means that I am calling print() maybe 10 times, once for each line number, which is an unacceptable solution. The code that accomplishes current flawed solution is as follows:
btnPrint.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
int wrappingLineNumber = (Integer) table.getValueAt(0, 0);
WrappingSheetsTableModel printModel = new WrappingSheetsTableModel();
for (int i = 0; i < table.getRowCount(); i++) {
if ((Integer)table.getValueAt(i, 0) == wrappingLineNumber) {
System.out.println(table.getValueAt(i, -1));
printModel.addRow((WrappingSheets) table.getValueAt(i, -1));
} else {
wrappingLineNumber = (Integer) table.getValueAt(i, 0);
// if not the same, i.e., value changed
JTable toPrint = new JTable(printModel);
toPrint.setSize(toPrint.getPreferredSize());
JTableHeader tableHeader = toPrint.getTableHeader();
tableHeader.setSize(tableHeader.getPreferredSize());
toPrint.print(JTable.PrintMode.FIT_WIDTH);
printModel.removeAll();
printModel.addRow((WrappingSheets) table.getValueAt(i, -1));
}
}
System.out.println("success printing");
} catch (PrinterException pe) {
System.out.println("printing failed");
pe.printStackTrace();
}
};
});
Can anyone provide a better solution that will start printing on a new page whenever the value in the line number column changes?
Many thanks in advance for any help provided!
After further research and thought I realized that it is possible to create sub-tables/temporary tables holding only the information relevant to each wrapping line. The question then is how to print multiple JTables as one print job. Variations of this question have been asked and answered here and particularly here. Following the information provided in the second of those links, the solution I came up with is as follows:
Solution utilizes unaltered PrintableWrapper provided by Durandal at link 2 above, included here for information purposes "to spare us the hassle of iterating over each page":
public class PrintableWrapper implements Printable {
private Printable delegate;
private int offset;
public PrintableWrapper(Printable delegate, int offset) {
this.offset = offset;
this.delegate = delegate;
}
#Override
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
return delegate.print(graphics, pageFormat, pageIndex-offset);
}}
Solution also utilizes unaltered kleopatra / Durandal's code from same link for getting number of pages required for each table:
public int getNumberOfPages(Printable delegate, PageFormat pageFormat) throws PrinterException {
Graphics g = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB).createGraphics();
int numPages = 0;
while (true) {
int result = delegate.print(g, pageFormat, numPages);
if (result == Printable.PAGE_EXISTS) {
++numPages;
} else {
break;
}
}
return numPages;
}
From this, the solution was to create a PrinterJob, Book and Temporary JTables. Then add the temporary tables to the book, using the above class and methods. And lastly to print the book. Current code for this solution can be found below, with explanatory comments included in the code:
btnPrint.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
//Code revised from https://stackoverflow.com/questions/14775753/printing-multiple-jtables-as-one-job-book-object-only-prints-1st-table?rq=1
// \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
PrinterJob printerJob = PrinterJob.getPrinterJob();
//Set 1/4 " margins and orientation
PageFormat pf = printerJob.defaultPage();
pf.setOrientation(PageFormat.LANDSCAPE);
Paper paper = new Paper();
//double margin = 36; // half inch
double margin = 18; // quarter inch
paper.setImageableArea(margin, margin, paper.getWidth() - margin * 2, paper.getHeight() - margin * 2);
pf.setPaper(paper);
Book bookToPrint = new Book();
// /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\
//Code revised from https://stackoverflow.com/questions/14775753/printing-multiple-jtables-as-one-job-book-object-only-prints-1st-table?rq=1
// List to store temporary tables to print
List<JTable> tablesToPrint = new ArrayList<JTable>();
// create temporary print tables by wrapping line number
int wrappingLineNumber = (Integer) table.getValueAt(0, 0);
WrappingSheetsTableModel printModel = new WrappingSheetsTableModel();
for (int i = 0; i < table.getRowCount(); i++) {
if ((Integer)table.getValueAt(i, 0) == wrappingLineNumber) {
// add wrapping sheet row to print model
printModel.addRow((WrappingSheets) table.getValueAt(i, -1));
} else {
// if not the same, i.e., value changed
// create a new table
JTable toPrint = new JTable(printModel);
// set size of table as if size isn't set the table contents aren't printed
toPrint.setSize(toPrint.getPreferredSize());
// reduce row height for printing
toPrint.setRowHeight(16);
// add table to print to list of tables to be printed
tablesToPrint.add(toPrint);
// create a new print model for next table to be printed
printModel = new WrappingSheetsTableModel();
// add first new wrapping sheet row to print model
printModel.addRow((WrappingSheets) table.getValueAt(i, -1));
// increment the wrapping line number
wrappingLineNumber = (Integer) table.getValueAt(i, 0);
}
}
// add in last table to print
JTable toPrint = new JTable(printModel);
// set size of table as if size isn't set the table contents aren't printed
toPrint.setSize(toPrint.getPreferredSize());
// reduce row height for printing
toPrint.setRowHeight(16);
// add last table to print to list of tables to be printed
tablesToPrint.add(toPrint);
// add each table to be printed to book for printing
int totalPages = 0;
for (JTable table : tablesToPrint) {
// get the table header information from table
JTableHeader tableHeader = table.getTableHeader();
// set size so that table header will be visible
tableHeader.setSize(tableHeader.getPreferredSize());
// get number of pages in printable table
int pages = getNumberOfPages(table.getPrintable(PrintMode.FIT_WIDTH, null, null), pf);
// create temporary printable to add to book
Printable p = table.getPrintable(PrintMode.FIT_WIDTH, null, null);
// add printable to book using printable wrapper
// p - printable, totalPages - total pages, pf - page format, pages - num pages to add
bookToPrint.append(new PrintableWrapper(p, totalPages), pf, pages);
// increase total pages count
totalPages += pages;
}
//Checks for page count:
//System.out.println(totalPages);
//System.out.println(bookToPrint.getNumberOfPages());
// Queries document for the number of pages
// and the PageFormat
// and Printable
// for each page held in the Pageable instance, document.
printerJob.setPageable(bookToPrint);
// show print dialog
// - printer selection and pages to print work
// - changing from e.g. landscape to portrait does not work currently
if(printerJob.printDialog()) printerJob.print();
System.out.println("success printing X");
} catch (PrinterException pe) {
System.out.println("printing failed");
pe.printStackTrace();
}
};
});
Each page now contains only those rows with the same wrapping line number and a new page is started when the wrapping line number changes. (More research is still needed in relation to the PageFormat and PrintDialog, as changes to page orientation in the print dialog do not currently affect the final print layout).
I'm writing an application where I show markers on a map using the library Unfolding Maps.
The application lets the user choose a year and depending on that value other markers are shown. This works perfect, but when the user selects another year I can't seem to get the other markers shown.
I've tried to completely renew the map but after that first time it doesn't redraw a map.
Besides that I've tried to add a MarkerManager to the map but then I get errors of OpenGL.
setup function:
public void setup() {
/*
* Provincies, set zoom to 10
*/
size(1000, 800, OPENGL);
this.map = new UnfoldingMap(this, new Microsoft.RoadProvider());
map.zoomAndPanTo(belgie, 8);
map.setPanningRestriction(belgie, 1);
map.setZoomRange(8, 8);
drawOtherMarker();
//map.getMarkerManager(markerRemarck.get(keyM)).enableDrawing();
MapUtils.createDefaultEventDispatcher(this, map);
}
function that creates the MarkerManager and adds it to the map
private void createMarkers(ArrayList<double[]> dataMarker) {
float size = 0;
int i = 0;
ListIterator<double[]> dataIt = dataMarker.listIterator();
ArrayList<SimplePointMarker> markList = new ArrayList<SimplePointMarker>();
while (dataIt.hasNext()) {
double[] element = dataIt.next();
SimplePointMarker point = new SimplePointMarker(new Location(
element[0], element[1]));
if (element[2] > 1000)
size = 120;
else if (element[2] > 100)
size = 60;
else if (element[2] > 10)
size = 30;
else
size = 20;
point.setRadius(size);
point.setColor(color(64,64,64,100));
point.setStrokeColor(color(178,34,34));
point.setStrokeWeight(30);
point.setStrokeWeight(0);
point.setId(Integer.toString(i++));
markList.add(point);
}
MarkerManager man = new MarkerManager(markList);
map.addMarkerManager(man);
}
When the map is drawn and another set of markers must be drawn the following function is called:
public void drawOtherMarker(){
if(!markerRemarck.containsKey(keyM)){
markerRemarck.put(keyM, totalMark++);
createMarkers(dataMarkerProvince);
}
if(dataMarkerTown != null){
markerRemarck.put(keyM + "city", totalMark++);
createMarkers(dataMarkerTown);
}
for(int i = 0; i < totalMark;++i)
map.getMarkerManager(i).disableDrawing();
map.getMarkerManager(markerRemarck.get(keyM)).enableDrawing();
}
another function brings in the data required to make the markers. I just don't seem to manage to add a MarkerManager after the first draw.
EDIT
This map is placed inside a JPanel. And the years are choosen with the help of a JComboBox. Once a year is chosen the "dataMarker" variable containing the information for creating markers is updated
thanks in advance for helping me out.
I am looking for a way to display text progressively with libgdx, but I can't find a way to do it exactly the way I want. Here is what I did:
I have a text label that is being updated periodically to display a different text. The label is set to setWrap(true); and setAlignment(Align.center);
Every time I change the text of the label I use a custom Action which I built like this
public class DisplayTextAction extends TemporalAction{
private CharSequence completeText;
#Override
protected void update(float percent) {
((Label)actor).setText(
completeText.subSequence(
0,
(int)Math.round(completeText.length()*percent));
}
public void setText(String newText){
completeText = newText;
}
}
Every text update, I call the action from a pool, change the text and add the action to the label.
Here is my problem: This doesn't work the way I want with a centered and wrapped text.
This happens when text isn't centered (dots represent space):
|h........|
|hel......|
|hello....|
(Works as intended)
This is what happens when the text is centered:
|....h....|
|...hel...|
|..hello..|
And this is how I want it to behave:
|..h......|
|..hel....|
|..hello..|
My original idea to fix this was to use 2 sets of strings, one that is the visible text, and one invisible that acts as "padding". I came up with something like this:
CharSequence visibleText = completeText.subSequence(
0,
(int)Math.round(completeText.length()*percent));
CharSequence invisibleText = completeText.subSequence(
(int)Math.round(completeText.length()*percent),
completeText.length());
So I have my two sets of strings, but I can't find a way to display two different fonts (one visible, and another one which is the same but with an alpha of 0) or styles in the same label with Libgdx.
I'm stuck, I don't know if my approach is the right one or if I should look into something completely different, and if my approach is correct, I don't know how to follow it up using libgdx tools.
EDIT:
I followed Jyro117's instructions and I could make great progress, but I couldn't make it work with centred text on multiple lines.
imagine this text:
|all those lines are|
|..for a very long..|
|........text.......|
And it has to be displayed like this
|all th.............|
|...................|
|...................|
|all those line.....|
|...................|
|...................|
|all those lines are|
|..for a ve.........|
|...................|
|all those lines are|
|..for a very long..|
|........text.......|
Jyro117's solution give either
|all those lines are|
|for a very long....|
|text...............|
displayed correctly.
or
|...................|
|......all tho......|
|...................|
|...................|
|...all those lin...|
|...................|
|all those lines are|
|......for a v......|
|...................|
You are over-complicating the solution. All you really need is to determine the size of the label when all the text is added. Once you have determined that, lock the label size to those dimensions, put it inside of a table that expands to fill up the area around it, and then update your label with the action. (You can use a pool and such as needed, but for simplicity I left that out of the code below).
You will have to obviously adapt the code to yours, but this gives you a code reference to what I mean.
Here is a code snippet on one way to do it:
stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
Gdx.input.setInputProcessor(stage);
uiSkin = new Skin(Gdx.files.internal("skin/uiskin.json"));
Table fullScreenTable = new Table();
fullScreenTable.setFillParent(true);
final String message = "hello";
final Label progressLabel = new Label(message, this.uiSkin);
final TextBounds bounds = progressLabel.getTextBounds(); // Get libgdx to calc the bounds
final float width = bounds.width;
final float height = bounds.height;
progressLabel.setText(""); // clear the text since we want to fill it later
progressLabel.setAlignment(Align.CENTER | Align.TOP); // Center the text
Table progressTable = new Table();
progressTable.add(progressLabel).expand().size(width, height).pad(10);
final float duration = 3.0f;
final TextButton button = new TextButton("Go!", this.uiSkin);
button.addListener(new ClickListener() {
#Override public void clicked(InputEvent event, float x, float y) {
progressLabel.addAction(new TemporalAction(duration){
LabelFormatter formatter = new LabelFormatter(message);
#Override protected void update(float percent) {
progressLabel.setText(formatter.getText(percent));
}
});
}
});
stage.addActor(button);
fullScreenTable.add(progressTable);
fullScreenTable.row();
fullScreenTable.add(button);
stage.addActor(fullScreenTable);
Edit:
Added code to center and top align text in label. Also added code to fill spaces on the end to allow for proper alignment. Note: Only useful for mono-spaced fonts.
class LabelFormatter {
private final int textLength;
private final String[] data;
private final StringBuilder textBuilder;
LabelFormatter(String text) {
this.textBuilder = new StringBuilder();
this.data = text.split("\n");
int temp = 0;
for (int i = 0 ; i < data.length; i++) {
temp += data[i].length();
}
textLength = temp;
}
String getText(float percent) {
textBuilder.delete(0, textBuilder.length());
int current = Math.round(percent * textLength);
for (final String row : data) {
current -= row.length();
if (current >= 0) {
textBuilder.append(row);
if (current != 0) {
textBuilder.append('\n');
}
} else {
textBuilder.append(row.substring(0, row.length() + current));
// Back fill spaces for partial line
for (int i = 0; i < -current; i++) {
textBuilder.append(' ');
}
}
if (current <= 0) {
break;
}
}
return textBuilder.toString();
}
}