FEST Swing new frame on click, can't make new frame fixture - java

I am trying to write a Fest Swing test but am having trouble making / finding a frame fixture. I have two JFrames, one opens the other on click, and I'd like to either:
1.) find the frame fixture of the new JFrame opened
2.) make a new frame fixture out of the the new JFrame object created (I can get the object from the original JFrame Object.)
I have tried using
GenericTypeMatcher<secondGUI> matcher = new GenericTypeMatcher<secondGUI>(secondGUI.class) {
protected boolean isMatching(secondGUI frame) {
System.out.println("0".equals(frame.getTitle()) && frame.isShowing());
return "0".equals(frame.getTitle()) && frame.isShowing();
}
};
Robot robot = BasicRobot.robotWithCurrentAwtHierarchy();
to find the frame, but run into an EdtViolationException.
I have also tried
secondGUI secGUI = GuiActionRunner.execute(new GuiQuery<secondGUI>() {
#Override
protected secondGUI executeInEDT() throws Throwable {
return firstGUI.getController().getWindows().get("0");
}
});
FrameFixture secondWindow = new FrameFixture(secGUI);
But the last line gave an EdtViolationException as well.
Any suggestions?
Thanks!

Try finding your frame using the title of the frame:
Robot robot = BasicRobot.robotWithCurrentAwtHierarchy();
FrameFixture frame = WindowFinder.findFrame("Title of my frame").using(robot);
Also, secondGUI should be SecondGUI since it's a class name.
BTW, glad to see another FEST user.

Related

Application turns black when dragged from a 4k monitor to a FullHD monitor

My notebook has a 4k display. My external monitor is 1920. When I drag my Java Swing app window from the 4k display onto the external monitor it gets completely black except for the window frame. It doesn't matter whether I maximize it on the external monitor or not.
Here is the HelloWorldSwing example I got from Oracle.com. It shows the exact same behaviour.
import javax.swing.*;
public class HelloWorldSwing {
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Add the ubiquitous "Hello World" label.
JLabel label = new JLabel("Hello World");
frame.getContentPane().add(label);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
It looks like a bug in Swing. Anyway, I have to find a solution/work-around. Any ideas?
I'm running jdk/jre 1.8.0 121.
Although I didn't encounter such a problem yet on any multi-screen environment I've tried so far with Swing - I might help debugging it.
Try running this code example:
public class HelloWorldSwing
{
private static void createAndShowGUI ( final GraphicsDevice device )
{
final GraphicsConfiguration conf = device.getDefaultConfiguration ();
final JFrame frame = new JFrame ( "HelloWorldSwing", conf );
frame.setDefaultCloseOperation ( JFrame.EXIT_ON_CLOSE );
final JLabel label = new JLabel ( "Hello World", SwingConstants.CENTER );
frame.getContentPane ().add ( label );
final Rectangle sb = conf.getBounds ();
frame.setBounds ( sb.x + sb.width / 2 - 100, sb.y + sb.height / 2 - 100, 200, 200 );
frame.setVisible ( true );
}
public static void main ( final String[] args )
{
SwingUtilities.invokeLater ( new Runnable ()
{
#Override
public void run ()
{
final GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment ();
final GraphicsDevice[] devices = env.getScreenDevices ();
for ( final GraphicsDevice device : devices )
{
if ( device.getType () == GraphicsDevice.TYPE_RASTER_SCREEN )
{
createAndShowGUI ( device );
}
}
}
} );
}
}
This will basically place one frame on each of the screens devices available in your system. It will also provide default screen graphics configuration into each frame.
Check if you have the same problems dragging frame to your notebook screen or not and whether there are any other problems.
Edit1: Also it might be quite important to know which JDK/JRE you are using to run your code example since there were some related internal changes. If you are running some old JDK it might not be the best idea on newer Mac OS X versions.
Edit2: I would try doing a few more things to find out more:
Setup Nimbus Look and Feel before displaying frames and try dragging them with that custom L&F installed.
Setup system (native) look and feel as shown in the tutorial here - this might have some effect on Mac OS X.
Try to run Java FX example and drag it between displays and see if you get the same problem there or not - you are already using JDK 8 so it should be easily doable. Java FX is just the new UI framework that was introduced some time ago.
And in general I could say that Swing has quite poor support for high-res displays, so even if everything runs properly and you don't get the black screen you will see other issues like the UI being blurry or low-quality text rendering.
I found a solution. Basically I added a component listener to my main frame and listen on move events. Whenever the frame is moved I check on which display it is located. As soon as the frame has been moved to another display I set it invisible, then set new bounds located on the "new" display, set the extended state to maximized and finally make the frame visible again.
For the last minutes I wildly dragged windows from one display to another all while jumping for joy. If you also want that much fun in your life, here is the code:
mainFrame.addComponentListener(new ComponentListener()
{
#Override
public void componentMoved(ComponentEvent evt)
{
GraphicsConfiguration conf = mainFrame.getGraphicsConfiguration();
GraphicsDevice curDisplay = conf.getDevice();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice[] allDisplays = env.getScreenDevices();
for (int i = 0; i < allDisplays.length; i++)
{
if (allDisplays[i].equals(curDisplay))
{
//the window has been dragged to another display
if (i != _currentDisplayIndex)
{
final Rectangle sb = conf.getBounds();
mainFrame.setVisible(false);
//it is important to set the bounds somewhere on the new display before setting the extended state to maximized
mainFrame.setBounds(sb.x, sb.y, 1000, 800);
mainFrame.setExtendedState(Frame.MAXIMIZED_BOTH);
mainFrame.setVisible(true);
_currentDisplayIndex = i;
}
}
}
}
#Override
public void componentShown(ComponentEvent evt)
{
}
#Override
public void componentResized(ComponentEvent evt)
{
}
#Override
public void componentHidden(ComponentEvent evt)
{
}
});
Yippie!
Side note: I tried to take a screenshot of the black window earlier. However, the screenshot isn't black, but just normally shows all swing components. That makes me believe, that it is not only a swing issue, but also some sort of a windows/display driver issue. Pressing "printscreen" doesn't trigger anything in java (I guess), but only refreshes the display.

Is there a way to prevent JFrame from resizing when you call pack() in java?

I'm trying to make a program, and I want it to start out maximized, but I also want to be able to resize it. The only problem is that, whenever I call frame.pack(), it snaps back to the size I set it when I called frame.setExtendedState(int) which I made java.awt.Frame.MAXIMIZED_BOTH so as to make the frame maximized when I first open it. Is there a way to prevent this?
and I want it to start out maximized,
That is a one time setting of the state which can be changed at any time.
So you should be able to use:
frame.setExtendedState(JFrame.NORMAL);
frame.pack();
// or pack() / setExtendedState(...)
That will not prevent the user from clicking on the maximize icon later if they desire to do so.
maximized and resizable,
public class Test {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame();
f.setExtendedState(java.awt.Frame.MAXIMIZED_BOTH);
final Timer tt = new Timer(68, e -> {
Dimension r = f.getSize();
f.setExtendedState(java.awt.Frame.NORMAL);
f.pack();
f.setSize(r);
});
tt.setRepeats(false);
tt.start();
f.setVisible(true);
});
}
}

