How do I set background image fill screen completely? - java

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.

Related

Java screenshot capture - JFrame paints old component for a second & disappears even though all components were removed & repainted

Before you read, this will be informative: Java JFrame won't show up after using .setVisible(true) after being invisible
Hello I am working on a library API that let's you capture an area of the screen, and it returns you a class that contains the ByteArrayInputStream and utility methods like createBufferedImage, createFile, etc.
Basically you create a Bootstrap instance, and pass the capturer type you want as a dependency (ScreenshotCapturer or GifCapturer):
Bootstrap b = new Bootstrap(new ScreenshotCapturer());
And the beginCapture method receives an object that implements ScreenCaptureCallback which is the callback event that the captured result will be passed to.
This is a short background.
Now when you use the beginCapture method, basically what it does is creates new instance of SelectionCamera, this is basically the component that paints the selection area you're selecting when dragging the mouse, and updates the listeners.
once created instance, it calls super.setVisible(true);
After that method gets called, the frame will show up, and also show the old painted screen for like 600-500miliseconds, I am not exactly sure, but it disappears so quickly.
Take a look at this live example:
Note use the video option, otherwise you will not see what I'm seeing as gif is too slow to show it!
http://gyazo.com/d2f0432ada37842966b42dfd87be4240
You can see after I click Screenshot again, it shows the old selected area and disappears quickly. (by the way the frame you see in the gif is not part of the app, just dummy hello world example usage).
The process of image capture.
Step 1
beginCapture gets called:
public void beginCapture(final ScreenCaptureCallback c) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
capturer.setCallback(c);
capturer.beginSelection();
}
});
}
Step 2
beginSelection gets called in the Capturer class (ScreenshotCapturer extends Capturer (abstract)
#Override
public void beginSelection() {
super.init();
this.setHotkeys();
super.getCamera().startSelection();
}
Step 3
CaptureCamera#startSelection() gets called
public void startSelection() {
super.getContentPane().removeAll();
super.getContentPane().repaint();
super.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
this.selector = new SelectionCamera();
this.selectionMosueAdapter.updateCamera(this.selector);
this.selectionMouseMotion.updateCamera(this.selector);
super.add(this.selector);
super.setVisible(true);
super.repaint();
super.getContentPane().repaint();
}
Step 4
The user selects an area, and both mouse listener and mouse motion listens to it(Take a look at mouse motion):
#Override
public void mouseDragged(MouseEvent e) {
Point dragPoint = e.getPoint();
Point startPoint = this.selector.getStartPoint();
int x = Math.min(startPoint.x, dragPoint.x);
int y = Math.min(startPoint.y, dragPoint.y);
int width = Math.max(startPoint.x - dragPoint.x, dragPoint.x - startPoint.x);
int height = Math.max(startPoint.y - dragPoint.y, dragPoint.y - startPoint.y);
this.selector.setCameraDimension(width, height);
this.selector.setCoordinates(x, y);
this.camera.repaint(); // important
}
by the way this.selector is SelectorCamera which is the component that paints the selection area.
Step 5
CaptureCamera#endSelection() gets called, this method gets the x,y, width, height from the selection camera and passes it to the capturer class which uses Robot to get screenshot with that rectangle, and before that it removes ALL components from the content pane, and repaints everything and then sets visibility to false.
public void endSelection() {
super.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
int x = this.selector.getCameraX();
int y = this.selector.getCameraY();
int w = this.selector.getCameraWidth();
int h = this.selector.getCameraHeight();
super.getContentPane().removeAll();
super.getContentPane().repaint();
//super.repaint();
super.setVisible(false);
this.c.startCapturing(x, y, w, h);
}
Basically this is the last step, rest steps are unnecessary for the debugging as it only sends back the callback.
I really tried my best explaining the process of my application, I've tried figuring it out for 5 and half hours now, and no luck at all. Tried different ways, by creating new SelectionCamera object as you see, doesn't work.
Why is it doing this? Is it something to do with the swing core?
SelectionCamera code: https://github.com/BenBeri/WiseCapturer/blob/master/src/il/ben/wise/SelectionCamera.java
Thanks in advance.
Based on this example...
try {
final Bootstrap b = new Bootstrap(new ScreenshotCapturer());
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
b.beginCapture(new ScreenCaptureCallback() {
#Override
public void captureEnded(CapturedImage img) {
System.out.println("...");
JFrame frame = new JFrame();
frame.add(new JLabel(new ImageIcon(img.getBufferedImage())));
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
});
}
});
}
});
System.out.println("Hello");
} catch (AWTException exp) {
exp.printStackTrace();
}
I won't focus on the initialise stage of the first round, I will focus on the initialisation of the second round as this is where the problem is...
b.beginCapture call's this.capturer.beginSelection();, which calls super.getCamera().startSelection(); which calls setVisible(true) (CaptureCamera been a JFrame).
This will immediately show what ever was previously displayed on the CaptureCamera. It's important to note here, that no new instances of objects were created through the process...
Now, I made a lot of changes to the base testing this, but it appears that the problem is with the restoration of the frame when it's made visible for the second time. This seems to be an issue with the transparency support of the Window as it seems to restore the last "known" state instead of repainting the window immediately...
Now, I tried clearing the selector before making the CaptureCamera invisible to no eval, as the window seems to be made invisible before the selector is painted.
The final solution I came up with was to call dispose on the CaptureCamera, which releases it's native peer and therefore destroys the old graphics context, forcing the frame to rebuild itself when it is made visible again.
"A" problem with this could be the fact that when all the windows are disposed (and the only running threads are daemon threads), the JVM will exit...
This was an issue during my testing as I was using a javax.swing.Timer to put a delay between the first and second capture process so I could see where the problem was occurring and this caused my JVM to exit (as the timer uses a daemon thread and I had no other windows open).
I got around this by creating a tiny (1x1) transparent window in the Capturer class, keep this in mind if the JVM exists gracefully for no reason ;)
Side Notes...
Now, there is an issue with SelectionCamera (which extends JPanel), it is opaque, but is using a transparent background, this is incredibly dangerous as Swing only knows how to deal with opaque or fully transparent components.
public SelectionCamera() {
super.setBackground(new Color(0, 0, 0, 0));
super.setVisible(false);
}
Should be updated to something like...
public SelectionCamera() {
setOpaque(false);
//super.setBackground(new Color(0, 0, 0, 0));
super.setVisible(false);
}
I'm also confused over the use of super.xxx, the only reason you would do this is if you had overrriden those methods and didn't want to call them at this time...In my testing, I removed all the calls to super where a method wasn't overridden in the current class (and I wasn't already in the overriden method)
Also, the paintComponent method should be calling super.paintComponent
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(new Color(0, 0, 0, 0.5f));
g.fillRect(this.x, this.y, this.width, this.height);
}
Make Frame left to be -10,000 then set visible true, add a timer 2 seconds (try lower to 25-100 milliseconds, just to give it sligth pause to invalidate content) , on timer :left to 0 . I think it works due to caching & double buffereing. Frame shows what it had in buffer, buffer points to old image due to caching/ lazy repaint.
Alternative :
Maybe a repaint or invalidate before your show would work too, and don't need to do the left -10,000. I dont work much with ui-swing, just a but years back and remember some strange things like this.

