Combobox1 has 3 items (Spain, France, UK) and Combobox2 6 items (Barcelona, Madrid, Paris, Marseille, London, Bristol).
When one item is selected from Combobox1 (Spain) it should be available to Combobox2 the specific items (Barcelona, Madrid).
Can anyone help me with this?
Thanks in advance
Three combox listener example code.i think this solution use ful for your.
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package threecombobox;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ComboBox;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* #author reegan
*/
public class ThreeComboBox extends Application {
#Override
public void start(Stage primaryStage) {
List combox1List = new ArrayList();
for (int i = 1; i < 10; i++) {
combox1List.add(i);
}
final Map combox2Map = new HashMap();
for (int i = 0; i < combox1List.size(); i++) {
List l = new ArrayList();
for (int j = 1; j < 10; j++) {
int k = (int) combox1List.get(i) * 10 + j;
l.add(k);
}
combox2Map.put(combox1List.get(i), l);
}
final Map combox3Map = new HashMap();
for (Object o : combox1List) {
for (Object o1 : (List) combox2Map.get(o)) {
List l = new ArrayList();
for (int i = 1; i < 10; i++) {
int value = (int) o1 * 10 + i;
l.add(value);
}
combox3Map.put(o1, l);
}
}
ObservableList combox1 = FXCollections.observableList(combox1List);
HBox box = new HBox(20);
box.setPadding(new Insets(20, 20, 20, 20));
ComboBox cb1 = new ComboBox();
final ComboBox cb2 = new ComboBox();
final ComboBox cb3 = new ComboBox();
cb1.setItems(combox1);
cb1.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue ov, Object t, Object t1) {
ObservableList combox2 = FXCollections.observableArrayList((List) combox2Map.get(t1));
cb2.setItems(combox2);
}
});
cb2.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue ov, Object t, Object t1) {
if (t1 != null) {
ObservableList combox3 = FXCollections.observableArrayList((List) combox3Map.get(t1));
cb3.setItems(combox3);
}
}
});
box.getChildren().addAll(cb1, cb2, cb3);
Scene scene = new Scene(box, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
/**
* The main() method is ignored in correctly deployed JavaFX application.
* main() serves only as fallback in case the application can not be
* launched through deployment artifacts, e.g., in IDEs with limited FX
* support. NetBeans ignores main().
*
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Well, we don't know your data structure, but if a city is attached to a country, add a listener to your country combobox and each time the selection change, you reconfigure the items on the city combobox.
I'll do something like that :
ComboBox<City> cityBox;
ComboBox<Country> countryBox;
countryBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener() {
#Override
public void changed(ObservableValue observableValue, Country oldCountry, Country newCountry) {
//Here configure your cityBox corresponding with newCountry
}
});
or with binding
cityBox.itemsProperty().bind(new ListBinding<City>() {
{
bind(cityBox.getSelectionModel().selectedItemProperty());
}
#Override
protected ObservableList<City> computeValue() {
Country country = countryBox.getValue();
// add the city corresponding to the country on a new list
return //The list with the city filtered with the country
}
});
Related
Hi Guys: I´m trying with Uber Clone code and I´m using Netbeans . I have two questions:
1).- In the countryPickerForm Listing 4.12 (The Listing number is the book´s listing "Create an Uber Clone..."); Netbeans marks me an error,("Cannot find symbol variable CommonCode"), of course, in the CommonCode object, i don´t know what library to use
´´´
public class CountryPickerForm extends Form{
//#SuppressWarnings("LeakingThisInConstructor")
public CountryPickerForm(Button sourceButton, Resources Flag){
super(BoxLayout.y());
**CommonCode.initBlackTitleForm(this,"Select a Country", val-> search(val));**
Image blankIcon = Image.createImage(100, 70, 0);
´´´
2).- And the second question: What is te correct place to the Listing (5.22) "Toogling the "WhereTo?" UI when focus changes". I placed it Inside the MapForm class outside from any method, but Neatbeans marks me an error: "< identifier > expected. Ilegal start of type "
This is the code:
from.addFocusListener(new FocusListener(){
public void focusGained(Component cmp){
fromSelected.setIcon(square);
if(layer.getComponentCount()> 1){
Component c = layer.getComponentAt(1);
c.setY(getDisplayHeight());
layer.animateUnlayout(200,150,() ->{
c.remove();
revalidate();
});
}
}
public void focusLost(){
fromSelected.setIcon(circle);
}
});
to.addFocusListener(new FocusListener(){
public void focusGained(Component cmp){
fromSelected.setIcon(circle):
toSelected.setIcon(square);
showToNavigationBar(layer);
}
public void focusLost(Component cmp){
toSelecte3dsetIcon(circle);
}
});
Thanks Guys!!!!
CommonCode was somehow lost in one of the edits to the book. It's a part of the downloadable zip listed at the start of the book and should be there. This is the full listing of that class:
package com.codename1.apps.uberclone.forms;
import com.codename1.apps.uberclone.server.UserService;
import com.codename1.components.MultiButton;
import com.codename1.io.Log;
import com.codename1.ui.Button;
import static com.codename1.ui.CN.*;
import com.codename1.ui.Command;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.FontImage;
import com.codename1.ui.Form;
import com.codename1.ui.Graphics;
import com.codename1.ui.Image;
import com.codename1.ui.Label;
import com.codename1.ui.TextField;
import com.codename1.ui.Toolbar;
import com.codename1.ui.animations.CommonTransitions;
import com.codename1.ui.animations.Transition;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.events.ActionListener;
import com.codename1.ui.layouts.BorderLayout;
import com.codename1.ui.layouts.LayeredLayout;
import com.codename1.ui.plaf.Style;
import com.codename1.util.LazyValue;
import com.codename1.util.SuccessCallback;
import java.io.IOException;
/**
* Common code for construction and initialization of various classes e.g. the side menu logic etc.
*
* #author Shai Almog
*/
public class CommonCode {
private static Image avatar;
public static Image getAvatar(SuccessCallback<Image> avatarChanged) {
if(avatar == null) {
int size = convertToPixels(10);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
UserService.fetchAvatar(i -> {
avatar = i.fill(size, size).applyMask(mask);
avatarChanged.onSucess(avatar);
});
if(avatar != null) {
return avatar;
}
Style s = new Style();
s.setFgColor(0xc2c2c2);
s.setBgTransparency(255);
s.setBgColor(0xe9e9e9);
FontImage x = FontImage.createMaterial(FontImage.MATERIAL_PERSON, s, size);
avatar = x.fill(size, size);
if(avatar instanceof FontImage) {
avatar = ((FontImage)avatar).toImage();
}
avatar = avatar.applyMask(mask);
}
return avatar;
}
public static Image setAvatar(String imageFile) {
int size = convertToPixels(10);
Image temp = Image.createImage(size, size, 0xff000000);
Graphics g = temp.getGraphics();
g.setAntiAliased(true);
g.setColor(0xffffff);
g.fillArc(0, 0, size, size, 0, 360);
Object mask = temp.createMask();
try {
Image img = Image.createImage(imageFile);
avatar = img.fill(size, size).applyMask(mask);
} catch(IOException err) {
// this is unlikely as we just grabbed the image...
Log.e(err);
}
return avatar;
}
public static MultiButton createEntry(char icon, String title) {
MultiButton b = new MultiButton(title);
b.setUIID("Container");
b.setUIIDLine1("WhereToButtonLine1");
b.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(b, icon);
return b;
}
public static MultiButton createEntry(char icon, String title, String subtitle) {
MultiButton b = new MultiButton(title);
b.setTextLine2(subtitle);
b.setUIID("Container");
b.setUIIDLine1("WhereToButtonLineNoBorder");
b.setUIIDLine2("WhereToButtonLine2");
b.setIconUIID("WhereToButtonIcon");
FontImage.setMaterialIcon(b, icon);
return b;
}
public static Label createSeparator() {
Label sep = new Label("", "WhereSeparator");
sep.setShowEvenIfBlank(true);
return sep;
}
public static void constructSideMenu(Toolbar tb) {
Button userAndAvatar = new Button("Shai Almog", "AvatarBlock");
userAndAvatar.setIcon(getAvatar(i -> userAndAvatar.setIcon(i)));
userAndAvatar.setGap(convertToPixels(3));
userAndAvatar.addActionListener(e -> new EditAccountForm().show());
tb.addComponentToSideMenu(userAndAvatar);
MultiButton uberForBusiness = new MultiButton("Do you Uber for business?");
uberForBusiness.setTextLine2("Tap to create your business profile");
uberForBusiness.setUIID("UberForBusinessBackground");
uberForBusiness.setUIIDLine1("UberForBusinessLine1");
uberForBusiness.setUIIDLine2("UberForBusinessLine2");
tb.addComponentToSideMenu(uberForBusiness);
tb.addCommandToSideMenu("Payment", null, e -> {});
tb.addCommandToSideMenu("Your Trips", null, e -> {});
tb.addCommandToSideMenu("Help", null, e -> {});
tb.addCommandToSideMenu("Free Rides", null, e -> {});
tb.addCommandToSideMenu("Settings", null, e -> new SettingsForm().show());
Button legalButton = new Button("Legal", "Legal");
Container legal = BorderLayout.centerCenterEastWest(null, new Label("v4.178.1001", "VersionNumber"), legalButton);
legal.setLeadComponent(legalButton);
legal.setUIID("SideNavigationPanel");
tb.setComponentToSideMenuSouth(legal);
}
/**
* Initializes a form with a black background title animation style
* #param f the form
*/
public static void initBlackTitleForm(Form f, String title, SuccessCallback<String> searchResults) {
Form backTo = getCurrentForm();
f.getContentPane().setScrollVisible(false);
Button back = new Button("", "TitleCommand");
removeTransitionsTemporarily(backTo);
back.addActionListener(e -> backTo.showBack());
back.getAllStyles().setFgColor(0xffffff);
FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK);
f.setBackCommand(new Command("") {
#Override
public void actionPerformed(ActionEvent evt) {
backTo.showBack();
}
});
Container searchBack = null;
if(searchResults != null) {
Button search = new Button("", "TitleCommand");
search.getAllStyles().setFgColor(0xffffff);
FontImage.setMaterialIcon(search, FontImage.MATERIAL_SEARCH);
search.addActionListener(e -> {
});
searchBack = BorderLayout.north(
BorderLayout.centerEastWest(null, search, back));
} else {
searchBack = BorderLayout.north(
BorderLayout.centerEastWest(null, null, back));
}
Label titleLabel = new Label(title, "WhiteOnBlackTitle");
titleLabel.getAllStyles().setMarginTop(back.getPreferredH());
titleLabel.getAllStyles().setMarginUnit(Style.UNIT_TYPE_PIXELS, Style.UNIT_TYPE_DIPS, Style.UNIT_TYPE_DIPS, Style.UNIT_TYPE_DIPS);
f.getToolbar().setTitleComponent(LayeredLayout.encloseIn(searchBack, titleLabel));
f.getAnimationManager().onTitleScrollAnimation(titleLabel.createStyleAnimation("WhiteOnBlackTitleLeftMargin", 200));
f.setTransitionInAnimator(CommonTransitions.createCover(CommonTransitions.SLIDE_VERTICAL, false, 300));
f.setTransitionOutAnimator(CommonTransitions.createUncover(CommonTransitions.SLIDE_VERTICAL, true, 300));
}
public static void removeTransitionsTemporarily(final Form f) {
final Transition originalOut = f.getTransitionOutAnimator();
final Transition originalIn = f.getTransitionInAnimator();
f.setTransitionOutAnimator(CommonTransitions.createEmpty());
f.setTransitionInAnimator(CommonTransitions.createEmpty());
f.addShowListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
f.setTransitionOutAnimator(originalOut);
f.setTransitionInAnimator(originalIn);
f.removeShowListener(this);
}
});
}
}
The second listing appears in MapForm in showNavigationToolbar. This code goes through some additional refactoring later on and looks like this:
void showNavigationToolbar() {
final Container layer = getLayeredPane(MapForm.class, true);
final Container pinLayer = createPinLayer(layer);
Button back = new Button("", "TitleCommand");
FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK);
CompletionContainer cc = new CompletionContainer();
AutoCompleteAddressInput from = new AutoCompleteAddressInput("Current Location", "From", layer, cc);
AutoCompleteAddressInput to = new AutoCompleteAddressInput("", "Where To?", layer, cc);
from.setCurrentLocation(LocationService.getCurrentLocation());
Image circle = createCircle();
Label fromSelected = new Label(circle);
Label toSelected = new Label(square);
SearchService.nameMyCurrentLocation(LocationService.getCurrentLocation(), name -> from.setTextNoEvent(name));
to.requestFocus();
lastFocused = to;
from.addFocusListener(createFromFocusListener(fromSelected, from, circle));
to.addFocusListener(createToFocusListener(fromSelected, circle, toSelected, to));
addMapListener((source, zoom, center) -> onMapChangeEvent(center));
Container navigationToolbar = BoxLayout.encloseY(back,
BorderLayout.centerCenterEastWest(from, null, fromSelected),
BorderLayout.centerCenterEastWest(to, null, toSelected)
);
navigationToolbar.setUIID("WhereToToolbar");
navigationToolbar.getUnselectedStyle().setBgPainter((g1, rect) ->
paintWhereToToolbarBackground(g1, layer, rect, fromSelected, circle, toSelected)
);
cc.addCompletionListener(e ->
onCompletionEvent(to, from, pinLayer, navigationToolbar, layer));
back.addActionListener(e ->
onBackFromNavigation(pinLayer, navigationToolbar, layer));
layer.add(NORTH, navigationToolbar);
navigationToolbar.setWidth(getDisplayWidth());
navigationToolbar.setHeight(getPreferredH());
navigationToolbar.setY(-navigationToolbar.getHeight());
getAnimationManager().addAnimation(layer.createAnimateLayout(200),
() -> cc.showCompletionBar(layer));
}
private FocusListener createToFocusListener(final Label fromSelected, Image circle, final Label toSelected, AutoCompleteAddressInput to) {
return new FocusListener() {
#Override
public void focusGained(Component cmp) {
fromSelected.setIcon(circle);
toSelected.setIcon(square);
lastFocused = to;
}
#Override
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
};
}
private FocusListener createFromFocusListener(final Label fromSelected, AutoCompleteAddressInput from, Image circle) {
return new FocusListener() {
#Override
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
lastFocused = from;
}
#Override
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
};
}
Current out put of code is output image
import java.io.Serializable;
import java.util.HashMap;
import java.util.Objects;
import org.eclipse.jface.layout.TableColumnLayout;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ColumnPixelData;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.part.ViewPart;
public class Theartview extends ViewPart implements Serializable {
Table table;
private TableViewer tableViewer;
public void createPartControl(Composite parent) {
System.out.println("createPartControl call");
Composite tableComposite = new Composite(parent, SWT.NONE);
TableColumnLayout tableColumnLayout = new TableColumnLayout();
tableComposite.setLayout(tableColumnLayout);
tableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true,
true));
tableViewer = new TableViewer(tableComposite, SWT.MULTI | SWT.H_SCROLL
| SWT.V_SCROLL);
tableViewer.setContentProvider(ArrayContentProvider.getInstance());
// TODO viewer.setLabelProvider(new ViewLabelProvider());
table = tableViewer.getTable();
// Table table = tableViewer.getTable();
System.out.println("#############table$$$$$$$$" + table);
table.setHeaderVisible(true);
table.setLinesVisible(true);
String[] titles = { "Threat Name", "Category Name", "Status",
"Priority", "Description", "Justification" };
for (int loopIndex = 0; loopIndex < titles.length; loopIndex++) {
TableViewerColumn tableViewerColumn = new TableViewerColumn(
tableViewer, SWT.NONE);
TableColumn tblclmn = tableViewerColumn.getColumn();
tableColumnLayout.setColumnData(tblclmn, new ColumnPixelData(200,
true, true));
tblclmn.setText(titles[loopIndex]);
}
}
private static class Dummy {
public String value;
public Dummy(String value) {
this.value = value;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
#SuppressWarnings("static-access")
public void fillTableRoWData() {
System.out.println("After connection fillTableRoWData call");
System.out.println("No of Connected object = no of fillTableRoWData call ");
if (Connection.Number_Of_Connection != 0) {
// item = new TableItem(table, SWT.NONE);
if (Service.class.isInstance(sourceNode)) {
String id = "S1";
shortDescription = threattypexmltoobject.shortdescription(id,
sourceNode.getName(), targetNode.getName(), null);
category = "Spoofing";
description = threattypexmltoobject.longdescription(id,
sourceNode.getName(), targetNode.getName(), null);
fillRows(shortDescription, category, description);
}
if (Service.class.isInstance(sourceNode)
&& (connectionType == Connection.CONNECTION_DESIGN)) {
String id = "T1";
System.out.println(conn.getConnectionDesign());
shortDescription = threattypexmltoobject.shortdescription(id,
sourceNode.getName(), targetNode.getName(),
conn.getConnectionDesign());
category = "Tampering";
description = threattypexmltoobject.longdescription(id,
sourceNode.getName(), targetNode.getName(),
conn.getConnectionDesign());
fillRows(shortDescription, category, description);
}
}
private void fillRows(String shortdesc, String categ, String descp) {
System.out.println("fillRows call from above method.");
TableItem item = new TableItem(table, SWT.NONE);
// for Threat_Name
item.setText(0, "x");
// For Category_Name
item.setText(1, "y");
// For Status_Name
item.setText(2, "z");
// For Priority_Name
item.setText(3, "a");
// For Descrption_Name
item.setText(4, "b");
// For justification
item.setText(5, "c");
}
public static class FirstValueEditingSupport extends EditingSupport {
private final TableViewer viewer;
private final CellEditor editor;
private final String[] possibleValues = { "Mitigated",
"Not Applicable", "Not Started", "Needs Investigation" };
public FirstValueEditingSupport(TableViewer viewer) {
super(viewer);
this.viewer = viewer;
this.editor = new ComboBoxCellEditor(viewer.getTable(),
possibleValues);
}
#Override
protected CellEditor getCellEditor(Object element) {
return editor;
}
#Override
protected boolean canEdit(Object element) {
return true;
}
#Override
protected Object getValue(Object element) {
Dummy dummy = (Dummy) element;
int index = 0;
for (int i = 0; i < possibleValues.length; i++) {
if (Objects.equals(possibleValues[i], dummy.getValue())) {
index = i;
break;
}
}
return index;
}
#Override
protected void setValue(Object element, Object value) {
Dummy dummy = (Dummy) element;
int index = (Integer) value;
dummy.setValue(possibleValues[index]);
viewer.update(element, null);
}
}
}
Questions
How to set combo box in the 3rd and 4th column of table viewer. here FirstValueEditingSupport is combobox options value which is display comobo dropdown
String shortDescription, set into 1st and 2ed column how to set ?
in Output image "Status" and "Priority", which is column name of the table where set combo box in the table.
Please only ask one question in a question.
You set the editing support in the TableColumnViewer for the column you want to edit. So for the columns you want to edit do:
tableViewerColumn.setEditingSupport(new FirstValueEditingSupport());
To set the data shown in each column you set a label provider of the column.
tableViewerColumn.setLabelProvider(column label provider);
where the label provider is derived from CellLabelProvider or one of its many subclasses.
Note: NEVER set the table viewer contents by creating TableItems - you must always use a content provider and a setInput call on the table viewer. TableViewer is in complete control of the underlying Table and is free to discard any TableItems you may create. With very few exceptions you should never be looking at the Table or TableItem objects when using TableViewer.
The content provider should provide one object for each row in the table, the column label providers should use this row object to get labels for the individual columns.
Am new to Javafx and wondering how to populate a tableview from a 2-dimensional array of String:
String[][] staffArray = (String[][]) connection.getAll("StaffServices");
ObservableList row = FXCollections.observableArrayList(staffArray);
//don't know what should go in here
staffTable.setItems(row);
would really appreciate a response.
I think JavaFX should have a method that just takes 2d arrays and makes tables but it's not that hard to make. The trick is to use the CellValueFactory to get the right array index for each column instead of getting a bean. This is similar to code I use.
import java.util.Arrays;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TableColumn.CellDataFeatures;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewSample extends Application {
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
String[][] staffArray = {{"nice to ", "have", "titles"},
{"a", "b", "c"},
{"d", "e", "f"}};
ObservableList<String[]> data = FXCollections.observableArrayList();
data.addAll(Arrays.asList(staffArray));
data.remove(0);//remove titles from data
TableView<String[]> table = new TableView<>();
for (int i = 0; i < staffArray[0].length; i++) {
TableColumn tc = new TableColumn(staffArray[0][i]);
final int colNo = i;
tc.setCellValueFactory(new Callback<CellDataFeatures<String[], String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(CellDataFeatures<String[], String> p) {
return new SimpleStringProperty((p.getValue()[colNo]));
}
});
tc.setPrefWidth(90);
table.getColumns().add(tc);
}
table.setItems(data);
root.getChildren().add(table);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
}
}
Best practices for TableView in JavaFX are to use Objects with Properties and bind them to Columns.
I would suggest moving on or converting your 2 dimensional array to a more Strongly Typed model.
What you are aiming for is to have a ObservableList<Model> that you can then assign to your TableView.
Oracle has a really good introduction to the TableView that show cases the recommendations I suggested.
Additionally to answer of Brian, I added proper CellFactory, to avoid using toString() method, when we are going to view results with good design. My solution is OK, when you are using Model - View - Controller model. Here is the code for Controller block:
#FXML
private TableView<String[]> table = new TableView<>();
#FXML
public void initialize() {
//binding our ObservableList with TableView
String[][] staffArray = {{"a", "b", "c"},
{"d", "e", "f"}};
ObservableList<String[]> data = FXCollections.observableArrayList();
data.addAll(Arrays.asList(staffArray));
for (int i = 0; i < data.get(0).length; i++) {
TableColumn tc = new TableColumn();
tc.setSortable(false);
final int colNo = i;
tc.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<String[], String>, ObservableValue<String>>() {
#Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<String[], String> p) {
return new SimpleStringProperty((p.getValue()[colNo]));
}
});
tc.setCellFactory(col -> {
TableCell<String[], String> cell = new TableCell<>();
cell.itemProperty().addListener((observableValue, o, newValue) -> {
if (newValue != null) {
Node graphic = createPriorityGraphic(newValue);
cell.graphicProperty().bind(Bindings.when(cell.emptyProperty()).then((Node) null).otherwise(graphic));
}
});
return cell;
});
table.getColumns().add(tc);
}
// making Headers of table hidden
table.widthProperty().addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> ov, Number t, Number t1) {
// Get the table header
Pane header = (Pane) table.lookup("TableHeaderRow");
if (header != null && header.isVisible()) {
header.setMaxHeight(0);
header.setMinHeight(0);
header.setPrefHeight(0);
header.setVisible(false);
header.setManaged(false);
}
}
});
table.setItems(data);
table.setSelectionModel(null);
table.setMaxSize(315.0, 502.0);
}
//prepare some special design for tableview output, if needed
#FXML
private Node createPriorityGraphic(String value) {
if (!value.equals("0") && value != "") {
Rectangle graphic = new Rectangle();
graphic.setHeight(25);
graphic.setWidth(25);
graphic.setOpacity(80);
return graphic;
}
return null;
}
I'm using CombinedDomainXYPlot to plot the charts. I have another requirement where, I need to show the two charts horizontally.
Currently i'm having only one chart. what i need is, i need two charts in the first row.
like Chart1 Chart2
Code:
CombinedDomainXYPlot plot = new CombinedDomainXYPlot();
plot.add(getChart1(), 2);
plot.add(getChart2(), 2);
It is giving only one chart in the first row. and second chart2 in the another row.
Is there any way I can make these two charts into single row?
Edit: Actually I wanted it like your ThermometerDemo example. For that you have used JPanel, but here I'm using JFrame.
I wanted it like your ThermometerDemo example.
Based on this example, the code below adds two panels to a GridLayout(1, 0). Each panel includes it's own chart and control panel.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.Random;
import javax.swing.*;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
/**
* #see https://stackoverflow.com/a/20243624/230513
* #see https://stackoverflow.com/q/11870416/230513
*/
public class CombinedPlot {
private static final int MAX = 3;
private static final Random rand = new Random();
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
init();
}
});
}
private static void init() {
JFrame frame = new JFrame("Combined Plot Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridLayout(1, 0));
frame.add(createPanel());
frame.add(createPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static JPanel createPanel() {
JPanel p = new JPanel(new BorderLayout());
XYItemRenderer renderer = new StandardXYItemRenderer();
XYPlot plot1 = new XYPlot(
generateData(), null, new NumberAxis("Range 1"), renderer);
XYPlot plot2 = new XYPlot(
generateData(), null, new NumberAxis("Range 2"), renderer);
final CombinedDomainXYPlot plot
= new CombinedDomainXYPlot(new NumberAxis("Domain"));
plot.add(plot1);
plot.add(plot2);
plot.setOrientation(PlotOrientation.VERTICAL);
JFreeChart chart = new JFreeChart(
"Combined Plots", JFreeChart.DEFAULT_TITLE_FONT, plot, false);
ChartPanel chartPanel = new ChartPanel(chart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(320, 320);
}
};
JPanel controlPanel = new JPanel();
controlPanel.add(new JButton(new UpdateAction(plot, 0)));
controlPanel.add(new JButton(new UpdateAction(plot, 1)));
p.add(chartPanel, BorderLayout.CENTER);
p.add(controlPanel, BorderLayout.SOUTH);
return p;
}
private static class UpdateAction extends AbstractAction {
private final XYPlot plot;
public UpdateAction(CombinedDomainXYPlot plot, int i) {
super("Update plot " + (i + 1));
this.plot = (XYPlot) plot.getSubplots().get(i);
}
#Override
public void actionPerformed(ActionEvent e) {
plot.setDataset(CombinedPlot.generateData());
}
}
private static XYSeriesCollection generateData() {
XYSeriesCollection data = new XYSeriesCollection();
for (int i = 0; i < MAX; i++) {
data.addSeries(generateSeries("Series " + (i + 1)));
}
return data;
}
private static XYSeries generateSeries(String key) {
XYSeries series = new XYSeries(key);
for (int i = 0; i < 16; i++) {
series.add(rand.nextGaussian(), rand.nextGaussian());
}
return series;
}
}
I've got stacked bar chart where I want to be able to select individual bars in the stack. But ChartMouseListener doesn't resolve ChartMouseEvent into corresponding ChartEntity. Here's the listener snippet :
public void chartMouseClicked(ChartMouseEvent event){
ChartEntity entity = event.getEntity();
if(entity != null && (entity instanceof XYItemEntity) ){
XYItemEntity item = (XYItemEntity)entity;
renderer.select(item.getSeriesIndex(), item.getItem());
return;
}
// deselect
renderer.select(-1,-1);
}
The problem is that event.getEntity() returns null when I am obviously clicking on some of the bars. Note that NOT all the bars fail. The further I go to the right end of the chart, the more obvious is the shift in coordinates. Snap shot below showing that selected bar actually appears when clicking outside of it. I am using JFreeChart within SWT composite. Can anyone confirm that this is a buggy behavior or is there a workaround?
Below is complete sscce, after you run it and click on bars - it will show up pinky. Then re-size the window and try to select bars - it will miss. And I think the miss is the function of the new size.
import java.awt.Color;
import java.awt.Paint;
import java.util.Random;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.data.xy.TableXYDataset;
import org.jfree.experimental.chart.swt.ChartComposite;
public class StackedChartSwt {
private StackedRenderer renderer;
private Color[] colors = new Color[]{
new Color(230,240,255),
new Color(240,255,240),
new Color(255,255,255),
new Color(255,255,240),
new Color(255,240,240),
new Color(240,240,240)
};
public StackedChartSwt(){
Display display = new Display();
final Shell shell = new Shell(display);
shell.setLayout(new FillLayout());
JFreeChart chart = createStackedChart(createStackedDataset());
ChartComposite chartComposite = new ChartComposite(shell, SWT.NONE, chart, false, false, false, false, false);
chartComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
chartComposite.setRangeZoomable(false);
chartComposite.setMenu(null);
chartComposite.addChartMouseListener(new ThisMouseListener());
shell.setSize(800, 600);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
private JFreeChart createStackedChart(TableXYDataset tablexydataset) {
DateAxis dateaxis = new DateAxis();
dateaxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
NumberAxis numberaxis = new NumberAxis("Event counts");
renderer = new StackedRenderer();
XYPlot plot = new XYPlot(tablexydataset, dateaxis, numberaxis, renderer);
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.lightGray);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.lightGray);
JFreeChart chart = new JFreeChart(null, plot);
chart.setBackgroundPaint(Color.white);
chart.setBorderVisible(false);
chart.setBorderPaint(null);
return chart;
}
class StackedRenderer extends StackedXYBarRenderer{
int selectedRow=-1, selectedCol=-1;
public StackedRenderer(){
setDrawBarOutline(true);
setBarPainter(new StandardXYBarPainter());
setShadowVisible(false);
setSeriesPaint(0, Color.blue);
setMargin(0.2);
}
public void select(int row, int col){
selectedRow = row;
selectedCol = col;
notifyListeners(new RendererChangeEvent(this));
}
#Override
public Paint getItemPaint(final int row, final int col){
if(row == selectedRow && col == selectedCol)
return Color.pink;
return colors[row];
}
}
class ThisMouseListener implements ChartMouseListener{
public void chartMouseMoved(ChartMouseEvent event){
}
public void chartMouseClicked(ChartMouseEvent event){
ChartEntity entity = event.getEntity();
if(entity != null && (entity instanceof XYItemEntity) ){
XYItemEntity item = (XYItemEntity)entity;
renderer.select(item.getSeriesIndex(), item.getItem());
return;
}
// deselect
renderer.select(-1,-1);
}
}
private TableXYDataset createStackedDataset(){
Random random = new Random(0);
TimeTableXYDataset ds = new TimeTableXYDataset();
Day day = new Day();
for( int i = 0; i < 24; i++ ){
Hour hour = new Hour( i, day );
ds.add(hour, random.nextInt( 20 ), "A");
ds.add(hour, random.nextInt( 20 ), "B");
ds.add(hour, random.nextInt( 20 ), "C");
ds.add(hour, random.nextInt( 20 ), "D");
ds.add(hour, random.nextInt( 20 ), "E");
ds.add(hour, random.nextInt( 20 ), "F");
}
return ds;
}
public static void main(String[] args){
new StackedChartSwt();
}
}
Your exemplary renderer has the correct geometry when run from Swing, as shown below. I'm unsure why things are awry with SWT, but this result may narrow the search.
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Paint;
import java.util.Random;
import javax.swing.JFrame;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.DateTickMarkPosition;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.entity.XYItemEntity;
import org.jfree.chart.event.RendererChangeEvent;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.data.time.Day;
import org.jfree.data.time.Hour;
import org.jfree.data.time.TimeTableXYDataset;
import org.jfree.data.xy.TableXYDataset;
public class StackedChartSwing {
private ChartPanel panel;
private StackedRenderer renderer;
private Color[] colors = new Color[]{
new Color(230, 240, 255),
new Color(240, 255, 240),
new Color(255, 255, 255),
new Color(255, 255, 240),
new Color(255, 240, 240),
new Color(240, 240, 240)
};
public StackedChartSwing() {
JFreeChart chart = createStackedChart(createStackedDataset());
panel = new ChartPanel(chart);
panel.addChartMouseListener(new ThisMouseListener());
}
private JFreeChart createStackedChart(TableXYDataset tablexydataset) {
DateAxis dateaxis = new DateAxis();
dateaxis.setTickMarkPosition(DateTickMarkPosition.MIDDLE);
NumberAxis numberaxis = new NumberAxis("Event counts");
renderer = new StackedRenderer();
XYPlot plot = new XYPlot(tablexydataset, dateaxis, numberaxis, renderer);
plot.setBackgroundPaint(Color.white);
plot.setDomainGridlinePaint(Color.lightGray);
plot.setDomainGridlinesVisible(true);
plot.setRangeGridlinesVisible(true);
plot.setRangeGridlinePaint(Color.lightGray);
JFreeChart chart = new JFreeChart(null, plot);
chart.setBackgroundPaint(Color.white);
chart.setBorderVisible(false);
chart.setBorderPaint(null);
return chart;
}
class StackedRenderer extends StackedXYBarRenderer {
int selectedRow = -1, selectedCol = -1;
public StackedRenderer() {
setDrawBarOutline(true);
setBarPainter(new StandardXYBarPainter());
setShadowVisible(false);
setSeriesPaint(0, Color.blue);
setMargin(0.2);
}
public void select(int row, int col) {
selectedRow = row;
selectedCol = col;
notifyListeners(new RendererChangeEvent(this));
}
#Override
public Paint getItemPaint(final int row, final int col) {
if (row == selectedRow && col == selectedCol) {
return Color.pink;
}
return colors[row];
}
}
class ThisMouseListener implements ChartMouseListener {
#Override
public void chartMouseMoved(ChartMouseEvent event) {
}
#Override
public void chartMouseClicked(ChartMouseEvent event) {
ChartEntity entity = event.getEntity();
if (entity != null && (entity instanceof XYItemEntity)) {
XYItemEntity item = (XYItemEntity) entity;
renderer.select(item.getSeriesIndex(), item.getItem());
return;
}
// deselect
renderer.select(-1, -1);
}
}
private TableXYDataset createStackedDataset() {
Random random = new Random(0);
TimeTableXYDataset ds = new TimeTableXYDataset();
Day day = new Day();
for (int i = 0; i < 24; i++) {
Hour hour = new Hour(i, day);
ds.add(hour, random.nextInt(20), "A");
ds.add(hour, random.nextInt(20), "B");
ds.add(hour, random.nextInt(20), "C");
ds.add(hour, random.nextInt(20), "D");
ds.add(hour, random.nextInt(20), "E");
ds.add(hour, random.nextInt(20), "F");
}
return ds;
}
private void display() {
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new StackedChartSwing().display();
}
});
}
}
OK, I've found the problem. In SWT there are several constructors to create ChartComposite, most of the use defaults which specify min/max width and height. In my case, whenever I've enlarged the chart above DEFAULT_MAXIMUM_DRAW_WIDTH (800px) - the coordinates start to get messy. So, the solution is to use full constructor and specify relevant boundaries for your display. It was a tough one to crack... mainly due to lack of proper documentation.