ImageJ opening imagePlus window as an internal frame inside a desktopPane

I am having some trouble in ImageJ with one of its files. Basically set up a desktop pane that analyzes and opens images. But when the program opens the image it opens it as a separate JFrame. I would like to be an internal JFrame. So basically the image opens up in the desktop pane. I have tried a couple of things like creating a internal frame class and adding the win to the desktopPane but nothing seems to work it still opens it as a separate JFrame. I was wondering if anyone knows how to do this.
This is my code (this function is just calling .show() to display the image, the code for the actual JFrame that opens the window is in ImageWindow.java):
public void actionPerformed(ActionEvent arg0) {
// TODO Auto-generated method stub
FileOpener open = new FileOpener(file);
ImagePlus fopen = open.open(false);
if(fopen != null){
BufferedImage openImage = fopen.getBufferedImage();
new ImagePlus(path,openImage).show(desktop); //This functions displays the image
ImagePlus newImage = new ImagePlus(path,openImage);
img = newImage;
}
frame.setVisible(false);
}
The creation of a new JFrame is hardcoded into ImageJ's ImagePlus class:
if (stackSize>1)
win = new StackWindow(this);
else
win = new ImageWindow(this);
If you want to adapt the GUI, you can extend the ImageWindow or StackWindow classes. See the Trainable Weka Segmentation plugin for a nice example.
Alternatively, use the data structures of ImageJ2, namely ImgLib's ImgPlus. These are designed to be independent of any user interface.

Changing layout/frame in response to a button press