LibGDX - Stage.setViewport(new Viewport()) black screen

For organization's sake, I use multiple scenes for my game and rather than having each scene have a constructor that receives a Viewport (my game is scalable), I would like to set each stage's viewport separate of the constructor, then after the viewport is set, add the actors. In the main class, it would happen like this:
public void setStage(Stage s)
{
if(currentStage != null)
currentStage.dispose();
currentStage = s;
currentStage.setViewport(view);
}
To make this go fluidly, each stage has an init method that is called within an overriden setViewport:
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
init();
}
However, all this gives me is a black screen... I have tried updating the camera and viewport, but no avail (note that the actors are having their render methods called).
Why am I getting this black screen and how do I fix it? If it's not possible I'll just revert to using the constructor.
If I understood correctly you want to do this:
Stage stage1 = new Stage();
stage1.getViewport().update(width, height);
rather than this:
Stage stage1 = new Stage (new StretchViewport(width, height)); // It doesn't have to be StretchViewport
In the first case (what you are trying to do) a ScalingViewport will be costructed automatically for you with dimensions of the Gdx.graphics and an orthographic camera and acts like a StretchViewport. Why not using the second case directly where you pass the viewport you want. You can always alter your viewport whenever you want by calling stage1.getViewport().update(width, height);
or by calling stage1.setViewport(width, height, false); in older Libgdx versions.
Viewport has changed recently so if you can extend Viewport class to Override the update method maybe you can achieve what you want:
public class ViewportExtendClass extends StretchViewport{
public ViewportExtendClass(float worldWidth, float worldHeight) {
super(worldWidth, worldHeight);
}
#Override
public void update (int screenWidth, int screenHeight, boolean centerCamera) {
super.update(screenWidth, screenHeight, centerCamera);
// DO YOUR INITIALIZATION HERE
}
}
From your main class you create new stage :
Stage stage1 = new Stage (new ViewportExtendClass (width, height));
and then you call :
stage1.getViewport().update(width, height);
Like this you can alter stage viewport and re initialize your assets.
#Override
public void setViewport(Viewport v)
{
super.setViewport(v);
this.getViewport().update(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), false);
Camera c = this.getViewport().getCamera();
c.position.set(c.viewportWidth/2, c.viewportHeight/2, 0);
init();
}
This works, but you should also be able to update the Viewport like that at the begin of your application, if you continue to use the same one. I set the position like that instead of centering because some of my Stages will be larger than the screen.

