My goal is to have a splash screen with an animated gif 80 pixels below center of the screen. Loading the screen's background image and animated gif is easy, as is positioning the animated gif 80px below center. My problem is that the VerticalFieldManager background (which contains the animated gif field) is filled with all white (by default). I can set the manager's background color, but the screen's background image isn't just one solid color.
public final class SplashScreen extends MainScreen {
public SplashScreen() {
// create and load the background image BitmapField
this.add(backgroundImage);
// create and load the progress bar
BitmapField progressBar = new BitmapField(progressBarImage, Field.FIELD_HCENTER | Field.USE_ALL_WIDTH | Field.NON_FOCUSABLE);
VerticalFieldManager manager = new VerticalFieldManager(Field.USE_ALL_WIDTH | Field.FIELD_HCENTER) {
protected void sublayout(int maxWidth, int maxHeight) {
// positioning code...
}
};
manager.add(progressBar);
this.setStatus(manager);
}
}
I've tried various subpaint() overrides to set the Graphics, but can't seem to set anything other than a solid color. Calling setGlobalAlpha() doesn't have the desired results either (as noted in other posts).
Any thoughts?
You may try using the paintBackground method to paint all of your background images and colors.
protected void paintBackground(Graphics g) {
g.setGlobalAlpha(255);
g.setColor(backgroundColor);
... more background drawing ...
}
For modifying the background on screens, use
this.getMainManager().setBackground(...);
You should be able to set and image, a color, whatever you need for the background to the screen.
Related
More specifically, how would I go about implementing a drag and drop feature so that the image file dragged on to the canvas would be drawn on the canvas? I've tried using a VBox listener on top of the canvas, but that didn't work. The source code of by program is available here.
In my controllers initialize() function, I have the following code. canvas is passed from the FXML file via the #FXML annotation:
public void initialize() {
GraphicsContext g = canvas.getGraphicsContext2D();
// Setter for brush type
setBrushBrush();
// Get screen dimensions and set the canvas accordingly
Dimension screenSize = getScreenSize();
double screenWidth = screenSize.getWidth();
double screenHeight = screenSize.getHeight();
canvas.setHeight(screenHeight/1.5);
canvas.setWidth(screenWidth/1.5);
canvas.setOnMouseDragged(e -> {
//Drawing code here
});
canvas.setOnDragOver(e -> {
// Need to read data of dragged image
});
canvas.setOnMouseDragReleased(e -> {
// Need to put dragged data on to canvas
});
}
The mouseDragReleased event is the wrong event to listen for here. That event is triggered when the mouse is released during a "full press-drag-release gesture" within the application; not when data is dropped during a "platform-supported drag-and-drop gesture" (see the documentation for MouseEvent for a description of these different dragging modes). So instead of canvas.setOnMouseDragReleased(...), you need:
canvas.setOnDragDropped(e -> {
// ...
});
Assuming the implementations of the handlers are correct, this should enable you to drop an image from a file and draw it on the canvas.
I want to achieve something similar to the following image:
Problem: how can we achieve red coloured, unread counter? am I going to design some psd and then reuse it in the app? but then I have to duplicate alot of .png's for each number (let's say my limit is 99 for that). but that would be redundancy.
What is the best practice to achieve this effect ?
You could create a custom View and override the onDraw() method to draw the numbers. What you would probably want to do is to have an icon fully prepared like above except for the number missing in the red circle. Then, in the custom View, you first draw that icon and then you draw the number (you will have to work a little to figure our the precise position in pixels where to draw it, and how to draw it, i.e. text-size, font, color).
Modulo a method getSomeBitmapFromResources() that imports a bitmap from resources (see e.g. here), your custom View could look something like this:
public class MyView extends View {
//Fields:
private Paint paint; //Need a Paint object for colors, fonts, etc.
private RectF rect;
private int numberToPaint;
//Constructors:
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
//Choose the text properties that work for you here:
paint.setColor(Color.WHITE);
paint.setTypeface(Typeface.create("sans-serif", Typeface.BOLD));
paint.setTextSize(12);
}
public MyView(Context context) {
this(context, null);
}
//Most importantly: override onDraw for rendering of the view:
#Override
protected void onDraw(Canvas canvas) {
rect.set(0, 0, getWidth(), getHeight()); //But: make sure your View
//will have the same size of the Bitmap you use! Set the size in XML!
canvas.drawBitmap(getSomeBitmapFromResources(), null, rect, paint);
//Here you will have to carefully choose the position of the text.
//Also consider that depending on numberToPaint the x-coordinate may have to
//be modified. Likely you want to use the Paint.getTextBounds method determine the size.
canvas.drawText("" + numberToPaint, 60, 30, paint);
}
public void chooseNumberAndDraw(int n) {
numberToPaint = n;
postInvalidate(); //Force redraw
}
}
In XML, you want to add your custom View using a tag like
<com.mysite.myproject.MyView
android:layout_width="64dp"
android:layout_height="64dp"
/>
of course replacing width and height by the actual bitmap dimensions.
Use public TabLayout.Tab setCustomView (int layoutResId)
Create a Layout with TextView and Button use this in Custom view. you may use textView for showing counter.
For reference
setCustomView
Following is the complete Example:
Example
You can also use this library.
I've created a super class (ImagePanel) which extends JPanel and paints an image as the background. In my ImagePanel subclass I'm using GroupLayout (via the NetBeans GUI Designer) to overlay the panel with JTextFields which are aligned with the underlying image.
This approach works as intended on a single platform; however, when I run the application on a different platform, the JTextFields are resized/moved based on the Look and Feel. If I set the layout manager to null the JTextFields remain in the appropriate position, but I lose the resizing of the JTextFields. Ideally, I would like to keep the position of the JTextFields, but have them sized according to the L&F? How can I approach this differently?
/**
* Extends JPanel adding the ability to paint a background image.
*/
public class ImagePanel extends JPanel implements Serializable
{
public static final String PROP_IMAGEFILE = "imageFile";
//~--- fields -------------------------------------------------------------
private ImageIcon imageIcon;
private String imageFile;
/**
* Constructs a new ImagePanel.
*/
public ImagePanel()
{
// required by Beans specification.
}
/**
* Get the path to the image file used to paint the background.
*
* #return the path.
*/
public String getImageFile()
{
return imageFile;
}
/**
* Set the path to the image file used to paint the background.
*
* #param imageFile the image file path.
*/
public void setImageFile(String imageFile)
{
String oldImageFile = this.imageFile;
this.imageFile = imageFile;
imageIcon = new ImageIcon(getClass().getResource(imageFile));
firePropertyChange(PROP_IMAGEFILE, oldImageFile, imageFile);
}
/**
* Overridden to draw image background image.
*/
#Override
public void paintComponent(Graphics g)
{
/* Draw image on the panel */
super.paintComponent(g);
if (imageIcon != null)
{
/* create image icon to get image */
Image image = imageIcon.getImage();
if (image != null)
{
g.drawImage(image, 0, 0, getWidth(), getHeight(), this);
}
}
}
}
On Windows:
On Linux:
I am not sure how well compound layouts will work in this case and it might very well be one of the 1% of cases where you do need a null layout (though that should be avoided whenever humanly possible). as mentioned, miglayout might work with with a little playing around, but what you might have to do is hard code ratio values rather than position values. Calculate the percentage of the image that represents the location and size of each component and, after the image has been drawn, and use those ratio values to programatically lay out your components.
A new layoutmanager could be written to accomplish the same thing (and would probably be preferred to the null layout method above. The add(); method could take 5 variables (component, ratio value for location x, ratio value for location y, size value for locaton x, size value for locaton y);. I am not well versed as to how to write a layout manager, but it is an option.
I have a background image, and overlay 2 LabelFields, a BasicEditField, and a ButtonField overlayed on one screen. My issue is that my background image cuts off after the bottom of the button, instead of filling the screen completely. (I removed superfluous code for ease of reading)
VerticalFieldManager bgManager = new VerticalFieldManager(Manager.USE_ALL_WIDTH |
Manager.NO_VERTICAL_SCROLL |
Manager.NO_VERTICAL_SCROLLBAR) {
//Override the paint method to draw the background image.
public void paint(Graphics graphics)
{
//Draw the background image and then call super.paint
//to paint the rest of the screen.
graphics.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), backgroundBitmap, 0, 0);
super.paint(graphics);
}
};
this.add(bgManager);
LabelField header = new LabelField("", LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER);
header.setText("Search by Drug Name");
bgManager.add(header);
LabelField subtitle = new LabelField("", LabelField.USE_ALL_WIDTH | DrawStyle.HCENTER);
subtitle.setText("(brand name or generic)");
bgManager.add(subtitle);
HorizontalFieldManager hfm = new HorizontalFieldManager();
final BasicEditField edit = new BasicEditField("", "", 50, EditField.EDITABLE | BasicEditField.NO_NEWLINE) {
//code to make background of text box white
}
};
hfm.add(edit);
ButtonField search = new ButtonField("Search");
search.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
//do something
}
});
My background image fills the screen completely if I add Manager.USE_ALL_HEIGHT to bgManager, but then my entire screen becomes scrollable infinitely. Without Manager.USE_ALL_HEIGHT, my screen is not scrollable at all (correct), but the background image cuts off at the end of the content.
How can I build this screen so it is not scrollable and has a background image that takes up the entire visible screen?
Here is what it looks like wrong:
Here is what it looks like correct (but scrolls incorrectly):
Here is the background image I am using:
I believe that the easiest way to change your code is to in fact use the USE_ALL_HEIGHT flag.
VerticalFieldManager bgManager =
new VerticalFieldManager(Manager.NO_VERTICAL_SCROLL |
Manager.NO_VERTICAL_SCROLLBAR |
Manager.USE_ALL_WIDTH |
Manager.USE_ALL_HEIGHT) {
Which will fill your screen with the background image.
You don't show this code, but I'm guessing the problem is not that bgManager is actually allowing scrolling, but that the Screen that it's in is allowing vertical scrolling. So, make sure the container you put your code in disables scrolling. Something like this:
public class BgCropScreen extends MainScreen {
public BgCropScreen() {
super(MainScreen.NO_VERTICAL_SCROLL); // <<<<<< THIS IS THE CRITICAL LINE !!!!!!
VerticalFieldManager bgManager = new VerticalFieldManager(Manager.NO_VERTICAL_SCROLL | Manager.NO_VERTICAL_SCROLLBAR | Manager.USE_ALL_WIDTH | Manager.USE_ALL_HEIGHT) {
// to draw the background image.
public void paint(Graphics graphics) {
graphics.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(), backgroundBitmap, 0, 0);
super.paint(graphics);
}
};
this.add(bgManager);
Here is the documentation for doing this. It points out that in newer versions of the OS, it's probably easier to use the BackgroundFactory methods for creating backgrounds, using Bitmaps, gradients, colors, etc. Just another option, though.
I have to write a simple Java app which can load pictures, show it in a GUI form, allow the user to apply some transformation, and show the transformed picture.
My solution is working fine, but the UI is flickering a bit, because the repaint method called too often (for example when the user scaling the image with a JSlider)
My code looks like this:
public class ImageCanvas extends Canvas
{
private BufferedImage image;
// ...
#Override
public void paint(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
if(image != null)
{
// I draw out the image...
}
}
public void setImage(BufferedImage image)
{
this.image = image;
this.repaint();
}
public void setRotation(double rotation)
{
this.rotation = rotation;
this.repaint();
}
public void setScale(double scaleX, double scaleY)
{
//set the scaling field, then repaint ....
}
// and so on...
}
And, of course, I have an ImageCanvas control on my main UI, and I simply call the public methods (see for example the "setRotation" method above) which repaint the canvas area. I know it's a simple question, but I don't even find a DoubleBuffered property on the Canvas...
Any help appreciated.
Double buffering is built-in for Swing (i.e. JComponent derived) classes.
If you want built-in double-buffering, you should extend JPanel rather than Canvas, and override paintComponent, not paint.
If you can use JPanel than go for it. Please make sure you are not overriding the JPanel.paint method, override JPanel.paintComponent instead.
See this link for details.
Usually graphic lags in these applications can be caused by setting a empty variable at the top of the script, then changing its value, then waiting for the repaint to update it. You could try changing the:
setRotation(double rotation);
so that it rotates the image in that method.
Just a general thing I happen to see while dealing with graphics.