Searching and highlighting in a TextArea - javafx

I have a TextArea with a text in which I want to search for word(s). The search works, but highlighting the word with selectRange() does not. Is there a different method for highlighting?
findButton.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent e) {
if (textField.getText() != null && !textField.getText().isEmpty()) {
int index = textArea.getText().indexOf(textField.getText());
if (index == -1) {
errorText.setText("Search key Not in the text");
} else {
// errorText.setText("Found");
textArea.selectRange(textField.getText().charAt(0), textField.getLength());
}
} else {
errorText.setText("Missing search key");
// errorText.setFill(Color.RED);
}
}
});

Surely you mean
textArea.selectRange(index, index + textField.getLength());

Related

Xamarin forms: Auto scrolling for CarouselPage children

I have 4 children (page1,page2,page3, and page4) in a CarouselPage, I need to auto-scroll the children in every 3 seconds. Initially, page1 is showing on the UI, then page2 -> page3 -> page 4 again starting from page1.
I have done like below for this feature using OnCurrentPageChanged() and await Task.Delay(TimeSpan.FromSeconds(3));:
protected async override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
await Task.Delay(TimeSpan.FromSeconds(3));
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
}
else if (index == 1)
{
CurrentPage = Children[2];
}
else if (index == 2)
{
CurrentPage = Children[3];
}
else if (index == 3)
{
CurrentPage = Children[0];
}
}
The auto-scroll is successful by this approach.
But if I manually scroll the page in between the auto-scroll, then the time delay is reducing. Suddenly(less than 3 sec) the next page is showing on the screen. If I manually swipe the page I need to wait on the page for 3 seconds. How can I solve this issue?
There is a Exciting Library CardsView please look into it.
it will not only solve your problem but your apps looks cool as well.
here is Source Project , https://github.com/AndreiMisiukevich/CardView .
check CarouselSampleXamlView in that, SlideShowDuration property for carousel which handles all stuff.
Hope it helps.
Please do not put the transfer page to the OnCurrentPageChanged method.
You can put it in your Page's constructor.
public partial class MainPage : CarouselPage
{
bool isStart = true;
public MainPage()
{
InitializeComponent();
Device.StartTimer(new TimeSpan(0, 0, 3), () =>
{
Device.BeginInvokeOnMainThread(() =>
{
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
isStart = true;
}
else if (index == 1)
{
CurrentPage = Children[2];
isStart = true;
}
else if (index == 2)
{
CurrentPage = Children[3];
isStart = true;
}
else if (index == 3)
{
CurrentPage = Children[0];
isStart = true;
}
});
return isStart; // runs again, or false to stop
});
}
}
If you change the page by swipe, the time delay is not reducing.
However, If you want to wait on the page for 3 seconds after swiping. You have to use custom renderer to achieve it. You should monitor the viewpager's onTouchEventin android(but I cannot found a solution in IOS). This way will have caton, so above way will be better.
[assembly: ExportRenderer(typeof(CarouselPage), typeof(CustomCarouselPageRenderer))]
namespace CarouselPageDemo.Droid
{
public class CustomCarouselPageRenderer: CarouselPageRenderer
{
public CustomCarouselPageRenderer(Context context) : base(context) {
}
protected override void OnElementChanged(ElementChangedEventArgs<CarouselPage> e)
{
base.OnElementChanged(e);
if (this.ChildCount > 0 && this.GetChildAt(0) is ViewPager viewPager)
{
viewPager.Touch -= ViewPagerTouched;
viewPager.Touch += ViewPagerTouched;
}
}
private void ViewPagerTouched(object sender, TouchEventArgs e)
{
MessagingCenter.Send<App, string>(App.Current as App, "OpenPage", "stop");
}
}
}
CarouselPage_CurrentPageChanged method
private async void CarouselPage_CurrentPageChanged(object sender, EventArgs e)
{
var tokenSource = new CancellationTokenSource();
await Task.Delay(TimeSpan.FromSeconds(3), tokenSource.Token);
MessagingCenter.Subscribe<App, string>(App.Current, "OpenPage", (snd, arg) =>
{
tokenSource.Cancel();
});
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
CurrentPage = Children[1];
}
else if (index == 1)
{
CurrentPage = Children[2];
}
else if (index == 2)
{
CurrentPage = Children[3];
}
else if (index == 3)
{
CurrentPage = Children[0];
}
}

How to add multiple BooleanBinding to single button?