Placing an image within a jmenubar + jtoolbar

I would like to know if it's possible to set an image as background for a jmenubar+jtoolbar (not only for one of theym, not one for each of theym But on for BOTH) ...
Anyone's got an idea ??
How should I do that if it's possible ?
Thanks !
Here an image to explain :
Solved :: I used two images (cutted to the right size to suite my jmenubar+jtoolbar) and added these to the object's declarations as overrides and it works great ! Here is a piece of code :
///////////////////////////////
JToolBar toolBar = new JToolBar(){
#Override
protected void paintComponent(Graphics g){
Image photo = getToolkit().getImage("src/MainFrame/Images/xtremeCalliBottom.png");
super.paintComponent(g) ;
int x=(mainFrame.getWidth()-200), y=0 ;
if(photo != null)
g.drawImage (photo, x, y, this);
}
};
// ............
//========== Menu Bar
jMenuBar = new JMenuBar(){
#Override
protected void paintComponent(Graphics g){
Image photo = getToolkit().getImage("src/MainFrame/Images/xtremeCalliTop.png");
super.paintComponent(g) ;
int x=(mainFrame.getWidth()-200), y=0 ;
if(photo != null)
g.drawImage (photo, x, y, this);
}
};
// ................
jMenuBar.setPreferredSize(new Dimension(100, 25));
toolBar.setPreferredSize(new Dimension(100,40));
Sure, but you'll have to override them separately. You'll also need to keep some global variable (or one that you can pass between the two) so that they can know how big each of them are.
You'll need to override paintComponent() or add your own UI delegate to do the painting. You can load the image and paint just the top portion (or relative percentage) on the menubar, then paint just the bottom portion or relative percentage on the toolbar.

Transparent VerticalFieldManager background

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.

JTabbedPane - set default border around tabs..?

