JavaFX TabPane : Why is the content not refreshed after selecting different tab? - javafx

So I am currently working with tabpane in JavaFx for the first time.
After it didn't work as expected I reduced the tabpanes content one bit at a time until it looked like this:
<ScrollPane prefWidth="Infinity" prefHeight="Infinity" fitToWidth="true" xmlns:fx="http://javafx.com/fxml"
fx:controller="de.Cos4U.ui.scene.control.CosplayView">
<VBox alignment="top_left" minWidth="200" prefHeight="200" spacing="5">
<TabPane prefHeight="Infinity" minHeight="Infinity">
<tabs>
<Tab text="Tab1">
<content>
<Label text="test"/>
</content>
</Tab>
<Tab text="Tab2">
<content>
<Label text="tests2"/>
</content>
</Tab>
</tabs>
</TabPane>
</VBox>
</ScrollPane>
After selecting "Tab2", the content area still shows the label "test". It is refreshed as soon as you scroll. It's a this simple tabpane, so why doesn't it refresh its content?
Edit: I am using 1.8u74 right now. I edited the fxml so now its as complete as needet but as reduced as possible.
The controller doesn't affect the tab pane in any way so. So far it handles simple user inputs. After removing anything i don't need for this example, it is reduced to 0.

I used to have the same problem. I don't have the exact reason why it doesn't update correctly, but if you want to force a refresh of the Layout, you can request it instead of using a workaround like changing the size.
requestLayout();
Suppose you want to set the content of a tab inside your controller.
class Panel extends TabPane {
private Tab tab;
public void setTabContent(Node container) {
tab.setContent(container);
getSelectionModel().select(tab);
requestLayout(); // to force refresh the layout
}
}
You then call this method from your controller.

Related

JavaFX Change Color of Table Row when Button is clicked

I want my table to change the color of a row depending on a column is checked or not or when a button is clicked.
I searched for solutions but it never worked the way I wanted to. I am happy for every keyword or help you have. Maybe I was just looking for the wrong thing?
My code looks like this:
public class Cellexample_presenter implements Initializable{
#FXML
TableColumn<ExampleData, Boolean> checkcol;
#FXML
TableView<ExampleData> testtable;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
checkcol.setText("Check");
ObservableList<ExampleData> exList = FXCollections.observableArrayList();
exList.add(new ExampleData(true));
exList.add(new ExampleData(false));
checkcol.setCellValueFactory(
new Callback<CellDataFeatures<ExampleData, Boolean>, ObservableValue<Boolean>>() {
#Override
public ObservableValue<Boolean> call(CellDataFeatures<ExampleData, Boolean> param) {
return param.getValue().checkProperty();
}
});
testtable.setItems(exList);
testtable.setEditable(true);
checkcol.setCellFactory(CheckBoxTableCell.forTableColumn(checkcol));
}
#FXML
private void clicked() {
ObservableList<ExampleData> tabledata = testtable.getItems();
for (ExampleData e : tabledata) {
System.out.println(e.isCheck());
}
}
}
I found solutions with another setCellFactory, but I doesn't seem to work when I already have a setCellFactory and I was unable to combine then. Moreover there is still the connection missing to the
change of the Checkbox.
Another solution I came across was something with a PseudoClass but this also required another setCellFactory
The method private void clicked() I used to check if the data in my object was really changed.
Also I want as another Feature to click a Button and change the color of rows with wrong data.
I was hoping there was a way to iterate trough the table, check the data and if something doesn't equals something else. It changes color.
Like this in pseudo-code
for (tablerow row: table)
if (row.ischecked()) {
row.changecolor();
}
Here is the .FXML for putting everything together:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.Pane?>
<AnchorPane prefHeight="254.0" prefWidth="700.0" xmlns="http://javafx.com/javafx/11.0.1"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="pathToFXML/Cellexample_presenter">
<children>
<Pane layoutX="-269.0" prefHeight="315.0" prefWidth="700.0" AnchorPane.bottomAnchor="0.0"
AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TableView fx:id="testtable" layoutX="142.0" layoutY="27.0" prefHeight="200.0"
prefWidth="340.0">
<columns>
<TableColumn fx:id="checkcol" prefWidth="75.0" text="C1" />
</columns>
</TableView>
<Button fx:id="checkbtn" layoutX="70.0" layoutY="36.0" mnemonicParsing="false"
onAction="#clicked" text="isChecked" />
</children>
</Pane>
</children>
</AnchorPane>
You can use a custom TableRow for this. I also prefer to use CSS and PseudoClasses to manage the color of rows.
What needs to happen here is that the row needs to know if the checked property in the ExampleData instance currently displayed by the row changes, and needs to change color if that happens.
Of course, for any given table row, the ExampleData instance displayed by that table row may also change (e.g. if the underlying data list changes, or if the user scrolls the table, etc.)
So the basic strategy here is:
Create a listener that observes the current item's checked property, and updates the pseudoclass state if it does (which in turn causes the style to change). In the code below I call this listener checkListener.
If the item displayed by the row changes, we need to stop observing the old item's checked property and start observing the new item's checked property instead. This can be achieved via a listener on the item property of the table row. That listener on the itemProperty can then remove the checkListener from the checkedProperty of the old item (if there was an old item), and add it to the checkedProperty of the new item (if there is one). It also needs to update the pseudoclass state according to the current state of the new item's checkedProperty.
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
// Existing code....
testTable.setRowFactory(tv -> new TableRow<ExampleData>() {
private final PseudoClass checkedPC = PseudoClass.getPseudoClass("checked");
private final ChangeListener<Boolean> checkListener = (obs, wasChecked, isNowChecked) ->
pseudoClassStateChanged(checkedPC, isNowChecked);
{
itemProperty().addListener((obs, oldItem, newItem) -> {
if (oldItem != null) {
oldItem.checkedProperty().removeListener(checkListener);
}
if (newItem == null) {
pseudoClassStateChanged(checkedPC, false);
} else {
pseudoClassStateChanged(checkedPC, newItem.isChecked());
newItem.checkedProperty().addListener(checkListener);
}
});
}
});
}
And then in your external CSS file include
.table-row-cell:checked {
-fx-background-color: red ;
}