I need to make multiple bindings and address them to the same button.
Right now I have this BooleanBinding:
BooleanBinding even = new BooleanBinding() {
{ super.bind(plaintextHex.textProperty()); }
#Override
protected boolean computeValue() {
return ((plaintextHex.getText().length() % 2) != 0);
}
};
And this one:
BooleanBinding maxS = new BooleanBinding() {
{ super.bind(keyHex.textProperty()); }
#Override
protected boolean computeValue() {
return (keyHex.getText().length() > 32);
}
};
If I want to assign one BooleanBinding it looks like this: crButton.disableProperty().bind(even);, but if I want to assgin muttiple I can't find any info on how to do it. The idea was that it would look something like this: crButton.disableProperty().bind(even, maxS);, but of course it doesn't work like that. Do I have to make both in the same BooleanBinding or there is a method to combine them?
Depending on exactly what you need, you can do
crButton.disableProperty().bind(even.or(maxS));
or
crButton.disableProperty().bind(even.and(maxS));
Or you can just create a single binding:
BooleanBinding maxSOrEven = new BooleanBinding() {
{ super.bind(keyHex.textProperty(), plaintextHex.textProperty()); }
#Override
protected boolean computeValue() {
return keyHex.getText().length() > 32 || plaintextHex.getText().length() % 2 != 0 ;
}
};
crButton.disableProperty().bind(maxSOrEven);
etc.

Spinner control value

I'm using Spinner from 8u40b17.
SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
Spinner sp = new Spinner();
sp.setValueFactory(svf);
sp.setEditable(true);
sp.setPrefWidth(80);
I noticed that when I enter some value from keyboard and I increase the upper value the expected number is not the next. Instead of this it's the next default value. How I can fix this?
For example: if I have 5 as default value and I enter 34, then press the upper arrow I expect to get 35 by actually get 6.
I had the same problem with the spinner control. Your bug has been documented here: JDK-8094205
Here is the last comment:
Jonathan Giles added a comment - Dec, 15 2014 12:59 AM
Fixed locally in my repo, will push to the 8u60 repo this week once it
opens. Now the text editor input is committed when increment /
decrement are called (although the value is still not committed when
focus is lost).
Unit tests:
javafx.scene.control.SpinnerTest.test_rt_39655_decrement()
javafx.scene.control.SpinnerTest.test_rt_39655_increment()
The changeset: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/89ca7d3f699e
Here is my take on an Autocommit spinner. This one will auto commit anything that the factory will accept.
public class SpinnerAutoCommit<T> extends Spinner<T> {
public SpinnerAutoCommit() {
super();
addListenerKeyChange();
}
public SpinnerAutoCommit(int min, int max, int initialValue) {
super(min, max, initialValue);
addListenerKeyChange();
}
public SpinnerAutoCommit(int min, int max, int initialValue, int amountToStepBy) {
super(min, max, initialValue, amountToStepBy);
addListenerKeyChange();
}
public SpinnerAutoCommit(double min, double max, double initialValue) {
super(min, max, initialValue);
addListenerKeyChange();
}
public SpinnerAutoCommit(double min, double max, double initialValue, double amountToStepBy) {
super(min, max, initialValue, amountToStepBy);
addListenerKeyChange();
}
public SpinnerAutoCommit(ObservableList<T> items) {
super(items);
addListenerKeyChange();
}
public SpinnerAutoCommit(SpinnerValueFactory<T> valueFactory) {
super(valueFactory);
addListenerKeyChange();
}
private void addListenerKeyChange() {
getEditor().textProperty().addListener((observable, oldValue, newValue) -> {
commitEditorText();
});
}
private void commitEditorText() {
if (!isEditable()) return;
String text = getEditor().getText();
SpinnerValueFactory<T> valueFactory = getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
}
}
By design, the changes in the textfield of the Spinner control are commited only when the user hits ENTER key, via action handler:
getEditor().setOnAction(action -> {
String text = getEditor().getText();
SpinnerValueFactory<T> valueFactory = getValueFactory();
if (valueFactory != null) {
StringConverter<T> converter = valueFactory.getConverter();
if (converter != null) {
T value = converter.fromString(text);
valueFactory.setValue(value);
}
}
});
Note that if the typed value can't be converted, this will throw a NumberFormatException, keeping the wrong value in the textfield.
We can provide our own implementation, listening to other keys, like TAB key, via event filter, and at the same time, and in case of exception, restore the last valid value.
Something like this:
private final Spinner sp = new Spinner();
#Override
public void start(Stage primaryStage) {
SpinnerValueFactory svf = new SpinnerValueFactory.IntegerSpinnerValueFactory(0, 100);
sp.setValueFactory(svf);
sp.setEditable(true);
sp.setPrefWidth(80);
// Commit on TAB
sp.addEventFilter(KeyEvent.ANY, e->{
if (sp.isEditable() && e.getCode().equals(KeyCode.TAB)) {
doCommit();
e.consume();
}
});
// Override Commit on ENTER
sp.getEditor().setOnAction(e->{
if(sp.isEditable()) {
doCommit();
e.consume();
}
});
Scene scene = new Scene(new StackPane(sp), 300, 250);
primaryStage.setScene(scene);
primaryStage.show();
}
/*
Commit new value, checking conversion to integer,
restoring old valid value in case of exception
*/
private void doCommit(){
String text = sp.getEditor().getText();
SpinnerValueFactory<Integer> valueFactory = sp.getValueFactory();
if (valueFactory != null) {
StringConverter<Integer> converter = valueFactory.getConverter();
if (converter != null) {
try{
Integer value = converter.fromString(text);
valueFactory.setValue(value);
} catch(NumberFormatException nfe){
sp.getEditor().setText(converter.toString(valueFactory.getValue()));
}
}
}
}
This solved the problem for me but it relys on Apache Commons Validator to validate entered value in the spinner (org.apache.commons.validator.GenericValidator)
valueSpinner.getEditor().textProperty().addListener((observable, oldValue, newValue) -> {
try {
if (GenericValidator.isInt(newValue)) {
valueSpinner.getValueFactory().setValue(Integer.parseInt(newValue));
}
} catch (NumberFormatException e) {
if (GenericValidator.isInt(oldValue)) {
valueSpinner.getValueFactory().setValue(Integer.parseInt(oldValue));
}
}
});
Edit :-
You can validate the value without using Apache Commons Validator like this example :-
private boolean isInteger(String value) {
if (value == null) {
return false;
}
try {
new Integer(value);
return true;
} catch (NumberFormatException e) {
return false;
}
}
valueSpinner.getEditor().textProperty().addListener((observable, oldValue, newValue) -> {
try {
if (isInteger(newValue)) {
valueSpinner.getValueFactory().setValue(Integer.parseInt(newValue));
}
} catch (NumberFormatException e) {
if (isInteger(oldValue)) {
valueSpinner.getValueFactory().setValue(Integer.parseInt(oldValue));
}
}
});

