Working with a login control (username and password) I can press enter on the control and then tab (without entering anything) and I get the warning that says to enter a valid user name. This is the desired effect, however if I just tab or click out of the field the event does not trigger, nor does the cursor move to the next field if the user enters a username and just presses enter. Any suggestions?
Controller Code
void getUserName(ActionEvent event) {
userName.focusedProperty().addListener((ov, oldV, newV) -> {
if (!(userName.getText().isEmpty())) {
if (!newV) {
String textUserValue = userName.getText();
warningLabel.setVisible(false);
userPwd.requestFocus();
}
} else {
warningLabel.setText("Please enter a valid user name");
warningLabel.setVisible(true);
warningLabel.setStyle("-fx-text-fill: red; -fx-font-size: 12;");
userName.requestFocus();
}
});
}
#FXML
void pwdController(ActionEvent event) {
userPwd.focusedProperty().addListener((ov, oldV, newV) -> {
if (!newV) {
if (!(userPwd.getText().isEmpty())) {
String textPwdValue = userPwd.getText();
warningLabel.setVisible(false);
String uName = userName.getText();
ServiceWrapper.conn1(uName, textPwdValue);
srcUpi.setDisable(false);
tgtUpi.setDisable(false);
mrgEqstDt.setDisable(false);
userName.setDisable(true);
userPwd.setDisable(true);
srcUpi.requestFocus();
}
} else {
warningLabel.setText("Please enter a valid password");
warningLabel.setVisible(true);
warningLabel.setStyle("-fx-text-fill: red; -fx-font-size: 12;");
userPwd.requestFocus();
}
});
}
FXML Code
<TextField fx:id="userName" layoutX="15.0" layoutY="14.0" onAction="#getUserName" onMouseReleased="#getUserName" promptText="User Name" />
<Label layoutX="15.0" layoutY="42.0" text="User Name" />
<TextField fx:id="userPwd" layoutX="15.0" layoutY="72.0" nAction="#pwdController" promptText="Password" />
<Label layoutX="15.0" layoutY="100.0" text="Password" />
<Label fx:id="warningLabel" focusTraversable="false" layoutX="15.0" layoutY="138.0" prefHeight="18.0" prefWidth="170.0" text="securitywarning" visible="false" />
<Separator layoutY="168.0" prefHeight="7.0" prefWidth="200.0" />
Related
I feel this is weird. i can't get the Radio button to pre-select a saved value and it's driving me mad. I have this xaml:
<StackLayout Orientation="Horizontal" RadioButtonGroup.GroupName="Parities"
RadioButtonGroup.SelectedValue="{Binding Parity}">
<RadioButton Value="1" Content="Income" />
<RadioButton Value="-1" Content="Expense" />
<RadioButton Value="0" Content="Neutral" />
</StackLayout>
Furthermore, even if I replace SelectedValue with a hard coded literal value "1" (for Income), the radio button still show up blank. The only way that works is by setting IsChecked on each of the 3 options to have the them pre-selected.
What am I missing?
Based on your code ,I created a simple demo, but I couldn't reproduce this problem. It just works properly.
You can refer to the following code:
MyPage.xaml
<ContentPage.BindingContext>
<radiobuttondemos:MyViewModel></radiobuttondemos:MyViewModel>
</ContentPage.BindingContext>
<StackLayout>
<StackLayout Orientation="Horizontal" RadioButtonGroup.GroupName="{Binding GroupName}"
RadioButtonGroup.SelectedValue="{Binding Parity}">
<RadioButton Value="1" Content="Income" />
<RadioButton Value="-1" Content="Expense" />
<RadioButton Value="0" Content="Neutral" />
</StackLayout>
</StackLayout>
The MyViewModel.cs
public class MyViewModel : INotifyPropertyChanged
{
string groupName;
object parity;
public object Parity
{
get => parity;
set
{
parity = value;
OnPropertyChanged(nameof(Parity));
}
}
public MyViewModel () {
GroupName = "Parities";
Parity = "1";
}
public string GroupName
{
get => groupName;
set
{
groupName = value;
OnPropertyChanged(nameof(GroupName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note:
In the constructor of MyViewModel, I initialize the value of variable Parity as follows:
Parity = "1";
And if we initialize a value as follows, the UI will not pre-select the saved value :
Parity = 1;
I am facing an issue when I submit my form in xamarin form using mvvm architecture my form UI is still able and user can interact while fetching the data from server. I want to disable my UI elements when my submit button is running to fetch the data from server. Actually, I want to bind isEnabled property in my viewmodel. But I do not know how to set it to bool value from my view model and then bind it to the UI elements. What i need to add in my set function so that when someone click on submit button my UI elements will be inactive and user can not edit till the response comes from server.
what to do please assist. Here is my code.
Blockquote
<StackLayout>
<Entry x:Name="entryFullName"
Text="{Binding FullName}"
Placeholder="Full Name"
IsEnabled="{Binding block}"
/>
<Picker x:Name="pickerGender"
Title="Gender"
ItemsSource="{Binding Genders}"
SelectedItem="{Binding SelectedGender}"
IsEnabled="{Binding gender}"
/>
</StackLayout>
<StackLayout>
<Button x:Name="btnSubmit"
Command="{Binding SubmitCommand}"
Text="Submit"
/>
</StackLayout>
<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" />
here is my code for my viewmodel submit button function
Blockquote
private string _Block;
public string Block
{
get { return _Block }
set { _Block = value; OnPropertyChanged(); }
}
private void OnSubmit()
{
if (string.IsNullOrEmpty(this.FullName))
{
this.ErrorOccurred?.Invoke(this, "Please enter full name");
return;
}
Device.BeginInvokeOnMainThread(async () => await this.SaveProfile();
}
first, bind all of your IsEnabled properties to the same VM property
<Entry x:Name="entryFullName" IsEnabled="{Binding NotBusy}" ... />
<Picker x:Name="pickerGender" IsEnabled="{Binding NotBusy}" ... />
...
<Button x:Name="btnSubmit" IsEnabled="{Binding NotBusy}" ... />
then in your MV create a bool property
private bool _NotBusy = true;
public bool NotBusy
{
get { return _NotBusy }
set { _NotBusy = value; OnPropertyChanged(); }
}
finally, when saving set the property
private void OnSubmit()
{
if (string.IsNullOrEmpty(this.FullName))
{
this.ErrorOccurred?.Invoke(this, "Please enter full name");
return;
}
NotBusy = false;
Device.BeginInvokeOnMainThread(async () => await this.SaveProfile();
}
you can add a property IsNotSubmitting,
private bool _isNotSubmitting = true;
public bool IsNotSubmitting {
get => _isNotSubmitting ;
set {
_isNotSubmitting = value;
OnPropertyChanged();
}
}
binding in Xaml:
<Entry x:Name="entryFullName"
Text="{Binding FullName}"
Placeholder="Full Name"
IsEnabled="{Binding IsNotSubmitting}" />
now you can set "IsNotSubmitting=false" in the beginning of method SubmitCommand, and you can set "IsNotSubmitting=true" when the commiting is finished
<Frame HasShadow="False">
<StackLayout Orientation="Vertical" >
<Entry Placeholder="NAME" x:Name="name"></Entry>
<Entry Placeholder="SURNAME" x:Name="surname"></Entry>
<StackLayout Orientation="Horizontal" >
<Label Text="BIRTHDATE" VerticalOptions="Center" HorizontalOptions="Center" ></Label>
<DatePicker x:Name="birdthdate" HorizontalOptions="Center" VerticalOptions="Center"></DatePicker>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="PICK YEARS" HorizontalOptions="Center" VerticalOptions="Center"></Label>
<Picker Title="YEARS" x:Name="years" HorizontalOptions="Center" VerticalOptions="Center"></Picker>
</StackLayout>
<StackLayout Spacing="0">
<Label Text="Number of docs:"></Label>
<Entry Keyboard="Numeric" x:name="docs"></Entry>
</StackLayout>
<Button Text="SAVE" TextColor="White" Padding="0,-20" BackgroundColor="#07987f" IsEnabled="false" >
</Button>
</StackLayout>
</Frame>
My idea is only when user will enter Name Surname Birdthdate Years NumberOfDocs the button will become enable and can save the data. Any suggestion how to do that?
Here is the logic for a simple login with login name + password, where the login button only gets enabled when LoginName and LoginPassword contains text:
private string _loginName;
public string LoginName
{
get { return _loginName; }
set
{
SetProperty(ref _loginName, value);
RaisePropertyChanged("IsLoginButtonEnabled");
}
}
private string _loginPassword;
public string LoginPassword
{
get { return _loginPassword; }
set
{
SetProperty(ref _loginPassword, value);
RaisePropertyChanged("IsLoginButtonEnabled");
}
}
public bool IsLoginButtonEnabled
{
get
{
if (!string.IsNullOrEmpty(LoginName) &&
!string.IsNullOrEmpty(LoginPassword))
{
return true;
}
return false;
}
}
Just extend this to your needs and it should work.
There are multiple ways you can do that. The easiest way is like the answer from Dennis Schröer. But it doesn't look like you are using MVVM so i have another solution using converters.
Change your button to this:
<Button Padding="0,-20"
BackgroundColor="#07987f"
Text="SAVE"
TextColor="White">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource EnableButtonConverter}">
<Binding Path="Text"
Source="{x:Reference name}" />
<Binding Path="Text"
Source="{x:Reference surname}" />
<Binding Path="Date"
Source="{x:Reference birdthdate}" />
<Binding Path="SelectedItem"
Source="{x:Reference years}" />
</MultiBinding>
</Button.IsEnabled>
</Button>
The property IsEnabled is bound to all the properties you want it to be dependent on.
The converter does the logic:
public class EnableButtonConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var name = (string)values[0];
var surname = (string)values[1];
//var date = (DateTime)values[2];
//var year = (string)values[3];
return !string.IsNullOrWhiteSpace(name) && !string.IsNullOrWhiteSpace(surname); //&& !year.Equals("YEARS"); //Todo: add a check for the date
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Put the Converter in your pages ResourceDictionary and you are good to go.
PS: It's better for performance to use Grid-layout instead of multiple StackLayouts
The fxml file is as follows (headers omitted):
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity"
minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
fx:id="pane"
fx:controller="com.github.parboiled1.grappa.debugger.mainwindow.MainWindowUi">
<top>
<MenuBar BorderPane.alignment="CENTER">
<Menu mnemonicParsing="false" text="File">
<MenuItem fx:id="loadInput" mnemonicParsing="false"
text="Load file" onAction="#loadFileEvent"/>
<MenuItem fx:id="parse" mnemonicParsing="false"
text="Parse" onAction="#parseEvent"/>
<MenuItem fx:id="closeButton" mnemonicParsing="false"
text="Close" onAction="#closeWindowEvent"/>
</Menu>
</MenuBar>
</top>
<center>
<SplitPane dividerPositions="0.5" prefHeight="160.0" prefWidth="200.0"
BorderPane.alignment="CENTER">
<SplitPane dividerPositions="0.5" orientation="VERTICAL">
<TreeView fx:id="traceTree" prefHeight="200.0"
prefWidth="200.0" editable="false"/>
<TextArea fx:id="traceDetail" prefHeight="200.0"
prefWidth="200.0"/>
</SplitPane>
<TextArea fx:id="inputText" prefHeight="200.0" prefWidth="200.0"/>
</SplitPane>
</center>
</BorderPane>
I can set the root of the TreeView with no problem at all. The tree is updated with no problem.
The problem I have is that I cannot manage to have an event fired on a given item in the view. I tried and added a onMouseClicked event with a simple System.out.println() and I can see the event being fired, whichever item I click in the tree. But I cannot manage to get the item which has been clicked in the view at all.
How do I do that?
Register a mouse listener with each tree cell, using a cell factory. I don't know the data type you have in your TreeView, but if it were String it might look something like this:
// Controller class:
public class MainWindowUi {
#FXML
private TreeView<String> traceTree ;
// ...
public void initialize() {
traceTree.setCellFactory(tree -> {
TreeCell<String> cell = new TreeCell<String>() {
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty) ;
if (empty) {
setText(null);
} else {
setText(item);
}
}
};
cell.setOnMouseClicked(event -> {
if (! cell.isEmpty()) {
TreeItem<String> treeItem = cell.getTreeItem();
// do whatever you need with the treeItem...
}
});
return cell ;
});
}
// ...
}
since yesterday, i'm trying to change the color of my dialog title (or maybe all title colors of my application) to get a black or dark color, because it's white color and not readable with grey background.
I still think it should work with css but i can't really find the specific entry for the title color.
I tried something like this in dialog.css but did not work, so commented out:
/*
.root {
-fx-text-base-color: blue;
-fx-text-background-color: green;
-fx-text-inner-color: red;
-fx-selection-bar-text: yellow;
}
*/
Here my Dialog class:
package de.test.dialog;
import java.io.IOException;
import javafx.event.EventHandler;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
public class Dialog extends Stage {
public static final String OK_DIALOG = "OK";
private final String OK_XML = "/fxml/dialog_ok.fxml";
public enum DIALOG_ACTION {
BUTTON_1, BUTTON_2, BUTTON_3, NOTHING, CLOSE_WINDOW
}
private DialogController controller = null;
private String message = null;
public Dialog(String name, String ... buttonName) {
String resource = getFXMLResource(name);
if (resource != null) {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource(resource));
Parent root = (Parent) fxmlLoader.load();
controller = fxmlLoader.getController();
controller.setButtons(buttonName);
setScene(new Scene(root));
}
catch (IOException e) {
e.printStackTrace();
}
}
setOnCloseRequest(new EventHandler<WindowEvent>() {
#Override
public void handle(WindowEvent event) {
System.out.println("Closing?");
}
});
}
private String getFXMLResource(String name) {
String fxmlResource = null;
switch(name) {
case OK_DIALOG:
fxmlResource = OK_XML;
break;
default:
break;
}
return fxmlResource;
}
public Dialog.DIALOG_ACTION getAction() {
if (controller != null) {
return controller.getAction();
}
else {
return DIALOG_ACTION.NOTHING;
}
}
public void setMessage(String sMessage) {
this.message = sMessage;
if (controller != null) {
controller.setMessage(message);
}
}
public void setIcon(Image image) {
if (controller != null) {
controller.setIcon(image);
}
}
}
Dialog fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.image.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="176.0" prefWidth="400.0" stylesheets="#styles/dialog.css" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="de.test.dialog.DialogController">
<children>
<ImageView fx:id="imgIcon" fitHeight="48.0" fitWidth="48.0" layoutX="8.0" layoutY="25.0" pickOnBounds="true" preserveRatio="true" AnchorPane.leftAnchor="15.0" AnchorPane.topAnchor="25.0">
<image>
<Image url="#../icons/dialog/48a.png" />
</image>
</ImageView>
<Text fx:id="txtMessage" layoutX="85.0" layoutY="45.0" strokeType="OUTSIDE" strokeWidth="0.0" text="TEST" wrappingWidth="300.00" AnchorPane.leftAnchor="94.0" AnchorPane.rightAnchor="15.0" AnchorPane.topAnchor="25.0">
<font>
<Font size="14.0" />
</font>
</Text>
<Button fx:id="btn1" defaultButton="true" layoutX="295.0" layoutY="134.0" mnemonicParsing="false" onAction="#doAction" prefHeight="25.0" prefWidth="90.0" text="OK" AnchorPane.rightAnchor="15.0">
<font>
<Font size="14.0" />
</font>
</Button>
<Button fx:id="btn2" cancelButton="true" layoutX="180.0" layoutY="134.0" mnemonicParsing="false" onAction="#doAction" prefHeight="25.0" prefWidth="90.0" text="Abbrechen" visible="false" AnchorPane.rightAnchor="120.0">
<font>
<Font size="14.0" />
</font>
</Button>
<Button fx:id="btn3" layoutX="102.0" layoutY="134.0" mnemonicParsing="false" onAction="#doAction" prefHeight="25.0" prefWidth="90.0" text="Button 3" visible="false" AnchorPane.rightAnchor="225.0">
<font>
<Font size="14.0" />
</font>
</Button>
</children>
</AnchorPane>
Calling my dialog:
Dialog dialog = new Dialog(Dialog.OK_DIALOG, "Löschen", "Abbrechen");
dialog.initModality(Modality.APPLICATION_MODAL);
dialog.initOwner(((Node)e.getSource()).getScene().getWindow());
dialog.setResizable(false);
dialog.setTitle("Dateianhang löschen");
dialog.setMessage("Wollen Sie die ausgewählte(n) Datei(en) wirklich löschen?");
// Get the Stage.
//Stage stage = (Stage) dialog.getScene().getWindow();
// Add a custom icon.
//stage.getIcons().add(new Image("/icons/dialog/48a.png"));
dialog.showAndWait();
As you can see, i tried to change the title icon (commented out), and that worked. But no chance to change the color of the title.
If i try google whith e.g. javafx, i can see a lot of images with black title colors. So it must be possible to change the color, but i don't know how.
Any suggestions?
Greetings,
Tom
I stand to be corrected but I don't think you can set the color of the NATIVE title bar. I think what you are seeing in the google results are custom (user) made title bars.
Maybe this link is useful to you: https://arnaudnouard.wordpress.com/2013/02/02/undecorator-add-a-better-look-to-your-javafx-stages-part-i/
You can also have a look at the FXControls Dialogs source code and see how they have done it: http://fxexperience.com/controlsfx/features/dialogs/