Minimize/maximize parent JFrame - java

Im making a quiz application. And when a team pushed their button, they aren't allowed to still see the question or see the video/audio piece. This kind of information is displayed in the quizview ( this is a jpanel ) added to a parent JFrame. What i'm trying to do is minimize the JFrame when a button is pushed from the teams. This works perfectly. If a button is pushed the administator get a pop up in his view. If the answer is incorrect the JFrame should be maximized again. So when he pushes a button if the answer is incorrect, a boolean will be set on true in the quiz model ( $maximize ). We update the views then. In the update of the view im checking if the boolean is set on true. If it is true, i call the maximize method. And maximize it again when the answer is wrong. Minimizing works perfectly, but maximizing not.
Anyone knows what's wrong?
This is my code in the view, this view is a JPanel in the bigger JFrame, where the maximizing happens :
public void update(Observable arg0, Object arg1) {
$question = (Question) arg1;
if(((QuizModel) getModel()).getMaximize()) /* Only maximize the JFrame when needed */
maximizeFrame(); /* Maximize the frame first */
repaint();
}
/**
* Maximize the parent JFrame so the teams can see the question
*/
protected void maximizeFrame() {
System.out.println("MAXIMIZE");
JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
topFrame.setState(JFrame.MAXIMIZED_BOTH);
}
The minimizing occurs when a team pushed their button, here is the code :
/**
* If a button gets pressed we call this function
* #param team the team that pressed their button
*/
protected void buttonPressed(int team) {
/* Check if a button is pressed */
if(((QuizModel) getModel()).getTeamPressed() > 0)
$isPressed = true;
else
$isPressed = false;
/* If there hasn't been pressed yet and the question is not null */
if(!$isPressed && $question != null){
minimizeFrame(); /* Minimize the frame */
/* If this question has a media path we need to pause the audio/video, we also check if the user has installed vlcplayer and selected the right path */
if($question.getMediaPath() != null && QuizSoftwareModel.$vlcPath != null)
((QuizController)getController()).pause(); /* Pause the video */
/* Give a pop up message to the admin that a team has pushed their button */
((QuizController)getController()).showScoreView(team);
}
}
/**
* Minimize the parent JFrame so the teams can't see the question anymore
*/
protected void minimizeFrame() {
JFrame topFrame = (JFrame) SwingUtilities.getWindowAncestor(this);
topFrame.setState(JFrame.ICONIFIED);
}
[EDIT] Reduced the code.
Thanks!

The solution is using topFrame.setExtendedState(JFrame.MAXIMIZED_BOTH); instead of setState.
Setstate only sets the state of the current frame, because i needed the parent frame i needed to use setExtendedState.
Also missed some booleans to maximize/minimize when needed.

Related

JavaFX Robot.getScreenCapture causing scene to not update prior

I have an options menu from which you can save the game and it should briefly close the menu and take a screenshot of the current game.
However, the menu does not close until after calling getScreenCapture even though it runs before causing the screenshot to always be of the settings menu.
(The screenshot itself is working it's just controlling what displays at the time of the screenshot)
!! Without the screenshot line it updates the scene immediately even though the scene change line comes before.
So far I have tried Thread.sleep but no length of time allows for the scene to update
//The initial call to save:
private void saveRoom() {
program.changeState(previous);
room.save();
}
//The changing of scenes: (State extends Scene)
public void changeState(State state) {
currentState = state;
stage.setScene(currentState);
currentState.paintAll();
}
//How the game scene draws to screen:
#Override
public void paintAll() {
ArrayList<Shape> toAdd = new ArrayList<>();
for(Furniture f : furniture) {
f.paint(toAdd);
}
optionsButton.paint(toAdd);
addFurnitureButton.paint(toAdd);
root.getChildren().clear();
root.getChildren().addAll(toAdd);
}
//How the options menu draws to screen (same as game):
#Override
public void paintAll() {
ArrayList<Shape> toAdd = new ArrayList<>();
toolsButton.paint(toAdd);
saveButton.paint(toAdd);
saveAndExitButton.paint(toAdd);
exitButton.paint(toAdd);
closeButton.paint(toAdd);
root.getChildren().clear();
root.getChildren().addAll(toAdd);
}
//The capture command:
robot.getScreenCapture(null, new Rectangle2D(x,y,x1,y1));
Update: I am now using the Scene.snapshot command to take the screenshot instead and it does not cause the problem, but am still open to finding out how to go about using Robot to take a screenshot since unlike Scene.snapshot, it captures the whole screen rather than just the program which could come in handy in a future project.

JavaFX How to drag and drop an image

I am making a card game in JavaFX and what I was able to find code that will allow me to drag a piece of text. However, this doesn't show the text being dragged.
What I am currently doing is setting my scene which is the root node to be the target and setting my cards to be the source. This allows me to drag cards which are image views on my desktop but I want two things which I am struggling with.
First I want to have the image actually show up when I am dragging it and second I want to be able to place the image on my scene.
Here is the code for the card
tempImageView.setOnDragDetected(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
/* drag was detected, start a drag-and-drop gesture*/
/* allow any transfer mode */
Dragboard db =
tempImageView.startDragAndDrop(TransferMode.ANY);
/* Put a string on a dragboard */
ClipboardContent content = new ClipboardContent();
content.putData(tempImageView);
db.setContent(content);
event.consume();
}
});
Here is the code for my scene
scene.setOnDragOver(new EventHandler<DragEvent>() {
public void handle(DragEvent event) {
/* data is dragged over the target */
/* accept it only if it is not dragged from the same node
* and if it has a string data */
/* allow for both copying and moving, whatever user chooses */
event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
event.consume();
}
});
Here is the tutorial I was trying to follow: https://docs.oracle.com/javafx/2/drag_drop/jfxpub-drag_drop.htm
I am new to JavaFX so any help would be awesome!