Get key combination code of multiple keys

I want to ask you can I get key code combination of multiple keys. For example I can get the key code from this example:
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.TAB) {
}
}
But how I can get the key code of this example:
textField.setText("");
// Process only desired key types
if (event.getCode().isLetterKey()
|| event.getCode().isDigitKey()
|| event.getCode().isFunctionKey()) {
String shortcut = event.getCode().getName();
if (event.isAltDown()) {
shortcut = "Alt + " + shortcut;
}
if (event.isControlDown()) {
shortcut = "Ctrl + " + shortcut;
}
if (event.isShiftDown()) {
shortcut = "Shift + " + shortcut;
}
textField.setText(shortcut);
shortcutKeyEvent = event;
} else {
shortcutKeyEvent = null;
}
Is it possible to get the key code combination of these keys Ctrl + Tab or Ctrl + A?
No, the handled keyEvent has only one main KeyCode, for example this code
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.TAB) {
}
}
will handle TAB, ALT + TAB, or CTRL + TAB etc. If you only interested in CTRL + TAB, you have 2 choices:
1) using isControlDown()
public void handle(KeyEvent event) {
if (event.getCode() == KeyCode.TAB && event.isControlDown()) {
}
}
2) using KeyCodeCombination
final KeyCombination kb = new KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN);
...
...
public void handle(KeyEvent event) {
if (kb.match(event)) {
}
}
I Don't see directly there is any way except Menus
but still We can handle multi key event e.g. Ctrl + S by below work around.
at controller class level keep
public static boolean halfCtrlSPressed=false;
and in Event filter add logic as
if(ke.getCode().getName() == "Ctrl") {
halfCtrlSPressed=true;
}else if(ke.getCode().getName() == "S" && halfCtrlSPressed) {
halfCtrlSPressed=false;
//doDomething
}

JFace button in TableViewerColumn

Is it possible to have a button in a TableViewerColumn? There are several posts that confirm this, but I've found no code that actually works. I've read about a DialogCellEditor, too, is that what to look into?
Regards,
Marcus
As this seems to be a common problem, I've tried a workaround. I use an image as label and add editing support like so:
col = createTableViewerColumn(titles[10], bounds[10], 10);
col.setEditingSupport(new DeleteSupport(viewer));
col.setLabelProvider(new ColumnLabelProvider() {
#Override
public Image getImage(Object element) {
return new Image(ApplicationRunner.getApp().getShell()
.getDisplay(), "ressources/images/delete.png");
}
#Override
public String getText(Object element) {
return "";
}
});
In the DeleteSupport class (extending EditingSupport), you have to let canEdit() return false, so the image is not selectable. But then, you can't work with getValue(). So, I do whatever I have to in canEdit() BEFORE returning false. That's the same behavior as a simple push button would have.
The DeleteSupport looks like this:
public class DeleteSupport extends EditingSupport {
private final TableViewer viewer;
public DeleteSupport(TableViewer viewer) {
super(viewer);
this.viewer = viewer;
}
#Override
protected CellEditor getCellEditor(Object element) {
return new TextCellEditor(viewer.getTable());
}
#Override
protected boolean canEdit(Object element) {
// if confirmed, try to delete the customer
if (MessageDialog.openConfirm( ApplicationRunner.getApp().getShell(),
"Confirm delete",
"Soll " + ((Customer) element).getFirstname()
+ " " + ((Customer) element).getLastname()
+ " be deleted? Cannot be undone!")) {
try {
CustomerDAO.getInstance().delete(((Customer) element).getId());
} catch (SQLException e) {
// TODO something
}
}
// reload anyways
try {
viewer.setInput(CustomerDAO.getInstance().getAll());
} catch (SQLException e) {
// TODO something else
}
viewer.refresh();
return false;
}
#Override
protected Object getValue(Object element) {
return "";
}
#Override
protected void setValue(Object element, Object value) {
}
}

Resources