I am using a JTabbedPane in my application. I have added two tabs which are instances of a custom class "ContentPanel". This extends JPanel and sets the background, border etc etc. Basically it means I dont have to set the properties of each JPanel I want to apply this colour scheme to. I notice that not only does their border appear but another border (which, I think, is blue - at least on my screen) appears around this border, connected to the tab "selectors" themselves (i.e. the buttons you click on to get the appropriate view). I would like to change this border as it just looks odd against a gold / brown colour scheme. Does anyone have any idea how to do this? I have tried JTabbedPane.setBorder(Border b) but that doesnt work. That simply sets a border around the entire thing, including the tab selectors.. not what I want.
Any help with this would be greatly appreciated.
These colors are defined in the Look and Feel. If you look at the code for BasicTabbedPaneUI, you will notice that installDefaults() sets a bunch of protected Color instance variables. The keys they are defined against in the L&F are also available here.
protected void installDefaults() {
LookAndFeel.installColorsAndFont(tabPane, "TabbedPane.background",
"TabbedPane.foreground", "TabbedPane.font");
highlight = UIManager.getColor("TabbedPane.light");
lightHighlight = UIManager.getColor("TabbedPane.highlight");
shadow = UIManager.getColor("TabbedPane.shadow");
darkShadow = UIManager.getColor("TabbedPane.darkShadow");
//...
// a lot more stuff
//...
}
If you do not want to go as far as define your own L&F, you have the ability to set a custom UI delegate on your tabbed pane:
myTabbedPane.setUI(new BasicTabbedPaneUI() {
#Override
protected void installDefaults() {
super.installDefaults();
highlight = Color.pink;
lightHighlight = Color.green;
shadow = Color.red;
darkShadow = Color.cyan;
focus = Color.yellow;
}
});
you may of course want to change those color settings. As set, you will see which vars are used where.
None affecting L&F and JVM run-time system-wide settings code solution.
Create your own tabbed-pane class and nested tabbed-pane-UI class to deal with the issue for a "specific" class of tabbed-pane. The code below is original: (The last answer was 2010, but this may be useful too.)
public class DisplayTabbedPane extends JTabbedPane implements
MouseListener, ChangeListener {
public DisplayTabbedPane() {
setTabPlacement(SwingConstants.BOTTOM);
// UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
// works but is a JVM system wide change rather than a specific change
NoInsetTabbedPaneUI ui = new NoInsetTabbedPaneUI();
// this will build the L&F settings for various tabbed UI components.
setUI( ui );
// override the content border insets to remove the tabbed-pane
// blue border around the pane
ui.overrideContentBorderInsetsOfUI();
}
/**
* Class to modify the UI layout of tabbed-pane which we wish to override
* in some way. This modification only applies to objects of this class.
* Doing UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
* would affect all tabbed-panes in the JVM run-time.
*
* This is free to use, no copyright but is "AS IS".
*/
class NoInsetTabbedPaneUI extends MetalTabbedPaneUI {
/**
* Create tabbed-pane-UI object to allow fine control of the
* L&F of this specific object.
*/
NoInsetTabbedPaneUI(){
super();
}
/**
* Override the content border insets of the UI which represent
* the L&F of the border around the pane. In this case only care
* about having a bottom inset.
*/
public void overrideContentBorderInsetsOfUI(){
this.contentBorderInsets.top = 0;
this.contentBorderInsets.left = 0;
this.contentBorderInsets.right = 0;
this.contentBorderInsets.bottom = 2;
}
}
........
}
Change Look And Feel with "UIManager"
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled+MouseOver].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Enabled+Pressed].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+MouseOver+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+Pressed+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Focused+Selected].backgroundPainter", new BackgroundPainter(Color.GRAY));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[MouseOver+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Pressed+Selected].backgroundPainter", new BackgroundPainter(Color.white));
UIManager.getLookAndFeelDefaults().put("TabbedPane:TabbedPaneTab[Selected].backgroundPainter", new BackgroundPainter(Color.white));
BackgroundPainter class
public class BackgroundPainter implements Painter<JComponent> {
private Color color = null;
BackgroundPainter(Color c) {
color = c;
}
#Override
public void paint(Graphics2D g, JComponent object, int width, int height) {
if (color != null) {
g.setColor(color);
g.fillRect(0, 0, width - 1, height - 1);
}
}
}

Categories

Resources