I'm trying to create a scroll aware header that hide or show header depending on scroll up or down.
I have a grid with a header menu and a collection view :
<Grid RowDefinitions="Auto, *">
<ContentView x:Name="Header"> ... </ContentView>
<CollectionView Grid.Row="1"
Scrolled="CollectionView_OnScrolled" ... />
</Grid>
In the scrolled event i tried to perform something like :
void OperationList_Scrolled(object sender, ItemsViewScrolledEventArgs e)
{
if (Header.IsVisible && e.VerticalDelta > 0)
{
Header.IsVisible = false;
}
else if (!Header.IsVisible && e.VerticalDelta < 0)
{
Header.IsVisible = true;
}
}
But it's not very smooth and it blinks. Do you have any ideas to accomplish this properly ?
You could use animations to simulate the header visible or not to avoid blinking.
Xaml:
<AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<CollectionView x:Name="collectionView" ItemsSource="{Binding Monkeys}" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" Scrolled="CollectionView_OnScrolled">
<CollectionView.Header>
<ContentView>
<StackLayout x:Name="HeaderView" />
</ContentView>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding Name}" FontSize="Large"></Label>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Frame
x:Name="HeaderLabelView"
Margin="16,8,16,8"
Padding="3"
AbsoluteLayout.LayoutBounds="0.5, 0, AutoSize, AutoSize"
AbsoluteLayout.LayoutFlags="PositionProportional"
CornerRadius="6"
HasShadow="True">
<Label HorizontalOptions="FillAndExpand" />
</Frame>
</AbsoluteLayout>
Code behind:
public partial class Page10 : ContentPage
{
public Page10()
{
InitializeComponent();
this.BindingContext = new MonkeyViewModel();
}
private void CollectionView_OnScrolled(object sender, ItemsViewScrolledEventArgs e)
{
var transY = Convert.ToInt32(HeaderLabelView.TranslationY);
if (transY == 0 &&
e.VerticalDelta > 15)
{
var trans = HeaderLabelView.Height + HeaderLabelView.Margin.Top;
Task.WhenAll(
HeaderLabelView.TranslateTo(0, -(trans), 200, Easing.CubicIn),
HeaderLabelView.FadeTo(0.25, 200));
}
else if (transY != 0 &&
e.VerticalDelta < 0 &&
Math.Abs(e.VerticalDelta) > 10)
{
Task.WhenAll(
HeaderLabelView.TranslateTo(0, 0, 200, Easing.CubicOut),
HeaderLabelView.FadeTo(1, 200));
}
}
}
public class MonkeyViewModel
{
public ObservableCollection<Monkey> Monkeys { get; set; }
public MonkeyViewModel()
{
Monkeys = new ObservableCollection<Monkey>()
{
new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"},
new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="D"}, new Monkey(){ Name="A"},
new Monkey(){ Name="B"},
new Monkey(){ Name="C"},
new Monkey(){ Name="g"},
};
}
}
public class Monkey
{
public string Name { get; set; }
}
Related
After looking at Trouble inserting data in a SQLite databae, I tried to add 'c.commit();' before I leave the stage and closing the connection c. However it keeps giving me busy for some reason. Don't know if the dynamically added buttons 'addClass' are causing problems with the on action event handlers or not.
the controller file:
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.GridPane;
import javafx.scene.text.TextAlignment;
import javafx.stage.Stage;
import userGroups.Student;
import java.io.IOException;
import java.sql.*;
public class ClassesController{
private Student user;
#FXML
private GridPane grid;
private int currentId;
private Connection c;
public void initialize(){
Statement stmt;
try{
c = DriverManager.getConnection("jdbc:sqlite:users.db");
//c.setAutoCommit(false);
stmt = c.createStatement();
int currentCol = 0;
int currentRow = 1;
currentId = 1;
ResultSet rs = stmt.executeQuery("SELECT * FROM Classes;");
//assuming all columns are NOT NULL
while(rs.next()){
Label label1 = new Label();
label1.setText(rs.getString("CLASSNAME"));
label1.setAccessibleText(rs.getString("CLASSNAME"));
grid.add(label1, currentCol++, currentRow);
Label label2 = new Label();
label2.setText(rs.getString("SIZE"));
grid.add(label2, currentCol++, currentRow);
Label label3 = new Label();
label3.setText(rs.getString("SPOTSTAKEN"));
grid.add(label3, currentCol++, currentRow);
Label label4 = new Label();
label4.setText(rs.getString("INSTRUCTOR"));
grid.add(label4, currentCol++, currentRow);
Label label5 = new Label();
label5.setText(rs.getString("CRN"));
label5.setTextAlignment(TextAlignment.CENTER);
grid.add(label5, currentCol++, currentRow);
Label label6 = new Label();
label6.setText(rs.getString("DAYS"));
grid.add(label6, currentCol++, currentRow);
Label label7 = new Label();
label7.setText(militaryToRegularTime(rs.getString("STARTTIME")) + "-"
+ militaryToRegularTime(rs.getString("ENDTIME")));
grid.add(label7, currentCol++, currentRow);
Label label8 = new Label();
label8.setText(rs.getString("AREA"));
grid.add(label8, currentCol++, currentRow);
Button addClass = new Button();
addClass.setMaxWidth(Double.MAX_VALUE);
addClass.setText("Add Class");
grid.add(addClass, currentCol, currentRow);
addClass.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e){
Object[] a = addClass.getProperties().values().toArray();//array of row and col values of addClass
int classIndex = Integer.parseInt(a[1].toString());//index of class corresponding to the button
String className = grid.getChildren().get(classIndex * 9).getAccessibleText();
if(studentHasClass(classIndex))//finds if student has the class at specific row of button
User.showAlert("You have already added this class!");
else
addClassToUser(classIndex, className);
addClass.setDisable(true);
}
});
currentCol = 0;
currentRow++;
currentId++;
}
rs.close();
stmt.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
}
//adds class at classIndex to student user in database in table CLASSES_HAVE_STUDENTS
private void addClassToUser(int classIndex, String className){
try{
PreparedStatement statement = c.prepareStatement(
"INSERT INTO CLASSES_HAVE_STUDENTS (CLASS_ID, CLASS_NAME, STUDENT_ID, S_USERNAME) VALUES(?,?,?,?)");
statement.setInt(1, classIndex);
statement.setString(2, className);
statement.setInt(3, user.getId());
statement.setString(4, user.getUserName());
statement.executeUpdate();
c.commit();
statement.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
}
//Return a boolean where if student user has a class at id
private boolean studentHasClass(int classIndex){
Statement stmt;
try{
stmt = c.createStatement();
ResultSet rs = stmt.executeQuery("SELECT S_USERNAME FROM CLASSES_HAVE_STUDENTS WHERE CLASS_ID= " + classIndex + ";");
while(rs.next()){
if(rs.getString("S_USERNAME").equals(user.getUserName())){
rs.close();
stmt.close();
return true;
}
}
rs.close();
stmt.close();
} catch ( Exception e ){
e.printStackTrace();
User.showAlert("Please contact an admin.");
System.exit(0);
}
return false;
}
//assumes militaryTime is in '00:00:00' format. returns regular time in '00:00' format
private String militaryToRegularTime(String militaryTime)
{
Integer hour = Integer.parseInt(militaryTime.substring(0, 2));
if(hour > 12){
hour = hour - 12;
return "0" + hour.toString() + militaryTime.substring(2, 5) + " pm";
}
return militaryTime.substring(0, 5) + " am";
}
//Changes stage to the previous stage
public void pressBack(ActionEvent event) throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("studentOptions.fxml"));
loader.load();
StudentOptionsController display = loader.getController();
display.setUser(user);
try{
//c.commit();
c.close();
} catch (Exception e){
e.printStackTrace();
User.showAlert("Please contact the admin.");
System.exit(0);
}
Parent userOption = loader.getRoot();
Scene classesToAddScene = new Scene(userOption);
Stage app_stage = (Stage) ((Node) event.getSource()).getScene().getWindow();
app_stage.setScene(classesToAddScene);
app_stage.show();
}
public void setUser(Student user){
this.user = user;
}
}
stacktrace:
org.sqlite.SQLiteException: [SQLITE_BUSY] The database file is locked (database is locked)
at org.sqlite.core.DB.newSQLException(DB.java:909)
at org.sqlite.core.DB.newSQLException(DB.java:921)
at org.sqlite.core.DB.execute(DB.java:822)
at org.sqlite.core.DB.executeUpdate(DB.java:863)
at org.sqlite.jdbc3.JDBC3PreparedStatement.executeUpdate(JDBC3PreparedStatement.java:99)
at login.ClassesController.addClassToUser(ClassesController.java:123)
at login.ClassesController.access$200(ClassesController.java:21)
at login.ClassesController$1.handle(ClassesController.java:94)
at login.ClassesController$1.handle(ClassesController.java:80)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Node.fireEvent(Node.java:8863)
at javafx.controls/javafx.scene.control.Button.fire(Button.java:200)
at javafx.controls/com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:206)
at javafx.controls/com.sun.javafx.scene.control.inputmap.InputMap.handle(InputMap.java:274)
at javafx.base/com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at javafx.base/com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
at javafx.base/com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
at javafx.base/com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
at javafx.base/com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
at javafx.base/com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
at javafx.base/com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
at javafx.base/javafx.event.Event.fireEvent(Event.java:198)
at javafx.graphics/javafx.scene.Scene$MouseHandler.process(Scene.java:3876)
at javafx.graphics/javafx.scene.Scene$MouseHandler.access$1300(Scene.java:3604)
at javafx.graphics/javafx.scene.Scene.processMouseEvent(Scene.java:1874)
at javafx.graphics/javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2613)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:397)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$2(GlassViewEventHandler.java:434)
at javafx.graphics/com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
at javafx.graphics/com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:433)
at javafx.graphics/com.sun.glass.ui.View.handleMouseEvent(View.java:556)
at javafx.graphics/com.sun.glass.ui.View.notifyMouse(View.java:942)
at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:175)
at java.base/java.lang.Thread.run(Thread.java:844)
I have a method which performs some task(reading, writing files and other tasks also) for almost 3 minutes.
I want to bind progress bar in javafx which can run with progress of the method.
This is my method
System.out.println("Going to load contract/security:"+new Date());
Map<Integer,FeedRefData> map = loadContractAndSecurityFromFile(loadFO);
addIndicesRefData(map);
BufferedWriter writer = createFile();
for (FeedRefData feedRefData : map.values()) {
try {
updateInstrumentAlias(map, feedRefData);
String refDataString = feedRefData.toString();
writer.write(refDataString, 0, refDataString.length());
writer.newLine();
writer.flush();
} catch (IOException e) {
e.printStackTrace();
log.info("Unable to write Quote Object to : " );
}
}
System.out.println("Ref Data File Generated:"+new Date());
For bind your method with progressbar you should do these steps :
Create a task which contains your method.
Create a thread which run this task.
Bind your progress property with your task property.
I made this simple example ,just change my code with your method code :
public class Bind extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
ProgressBar pb = new ProgressBar();
pb.setProgress(1.0);
Button button = new Button("start");
button.setOnAction((ActionEvent event) -> {
/*Create a task which contain method code*/
Task<Void> task = new Task<Void>() {
#Override
protected Void call() throws Exception {
File file = new File("C:\\Users\\Electron\\Desktop\\387303_254196324635587_907962025_n.jpg");
ByteArrayOutputStream bos = null;
try {
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
bos = new ByteArrayOutputStream();
for (int len; (len = fis.read(buffer)) != -1;) {
bos.write(buffer, 0, len);
updateProgress(len, file.length());
/* I sleeped operation because reading operation is quiqly*/
Thread.sleep(1000);
}
System.out.println("Reading is finished");
} catch (FileNotFoundException e) {
System.err.println(e.getMessage());
} catch (IOException e2) {
System.err.println(e2.getMessage());
}
return null;
}
};
Thread thread = new Thread(task);
thread.start();
/*bind the progress with task*/
pb.progressProperty()
.bind(task.progressProperty());
});
HBox box = new HBox(pb, button);
Stage stage = new Stage();
StackPane root = new StackPane();
root.getChildren().add(box);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
}
Operation started :
Operation finished :
PS: I used Thread.sleep(1000) because my file is so small.You can remove it if your progress time is long.
I am trying to get a screenshot of the chart node. So even though the axis values are added to the chart they are not displayed in the screenshot image..
public void saveProfitLineChartToFile(ObservableList<MonthlyRecord> monthlyRecords,String path) throws IOException {
CategoryAxis monthAxis = new CategoryAxis();
monthAxis.setLabel("Month");
NumberAxis profitAxis = new NumberAxis();
profitAxis.setLabel("Profit (Rs)");
LineChart profitLineChart = new LineChart(monthAxis, profitAxis);
XYChart.Series series1 = new XYChart.Series();
int[] profitValues = new int[monthlyRecords.size()];
int[] monthNo = new int[monthlyRecords.size()];
for (int i = 0; i < monthlyRecords.size(); i++) {
profitValues[i] = Integer.parseInt(monthlyRecords.get(i).getProfit());
monthNo[i] = Integer.parseInt(monthlyRecords.get(i).getMonth());
series1.getData().add(new XYChart.Data(monthName[monthNo[i]-1], profitValues[i]));
}
profitLineChart.getData().addAll(series1);
profitLineChart.setLegendVisible(false);
Scene sceneForChart = new Scene(profitLineChart, 800, 600);
WritableImage image = profitLineChart.snapshot(new SnapshotParameters(), null);
File file = new File(path);
try {
ImageIO.write(SwingFXUtils.fromFXImage(image, null), "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
i am having a problem when i click on the button it doesn t work.
actually for the moment i am just asking that the button execute a system.out.println() just for the test. the name of the button is btndetailUser
listRechercheUser.setCellFactory(new Callback<ListView<User>, ListCell<User>>() {
#Override
public ListCell<User> call(ListView<User> p) {
ListCell<User> cell;
cell = new ListCell<User>() {
#Override
protected void updateItem(User user, boolean bln) {
super.updateItem(user, bln);
if (user != null) {
ImageView img;
String mm=user.getPath().trim();
if (mm.equals("fusee.png")){
img = new ImageView(new Image("mto/cr/images/"+mm));}
else{
img = new ImageView(new Image("mto/cr/images/mains-fonds.png"));
}
VBox vb = new VBox(10);
HBox hb = new HBox(20);
VBox vb1 = new VBox(20);
VBox vb3= new VBox(20);
vb1.getChildren().add(new Label(" "));
hb.setStyle("-fx-border-color: #C8C8C8 ;");
vb.setAlignment(Pos.CENTER);
VBox vb2 = new VBox(30);
vb.setAlignment(Pos.CENTER);
vb2.setAlignment(Pos.BASELINE_LEFT);
vb3.setAlignment(Pos.CENTER_RIGHT);
Label id = new Label(user.getId()+"id firas:");
Label username = new Label(user.getUsername()+" username firas:");
Label nom = new Label(user.getNom()+"nom firas:");
Label prenom = new Label(user.getPrenom()+"prenom firas:");
Button btndetailUser = new Button();
btndetailUser.setId("btndetailUser");
btndetailUser.setText("btndetailUser "+user.getId());
Image imageAccesProjet = new Image("mto/cr/images/enter.png");
ImageView enterIV= new ImageView(imageAccesProjet);
enterIV.setFitHeight(10);
enterIV.setFitWidth(10);
btndetailUser.setGraphic(enterIV);
btndetailUser.getStyleClass().add("buttonLogin");
System.out.println(btndetailUser.getText());
btndetailUser.setOnMouseClicked(
(MouseEvent event2) ->
System.out.println("firas"));
btndetailUser.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
System.out.println(".handle()");
}
});
vb.getChildren().addAll(new Label(" "), img, new Label(" "),username);
vb2.getChildren().addAll(nom, prenom);
vb3.getChildren().addAll(btndetailUser);
hb.getChildren().addAll(vb1, vb, vb2,vb3);
setGraphic(hb);
}
}
};
return cell;
}
});
try something like,
btndetailUser.setOnAction(e -> {
System.out.println("freetext")
});
I have this code which is used to display text into combo box.
ProgressBar pb1 = new ProgressBar(0.6);
ProgressIndicator pi1 = new ProgressIndicator(0.6);
VBox vb1 = new VBox();
vb1.getChildren().addAll(new Label("Progressbar 1"), pi1);
ProgressBar pb2 = new ProgressBar(0.6);
ProgressIndicator pi2 = new ProgressIndicator(0.6);
VBox vb2 = new VBox();
vb2.getChildren().addAll(new Label("Progressbar 2"), pi2);
ProgressBar pb3 = new ProgressBar(0.6);
ProgressIndicator pi3 = new ProgressIndicator(0.6);
VBox vb3 = new VBox();
vb3.getChildren().addAll(new Label("Progressbar 3"), pi3);
TextChooser textChooser = new TextChooser(
vb1, vb2, vb3
);
textChooser.setStyle("-fx-font: 10px \"Verdana\";");
VBox layout = new VBox(textChooser);
layout.setPadding(new Insets(22, 22, 22, 22));
public static class TextChooser extends StackPane {
private Label label = new Label();
private ComboBox<String> combo = new ComboBox<>();
public TextChooser(String... options) {
StackPane.setAlignment(label, Pos.CENTER_LEFT);
StackPane.setAlignment(combo, Pos.CENTER_LEFT);
label.textProperty().bind(
combo.getSelectionModel().selectedItemProperty()
);
label.visibleProperty().bind(
combo.visibleProperty().not()
);
label.setPadding(new Insets(0, 0, 0, 10));
combo.getItems().setAll(options);
combo.getSelectionModel().select(0);
combo.setVisible(false);
label.setOnMouseEntered(event -> combo.setVisible(true));
combo.showingProperty().addListener(observable -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
combo.setOnMouseExited(event -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
getChildren().setAll(label, combo);
}
}
In my case I cannot insert VBox into the combo box. Any idea how I can fix this?
The biggest problem with your code is trying to construct a TextChooser using VBoxes when the formal parameters are Strings. Change your constructor to public TextChooser(VBox... options) and the ComboBox declaration to private ComboBox<VBox> combo = new ComboBox<>();.
Now you will be able to add the items to the combo box, and if it works, you are done. If you experience the issue with adding Nodes to a ComboBox, you may want to add more code. The problem and solution are described in the Javadoc for ComboBox: http://docs.oracle.com/javafx/2/api/javafx/scene/control/ComboBox.html. To get around the fact that the item you select will be removed from the combo box, you need to change this code (taken from the javadoc):
combo.setCellFactory(new Callback<ListView<VBox>, ListCell<VBox>>() {
#Override public ListCell<VBox> call(ListView<VBox> p) {
return new ListCell<VBox>() {
#Override protected void updateItem(VBox item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setGraphic(item);
}
}
};
}
});
after the line getItems().setAll(options);.
This is what your full example code would turn into:
ProgressBar pb1 = new ProgressBar(0.6);
ProgressIndicator pi1 = new ProgressIndicator(0.6);
VBox vb1 = new VBox();
vb1.getChildren().addAll(new Label("Progressbar 1"), pi1);
ProgressBar pb2 = new ProgressBar(0.6);
ProgressIndicator pi2 = new ProgressIndicator(0.6);
VBox vb2 = new VBox();
vb2.getChildren().addAll(new Label("Progressbar 2"), pi2);
ProgressBar pb3 = new ProgressBar(0.6);
ProgressIndicator pi3 = new ProgressIndicator(0.6);
VBox vb3 = new VBox();
vb3.getChildren().addAll(new Label("Progressbar 3"), pi3);
TextChooser textChooser = new TextChooser(
vb1, vb2, vb3
);
textChooser.setStyle("-fx-font: 10px \"Verdana\";");
VBox layout = new VBox(textChooser);
layout.setPadding(new Insets(22, 22, 22, 22));
public static class TextChooser extends StackPane {
private Label label = new Label();
private ComboBox<VBox> combo = new ComboBox<>();
public TextChooser(VBox... options) {
StackPane.setAlignment(label, Pos.CENTER_LEFT);
StackPane.setAlignment(combo, Pos.CENTER_LEFT);
label.textProperty().bind(
combo.getSelectionModel().selectedItemProperty()
);
label.visibleProperty().bind(
combo.visibleProperty().not()
);
label.setPadding(new Insets(0, 0, 0, 10));
combo.getItems().setAll(options);
// vvvv Begin Optional Part vvvv
combo.setCellFactory(new Callback<ListView<VBox>, ListCell<VBox>>() {
#Override public ListCell<VBox> call(ListView<VBox> p) {
return new ListCell<VBox>() {
#Override protected void updateItem(VBox item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setGraphic(null);
} else {
setGraphic(item);
}
}
};
}
});
// ^^^^ End Optional Part ^^^^
combo.getSelectionModel().select(0);
combo.setVisible(false);
label.setOnMouseEntered(event -> combo.setVisible(true));
combo.showingProperty().addListener(observable -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
combo.setOnMouseExited(event -> {
if (!combo.isShowing()) {
combo.setVisible(false);
}
});
getChildren().setAll(label, combo);
}
}