Open JFrame on same screen(monitor) as JavaFX' 8 dialog

I am working on application that has a usual login window (JavaFX' 8 dialog), and then on accept it opens new window (JFrame). If it runs in multi-monitor environment, it should work the way, that JFrame would be opened on the same monitor where JavaFX' 8 dialog was closed.
Right now I could open JFrame on monitor that I can choose manually using
GraphicsEnvironment, but at this point I can't figure out on which monitor JavaFX' 8 dialog was closed. Any ideas? Thank you.
Maybe you could save your Position when you close your JavaFX dialog:
private void saveWindowPosition() {
Preferences userPrefs = Preferences.userNodeForPackage(getClass());
userPrefs.putDouble("stage.x", primaryStage.getX());
userPrefs.putDouble("stage.y", primaryStage.getY());
}
and read it out like this:
private void restoreWindowPosition() {
Preferences userPrefs = Preferences.userNodeForPackage(getClass());
// get window location from user preferences: use x=100, y=100 as
// default
double x = userPrefs.getDouble("stage.x", 100);
double y = userPrefs.getDouble("stage.y", 100);
primaryStage.setX(x);
primaryStage.setY(y);
}
Well, here is what worked for me:
/**
* As an argument you pass a Scene(of Java FX 8 Dialog in my example),
* by closing it you want JFrame to open on same monitor.
**/
public static int getActiveStageLocation(Scene scene){
List interScreens = Screen.getScreensForRectangle(scene.getWindow().getX(),
scene.getWindow().getY(),
scene.getWindow().getWidth(),
scene.getWindow().getHeight());
Screen activeScreen = (Screen) interScreens.get(0);
Rectangle2D r = activeScreen.getBounds();
double position = r.getMinX();
return (int) position;
}
Then you simple set location of your JFrame:
/**
* Some code for instantiating frame and so on....
* Parameter scene you could get for example from your FXML
**/
myFrame.setLocation(getActiveStageLocation(scene), myFrame.getY());
myFrame.setVisible(true);

How to write a splash screen?

I'm making a game using Java.
At the moment, I have several classes. The important ones are:
the LevelBuilder class which, upon it's default constructor being called will create a jframe with the required components and then run a gameloop thread which will update even 1/20th of a second using a backbuffer.
The other class is the MainMenu class which i want to have the main method in and to display my logo in a JFrame.
In the end I want to have the MainMenu draw a splash screen to the JFrame, and then after 5 seconds the LevelBuilder to draw inside the original JFrame, without creating a new one.
Sorry if it's a basic question, I just started learning Java.
Well a splash-screen can simply be added to your jar via the manifest.
The problem is by default it will only show for as long as it takes Swing app to load. Thus the 2nd (3rd 4th etc) execution(s) shows the splash-screen fast as JVM and classes etc used by GUI have already been loaded.
In my game to create a splash that stays for longer I had these 2 methods:
/**
* This will render the splash for longer than just loading components
*
* #return true if there is a splash screen file supplied (set via java or
* manifest) or false if not
* #throws IllegalStateException
*/
private boolean showSplash() throws IllegalStateException {
final SplashScreen splash = SplashScreen.getSplashScreen();
if (splash == null) {
return false;
}
Graphics2D g = splash.createGraphics();
if (g == null) {
return false;
}
for (int i = 0; i < 100; i++) {//loop 100 times and sleep 50 thus 100x50=5000milis=5seconds
renderSplashFrame(g);
splash.update();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
splash.close();
return true;
}
private void renderSplashFrame(Graphics2D g2d) {
//draw anyhting else here
}
which will be called something like:
JFrame frame=...;
...
//show splash
if (!showSplash()) {
JOptionPane.showMessageDialog(null, "SplashScreen could not be shown!", "Splash Error: 0x003", JOptionPane.ERROR_MESSAGE);
}
// set JFrame visible
frame.setVisible(true);
frame.toFront();
Please note as showSplash() says it will return false if there is no splash-screen supplied i.e you have not added one to the manifest.
I also would recommend a read on How to Create a Splash Screen if you already haven't.
Also see this other similar answer/question: Make splash screen with progress bar like Eclipse

JColorChooser: Save/restore recent colors in Swatches panel

I am using a JColorchooser at various places in an application. There can be multiple instances of the panel that can invoke a JColorChooser.
The "Swatches" panel in the chooser has an area of "recent" colors, which only persists within each instance of JColorChooser. I would like to (a) have the same "recent" colors in all my choosers in my application, and (b) to save the colors to disk so that these colors survive close and restart of the application.
(At least (a) could be solved by using the same single chooser instance all over the whole app, but that apears cumbersome because I would need to be very careful with attached changelisteners, and adding/removing the chooser panel to/from various dialogs.)
I did not find any method that lets me set (restore) these "recent" colors in the chooser panel. So to me, it appears that the only ways of achieving this would be:
serialize and save / restore the whole chooser (chooser panel?)
or
create my own chooser panel from scratch
Is this correct, or am I missing something?
BTW: I would also like to detect a double click in the chooser, but it seems hard to find the right place to attach my mouse listener to. Do I really need to dig into the internal structure of the chooser panel to do this? (No, it does not work to detect a second click on the same color, because the change listener only fires if a different color is clicked.)
As you noticed, there is no public api to access the recent colors in the DefaultSwatchChooserPanel, even the panel itself isn't accessible.
As you'll need some logic/bean which holds and resets the recent colors anyway (plus the extended mouse interaction), rolling your own is the way to go. For some guidance, have a look at the implementation of the swatch panel (cough ... c&p what you need and modify what you don't). Basically, something like
// a bean that keeps track of the colors
public static class ColorTracker extends AbstractBean {
private List<Color> colors = new ArrayList<>();
public void addColor(Color color) {
List<Color> old = getColors();
colors.add(0, color);
firePropertyChange("colors", old, getColors());
}
public void setColors(List<Color> colors) {
List<Color> old = getColors();
this.colors = new ArrayList<>(colors);
firePropertyChange("colors", old, getColors());
}
public List<Color> getColors() {
return new ArrayList<>(colors);
}
}
// a custom SwatchChooserPanel which takes and listens to the tracker changes
public class MySwatchChooserPanel ... {
ColorTracker tracker;
public void setColorTracker(....) {
// uninstall old tracker
....
// install new tracker
this.tracker = tracker;
if (tracker != null)
tracker.addPropertyChangeListener(.... );
updateRecentSwatchPanel()
}
/**
* A method updating the recent colors in the swatchPanel
* This is called whenever necessary, specifically after building the panel,
* on changes of the tracker, from the mouseListener
*/
protected void updateRecentSwatchPanel() {
if (recentSwatchPanel == null) return;
recentSwatchPanel.setMostRecentColors(tracker != null ? tracker.getColors() : null);
}
// the mouseListener which updates the tracker and triggers the doubleClickAction
// if available
class MainSwatchListener extends MouseAdapter implements Serializable {
#Override
public void mousePressed(MouseEvent e) {
if (!isEnabled())
return;
if (e.getClickCount() == 2) {
handleDoubleClick(e);
return;
}
Color color = swatchPanel.getColorForLocation(e.getX(), e.getY());
setSelectedColor(color);
if (tracker != null) {
tracker.addColor(color);
} else {
recentSwatchPanel.setMostRecentColor(color);
}
}
/**
* #param e
*/
private void handleDoubleClick(MouseEvent e) {
if (action != null) {
action.actionPerformed(null);
}
}
}
}
// client code can install the custom panel on a JFileChooser, passing in a tracker
private JColorChooser createChooser(ColorTracker tracker) {
JColorChooser chooser = new JColorChooser();
List<AbstractColorChooserPanel> choosers =
new ArrayList<>(Arrays.asList(chooser.getChooserPanels()));
choosers.remove(0);
MySwatchChooserPanel swatch = new MySwatchChooserPanel();
swatch.setColorTracker(tracker);
swatch.setAction(doubleClickAction);
choosers.add(0, swatch);
chooser.setChooserPanels(choosers.toArray(new AbstractColorChooserPanel[0]));
return chooser;
}
As to doubleClick handling: enhance the swatchChooser to take an action and invoke that action from the mouseListener as appropriate.
You can use the JColorChooser.createDialog method - one of the parameters is a JColorChooser. Use a static instance of the JColorChooser and make it the Dialog modal - that way, only one color chooser is displayed at a time.
The createDialog method also takes ActionListeners as parameters for the OK and Cancel button. Thus, don't really have to manage listeners. Of course, this doesn't persist the recent colors across invocations of the app, just persists recent colors in the current app.
Here's a workaround using reflection - it will work provided the underlying implementation doesn't change. Assuming you have a JColorChooser, add your recent colors to it like this:
final JColorChooser chooser = new JColorChooser(Color.white);
for (AbstractColorChooserPanel p : chooser.getChooserPanels()) {
if (p.getClass().getSimpleName().equals("DefaultSwatchChooserPanel")) {
Field recentPanelField = p.getClass().getDeclaredField("recentSwatchPanel");
recentPanelField.setAccessible(true);
Object recentPanel = recentPanelField.get(p);
Method recentColorMethod = recentPanel.getClass().getMethod("setMostRecentColor", Color.class);
recentColorMethod.setAccessible(true);
recentColorMethod.invoke(recentPanel, Color.BLACK);
recentColorMethod.invoke(recentPanel, Color.RED);
//add more colors as desired
break;
}
}

Categories