I am working on a project using Synth for the UI and want to implement some custom buttons. The buttons need to make use of style settings from a synth XML settings file - e.g. font colors which are different for different states (MOUSE_OVER, PRESSED, etc).
The problem I'm stuck on is that some of the buttons need to have extra sub-components - e.g. some need more than one label. I want the sub-components to pick up the same style settings as the standard button sub-components.
I feel like I ought to be able to just extend JButton and override/extend paintComponent to call the draw methods of some child components. I'm a bit unsure about a few aspects of that approach though: e.g. what parameters to pass to paintComponent; and how to ensure the sub-components get the correct Synth style settings (particularly wrt. the states).
An aside: I have tried extending JPanel but have run into some difficulties with that approach (see here: JPanel states for Synth).
EDIT: So, I've discovered that it is possible to add sub-components to buttons and have them render correctly. It seems that even though JButton.getLayout() returns null, the button will use an OverlayLayout unless you call JButton.setLayout(). Calling JButton.setLayout(null) does prevent the OverlayLayout being used, so that's how I'm handling the layout.
I'm looking into a couple of different approaches to updating the styles for the child controls, will report back on those later.
So, in case it's of use to anyone else here's the approach I took in the end:
class CustomButton extends JButton {
CustomButton() {
// ... normal button init
// Enable absolute positioning of sub-components.
setLayout(null);
updateStyles();
getModel().addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
updateStyles();
}
});
}
private void updateStyles() {
// See below for implementation.
}
private int getSynthComponentState() {
// This is basically a copy of SynthButtonUI.getComponentState(JComponent)
int state = SynthConstants.ENABLED;
if (!isEnabled()) {
state = SynthConstants.DISABLED;
}
if (model.isPressed()) {
if (model.isArmed()) {
state = SynthConstants.PRESSED;
} else {
state = SynthConstants.MOUSE_OVER;
}
}
if (model.isRollover()) {
state |= SynthConstants.MOUSE_OVER;
}
if (model.isSelected()) {
state |= SynthConstants.SELECTED;
}
if (isFocusOwner() && isFocusPainted()) {
state |= SynthConstants.FOCUSED;
}
if (isDefaultButton()) {
state |= SynthConstants.DEFAULT;
}
return state;
}
}
I found 2 approaches to how to implement the updateStyles() method: (A) change the name of the component to use a different named style, or (B) copy the style settings from the button to the sub-components. Approach (A) is pretty straightforward, approach (B) works as follows:
private void updateStyles() {
SynthStyle ss = SynthLookAndFeel.getStyle(this, Region.BUTTON);
SynthContext sc = new SynthContext(this, Region.BUTTON, ss, getSynthComponentState());
for (Component c : getComponents()) {
c.setFont(ss.getFont(sc));
c.setBackground(ss.getColor(sc, ColorType.BACKGROUND));
c.setForeground(ss.getColor(sc, ColorType.FOREGROUND));
// ... and so on if you have other style elements to be changed.
}
}
Approach (A) is probably better if you're changing more than a couple of style settings with each different state, although it could get unwieldy if you have different styles for a lot of different states. If you're only changing a couple of style settings (e.g. in my case I only care about colours, at least for now) then approach (B) seems best.
There's also the approach suggested by trashgod of implementing a custom UI delegate (extending BasicButtonUI) but if you take that route I think you'll have to re-implement much of SynthButtonUI.
Related
I know Piccolo2d is an old project, but I have a couple of questions.
1) Is it possible to disable dragging a selected object? For this particular use case, I only want to select an object, not move or delete it. I know I can disable deletion using:
this.selector.setDeleteKeyActive(false);
But I don't see an option to disable dragging. Is the only option to override the drag functionality in the event handler?
2) Is there no way to have the selection handler active at the same time as the pan/zoom handlers? It seems a bit archaic to disable pan/zoom when you want to support object picking. Or do I have to create my own handlers?
My current code is:
...
this.pluginContext.getCanvas().setPanEventHandler(null);
this.selector = new PSelectionEventHandler(this.mapLayer.getNode(), this.mapLayer.getNode()) {
};
this.selector.setDeleteKeyActive(false);
this.pluginContext.getCanvas().addInputEventListener(this.selector);
PNotificationCenter.defaultCenter().addListener(this, "nodeSelected",
PSelectionEventHandler.SELECTION_CHANGED_NOTIFICATION, this.selector);
...
public void nodeSelected(final PNotification notification) {
logger.debug("Selection - " + this.selector.getSelection().toString());
}
In true developer tradition, I found an answer.
My pickable nodes are all grouped under individual grouping nodes. This lets me add an event listener on the grouping node, like this:
groupNode.addInputEventListener(new PBasicInputEventHandler() {
public void mouseReleased(final PInputEvent event) {
PNode node = event.getPickedNode();
if (node != null) {
onNodeSelected(node); // your logic here
}
}
});
The beauty of this is that the event contains the picked node that is grouped under that group node. Perfect! Also, you don't have to disable the pan/zoom handlers.
The only downside is that this doesn't give you the selection decorator around the node. Can't win 'em all!
I have a JPanel that have a lot of JTextFields and JComboBoxes and JRadioButtons, so i want to make them all in the default values in one shot.
I used to empty every field one by one but this take lot of time, and maybe i miss some fields, or some times i can add another fields, so it is not practice at all.
public void empty(){
field1.setText("");
field2.setText("");
field3.setText("");
...
}
So is there any way to make all the fields empty in one shot?
Thank you.
If the JTextFields are not all in the same container, this would be a possible approach:
private List<JTextField> allTextFields = new ArrayList<JTextField>();
private JTextField createNewTextField(String text) {
JTextField textField = new JTextField(text);
allTextFields.add(textField);
return textField;
}
private void resetAllTextFields(){
for (JTextField textField : allTextFields) {
textField.setText("");
}
}
..and then instead of using the constructor JTextField myTextField = new JTextField("content") use JTextField myTextField = createNewTextField("content");
Your question is a bit broad, and no one-size-fits all solution is optimal, but I can say that iterating through a JPanel's components, and clearing all is not the best solution for several reasons, including:
You may later wish to add a component that is not cleared, or that is only cleared under certain conditions, and having code that directly clears components may make this hard to debug and fix.
Most GUI's have layers of JPanels, and if later you add a sub-JPanel, does this mean that you're going to want to recursively iterate through all components and clear them?
Better is to strive to separate concerns, to reduce coupling of the model to the view, and for this reason, likely the cleanest solution is to try to separate your model from your view, à la MVC for instance, clear portions of the model that need to be clear, and in the control clear only those portions of the view bound to that section of the model.
This should work:
Component[] tmp = p.getComponents(); // p is your JPanel
for(Component c : tmp) {
if(c instanceof JTextField) {
((JTextField) c).setText("");
}
}
and you can even do different code for different component types...
The link How to clear all input fields within a JPanel i think it help me, my code should look like this :
private void clearAllFields() {
for (Component C : myPanel.getComponents()) {
if (C instanceof JTextField || C instanceof JTextArea) {
((JTextComponent) C).setText("");
}
if (C instanceof JComboBox) {
((JComboBox) C).setSelectedIndex(0);
}
if (C instanceof JRadioButton) {
((JRadioButton) C).setSelected(false);
}
if(C instanceof JDateChooser){
((JDateChooser) C).setDate(null);
}
}
}
This is more of a general question. We have a lot of wizard, some of which start a long-running process and display the result after. The question is: what is the correct way to do long calculations?
Formerly most wizards did their calculations in DialogPage#setVisible, something like that:
public void setVisible(final boolean visible) {
if (visible) {
getWizard().getContainer().run(true, true, new MyCalculation());
}
super.setVisible(visible);
}
I don't think that's a good idea, since usually getWizard() gets called a lot in these methods. Moreover, usually the parent wizard gets cast to a specific implementation to get input values from or set the result to other pages. So usually it looks something like this:
public void setVisible(final boolean visible) {
if (visible) {
Input input = ((MyCalculationWizard)getWizard()).getInputPage().getInput();
MyCalculation calculation = new MyCalculation(input);
getWizard().getContainer().run(true, true, calculation);
Output output = calculation.getOutput();
((MyCalculationWizard)getWizard()).getOtherPage().setOutput(output);
}
super.setVisible(visible);
}
Just from looking at the code you know that's very bad style.
So we replaced it with something that calculates in Wizard#getNextPage():
public IWizardPage getNextPage(final IWizardPage page) {
final IWizardPage nextPage = super.getNextPage(page);
if (nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
return nextPage;
}
That way, the wizard is able to fine-tune a lot better than a page would, and the wizard already knows it's pages and can handle input and output a lot better than a page ever could.
The drawback is: getNextPage() gets called a lot for updating the buttons and every time really the wizard feels like it. So while it works for small processes, it does not cut it for long-running ones.
After some more poking around I found the following to work while overriding Wizard#setContainer:
public void setContainer(final IWizardContainer wizardContainer) {
final IWizardContainer oldContainer = getContainer();
if (oldContainer instanceof WizardDialog)
((WizardDialog) oldContainer).removePageChangingListener(this);
super.setContainer(wizardContainer);
if (wizardContainer instanceof WizardDialog)
((WizardDialog) wizardContainer).addPageChangingListener(this);
}
public void handlePageChanging(final PageChangingEvent event) {
final IWizardPage currentPage = (IWizardPage) event.getCurrentPage();
final IWizardPage nextPage = (IWizardPage) event.getTargetPage();
if (currentPage == this.myInputPage && nextPage == this.myResultPage)
getContainer().run(true, true, new MyCalculation());
}
The big advantage here is that the listener only gets called if the wizard wants to jump between pages, and we are able to really fine-tune the calculation (e.g. to not be called when calling 'Previous'). We are even able to not show the next page after all (event.doit = false).
The drawback is the cast of the container to WizardDialog, because potentially it could be an entirely different implementation.
So the question stands: What is the best way to start long processes in wizards?
I have a mvp structured javafx application. There is a view with a textfield, which has its own textProperty of type StringProperty. There is also a model which contains an Object called Item. Item has an IntegerProperty.
Now I'd like to bind these two Properties within my presenter-class, so that they get updated, when one or another changes. Eventhough they have different types, there is the possibility to bind them the following way:
Bindings.bindBidirectional( textField.textProperty(), item.percentProperty(), new NumberStringConverter() );
This works perfectly fine, unless the value of the textfield gets cleared, which results in a NullPointerException, because an empty value of textProperty results in a Null-Value and setting a null Value in IntegerProperty results in a NullPointerException. Can you think of any way to avoid this? Do I have to write my own NumberStringConverter?
Moreover I'd like to define, that Item can only hold a percent value between 0 and 100. The View should be informed, when the value is invalid, so the user can get feedback. Where should I verify these kind of businessrules?
I came up with a first example, but I am not sure, if that should be the way to go, so I'd be curious, if you might have better ideas how to solve this.
class PercentProperty extends SimpleIntegerProperty
{
private InvalidValueListener invalidValueListener = null;
public PercentProperty ( final Integer defaultValue )
{
set( defaultValue );
}
#Override
public void set( final int newValue )
{
if ( isValid( newValue ) )
{
super.set( newValue );
if ( invalidValueListener != null )
invalidValueListener.validValue();
}
else
{
if ( invalidValueListener != null )
invalidValueListener.invalidValue();
}
}
private boolean isValid( final int value )
{
return (value >= 0 && value <= 100);//FIXME: Better use Predicates to define Rules.
}
public void setListener( final InvalidValueListener listener )
{
invalidValueListener = listener;
}
public void removeListener( #SuppressWarnings( "unused" ) final InvalidValueListener listener )
{
invalidValueListener = null;
}
protected void fireInvalidationValue()
{
invalidValueListener.invalidValue();
}
}
interface InvalidValueListener
{
void validValue();
void invalidValue();
}
JavaFX is a simple graphical toolkit, not a comprehensive framework, and this means that lots of things you have to engineer yourself. Data validation is such a thing, and you have to find your own way among your previous experience and others' suggestions.
I would not bind the two properties: the text field should be initialized (just set, not bound, to avoid glitches while the user is typing without her explicit consensus) with the value from the model, and then the integer property should be updated by a listener (a text field's ChangeListener or a listener to the form submission, if appliable and depending on your likes), which is responsible for validating input and reporting errors to the user.
This way you decouple two things that are indeed unrelated: one is a widget for accepting user input (a text you need to parse to get a number), and the other is a number in your model, which is used to make a computation.
As a side note, I would not use two properties altogether, and I'd revisit your three tiers parition. MVP and all MVC derivatives proved to be good patterns to build GUI toolkits, but I was never convinced they were equally good for structuring GUI applications. I mean, if what you call model is a way to share session data between different parts of the application (kind of an events sink) then it's a perfectly legitimate implementation, otherwise I see no use in having a separate bunch of properties grouped in a class. In the latter case, the widgets themselves are the model:
// This is the controller
public class PesonalDetails {
// Model starts here: it's implicitely defined by the widgets
// You may also use #FXML
private final TextField first = new TextField();
private final TextField last = new TextField();
// Model ends here
}
Note I'm not saying MVC should be thrown away and everything should be collapsed in one single file. Just that MVC, MVP, MVVM are design patterns and it's up to you to decide when, where and how to implement them - depending on how much they buy to you. With JavaFX I like to use these tiers:
A visual layout tier (a layout builder implemented in Java or FXML)
Event handling code
If appliable, a data access layer (and you can apply a pattern here, like ActiveRecord)
(The new version of the answer)
I think the best aproach is to not let a user enter an incorrect value in the first place. You can achive this easily with help of JideFX Fields:
FormattedTextField<Integer> field = new FormattedTextField<>();
field.getPatternVerifiers().put("p", new IntegerRangePatternVerifier(0, 100));
field.setPattern("p");
field.valueProperty().bindBidirectional(item.percentProperty());
Particularly FormattedTextField is very convenient because it do text-to-value conversion and validation for you, so there is no need to implement any utility classes yourself.
Links:
JideFX Fields Developer Guide: http://www.jidesoft.com/jidefx/JideFX_Fields_Developer_Guide.pdf
Source code: https://github.com/jidesoft/jidefx-oss
Binary: http://search.maven.org/#search%7Cga%7C1%7Cjidefx
I often implement some panels, which provide common functionality like controls. For this I want to be able to add listeners, so that the caller can attach to the control and get notifications about changes.
So far I have simply used my own List where I keep the listeners and when I want to fire an action I loop through the list and call the listeners. From the outside this basically looks like any other Swing controls, however I was wondering if this is really the approach which should be used.
Especcially I was wondering if calling the listeners in a loop is what Swing itself also does, or if there is some kind of queue where you would put the actions, so that Swing decides when to deliver such actions.
When I investiaged this I came across this code:
protected void fireActionPerformed(ActionEvent event)
{
Object[] listeners = listenerList.getListenerList();
ActionEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length-2; i>=0; i-=2)
{
if(listeners[i] instanceof ActionListener)
{
// Lazily create the event:
if (e == null)
{
String actionCommand = event.getActionCommand();
e = new ActionEvent(this,
ActionEvent.ACTION_PERFORMED,
actionCommand,
event.getWhen(),
event.getModifiers());
e.setSource(event.getSource());
}
((ActionListener)listeners[i+1]).actionPerformed(e);
}
}
}
The member listenerList from JComponent is directly accessed, whcih feels a bit strange. However I didn't really find a better way so far. Also when adding a new listener to this, I do it now like shown below, but I'm not sure if this is really the appropriate way:
public void addQueryListener(ActionListener oListener)
{
listenerList.add(ActionListener.class, oListener);
}
public void removeQueryListener(ActionListener oListener)
{
listenerList.remove(ActionListener.class, oListener);
}
So I would like to know, is accessing the listenerList member the correct way to add and remove listeners, so that they behave like any other standard control? Or is there some best practice how this should be done, which I'm missing so far?
Keeping mind the restriction Swings put for Creating the gui. There is no harm accessing the
** listenerlist ** this way. May be this is not best approach.
Swing is Suppose to be Single Threaded and is not Thread Safe.
http://codeidol.com/java/java-concurrency/GUI-Applications/Why-are-GUIs-Single-threaded/
AddListener and RemoveListener needed to be called on EDT(Event Dispatch Thread)
see See http://en.wikipedia.org/wiki/Event_dispatching_thread.
Also See for iteration of Listenere i.e when you call getActionListeners
its creates a copy of ListenersList and returns you back
Below Code from EventListenerList
public <T extends EventListener> T[] getListeners(Class<T> t) {
Object[] lList = listenerList;
int n = getListenerCount(lList, t);
T[] result = (T[])Array.newInstance(t, n);
int j = 0;
for (int i = lList.length-2; i>=0; i-=2) {
if (lList[i] == t) {
result[j++] = (T)lList[i+1];
}
}
return result;
}
There's a good example in the EventListenerList docs, and this Converter example uses its own listenerList in ConverterRangeModel.