Archives for category: Controls

One of the big features I’ve known people have wanted for a long time (hey, I’ve wanted it too!) is support for returning a TableView back to its original, unsorted state after being sorted by the end user. In general the user interaction goes something like this:

  1. Click on a TableView column header once. Everything sorts in ascending order. Great!
  2. Click on the same column header again. Everything sorts in descending order. We’re on a roll here!
  3. Click on the same column again. The sort arrow disappears, and…….nothing :-(

Of course, what should happen here is that the order of the items in the table should be reset back to their original order, from before the user ever clicked on anything. If you step behind the curtains with me for the briefest of moments, you’ll realise that the only way we can really do this is to of course keep a copy of the list in its original state (or a list of all the changes to the original list, such that we can unwind the changes later on). I never really wanted to do this, as you’re just setting yourself up for failure / pain / bugs / etc. What I always wanted to do was follow the wonderful GlazedLists approach from the Swing days, where the collections themselves became smarter, and the TableView remained mostly* inconsiderate of the type of collection given to it.
(more…)

We have been working really hard on the new Modena theme for JavaFX 8. I think we are finally really close so I wanted to share with you where we got to. I really hope you like the progress and direction. We took a lot of the feedback from the last blog into consideration. Overall though I am really happy and feel that this is going to do as much as we can to make JavaFX applications look great out of the box.

Modena example windows

Retina Mac
For those lucky enough to be running on Retina Mac then we also have support for Retina now in JavaFX 8 and with Modena so enjoy.
retina-pic

Trying for your self
The almost final version of Modena will be available this week in Java 8 Early Access build 81. For instructions for enabling Modena and running the test application see the first Modena blog post.

(more…)

We have been working recently on a new theme for JavaFX 8. The current theme for FX, named Caspian, is showing its age and we wanted to take the opportunity to give JavaFX a face lift for 8. Because folks have created custom controls and designs for their app, we needed to make sure that selecting the theme was something that you could opt-out of. We will be providing both API and command line switches in 8 to allow you to specify caspian specifically. If you do nothing, you’ll get Modena, our new theme, by default. Without further ado this is what it looks like:

Modena-Windows
(more…)

Update: since announcing the JavaFX UI controls sandbox I have announced the ControlsFX project, which is a more convenient way to get access to a number of controls that do not ship with JavaFX. Check out the ControlsFX website for more information.

This is something I’ve been waiting a really, really, really long time to announce, but it has finally happened. Today I am so pleased to announce the opening of the JavaFX UI controls sandbox repository on OpenJFX. This repo is a fork of the JavaFX 8.0 controls repo, but will occasionally sync from there to keep it up to date. This repo is intended for OpenJFX developers to put their ‘toys’ until such time that they get called up to the big leagues for inclusion into OpenJFX itself (although there are no guarantees that this will ever happen). This means that the controls are functional, but most probably not feature complete with a finalised API or any significant documentation.

The reason why I’ve been wanting to open this sandbox up is so that members of the JavaFX community can get super early access to our controls as soon as they reach the most minimal level of maturity, and help guide them along their paths to adulthood. I also wanted to do this as it takes a long time between developing a UI control and having it appear in a JavaFX release. This is something that has frustrated me, and a number of you, to no end.

From the get-go there are a few controls in this repo that you may be interested to play with and give us feedback on. They are TreeTableView (although note this is currently undergoing a total rewrite), Dialogs (ala JOptionPane from Swing), TableView cell span support (look at TableView.spanModel for more info), and a RangeSlider control. These controls will develop over time, but of course we’re always on the lookout for others who want to improve these controls for us. If you’re interested specifically in tending to the new controls in the sandbox, please email me and we can discuss it.

(more…)

Now that JavaOne is over and everyone finally has a chance to exhale, it’s time to start blogging about all the stuff we talked about. For my part, I’m hoping to blog about a bunch of stuff that I covered in my two sessions (primarily TableView cell spanning, RangeSlider, Rating, SegmentedButton and whatever else I can find on my machine). For today, lets talk about adding cell spanning support to TableView. Just a quick pro tip: for those of you who just want a jar and don’t care about how cell spanning was developed, you might want to skip to the end of this post…

So, I need to start this post as per usual – this is not a product of Oracle – there is no support contract or guarantee that this code won’t format your hard drive or do something equally nefarious. Please act responsibly for your personal circumstances. Finally, if you do find something wrong (API, documentation, bug, etc), please email me and lets improve it!

With that out of the way, what exactly is cell spanning (and how does it differ from cell merging)? My understanding (and correct me if I’m wrong) is that cell spanning is when the cell at the ‘spanned index’ takes over the full area of the span, whereas in cell merging you essentially take the content of all cells in the span area and merge them into a single cell taking up the area. In other words, the cell will be the same size regardless of whether spanning or merging is used, and it is simply a question of where does the data come from in either case. My preference is cell spanning over cell merging, so that is what I’ve implemented in this blog post.

To make things even clearer, I guess I should clarify what I mean by the ‘spanned index’. What I mean is that, essentially, we continue to layout our TableView in the same way as we always do (TableRow by TableRow (top to bottom), with each TableRow laying out each TableCell within it (left to right)). As we’re doing this layout, we are basically doing what I show in the code fragment below (although I should note this is pseudocode – things are somewhat more complex internally). The ‘spanned index’ is basically the combination of row/column index as we do the layout. In other words, the value in a spanned cell is the row/column index at the ‘top-left’ of the spanned cell area. This means that all other values that are in row/column indices that are overlapped due to a span will be lost. Here’s the pseudocode:

for (int row = 0; row < maxRows; row++) {
    // start laying out a new TableRow.
    // We do this by laying out each column in the row.
    for (int column = 0; column < maxColumns; column++) {
        // laying out each column
    }
}

Now we’ve covered a bit of theory, I guess we better cover what exactly the end result is. Here’s a few screenshots below – click on them for the full-sized version.


               

Please excuse the actual data used in the screenshots – I paid precisely zero minutes preparing the demo data – I just used what I had on hand. Clearly what I am doing in the demo data makes no sense for cell spanning – please use your imagination (and ideally send me a better sample data set to use for improved screenshots). :-)

