Показаны сообщения с ярлыком javafx. Показать все сообщения
Показаны сообщения с ярлыком javafx. Показать все сообщения

пятница, 27 августа 2010 г.

ListView Multiple Selection 2

After reading the post about ListView Multiple Selection I started integrating a new ListView it into my project, but in few minutes I figured out that there were no normal key multiple selection support. So, I decided to fix this problem.

The problem

At first I was thinking about overriding callActionForEvent(e:KeyEvent):Void method in com.sun.javafx.scene.control.behavior.ListViewBehavior, but I've found out that it's not so simple. After applying a new behavior for a ListView in ListViewSkin like this:
class ListSkin extends ListViewSkin {
     override var behavior = ListBehavior{}
     ...
}
The ListView stops scrolling up/down if I use keys for navigation. I was thinking about putting some parameters in ListBehavior, but still no luck.

Workaround

As for workaround you'll need to put some extra code in MultiSelectListView class
override var onKeyPressed = function(e:KeyEvent):Void {
if ((e.code == KeyCode.VK_UP) or (e.code == KeyCode.VK_DOWN)
        or (e.code == KeyCode.VK_PAGE_DOWN) or (e.code == KeyCode.VK_PAGE_UP)
        or (e.code == KeyCode.VK_HOME) or (e.code == KeyCode.VK_END)) {
        if (not e.controlDown and not e.shiftDown) {
           delete selectedIndexes;
        }            
    }
    if (e.controlDown and e.code == KeyCode.VK_SPACE) {
        def index:Integer = (e.node as List).focusedIndex;
        if (-1 == Sequences.indexOf(selectedIndexes, index)) {
            insert index into selectedIndexes;
        } else {
            delete index from selectedIndexes;
            if (index == selectedIndex) select(selectedIndexes[0]);
        }
    }
}

As a result

  • So, now you are able to use Ctrl+Space to add new selected items or remove old items from selection.
  • If you use keys such as: HOME, END, PAGE_UP, PAGE_DOWN, UP or DOWN without holding a Ctrl button multiple selection will be lost(I think it's user expected behavior :) )
  • I didn't do anything with Shift key. So, it does nothing.

Small fix

The ListView by Jonathan Giles has a small bug, it's also about using keys for selecting items. In MultiSelectListCellBehavior class, he has a case for deselecting all previously selected items.
public class MultiSelectListCellBehavior extends ListCellBehavior {
    ...
    override function mouseReleased(e) {
       ...
       } else {
           delete listView.selectedIndexes;
           insert row into listView.selectedIndexes;
           listView.focus(row);
       }
    }
}
As you can see in the end he used listView.focus(row); for selecting an item, but this stuff wont wok correctly. If you made some selection with the help of keys you'll get at least two selected items. So, I think it's better to use listView.select(row); instead.

Have a nice code :)

понедельник, 23 августа 2010 г.

Creating Pseudo-class in JavaFx (TabPanel control)

Before reading this article I suggest to read Advanced JavaFX Control Styling by Dean Iverson.
After JavaFx 1.3 has been published we've got a new bunch of controls and a new way to produce our own ones and, of course, don't forget about new CSS support in this release. So, today I'm going to show you how to create your own JavaFx controls with CSS support.

Specification

Currently there are no tabs in JavaFx, and that's a good reason to start having them :). At the end I expect to get such a result:

Specification itself:

  • TabPanel has TabButtons
  • You are able to select only one TabButton in TabPanel
  • You are able to set styles for TabButtons and TabPanel
  • TabButtons can be aligned inside TabPanel
  • TabButtons can fit TabPanel by width, height or both
  • TabPanel can set common width or height for TabButtons

Implementation

I'm not going to explain all the code, but I'll stop in most interesting parts:

Creating your own pseudo-class

Each TabButton should have a status selected in order to display the button as selected and not to perform a click action on it.
public class TabButton extends ButtonBase, Labeled {
    
    override var skin = SkinAdapter {
        rootRegion:ButtonSkin{}
    }

    public var selected:Boolean = false on replace {
        impl_pseudoClassStateChanged("selected");
    }

    override function impl_getPseudoClassState():String[] {
        return [
            if (selected) "selected" else null,
            super.impl_getPseudoClassState()
        ]
    }
}
This is just a piece of the TabButton class. As you can see, I use two functions impl_pseudoClassStateChanged and impl_getPseudoClassState that will help me to organize my pseudo-class &quote;selected&quote; for this control.
Now let's take a look at the CSS file:
.tab-button {
    -fx-padding: 3 10 2 10;
    -fx-background-color: -fx-shadow-highlight-color, -fx-outer-border, -fx-inner-border, -fx-body-color;
    -fx-background-radius: 10 10 0 0;
    -fx-background-insets: 0 0 -1 0, 0, 1, 2;
    -fx-border-radius: 10 10 0 0;
    -fx-border-color: -fx-outer-border, -fx-inner-border;
    -fx-border-style: solid;
    -fx-text-fill: -fx-text-base-color;
    -fx-vpos: CENTER;
    -fx-graphic-vpos: CENTER;
}

.tab-button:hover {
    -fx-color: -fx-hover-base;
}

.tab-button:selected {
    -fx-color: -fx-pressed-base;
}
Please pay attention, that now I can use keyword selected as a name of the new pseudo-class for my control. Also I can use standard pseudo-classes of Button and Labeled controls cause I invoke a super.impl_getPseudoClassState() highlighted on line 14.
Now look at line 4, in order not to write my own Skin class, for this control, I'm using an existing one.

Source

To download a full source code press here

Have a nice code :)

четверг, 24 июня 2010 г.

Binding Java model in JavaFx

All this time I was looking for a good solution of binding java model class to javafx UI. There are some articles about that and the most interesting, on my mind, is on Mike's Blog, but it's seams like a lot of code to write and some of the examples are not working at all. There are also some frameworks for binding through aspects, but still it wasn't the way I want it to be.
So, I think I found a nice solution, that is really easy to implement and to use.


Making interfaces

Let's make an interface for our future model. No rocket-science just getters and setters.

public interface TextModel {
     public void setText(String text);
     public String getText();
}

Creating a JavaFx model

There are some restrictions for using binding in javafx. One of them is that you can't pass a method in bind. for example:

Label {
    text:bind model.getText() // wont work
}

For this reason we are going to create a javafx class, that implements our new interface and has a public field. It will helps us to use all the good binding stuff of javafx. After all we going to have a class that has a javafx property, that can be changed directly form java

public class JFxTextModel extends TextModel {
     public var text:String;
     public void setText(String text) {
         this.text = text;
     }
     public String getText() {
         return this.text;
     }
}

For newbies in JavaFx, there is no implements option for implementing interfaces, we use extends

Now we can move all our business login on Java side and leave only views and model as a bridge on JavaFx side

def model:JFxTextModel = JFxTextModel{};
Label {
    text:bind model.text
}

P.S.

It's really useful to have getters in interfaces, cause you can retrieve data on Java side, leaving javafx only for displaying and effect.

Have a nice code :)