I have a processing sketch which includes a slider. The code that generates this slider is below:
ControlP5 gui;
gui = new ControlP5(this);
gui.addSlider("Tolerance").setPosition(40, height-60).setSize(400, 20).setRange(0.00, 0.10).setValue(0.05).setNumberOfTickMarks(11).setSliderMode(Slider.FLEXIBLE);
gui.getController("Tolerance").getValueLabel().align(ControlP5.RIGHT, ControlP5.TOP_OUTSIDE).setPaddingX(0).setFont(font);
gui.getController("Tolerance").setCaptionLabel("Comparison Tolerance");
gui.getController("Tolerance").getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE).setPaddingX(0).setFont(font);
The problem I have is that the value 0.08 is displayed when the slider is at both the 0.08 TickMark and the 0.09 TickMark. 0.09 is the only value which displays incorrectly - see the below pictures:
The slider is actually selecting the correct value of 0.09 in the third image above, when the position of the slider is printed to the console, but this display error is confusing and not ideal. Any help would be much appreciated.
UPDATE: I have since discovered that the value displayed to the top right of the slider is always rounded down. When outputting the slider value to the console, the values are usually minutely different to what is intended - i.e. at the center position, the actual slider value printed to the console is 0.0500003. From looking at the true value for each slider position, the 0.09 position is the only one with a value under the intended value - 0.0899996. Therefore, it appears this is rounded down to 0.08 to display the value. So the question still stands - is there a way to display the correct value of 0.09, given this information?
Well spotted! Perhaps you should post an issue for the developer.
In the meantime, what you can do is subclass the Slider class and use Java's DecimalFormat class to fix the label:
import java.text.DecimalFormat;
import controlP5.*;
ControlP5 gui;
void setup(){
size(640,480);
gui = new ControlP5(this);
CustomSlider slider = new CustomSlider(gui,"Tolerance");
slider.setPosition(40, height-60).setSize(400, 20).setRange(0.00, 0.10).setValue(0.05);
slider.setFont(createFont("Verdana",12));
slider.setNumberOfTickMarks(11).setSliderMode(Slider.FLEXIBLE);
slider.getValueLabel().align(ControlP5.RIGHT, ControlP5.TOP_OUTSIDE).setPaddingX(0);
slider.setCaptionLabel("Comparison Tolerance");
slider.getCaptionLabel().align(ControlP5.LEFT, ControlP5.TOP_OUTSIDE).setPaddingX(0);
}
void draw(){
background(0);
}
//subclass slider
public class CustomSlider extends Slider{
//decimal format reference
DecimalFormat df;
//constructor
public CustomSlider( ControlP5 cp5 , String name ) {
super(cp5,name);
//setup decimal format proof of concept - hardcoded fractional digits for now (this can be nicer)
df = new DecimalFormat();
df.setMaximumFractionDigits(2);
}
#Override public Slider setValue( float theValue ) {
super.setValue(theValue);
//this can be improved, follow the CP5 component lifecycle to determine when an instance initialised in the constructor is ready
if(df != null){
_myValueLabel.set( df.format(getValue( )));
}else{
_myValueLabel.set( getValue( ) +"" );
}
return this;
}
}
Related
I have a quite complex scene graph which has led me to some resizing problems. I'd be glad if you could help me solve it.
My root node is a BorderPane that its center is filled with a ListView. Each cell of the ListView is filled with a customized zoomable ScrollPane as below:
public class ZoomableScrollPane extends ScrollPane {
Group zoomGroup;
Scale scaleTransform;
LineChart<Number , Number> content;
double scaleValue = 1.0;
double delta = 0.1;
public ZoomableScrollPane(LineChart<Number , Number> content, double height) {
this.content = content;
this.setPrefHeight(height);
Group contentGroup = new Group();
zoomGroup = new Group();
contentGroup.getChildren().add(zoomGroup);
zoomGroup.getChildren().add(content);
setContent(contentGroup);
scaleTransform = new Scale(scaleValue, scaleValue, 0, 0);
zoomGroup.getTransforms().add(scaleTransform);
}
}
As you can see there is a LineChart inside of each ZoomableScrollPane. I want to do two things with this chart. Firstly, to somehow bind its width with the root layout to get the desired result in case of resizing the window (not zooming, zooming is OK), and secondly to change the chart's width at run time whenever a button is pressed:
public void handleButton(ActionEvent actionEvent) {
MainController.lineChart1.setPrefWidth(MainController.lineChart1.getPrefWidth() + CONSTANT);
}
The problem is that here I face a conflict. Cause the LineChart is the child of a Group (not a pane), I just know one way of resizability and that is to bind its width manually with the root BorderPane's like this:
MainController.lineChart1.prefWidthProperty().bind(fourChannels.widthProperty().subtract(40));
And in that case, I cannot change the LineChart's width at run time and will get A bound value cannot be set Exception.
I guess one solution could be revising the ZoomableScrollPane class to somehow avoid the need of manual binding, but really have no idea how to do it.
Any help on this would be greatly appreciated.
You can detect if a property is bound and then unbind it before manipulating it:
if (content.prefWidthProperty().isBound()) {
content.prefWidthProperty().unbind();
}
...
Presumably when you are zoomed in on a chart and the window is resized the content will already be larger than the viewport, so a forced change in width shouldn't kick in until the window is resized beyond the zoomed in size of the chart?
Given the different conditions you have you might be better off monitoring the size of the BorderPane/ListView and when that changes adjust the size of the charts that need it.
I have created a Scene with ILNumerics that consists of 3 PlotCubes and a Colorbar.
Screenshot of the ILPanel
I wanted to add a method that exports the scene as an image in two ways, the first being the screenshot you see above.
The second export is supposed to only show the centric cube.
I attempted to follow the guidelines of ILNumerics for scene management.
I wrote the following code:
public void ExportAsImage(int resolutionWidth, int resolutionHeight, string path, bool includeSubCubes)
{
using (ILScope.Enter())
{
ILGDIDriver backgroundDriver = new ILGDIDriver(resolutionWidth, resolutionHeight, ilPanel1.Scene);
if (includeSubCubes)
{
// code for standard export here
}
else
{
// setting left and top cube and color bar invisible and
// adjusting main cube size is affecting the ilPanel.Scene
backgroundDriver.Scene.First<ILColorbar>().Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _leftCubeTag).Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _topCubeTag).Visible = false;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _mainCubeTag).ScreenRect = new RectangleF(0, 0, 1, 1);
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _mainCubeTag).DataScreenRect = new RectangleF.Empty;
backgroundDriver.Scene.Configure();
backgroundDriver.Render();
// save image
backgroundDriver.BackBuffer.Bitmap.Save(path,System.Drawing.Imaging.ImageFormat.Png);
// revert changes done to cubes and color bar
backgroundDriver.Scene.First<ILColorbar>().Visible = true;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _leftCubeTag).Visible = true;
GetElementByTag<ILPlotCube>(backgroundDriver.Scene, _topCubeTag).Visible = true;
AdjustCubeSizes();
}
}
}
Note: "GetElementByTag" is an own implementation to retrieve objects in the ILNumerics Scene.
I first expected that the new driver basically creates a copy of the Scene I can work on, but like the code shows I have to revert all changed after the export or the displayed ilPanel only shows the scene the way I exported it.
Is it possible at all to do export to image without affecting the real Scene? Am I just missing some details?
Regards,
Florian S.
Florian, it does make a copy. But you need to add the interesting part to a new scene. The magic is happening in the Add() method:
var scene4render = new ILScene();
scene4render.Add(oldScene.First<ILPlotCube>(mytag));
// ... configure scene4render here, it will be detached from the original scene
// with the exception of shared buffers.
// ... proceed with rendering
In order to also include + render interactive state changes to the original plot cube (let's say rotations by the users mouse) you'd use something like that:
scene4render.Add(panel.SceneSyncRoot.First<ILPlotCube>(mytag));
Also, I wonder what GetElementByTag does better than ILGroup.First<T>(tag, predicate) or ILGroup.Find<T>(...)?
See also: http://ilnumerics.net/scene-management.html
I am having issues collapsing a ControlP5 DropdownList object.
I select the item that I want, the arrow points up as if it wanted to collapse....but all of the choices are still there! It never collapses after a selection is made.
I have looked at the isOpen() function and it is telling me that the list is closed. I have also explored the isCollapse() function and it is telling me that the list is already collapsed......
Here is my code for instantiating the object:
SimilarityChoices = P5Controller.addDropdownList("SimChoices").setPosition((float)(width * .7), 450);
SimilarityChoices.addItem("Euclidian", 1);
SimilarityChoices.addItem("Manhattan", 2);
SimilarityChoices.setValue(2);
this.SimilarityChoices.enableCollapse();
this.SimilarityChoices.setItemHeight(20);
this.SimilarityChoices.actAsPulldownMenu(true);
If anybody can give me a hint on how to make this work, I'd be much obliged. (And I'm happy to supply more information as well)
You'll notice that the dropdownlist example sketch includes this:
void draw() {
background(128);
}
which draws over the pixels previously rendered while the list was expanded. I wrote a sketch using your code to illustrate the difference more clearly:
import controlP5.*;
ControlP5 P5Controller;
DropdownList SimilarityChoices;
void setup() {
size(500, 500);
P5Controller = new ControlP5(this);
SimilarityChoices = P5Controller.addDropdownList("SimChoices").setPosition((float)(width * .7), 450);
SimilarityChoices.addItem("Euclidian", 1);
SimilarityChoices.addItem("Manhattan", 2);
SimilarityChoices.setValue(2);
this.SimilarityChoices.enableCollapse();
this.SimilarityChoices.setItemHeight(20);
this.SimilarityChoices.actAsPulldownMenu(true);
}
void draw() {
//background(128);
}
Uncommenting the background(128); line makes it behave as expected. I hope that helps! Note that some of the settings you coded in may no longer be necessary.
I have a LWUIT form which contains a list, a number of items has been added to the list, items themselves are strings (I want to make them as statements).
returns
My simple problem is that end user cannot see the whole statements(strings). I tried the below method but the scrolling won't move.
All of form.setScrollableY(true), form.setScrollabelX(true), and form.setScrollable(true).
This is the code
import javax.microedition.midlet.*;
import com.sun.lwuit.layouts.*;
import com.sun.lwuit.*;
public class HelloLWUITMidlet3 extends MIDlet
{
public void startApp()
{
com.sun.lwuit.Display.init(this);
final com.sun.lwuit.Form form = new com.sun.lwuit.Form("");
final com.sun.lwuit.List l = new com.sun.lwuit.List();
l.addItem("MY favourite Science is computer Sciences");
l.addItem("MY favourite computer Science subject is programming");
l.addItem("MY favourite programming language is java ");
form.setScrollableY(true);
form.setScrollableX(true);
form.addComponent(l);
form.show( );
}
public void pauseApp()
{
}
public void destroyApp(boolean unconditional)
{
}
}
First of all, scrolling horizontally back and forth to read content is
really bad UX. This answer will solve only the vertical scrolling issue.
The problem with your code is that you are adding a scrollable (List)
inside another scrollable
(Form). This leads to unexpected results, since it is
not clear which component should handle scrolling. This can be fixed by
using the BorderLayout in the form and placing the list at the center.
...
form.setScrollable(false);
form.setLayout(new BorderLayout());
form.addComponent(BorderLayout.CENTER, l);
...
This will enable vertical scrolling, but the horizontal scrolling will not
work.
Clarification about scrolling:
LWUIT's approach
to scrolling is based on Focus, which means that a Container scrolls
because the focused element is out of the screen. This has the consequence
that LWUIT does not support scrolling elements bigger than the screen and, thus,
that your List will not be scrollable horizontally. (Source:LWUIT mini FAQ )
Suggestion:
The maximum element height is taken as the component height in a List. This
makes the List component adequate to show data that is "pre-formatted" in
a specific way, like contact lists of a folder's details list. If you
want to stack pieces of text of variable length, you should
use a Form with BoxLayoutY and put your text in various TextAreas.
void startApp() {
Display.init()
final Form form = new Form("Title");
addItem(form, "String..");
// as many times as you like
addItem(form, "String..");
form.setLayout(new BoxLayout(BoxLayout.Y_AXIS));
form.setScrollableY(true);
form.show()
}
void addItem(Form f, String s) {
TextArea t = new TextArea(s);
t.setGrowByContent(true);
f.addComponent(t);
}
i would like to design a component that look like a switch that has 3 position. One neutral position, and upper switch position, when the user click on the upper half of the component and a lower switch position, when the user click the lower half of the component. When the mouse is released the switch go back to neutral position. I have got 3 switch images for these position. I was thinking using a Button then check if the mouse click coordinate is in the upper half or the lower half then set images accordingly. I am looking for any better suggestion, if possible with the use of css for the images (i don't know if it is possible though), or any other suggestion with the use of another component if it is more suitable. Thank you.
Here is what i did, it works...
final Button rstButton = new Button();
final Image rstNeutral = new Image(MyClass.class.getResourceAsStream("images/switch_neutral.png"));
final Image rstUp = new Image(MyClass.class.getResourceAsStream("images/switch_on.png"));
final Image rstDown = new Image(MyClass.class.getResourceAsStream("images/switch_off.png"));
final ImageView rstImage = new ImageView();
rstImage.setImage(rstNeutral);
rstButton.setGraphic(rstImage);
rstButton.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent me) {
double mouseY = me.getY();
double buttonY = rstButton.getLayoutY();
double buttonHeight = rstButton.getHeight();
if(buttonY + mouseY > buttonY + (buttonHeight / 2)) {
rstImage.setImage(rstDown);
} else {
rstImage.setImage(rstUp);
}
}
});
rstButton.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent arg0) {
rstImage.setImage(rstNeutral);
}
});
I think you should use three component instead of one.
For exemple, you could use three instance of ToogleButton. This component is like a button in appearance, but have a toogle state (clicked/unclicked). I never use it in javaFX but I think you will find enough help on the oracle site (for example : http://docs.oracle.com/javafx/2/ui_controls/toggle-button.htm)
EDIT :
After comment, I think an image of a mechanical switch (http://docs.oracle.com/javafx/2/api/javafx/scene/image/Image.html) could be the solution. If you're showing the switch from the side you can change the rotation of the image according to the state of the switch.
For knowing where the user clicked, locating the position of the button could work.
Another solution could be to had three transparent region on top of the image and intercept the click event on these region, instead of the image. Having never used such a solution, I can really help you more.
Last solution I see could be the use of two another image component on the side of the switch image, showing two arrow, for pulling up or down the switch.