To support cell spanning support, the first new class is the CellSpanTableView. It simply extends TableView and adds support for a SpanModel. SpanModel is defined as such:

public interface SpanModel {
    // cell spanning is only run when isCellSpanEnabled() returns true.
    public boolean isCellSpanEnabled();

    // Returns the CellSpan for the given row/column index.
    public CellSpan getCellSpanAt(int rowIndex, int columnIndex);
}

The CellSpan class is (presently) quite simple, it is a final class with two immutable fields representing the amount of spanning that should occur in the horizontal and vertical directions. I should note that a rowSpan (or columnSpan) of one simply means that there is no spanning of multiple rows / columns – it is just the default layout. Here it is in its full glory:

public final class CellSpan {
    private final int rowSpan;
    private final int columnSpan;

    public CellSpan(int rowSpan, int columnSpan) {
        this.rowSpan = rowSpan;
        this.columnSpan = columnSpan;
    }

    public int getRowSpan() {
        return rowSpan;
    }

    public int getColumnSpan() {
        return columnSpan;
    }
}

Therefore, with this API you should do something like the following when creating your own CellSpanTableView instance:

CellSpanTableView cellSpanTableView = ...;

cellSpanTableView.setSpanModel(new SpanModel() {
    private final CellSpan spanTwoRows = new CellSpan(2, 1);

    @Override public CellSpan getCellSpanAt(int rowIndex, int columnIndex) {
        return rowIndex % 3 == 0 && columnIndex == 1 ? spanTwoRows : null;
    }

    @Override public boolean isCellSpanEnabled() {
        return true;
    }
});

Note that all the magic happens in the getCellSpanAt method – for the given row / column indices, you need to tell the SpanModel what the cell span is. If you return null, you are saying there is no spanning required. In the code above, we span two rows whenever the row index is cleanly divisible by three, and we’re looking at the ‘first’ column. This gets you the result shown in the first screenshot above. I have already heard some requests to improve this API – if you have any strong feelings please let me know!

