I want to place several LabelFields with right-aligned text on a MainScreen with an alice blue background. Unfortunately I can't seem to figure out how to make that happen.
The best I can do is set my backround to Color.ALICEBLUE on a MainScreen and place LabelFields on the screen (also with a alice blue background).
public void paint(Graphics graphics) {
graphics.setBackgroundColor(Color.ALICEBLUE);
graphics.clear();
super.paint(graphics);
}
and...
LabelField display = new LabelField("", LabelField.FIELD_RIGHT){
public void paint(Graphics graphics) {
graphics.setColor(Color.DIMGRAY);
graphics.setBackgroundColor(Color.ALICEBLUE);
graphics.clear();
super.paint(graphics);
}
};
Overriding the MainScreen paint routine gives me my alice blue background, but overriding the LabelFields' paint routines does not seem to be adequate. The result is a white row, with a alice blue background behind the label text only. Adding USE_ALL_WIDTH corrects the background issue, but I can't right align with USE_ALL_WIDTH.
Does anyone know a work around for this?
In versions <= 4.5 you can create VerticalFieldManager with overrided paint():
class BGManager extends VerticalFieldManager {
public BGManager() {
super(USE_ALL_HEIGHT|USE_ALL_WIDTH);
}
public void paint(Graphics graphics)
{
graphics.setBackgroundColor(Color.DARKRED);
graphics.clear();
super.paint(graphics);
}
}
Then use it on youre screen adding simple LabelField to it:
class Scr extends MainScreen {
BGManager manager = new BGManager();
public Scr() {
super();
add(manager);
manager.add(new LabelField("Hello!", FIELD_RIGHT));
manager.add(new LabelField("This is a test", FIELD_RIGHT));
}
}
In versions >= 4.6 you can use setBackgroud() method for default screen manager:
class Scr extends MainScreen {
public Scr() {
super();
VerticalFieldManager manager =
(VerticalFieldManager)getMainManager();
manager.setBackground(
BackgroundFactory.createSolidBackground(
Color.DARKRED));
manager.add(new LabelField("Hello!", FIELD_RIGHT));
manager.add(new LabelField("This is a test", FIELD_RIGHT));
}
}
See BB KB DB-00131 - How to - Change the background color of a screen
Use
new LabelField("",LabelField.USE_ALL_WIDTH | DrawStyle.RIGHT);
without overriding the paint method of the LabelField.
Related
I'm using Vaadin 8 and I have a HorizontalLayout at the very top of the page. It's in a VeritcalLayout which is the main content of the UI.
Something like:
UI
VerticalLayout (margin=false, spacing=false)
HorizontalLayout (margin=false, spacing=false)
So you would expect everything to align to the edges of the browser viewport. I also have set default component alignment on everything to TOP LEFT.
Now, I want to put an image in the upper-right of that HorizontalLayout. The image aligns to the right of the screen as expected but the top of the image has about 30-40 pixels of padding that I cannot get rid of.
Imagine the black box as the logo I am using:
My UI init:
#SpringUI
#Theme("valo")
#PushStateNavigation
public class CustomUI extends UI implements ViewDisplay {
private static final long serialVersionUID = -3026091945679596519L;
#Autowired
private SpringViewProvider viewProvider;
#Autowired
private SpringNavigator navigator;
#Override
protected void init(VaadinRequest vaadinRequest) {
setSizeFull();
final VerticalLayout root = new VerticalLayout();
root.setMargin(false);
root.setSpacing(false);
root.setSizeFull();
setContent(root);
navigator.init(this, root);
}
#Override
public void showView(View view) {
this.setContent((Component) view);
}
My HorizontalLayout:
HorizontalLayout layout = new HorizontalLayout();
layout.setMargin(false);
layout.setSpacing(false);
layout.setHeight(64, Unit.PIXELS);
layout.setWidth("100%");
String basePath = VaadinService.getCurrent().getBaseDirectory().getAbsolutePath();
FileResource logo = new FileResource(new File(basePath + "/WEB-INF/images/logo.PNG"));
Image logoImg = new Image("", logo);
layout.addComponent(logoImg);
layout.setComponentAlignment(logoImg, Alignment.TOP_RIGHT);
The image is 64 pixels tall. The HorizontalLayout is also 64 pixels tall according to the debugger.
But notice how far off it is on the top.
What am I doing wrong?
just change
Image logoImg = new Image("", logo);
into
Image logoImg = new Image(null, logo);
Components in a HorizontalLayout have their caption on top of the component. If the caption is not null, i.e. it is empty it does take the aforementioned 30-40 pixels.
For me it looks like it looks like that UI itself still has margin. So you need to disable in.
#Override
protected void init(VaadinRequest vaadinRequest) {
setSizeFull();
setMargin(false); // this was missing
final VerticalLayout root = new VerticalLayout();
root.setMargin(false);
root.setSpacing(false);
...
}
When opening a new dialog, while its loading, you click couple of times on parent shell, apparently the new dialog does not display correctly.
Please see the example below:
Examples
https://i.stack.imgur.com/ZovxE.png (eclipse IDE example)
https://i.stack.imgur.com/5zVar.png
https://i.stack.imgur.com/u86b9.png
https://i.stack.imgur.com/FGaAr.png
Initially I encountered the problem in december 2014, and back then also reported by vaious in house devlopers which were using different development systems and then same problem has been reported by our several customers.
This behavior can be reproduced using following environment:
Windows Version: 7 Pro 64 Bit - 6.1.7601
Java Version: RE 1.8.0_121_b13
SWT Versions
3.8.2
4.6.2
4.7M6
I20170319-2000
I could only reproduce the problem on Windows 7 with the windows basic theme/design/style (not with classic or aero).
On windows 10 its not reproducible.
reproduce
code to reproduce
package test;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Dialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
public class Main {
public static void main(String[] args) {
Display display = new Display();
final Shell shell = createShell(display);
createButton(shell);
shell.open();
eventLoop(display, shell);
display.dispose();
}
private static Shell createShell(Display display) {
final Shell shell = new Shell(display);
shell.setLayout(new RowLayout());
shell.setSize(500, 200);
return shell;
}
private static void createButton(final Shell shell) {
final Button openDialog = new Button(shell, SWT.PUSH);
openDialog.setText("Click here to open Dialog ...");
openDialog.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
TestDialog inputDialog = new TestDialog(shell);
inputDialog.open();
}
});
}
private static void eventLoop(Display display, final Shell shell) {
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
class TestDialog extends Dialog {
public TestDialog(Shell parent) {
super(parent, SWT.DIALOG_TRIM | SWT.APPLICATION_MODAL | SWT.MIN | SWT.MAX | SWT.RESIZE);
setText("Dialog");
}
public void open() {
Shell shell = new Shell(getParent(), getStyle());
shell.setText(getText());
createContents(shell);
shell.pack();
initializeBounds(shell);
shell.open();
eventLoop(shell);
}
private void createContents(final Shell shell) {
shell.setLayout(new GridLayout(2, true));
Label label = new Label(shell, SWT.NONE);
label.setText("Some Label text ...");
final Text text = new Text(shell, SWT.BORDER);
GridData data = new GridData(GridData.FILL_HORIZONTAL);
text.setLayoutData(data);
createCloseButton(shell);
/* time for the user to create the misbehavior */
try {
Thread.sleep(15000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void createCloseButton(final Shell shell) {
Button closeButton = new Button(shell, SWT.PUSH);
closeButton.setText("Close");
GridData data = new GridData(GridData.FILL_HORIZONTAL);
closeButton.setLayoutData(data);
closeButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent event) {
shell.close();
}
});
shell.setDefaultButton(closeButton);
}
private void initializeBounds(Shell shell) {
Rectangle bounds = shell.getBounds();
Rectangle parentBounds = getParent().getBounds();
bounds.x = parentBounds.x;
bounds.y = parentBounds.y;
shell.setBounds(bounds);
}
private void eventLoop(Shell shell) {
Display display = getParent().getDisplay();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
}
}
steps to reproduce
Start the application
it should look like: https://i.stack.imgur.com/dMJ9e.png
Click on the button.
Keep continuously clicking on right bottom corner of the parent shell (avoid hitting the new opening dialog), till mouse cursor changes to wait icon and parent shell changes its color.
it should look as following: https://i.stack.imgur.com/c1Ikp.png
Wait until the new dialog appears.
it looks likes as following: https://i.stack.imgur.com/kTDgQ.png (incorrectly displayed)
instead: https://i.stack.imgur.com/cHVjn.png (correctly displayed)
steps to reproduce done in video
https://youtu.be/7ukhloCPf0k
When you mouse hover some of the UI elements (the originally not correctly drawn), you can notice some of them to be get painted (e.g. table rows).
https://i.stack.imgur.com/kkMKn.png (before opening the dialog)
https://i.stack.imgur.com/ZXIKc.png (after opening the dialog)
https://i.stack.imgur.com/25M7S.jpg (after mouse over)
Even calling Shell.update() or Shell.redraw() after the Dialog opened does not fix it.
In Windows Performance Options -> Visual Effects -> disable "Use visual styles on windows and buttons" is the only option I found which provides a workaround,
which seems to be the same as changing the design/theme/style to classic.
https://www.sevenforums.com/tutorials/1908-visual-effects-settings-change.html (How to Change Windows Visual Effects)
In the end, I have following questions:
Is it a SWT or Windows problem?
Is there any related topic in bug entries for Windows or in Eclipse Bugzilla?
Is there someone else who experienced the same problem? please share the experience.
Is there any settings in SWT or Windows which could affect its look n feel and fix the problem?
In the end, I have following questions: Is it a SWT or Windows problem?
Neither. As others have mentioned, you certainly should not tie up the UI thread with any long-running task. That work belongs in a background thread.
In regards to using a background thread, there are several ways you could go about this depending on how you want your Dialog to behave.
One option would be to kick off the background thread and then open the dialog when the task is done. I personally don't care for this because while the task is running, a user may think that nothing is happening.
Another option would be to open the dialog but display a "Loading" message, or something to that effect to give meaningful feedback and let a user know that the application isn't frozen (like how it looks/responds in your example).
The strategy would be to:
Create the dialog
Start the long task on a background thread and register a callback
Open the dialog with a "Loading" message
When the task is complete, the dialog will be updated from the callback
If you search around a bit on using Executors, you should find some far better examples and detail on how to use them.
Here's a brief example to illustrate what that might look like:
(Note: There are definitely a few issues with this code, but for the sake of brevity and illustrating the point I opted for a slightly naive solution. Also there are Java 8-esque ways that would be a bit shorter, but again, this illustrates the idea behind using a background thread; the same concepts apply)
Given a Callable (or Runnable if you don't need a return value),
public class LongTask implements Callable<String> {
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
You can use the Executors class to create a thread pool, and then an ExecutorService to submit the Callable for execution. Then, using Futures.addCallback(), you can register a callback which will execute one of two methods depending on whether the task was successful or failed.
final ExecutorService threadPool = Executors.newFixedThreadPool(1);
final ListeningExecutorService executorService = MoreExecutors.listeningDecorator(threadPool);
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new FutureCallback(){...});
In this case I used the Google Guava implementation ListeningExecutorService which makes things a bit cleaner and simpler, in my opinion. But again, you may not even need this if you opt for a more "Java 8" approach.
As for the callback, when the task is successful, we update the Dialog with the results. If it fails, we can update it with something to indicate failure:
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
In this case I opted for the Callable to return a String, thus the FutureCallback should be parameterized with String. You may want to use some other class that you created, which will work just as well.
Notice that we use the Display.asyncExec() method to ensure that the code which updates the UI runs on the UI thread, because the callback may execute on the background thread.
Like I said, there are still a few issues here, including what happens when you click the cancel button before the task completes, etc. But hopefully this helps illustrate an approach for handling long-running background tasks without blocking the UI thread.
Full example code:
public class DialogTaskExample {
private final Display display;
private final Shell shell;
private final ListeningExecutorService executorService;
public DialogTaskExample() {
display = new Display();
shell = new Shell(display);
shell.setLayout(new GridLayout());
executorService = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(1));
final Button button = new Button(shell, SWT.PUSH);
button.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
button.setText("Start");
button.addSelectionListener(new SelectionAdapter() {
#SuppressWarnings("synthetic-access")
#Override
public void widgetSelected(final SelectionEvent e) {
final MyDialog dialog = new MyDialog(shell);
dialog.setBlockOnOpen(false);
dialog.open();
dialog.setStatus("Doing stuff...");
final ListenableFuture<String> future = executorService.submit(new LongTask());
Futures.addCallback(future, new DialogCallback(dialog));
}
});
}
public void run() {
shell.setSize(200, 200);
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
executorService.shutdown();
display.dispose();
}
public static void main(final String... args) {
new DialogTaskExample().run();
}
public static class DialogCallback implements FutureCallback<String> {
private final MyDialog dialog;
public DialogCallback(final MyDialog dialog) {
this.dialog = dialog;
}
#Override
public void onSuccess(final String result) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus(result);
}
});
}
#Override
public void onFailure(final Throwable t) {
dialog.getShell().getDisplay().asyncExec(new Runnable() {
#SuppressWarnings("synthetic-access")
#Override
public void run() {
dialog.setStatus("Failure");
}
});
}
}
public static class LongTask implements Callable<String> {
/**
* {#inheritDoc}
*/
#Override
public String call() throws Exception {
Thread.sleep(15000);
return "Hello, World!";
}
}
public static class MyDialog extends Dialog {
private Composite baseComposite;
private Label label;
/**
* #param parentShell
*/
protected MyDialog(final Shell parentShell) {
super(parentShell);
}
/**
* {#inheritDoc}
*/
#Override
protected Control createDialogArea(final Composite parent) {
baseComposite = (Composite) super.createDialogArea(parent);
label = new Label(baseComposite, SWT.NONE);
return baseComposite;
}
public void setStatus(final String text) {
label.setText(text);
baseComposite.layout();
}
}
}
The code seems to be straight forward, only that you are making the main Thread sleep for 15secs hence the delay. If not required remove the sleep or reduce the time for sleep to 5secs or so.
I created a custom layer, according to this material:
http://docs.gluonhq.com/charm/2.1.1/#_creating_a_layer, and added it to my application:
MobileApplication.getInstance().addLayerFactory(LAYER_NAME, () -> customLayer);
Now I would like to add a transition to this layer. You can use transitions on View like: view.setShowTransitionFactory(BounceInDownTransition:new)
Layer doesn't provide a method like that. So I tried this approach to apply a transition:
private void showLayer() {
MobileApplication.getInstance().showLayer(LAYER_NAME);
new BounceInDownTransition(customLayer).play();
}
When I call showLayer() for the first time the transition appears to be incomplete. The first part, where the layer should get transitioned out of view, is missing. Each further invocation of showLayer() shows the complete transition.
Are layers meant to be used in conjuction with transitions at all?
If possible what is the recommended way?
You can use the built-in transitions in Gluon Charm, since all you need is pass a node to them, and call play to start the animation.
In case of the Gluon's Layers, there's no built-in mechanism as for Views, but you can easily add it to your class.
This will create a bounce-in effect for showing and bounce-out effect for hiding.
public class MyLayer extends Layer {
private final Node root;
private final double size = 150;
public MyLayer() {
final BounceInDownTransition transitionIn = new BounceInDownTransition(this, true);
final BounceOutDownTransition transitionOut = new BounceOutDownTransition(this, true);
transitionOut.setOnFinished(e -> hide());
Button button = new Button("", MaterialDesignIcon.CLOSE.graphic());
button.setOnAction(e -> transitionOut.playFromStart());
root = new StackPane(button);
root.setStyle("-fx-background-color: white;");
getChildren().add(root);
getGlassPane().getLayers().add(this);
showingProperty().addListener((obs, ov, nv) -> {
if (nv) {
layoutChildren();
setOpacity(0);
transitionIn.playFromStart();
}
});
}
#Override
public void show() {
getGlassPane().setBackgroundFade(GlassPane.DEFAULT_BACKGROUND_FADE_LEVEL);
super.show();
}
#Override
public void hide() {
getGlassPane().setBackgroundFade(0.0);
super.hide();
}
#Override
public void layoutChildren() {
root.setVisible(isShowing());
if (!isShowing()) {
return;
}
root.resize(size, size);
resizeRelocate((getGlassPane().getWidth() - size)/2, (getGlassPane().getHeight()- size)/2, size, size);
}
}
And now, add the layer:
#Override
public void init() {
addViewFactory(BASIC_VIEW, () -> new BasicView(BASIC_VIEW));
addLayerFactory("My Layer", () -> new MyLayer());
}
I want to code a TextField component with icon.
So the behavior is as follow:
If the TextField contains an empty string, I use "lens.png".
Otherwise, i use "cross.png".
using the JavaFX Scene Builder, I added a TextFiled and an ImageView in the stack pane.
My code is the following:
#FXML
private TextField textSearch;
#FXML
private ImageView imageView;
final Image lensIcon = new Image("/issue/images/lens.png");
final Image crossIcon = new Image("/issue/images/cross.png");
//initialize () method
textSearch.textProperty().addListener(obs -> {
final String text = textSearch.getText();
Image icon = (text==null || text.isEmpty()) ? lensIcon : crossIcon;
imageView.setImage(icon);
imageView.setMouseTransparent(icon == lensIcon);
}
);
imageView.setOnMouseClicked(evt -> textSearch.setText(null));
my issue is the following:
How to prevent writing caracters below the icon (ImageView). the following figure illustrate my issue.
ControlsFX is an JavaFX API that supplies a ton of advanced controls UI that didn't come with JavaFX out of the box.
ControlsFX - http://fxexperience.com/controlsfx/
FontAwesomeFX supplies hundreds of icons (such as a cross in your case above)
FontAwesomeFX - https://bitbucket.org/Jerady/fontawesomefx/downloads/
Here is a demo solution to your problem after importing both these fantastic APIs
public class TextFields_Demo extends Application {
private Parent createContent() {
Pane root = new Pane();
CustomTextField customTextField = new CustomTextField();
FontAwesomeIconView icon = new FontAwesomeIconView(FontAwesomeIcon.CLOSE);
customTextField.setRight(icon);
root.getChildren().add(customTextField);
return root;
}
#Override
public void start(Stage primaryStage) {
Scene scene = new Scene(createContent());
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
I have to create a button to show an image. I created it using two activity, but I want that the button and the image view stay in the same page. So, I think I have to create only one activity, right? can you explain hot to do this? this is my code:
ACTIVITY ONE:
public class HomeWork extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_work);
Button getResultButton = (Button) findViewById(R.id.btn1);
getResultButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent resultIntent =new Intent(HomeWork.this,HomeWork2.class);
startActivity(resultIntent);
}
});
}
SECOND ACTIVITY:
public class HomeWork2 extends Activity {
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home_work2);
ImageView img=(ImageView)findViewById(R.id.imageView);
img.setBackgroundResource(R.drawable.apple);
}
the apk works correctly, the only problem is that I want button and imageview in the same image
Create a layout which contains both the Button and the ImageView.
Then in the Button's click listener, use
ImageView img=(ImageView)findViewById(R.id.imageView);
img.setBackgroundResource(R.drawable.apple);
instead of
Intent resultIntent =new Intent(HomeWork.this,HomeWork2.class);
startActivity(resultIntent);
Also remove (the now unused) HomeWork2 from your manifest.
[EDIT]
You may add more buttons, to change the contents of the ImageView.
You only have to put in their click listeners:
img.setBackgroundResource(R.drawable.orange);
or
img.setBackgroundResource(R.drawable.pineapple);
or ...