I'm trying to make a little game on Java using the Swing components (Boggle-type game).
The way I have it set up right now, it basically opens up to the game right away - but I want to have a start up window with two buttons - "Tutorial" and "Play". I already have the functionality (my Tutorial button just opens a new Window with all the things on it) I'm just not sure how to create a second JFrame and then switch to it when I press Play (or rather, create a JFrame, then switch to the one I've already created when the JButton is pressed). I guess I could cause a new JFrame to open on the same location and the old one to become non-visible - but I was hoping for a simpler solution.
I also want to do this on completion of the game, switching again automatically to a little stat page - so any info will be appreciated.
This is what I have so far in case you guys want to see my code (I haven't yet hooked up the Enter key send the userWord to be validated and scored in my other classes, or filled in the tileGrid with Tile Objects, or the timer.... but that will all come later!)
public class Game implements Runnable {
public void run(){
final JFrame frame = new JFrame("Boggle");
frame.setLocation(500,200);
// Input - holds typing box
final JLetterField typingArea = new JLetterField(1);
typingArea.setFocusTraversalKeysEnabled(false);
typingArea.setEditable(true);
typingArea.setFocusable(true);
typingArea.requestFocusInWindow(); //also this request isn't being granted..
//if anyone could explain why i would love you
// I want the focus on the TextField on startup
frame.add(typingArea, BorderLayout.SOUTH);
typingArea.addKeyListener(new KeyAdapter() {
public void keyPressed (KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) { // enter key is pressed
String userWord = typingArea.getText().toLowerCase();
typingArea.setText("");
}
}
});
final JLabel status = new JLabel("Running...");
// Main playing area
GridLayout tileGrid = new GridLayout(4,4);
final JPanel grid = new JPanel(tileGrid);
frame.add(grid, BorderLayout.CENTER);
// Reset button
final JPanel control_panel = new JPanel();
frame.add(control_panel, BorderLayout.NORTH);
final ImageIcon img = new ImageIcon("Instructions.png", "My Instructions...");
final JButton info = new JButton("Help");
info.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
final JFrame infoFrame = new JFrame("Tutorial");
infoFrame.setLocation(500,50);
JLabel tutorialImg = new JLabel(img);
int w = img.getIconWidth();
int h = img.getIconHeight();
infoFrame.setSize(w, h);
infoFrame.add(tutorialImg);
infoFrame.setVisible(true);
}
});
control_panel.add(info);
// Put the frame on the screen
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args){
SwingUtilities.invokeLater(new Game());
}
}
use CardLayout instead of second JFrame, your concept is heading to OutOfMemory
use JFrame.pack(after switch betweens Cards in CardLayout) if you want to change JFrames bounds on runtime,

Can't get image to show up in swing

I'm a college student and this is my first time I have ever created a gui in Java. Right now I looked at this answer GUI in Java using Swing and followed the instructions and still nothing happens. Here is the code. I cut out all the irrelevant junk.
import javax.imageio.ImageIO;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Lab4Shell
{
// this holds the current game board
private char[][] gameBoard = new char[7][8];
private JButton[][] gameButtons = new JButton[7][8];
private ImageIcon red = new ImageIcon("Red.jpg");
private ImageIcon black = new ImageIcon("Black.jpg");
private ImageIcon empty = new ImageIcon("Empty.jpg");
private JPanel panel = new JPanel();
private int currentPlayer = 1;
private int numMoves = 0;
//Why do you want everything in constructor?
public Lab4Shell()
{
CreateWindow();
ResetGame();
// set layout
// loop through buttons array creating buttons, registering event handlers and adding buttons to panel
// add panel to frame
// do other initialization of applet
}
public static void CreateWindow()
{
//Sets window title and create window object.
JFrame aWindow = new JFrame("Connect Four");
//Set window position and size
aWindow.setBounds(500,100,400,400);
//What close button does.
aWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Make window visible.
aWindow.setVisible(true);
}
public static void main(String args[])
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
Lab4Shell game = new Lab4Shell();
}
});
}
void ResetGame()
{
JLabel label = new JLabel();
label.setIcon(empty);
for(int r=0;r<gameBoard.length;r++)
{
java.util.Arrays.fill(gameBoard[r],0,gameBoard[r].length,'0');
//loop through board columns
for(int c=0;c<gameBoard[r].length;c++)
{
}
}
// loop through array setting char array back to ' ' and buttons array back to empty pic
// reset currentPlayer and numMoves variables
}
You have to add the created ImageIcons to the panel as Manos said, and being the images at the src folder of Eclipse project, do that:
java.net.URL url = getClass().getResource("red.JPEG");
ImageIcon red = new ImageIcon(url);
If the resources are embedded with the application (within in the jar), the you need to use Class#getResource to load them.
The preferred mechanism for loading images is through the ImageIO API. It supports more image formats (as well as providing a pluggable architecture) and guarantees an image that is ready to be displayed once the read method returns
BufferedImage redImage;
// ...
URL url = getClass().getResource("red.JPEG");
if (url != null) {
redImage = ImageIO.read(url);
} else {
throw new NullPointerException("Unable to locate red image resource");
}
You can try this
BufferedImage myPicture = ImageIO.read(new File("path-to-file"));
JLabel picLabel = new JLabel(new ImageIcon( myPicture ));
add( picLabel );
You've never adding anything to your frame - which is causing your problem. So in you createWindow method, you need to call:
aWindow.setContentPane(panel);
Then later on (like in your resetGame method), you'll add your content (like the JLabel) to the panel:
panel.add(empty);
Where it's added to your panel is determined by the LayoutManager of the panel (there are many of them - the default is BorderLayout)
Other helpful things:
Generally, when it makes sense, create/initialize your objects in the constructor and add/remove/update them in the runtime.
For troubleshooting, use the .setOpaque(true) and .setBackground(Color.blue) methods on what you want to see. If you don't see it then, either something is covering it up, or it was never added
Good luck.

Categories