To achieve the new layout, there is a small number of code changes that need to go into the backend of TableView. Because this post is already quite long I won’t bother to talk about that here – if people are interested I will do another post. Needless to say, the code is included in the links below, but it is definitely a proof of concept, not a final implementation!

Another important point to make is that you should definitely join the cell spanning discussion on Jira at RT-24747 – this is where I would appreciate people post feedback on the API. I already know there are a few things to improve (particularly related to what should be passed to the user in the CellSpan.getCellSpanAt(…) method).

Ok, with all that covered, you can download a zip file that contains both the source and a precompiled jar file. Note that these will only work with the JavaFX 8.0 developer preview releases – they use API that is not available in JavaFX 2.2. It is trivial enough to backport though, and if someone does I will happily host the source code and jar file here.

In summary – lets get the discussion around cell spanning started! I look forward to your comments :-)

One question I see occasionally is people asking how to go about using prebuilt cell factories (such as those provided in the DataFX project run by Johan Vos and I, those sitting in the OpenJFX 2.2 repo in the javafx.scene.control.cell package, or just those that they have created internally), and also show a context menu when the user right clicks. More generally, the problem is that cell factories are blackboxes, and there is no support for chaining cell factories together (or even getting hold of the cells as they are being used).

The answer is quite simple: wrap the cell factory inside another cell factory, and set the ContextMenu on the wrapping cell. In other words, you would write code such as this (for ListView):

// The cell factory you actually want to use to render the cell
Callback<ListView<T>, ListCell<T> wrappedCellFactory = ...; 

// The wrapping cell factory that will set the context menu onto the wrapped cell
Callback<ListView<T>, ListCell<T> cellFactory = new Callback<ListView<T>, ListCell<T>>() {
    @Override public ListCell<T> call(ListView<T> listView) {
        ListCell<T> cell = wrappedCellFactory  == null ? new DefaultListCell<T>() : wrappedCellFactory.call(listView);
        cell.setContextMenu(contextMenu);
        return cell;
    }
};

// Creating a ListView and setting the cell factory on it
ListView<T> listView = new ListView<T>();
listView.setCellFactory(cellFactory);

(more…)

One of the missing features of JavaFX in the 2.0 release was a ComboBox control, and I’m very pleased to say that we’ll be filling this gap in JavaFX 2.1. Indeed, it is already in the developer preview builds we’re putting out, and has been sitting in the OpenJFX mercurial repo for some weeks now. I’m fortunate enough to even be getting bug reports filed in our Jira issue tracker, which is justification enough to be getting early developer preview releases out into your hands as early as we have!

Non-editable and editable ComboBox controls of all shapes and sizes!

(more…)

One of Jasper’s favorite websites is called Dribbble, which is a place for designers to post whatever work they’re currently working on for others to view and be inspired from. I got hooked on Dribbble last Thursday and have been looking at a bunch of the mockups and itching to try implementing some of them in JavaFX. Here is my first attempt.

One of the use cases we used for our CSS support and our ToolBar API was that we wanted to support a style of toolbar button which (at least for me) was popularized on the Mac, which is referred to by Cocoa as a “segmented” button. This is essentially nothing more than an HBox of buttons that has been styled such that the first button has rounded left edges, the center buttons are squared up, and the last button has rounded right edges. In the image above by Bady, you can see the segmented button bar in the toolbar area of the application.
(more…)

I started writing an article about how to write new UI controls for OpenJFX using all the internal APIs and architecture and so forth. But then I discovered that the control I was writing as a proof of concept was not using any private API at all, and actually was implementing the Skin differently than I had imagined previously, and I thought I ought to blog about it. Behold, the MoneyField!

(more…)

I was inspired by Dean Iverson’s tweet with a audio equalizer in JavaFX:

#JavaFX rocks. Literally. An example from our upcoming Pro JavaFX 2 book: pic.twitter.com/tSI4Vry4
and the equalizer view from that Pro JavaFX 2 example app: pic.twitter.com/T6jxvrf9
. updated pic.twitter.com/FqzgVimG

So wanted to have a go at doing one my self, so little while later I have a design and built a working application. Demo video after the break.

(more…)