Add VirtualizedScrollPane to InlineCssTextArea or any related GenericStyledArea by Scene Builder

how can I add the scroll abiltiy with VirtualizedScrollPane (explained in GenericStyledArea-#Adding Scrollbars to the Area) for InlineCssTextArea in JavaFx Scene Builder? Any suggestions?
I found a workaround.Editing the FXML-file by hand.
Like the RichtTextFX-Issue descriped:
<VirtualizedScrollPane
fx:id="sourceContainerTextScreenVirtualizedScrollPane"
layoutX="265.0"
layoutY="98.0">
<content>
<InlineCssTextArea
fx:id="theICA"
layoutX="0.0"
layoutY="0.0"
onKeyReleased="#handler"
onMouseReleased="handelrer2"
prefHeight="277.0"
prefWidth="674.0"
wrapText="true"/>
</content>
</VirtualizedScrollPane>
but add also a
#FXML private VirtualizedScrollPane<InlineCssTextArea> sourceContainerTextScreenVirtualizedScrollPane;
to your controller, if you want to controll it. Otherwise in my code it also works without controller declaration.
I hope this will help you till it is included into the Scene Builder.

A button that (when pressed) creates an combobox in its place and moves itself down to the row below

Long story short:
I have an assignment that is going to interact with older people (patients) for medical purposes.
I have designed everything in scenebuilder and I am stuck at the moment.
The patients are going to fyll in some medical data, some days is going to require more input than others. Input such as heart rate, blood sugar, how they slept that night and so on.
I'm going to need a system that is adaptable since each day can vary on how much they want to fyll in. (depending on them and/or their doctor)
This is how the program is right now:
The first 2-3 rows in the gridpane is my focus right now.
what i want is that when i press the ADD button, it will create an combobox in its plane and movie itself down a row in the gridpane.
I dont actually know if it good to do this with a gridpane or if anyone has any other recomendations ( all appreciated).
you can see that in the rows 6-9 are hardcoded what input is what. Since these options may change with time i will need to make it adjustable. That is why my first combobox reads its different inputpotions from the database.
My attempt so far:
#FXML
GridPane gridPane;
#FXML
Button addButton;
#FXML
ComboBox<String> addedCombo;
#FXML
String amountCombo;
int count = 0;
#FXML
public void addComboBoxButton() {
amountCombo = "addedCombo";
addedCombo = new ComboBox();
addedCombo.setName(amountCombo + count);
count++;
}
Im trying to create a function that created an combobox evertyime the ADDbutton is pressed and then add count to it.
For example if you press it 3 times you should've created 3 comboboxes that are named:
addedCombo0, addedCombo1, addedCombo2
The error i get is shown on setName() and it says:
The method setName(String) is undefined for the type ComboBox
This is how it should look like after the ADDbutton is pressed
Thank you for your time!
I would recommend to use a separate GridPane(or VBox) for handling the ComboBoxes within the grid. This way everytime when you add a comboBox, you dont need to alter the row numbers of all the rows down the grid.
Something like..
<GridPane>
<children>
<VBox GridPane.rowIndex="0" GridPane.columnIndex="0" GridPane.columnSpan="2" alignment="CENTER_LEFT">
<!-- Keep adding your combo boxes here -->
</VBox>
<Button text="Add" GridPane.rowIndex="1" GridPane.columnIndex="0" />
<Label text="Heart Rate" GridPane.rowIndex="2" GridPane.columnIndex="0" />
<TextField GridPane.rowIndex="2" GridPane.columnIndex="1" />
<!-- Followed by your other rows.....>
</children>
</GridPane>

Javafx. Bug with TitledPane

Now I'm working with javafx and create small view with SplitPane.
In this SplitPane i have two TiteledPanes(named A and B). At first step of program working, only one TitledPane contains data (A). But after little user actions some information are put on B.
If i run my programm 10 times, at 7-8 times everything will be ok!
But in 2 times I have a problem with second titeledPane. It is consists with no data. This TitledPane loaded without any exceptions and all bindings are good, But it consists with no data. It is very strange, because in 80% of time everything is ok.
May be this is javafx bugs?
Any one have the same problem?
<fx:root type="MyView" dividerPositions="0.5" orientation="VERTICAL" style="-fx-background-color: darkgray">
<fx:define>
<TitledPane fx:id="A">
<AnhorPane>
<Label text="ALabel"/>
</AnhorPane>
</TitledPane>
<TitledPane fx:id="B"/>
<AnhorPane>
<Label text="BLabel"/>
</AnhorPane>
</TitledPane>
</fx:define>
</fx:root>
public class MyView extends SplitPane {
public MyView () {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("MyView .fxml"));
loader.setController(this);
loader.setRoot(this);
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
}
The problem was in loading fxml file proccess. There are a lot of data should be loaded after the load fxml file(in my model class relating to that fxml) and in future adding to existing fxml. Like binding properties and etc.
When I relocate above 80% of bindings in fxml file using ${} - the problem was solded.

titanium alloy open view from button

After being away from Titanium for awhile, seems I forgot even the simplest tasks. Case in point: I have a stack of buttons on a main page. Each button should open its respective view when clicked. How do I open that associated view when the button is clicked?
View
<Alloy>
<Tab title="Home">
<Window class="container">
<Label>This is the Home View</Label>
<ImageView id="kplLogo"/>
<View id="homeNav">
<Button class="navButton" id="recognizeButton" title="Recognize" onClick="doClick" />
<Button class="navButton" id="reactButton" title="React"/>
<Button class="navButton" id="reportButton" title="Report"/>
</View>
</Window>
</Tab>
</Alloy>
When the user clicks a button, such as the recognizeButton for now, it should open the recognizeView. I know it's simple, but I'm having brainlock at the moment.
Thanks for the help. Ask if you need more detail.
First, add a property to each Button which will make possible to invoke the child View controllers, such as:
<Button id="recognizeButton" title="Recognize" child_controller="recognizeView" />
Also use an id on the <tab> element:
<Tab id="hometab">
Then, in the controller, add the event listener:
$.recognizeButton.addEventListener('click', function(e) {
if (e.source.child_controller) {
controller = Alloy.createController(e.source.child_controller);
$.hometab.open(controller.getView());
}
});
This will open a new window in the same tab, preserving history so that when you click reutrn, you'll be back in the main tab. If you need a broader example, check this: https://github.com/asiviero/drupanium_app/tree/master/app in which I use the home view in that manner, opening up views from controllers inside "includes" folder

Resources