Good Afternoon, I'm back with another new-bee question. I am trying to create an program with a Star Trek inspired interface. I do not want to use dialog boxes with the program.
My interface is drawn on the screen in the fraMain class that my program calls first. It is shown below:
/**
* Troy Marker Enterprises
* TMEA-002-J: PHMS Database - Java
* Main Activity Code File
* Copyright (c) 2020 By Troy Marker Enterprises
* All Rights Under Copyright Reserved
*
* The code in this file was created for use with Troy Marker Enterprises Software.
* Use of this code by the public is strictly prohibited.
*/
package com.troymarkerenterprises;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Main program frame class
*/
public class fraMain extends JFrame implements ActionListener{
/**
* Program variable definitions
*/
private JPanel panMainMenu;
public static JPanel panSubMenu;
public static JPanel panTop;
private JPanel panBottom;
private int screenWidth;
private int screenHeight;
/**
* Method to start the program
* #param args - Method arguments
*/
public static void main(String[] args) {
new fraMain();
}
/**
* Method to draw the main window
*/
public fraMain() {
EventQueue.invokeLater(this::run);
}
/**
* Draw the main window
*/
private void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
GraphicsEnvironment graphics = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice device = graphics.getDefaultScreenDevice();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
this.setBackground(Color.BLACK);
GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
screenWidth = gd.getDisplayMode().getWidth();
screenHeight = gd.getDisplayMode().getHeight();
this.panMainMenu = new ClassMainMenu(screenWidth, screenHeight);
panSubMenu = new ClassSubMenu(screenWidth, screenHeight);
panSubMenu.setVisible(false);
panTop = new ClassTopFrame(screenWidth,screenHeight);
this.panBottom = new ClassBottomFrame(screenWidth, screenHeight);
this.add(this.panMainMenu);
this.add(panSubMenu);
this.add(panTop);
this.add(panBottom);
this.pack();
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
device.setFullScreenWindow(this);
}
#Override
public void actionPerformed(ActionEvent e) {
}
}
The screen is divided into four panels: panMainMenu, panSubMenu, panTop, and panBotom.
Each panel has its own class that draw its contents.
The panSubMenu is hidden until a button in the Main Menu is pressed, which show the sub menu. That part is working fine.
However, when I click the Exit Button on the main menu the only t hing that happens is the top frame turns white.
Here is my code for the Main Menu:
package com.troymarkerenterprises;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class ClassMainMenu extends JPanel implements ActionListener {
final TMButton department;
final TMButton grade;
final TMButton user;
final TMButton exit;
private String MainMenuOption;
private final int screenHeight;
private final int screenWidth;
public ClassMainMenu(int screenWidth, int screenHeight) {
this.screenWidth = screenWidth;
this.screenHeight = screenHeight;
this.setBackground(Color.BLACK);
this.setBounds(0, 0, 160, screenHeight);
department = new TMButton("DEPARTMENT", "green");
grade = new TMButton("GRADES", "green");
user = new TMButton("USERS", "green");
exit = new TMButton("EXIT","blue");
department.addActionListener(this);
grade.addActionListener(this);
user.addActionListener(this);
exit.addActionListener(this);
this.add(department);
this.add(grade);
this.add(user);
this.add(exit);
}
public void deselectAll() {
for (Component c : this.getComponents()) {
if (c instanceof TMButton) {
((TMButton)c).setSelected(false);
}
}
}
#Override
public void actionPerformed(ActionEvent e) {
ClassTopFrame topFrame = new ClassTopFrame();
if(e.getSource()==department) {
this.deselectAll();
fraMain.panSubMenu.setVisible(true);
department.setSelected(true);
MainMenuOption = "Department";
}
if(e.getSource()==grade) {
this.deselectAll();
fraMain.panSubMenu.setVisible(true);
grade.setSelected(true);
MainMenuOption = "Grade";
}
if(e.getSource()==user) {
this.deselectAll();
fraMain.panSubMenu.setVisible(true);
user.setSelected(true);
MainMenuOption = "User";
}
if(e.getSource()==exit) {
this.deselectAll();
exit.setSelected(true);
fraMain.panTop = topFrame.exitProgram(fraMain.panTop);
//System.exit(0);
}
}
}
And the code for the top panel:
package com.troymarkerenterprises;
import javax.swing.*;
import java.awt.*;
import java.util.Objects;
public class ClassTopFrame extends JPanel{
private int screenWidth;
private int screenHeight;
public ClassTopFrame(int Width, int Height) {
screenWidth = Width;
screenHeight = Height;
this.setBackground(Color.BLACK);
this.setBounds(160, 0, screenWidth-160, screenHeight/2);
JLabel jl=new JLabel();
jl.setIcon(new javax.swing.ImageIcon(Objects.requireNonNull(getClass().getResource("/i_TMEA-0002-J_Logo.png"))));
this.add(jl);
}
public ClassTopFrame() {
}
public JPanel exitProgram(JPanel returnPanel) {
returnPanel.setBackground(Color.BLACK);
returnPanel.setBounds(160, 0, screenWidth-160, screenHeight/2);
JLabel jl=new JLabel();
jl.setIcon(new javax.swing.ImageIcon(Objects.requireNonNull(getClass().getResource("/i_TMEA-0002-J_Logo.png"))));
returnPanel.add(jl);
return returnPanel;
}
}
My plan is the have a new panel replace the top panel when the Exit button is pressed. I know the current code will only display the same contents of the panel when the button is clicked, it just wanted to put something the int exitProgram method for it to display.
As I said, I am a Java new-bee. I am not even sure if what I want to do is possible, I want to think so. Can anyone help me figure this out?
Thanks, Troy
Here is a picture of what I am looking to do:
The right side of the screen will show the sub menu when one of the buttons is clicked.
ADDITION:
In response to some help I have been getting, I am trying to switch to a card layout, but am having problem. I tried posting here, but it looks like adding the required information will make this post to long. So I uploaded everything to my GitHub account. The main changes I made are in this fine: https://github.com/troy-marker/TMEA-0002-J/blob/main/src/com/troymarkerenterprises/ClassBottomFrame.java
Related
Thanks to a previous question answered I am now able to start my application as a tray icon (Java frame iconified issue), however I am now running into a few different issues and I am having trouble figuring out how to fix them. When the main program runs, the console window indeed no longer launches full screen as intended, however instead of just forming a system tray icon in the bottom right corner, the window also forms a traditional minimized window on the task bar. I have noticed that previously before I made this change, when the "Hide Window" button is pressed, the main taskbar window disappears leaving only the smaller system tray icon in the right corner. It seems the changes recommended in the previous question keeps the window running, but just seems to hide it from view. How can I change this behavior? I only expected to see the small system tray icon in the bottom right corner. Also, upon exiting the main application, the tray icons don't close down. They stay open, sometimes piling up if the main application is launched multiple times. If only I could figure out where the "Hide Window" action was coming from, I feel like I could figure this out, but alas, I cant see to find the actions of that button referenced anywhere in the code. Please help!
package com.skcraft.launcher.dialog;
import com.skcraft.launcher.Launcher;
import com.skcraft.launcher.swing.LinedBoxPanel;
import com.skcraft.launcher.swing.MessageLog;
import com.skcraft.launcher.swing.SwingHelper;
import com.skcraft.launcher.util.PastebinPoster;
import com.skcraft.launcher.util.SharedLocale;
import lombok.Getter;
import lombok.NonNull;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import static com.skcraft.launcher.util.SharedLocale.tr;
/**
* A frame capable of showing messages.
*/
public class ConsoleFrame extends JFrame {
private static ConsoleFrame globalFrame;
#Getter private final Image trayRunningIcon;
#Getter private final Image trayClosedIcon;
#Getter private final MessageLog messageLog;
#Getter private LinedBoxPanel buttonsPanel;
private boolean registeredGlobalLog = false;
/**
* Construct the frame.
*
* #param numLines number of lines to show at a time
* #param colorEnabled true to enable a colored console
*/
public ConsoleFrame(int numLines, boolean colorEnabled) {
this(SharedLocale.tr("console.title"), numLines, colorEnabled);
}
/**
* Construct the frame.
*
* #param title the title of the window
* #param numLines number of lines to show at a time
* #param colorEnabled true to enable a colored console
*/
public ConsoleFrame(#NonNull String title, int numLines, boolean colorEnabled) {
messageLog = new MessageLog(numLines, colorEnabled);
trayRunningIcon = SwingHelper.createImage(Launcher.class, "tray_ok.png");
trayClosedIcon = SwingHelper.createImage(Launcher.class, "tray_closed.png");
setTitle(title);
setIconImage(trayRunningIcon);
setSize(new Dimension(650, 400));
setExtendedState(JFrame.ICONIFIED); //This is the new line of code added to minimize the window on load
initComponents();
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent event) {
performClose();
}
});
}
/**
* Add components to the frame.
*/
private void initComponents() {
JButton pastebinButton = new JButton(SharedLocale.tr("console.uploadLog"));
JButton clearLogButton = new JButton(SharedLocale.tr("console.clearLog"));
buttonsPanel = new LinedBoxPanel(true);
buttonsPanel.setBorder(BorderFactory.createEmptyBorder(8, 8, 8, 8));
buttonsPanel.addElement(pastebinButton);
buttonsPanel.addElement(clearLogButton);
add(buttonsPanel, BorderLayout.NORTH);
add(messageLog, BorderLayout.CENTER);
clearLogButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
messageLog.clear();
}
});
pastebinButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pastebinLog();
}
});
hideMessages();
}
/**
* Register the global logger if it hasn't been registered.
*/
private void registerLoggerHandler() {
if (!registeredGlobalLog) {
getMessageLog().registerLoggerHandler();
registeredGlobalLog = true;
}
}
/**
* Attempt to perform window close.
*/
protected void performClose() {
messageLog.detachGlobalHandler();
messageLog.clear();
registeredGlobalLog = false;
dispose();
}
/**
* Send the contents of the message log to a pastebin.
*/
private void pastebinLog() {
String text = messageLog.getPastableText();
// Not really bytes!
messageLog.log(tr("console.pasteUploading", text.length()), messageLog.asHighlighted());
PastebinPoster.paste(text, new PastebinPoster.PasteCallback() {
#Override
public void handleSuccess(String url) {
messageLog.log(tr("console.pasteUploaded", url), messageLog.asHighlighted());
SwingHelper.openURL(url, messageLog);
}
#Override
public void handleError(String err) {
messageLog.log(tr("console.pasteFailed", err), messageLog.asError());
}
});
}
public static void showMessages() {
ConsoleFrame frame = globalFrame;
if (frame == null) {
frame = new ConsoleFrame(10000, false);
globalFrame = frame;
frame.setTitle(SharedLocale.tr("console.launcherConsoleTitle"));
frame.registerLoggerHandler();
frame.setVisible(true);
} else {
frame.setVisible(true);
frame.registerLoggerHandler();
frame.requestFocus();
}
}
public static void hideMessages() {
ConsoleFrame frame = globalFrame;
if (frame != null) {
frame.setVisible(false);
}
}
}
I'm brand new to Java and have only recently learnt about object oriented programming. I'm trying to create a program which can run a simulation, the general idea is that I want a part of the screen dedicated to buttons/sliders and another part to be dedicated the the Canvas running the simulation. For now I'm not worried about the simulation itself, I'm just trying to get some graphics on the canvas (which is smaller than the JFrame).
Here is my code (I'll try to leave some explanation below it)
public class Launcher {
public static void main(String[] args){
Display display = new Display();
}
}
.
import java.awt.*;
import javax.swing.*;
public class Display {
public final int width = 1280, height = 720;
public final int cwidth = 894, cheight = 504;
public final String title = "Mechancis Simulator";
private JFrame frame;
//private JPanel panel;
private Canvas canvas;
private Simulation simulation;
public Display(){
initDisplay();
simulation = new Simulation();
}
private void initDisplay(){
frame = new JFrame(title);
frame.setSize(width, height);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
/*panel = new JPanel();
panel.setSize(width, height);
panel.setLocation(0,0); */
canvas = new Canvas();
canvas.setPreferredSize(new Dimension(cwidth, cheight));
canvas.setMaximumSize(new Dimension(cwidth, cheight));
canvas.setMinimumSize(new Dimension(cwidth, cheight));
canvas.setLocation(width - (cwidth +15), 15);
//panel.add(canvas);
frame.add(canvas);
/* Add code for buttons/sliders/boxes here */
/* Add these to panel */
}
public JFrame getFrame(){
return frame;
}
public Canvas getCanvas(){
return canvas;
}
}
.
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import java.awt.*;
import javax.swing.*;
public class Simulation extends Display implements Runnable {
private boolean running = false;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
public Simulation(){
}
private void init(){
}
private void tick(){
}
private void render(){
bs = getCanvas().getBufferStrategy();
if(bs == null){
getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Draw Here!
//End Drawing!
bs.show();
g.dispose();
}
public void run(){
init();
while(running){
tick();
render();
}
stop();
}
public synchronized void start(){
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop(){
if(!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
When I run the program the window starts going crazy. I'm quite new to classes and threading so maybe that is the problem. I just want to be able to run the simulation after setting up Frame and Canvas in the Display object.
Thanks.
What you're doing basically is this:
class Display {
private final Simulation sim;
public Display() { sim = new Simulation(); }
}
class Simulation extends Display {
public Simulation() { }
}
when you create a new Display the constructor creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation which is a Display which creates a new Simulation...*
So don't. There's no reason for your Simulation to be a display and to own another Simulation. If you want all the control in Display define a constructor that takes as an argument the Simulation it's displaying and give it a simulation when you create it:
class Display {
private final Simulation sim;
public Display(Simulation sim) { this.sim = sim; }
}
class Simulation {
}
...
Display display = new Display(new Simulation());
*I suggest you google for a tutorial on inheritance, if you wish to know more. Here's the tutorial from oracle to get you started: "You can write a subclass constructor that invokes the constructor of the superclass, either implicitly or by using the keyword super." In your code example the constructor super() is invoked implicitly.
I'm trying to move a JButton to the location of another one but the button I want to move moves to a wrong point. My idea is that this happens because I use multiple JPanels. I tried: getLocationOnScreen, getBounds and getLocation, but none of them worked, how to solve it? When an user selects a card on the table or from a player by clicking this card the the target is set, the sender is set by clicking a card from the top panel. playerCardSpotTargetand playerCardSpotSender are both of type Card. When I try to move the for example eight of diamonds this card moves to a point behind the eight and nine of clubs.
Code:
This events belong to the blue cards on the table and the cards for the players(I have to change the name of the event, I know).
private void PlayerOneMouseClicked(java.awt.event.MouseEvent evt){
playerCardSpotTarget=(Card)evt.getSource();
if(playerCardSpotTarget.isBorderPainted()){
playerCardSpotTarget.setBorderPainted(false);
}
else{
playerCardSpotTarget.setBorderPainted(true);
}
}
This event belongs to the cards in the top panel.
private void MouseClicked(java.awt.event.MouseEvent evt) {
playerCardSpotSender=(Card)evt.getSource();
System.out.println(playerCardSpotSender.suit+" "+playerCardSpotSender.kind);
if (playerCardSpotTarget != null && playerCardSpotTarget.isBorderPainted()) {
playerCardSpotSender.setLocation(playerCardSpotTarget.getLocation());
System.out.println(playerCardSpotTarget.getLocationOnScreen());
System.out.println(playerCardSpotSender.getLocationOnScreen());
}
}
Layout for the center panel in the JFrame (BorderLayout.CENTER)
JPanel centerPanelNorth;
JPanel centerPanelCenter;
JPanel centerPanelEast;
JPanel centerPanelSouth;
JPanel centerPanelWest;
JLabel tablePicture;
JPanel centerPanel;
centerPanel=new JPanel(new BorderLayout());
tablePicture = new JLabel(new ImageIcon(this.getClass().getResource(Constants.POKERTABLE_ICON)));
centerPanelNorth=new JPanel();
centerPanelEast=new JPanel();
centerPanelSouth=new JPanel();
centerPanelWest=new JPanel();
centerPanelCenter=new JPanel();
centerPanel.add(centerPanelCenter,BorderLayout.CENTER);
centerPanelCenter.add(tablePicture);
//add
tablePicture.add(boardCard1);
tablePicture.add(boardCard2);
tablePicture.add(boardCard3);
tablePicture.setLayout(new GridBagLayout());
//PLAYER NORTH
centerPanel.add(centerPanelNorth,BorderLayout.NORTH);
centerPanelNorth.add(playerOneCardOne);
centerPanelNorth.add(playerOneCardTwo);
//PLAYER EAST
centerPanel.add(centerPanelEast,BorderLayout.EAST);
centerPanelEast.setLayout(new BoxLayout(centerPanelEast,BoxLayout.X_AXIS));
centerPanelEast.add(playerTwoCardOne);
centerPanelEast.add(playerTwoCardTwo);
//PLAYER SOUTH
centerPanel.add(centerPanelSouth,BorderLayout.SOUTH);
centerPanelSouth.add(playerThreeCardOne);
centerPanelSouth.add(playerThreeCardTwo);
//PLAYER WEST
centerPanel.add(centerPanelWest,BorderLayout.WEST);
centerPanelWest.setLayout(new BoxLayout(centerPanelWest,BoxLayout.X_AXIS));
centerPanelWest.add(playerFourCardOne);
centerPanelWest.add(playerFourCardTwo);
Card.java
public class Card extends JButton{
int suit;
int kind;
boolean known;
String iconPath;
Integer boardPosition;
}
Animating the button movement isn't actually the hardest problem, the hardest problem is trying to move the data about in away in which you can manage it and how to connect the source component with the target...
To start with, you need a means by which you can move a component across container boundaries. While there are probably a few ways to do this, the simplest is to probably use the glass pane of the frame
public class AnimationPane extends JPanel {
public AnimationPane() {
setOpaque(false);
setLayout(null);
}
}
This is nothing special, it's just a JPanel which is transparent and has no layout manager, normally, not recommended, but in the case, we're going to take control..
Now, we need some way to animate the movement...
public enum Animator {
INSTANCE;
private List<IAnimatable> animatables;
private Timer timer;
private Animator() {
animatables = new ArrayList<>(25);
timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
IAnimatable[] anins = animatables.toArray(new IAnimatable[animatables.size()]);
for (IAnimatable animatable : anins) {
animatable.update();
}
}
});
timer.start();
}
public void addAnimatable(IAnimatable animatable) {
animatables.add(animatable);
}
public void removeAnimatable(IAnimatable animatable) {
animatables.remove(animatable);
}
}
public interface IAnimatable {
public void update();
}
public interface IMoveAnimatable extends IAnimatable{
public JComponent getSourceComponent();
public IImportable getImportable();
}
So the Animator is the core "engine", it's basically a Swing Timer which simply calls update on any IAnimatables it might be managing. The intention with this approach is you can have a number of animations running, but it won't degrade the system (greatly) as you only have a single update/timer point.
Now, normally I'd just use something like the Timing Framework or the Trident Framework or even the Universal Tween Engine
The IAnimatable interfaces just define the basic contracts that provide functionality for the animation.
We need to define some kind of contract the defines objects which can take part in the animation process and receive information, or the "target"
public interface IImportable {
public JComponent getView();
public void importValue(String value);
}
public abstract class AbstractImportable extends JPanel implements IImportable {
#Override
public JComponent getView() {
return this;
}
}
Now it occurs to me that we could tap into the pre-existing Transferable API, which would allow you to also implement drag-n-drop (and even copy/cut and paste), this would be used to define a lookup mechanism where you match a given data type with potential targets based on the DataFlavor ... but I'll leave you to investigate how that might work...
The core mechanism basically removes the source component from it's current container, adds it to the AnimationPane, moves the source component across the AnimationPane and then imports the data into the target...
The problem is, you need to translate the location of component from it's current context to the AnimationPane.
A components location is relative to it's parents context. It's relatively easy to do with SwingUtilities.convertPoint(Component, Point, Component)
We calculate the origin point of the source component and the target point, relative to the AnimationPane. We then, on each call to update, calculate the progress of the animation. Instead of using a "delta" movement, we calculate the different between the time we started and a predefined duration (1 second in this case), this generally produces a more flexible animation
public class DefaultAnimatable implements IMoveAnimatable {
public static final double PLAY_TIME = 1000d;
private Long startTime;
private JComponent sourceComponent;
private IImportable importable;
private JComponent animationSurface;
private Point originPoint, destinationPoint;
private String value;
public DefaultAnimatable(JComponent animationSurface, JComponent sourceComponent, IImportable importable, String value) {
this.sourceComponent = sourceComponent;
this.importable = importable;
this.animationSurface = animationSurface;
this.value = value;
}
public String getValue() {
return value;
}
public JComponent getAnimationSurface() {
return animationSurface;
}
#Override
public JComponent getSourceComponent() {
return sourceComponent;
}
#Override
public IImportable getImportable() {
return importable;
}
#Override
public void update() {
if (startTime == null) {
System.out.println("Start");
IImportable importable = getImportable();
JComponent target = importable.getView();
originPoint = SwingUtilities.convertPoint(getSourceComponent().getParent(), getSourceComponent().getLocation(), getAnimationSurface());
destinationPoint = SwingUtilities.convertPoint(target.getParent(), target.getLocation(), getAnimationSurface());
destinationPoint.x = destinationPoint.x + ((target.getWidth() - getSourceComponent().getWidth()) / 2);
destinationPoint.y = destinationPoint.y + ((target.getHeight() - getSourceComponent().getHeight()) / 2);
Container parent = getSourceComponent().getParent();
getAnimationSurface().add(getSourceComponent());
getSourceComponent().setLocation(originPoint);
parent.invalidate();
parent.validate();
parent.repaint();
startTime = System.currentTimeMillis();
}
long duration = System.currentTimeMillis() - startTime;
double progress = Math.min(duration / PLAY_TIME, 1d);
Point location = new Point();
location.x = progress(originPoint.x, destinationPoint.x, progress);
location.y = progress(originPoint.y, destinationPoint.y, progress);
getSourceComponent().setLocation(location);
getAnimationSurface().repaint();
if (progress == 1d) {
getAnimationSurface().remove(getSourceComponent());
Animator.INSTANCE.removeAnimatable(this);
animationCompleted();
}
}
public int progress(int startValue, int endValue, double fraction) {
int value = 0;
int distance = endValue - startValue;
value = (int) Math.round((double) distance * fraction);
value += startValue;
return value;
}
protected void animationCompleted() {
getImportable().importValue(getValue());
}
}
Okay, now this produces a linear animation, which is pretty boring, now if you have plenty of time, you could create an easement like this or just use one of the animation frameworks...
Now, we need to put it together...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class AnimationTest {
public static void main(String[] args) {
new AnimationTest();
}
public AnimationTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
AnimationPane animationPane = new AnimationPane();
LeftPane leftPane = new LeftPane(animationPane);
RightPane rightPane = new RightPane();
leftPane.setImportabale(rightPane);
rightPane.setImportabale(leftPane);
JFrame frame = new JFrame("Testing");
frame.setLayout(new GridLayout(1, 2));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(leftPane, BorderLayout.WEST);
frame.add(rightPane, BorderLayout.WEST);
frame.setGlassPane(animationPane);
animationPane.setVisible(true);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class RightPane extends AbstractImportable {
private IImportable source;
private JButton imported;
private String importedValue;
public RightPane() {
setLayout(new GridBagLayout());
setBorder(new LineBorder(Color.DARK_GRAY));
}
public void setImportabale(IImportable source) {
this.source = source;
}
#Override
public void importValue(String value) {
if (imported != null) {
// May re-animate the movement back...
remove(imported);
}
importedValue = value;
imported = new JButton(">> " + value + "<<");
add(imported);
revalidate();
repaint();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public class LeftPane extends AbstractImportable {
private IImportable importable;
public LeftPane(AnimationPane animationPane) {
setLayout(new GridBagLayout());
JButton btn = new JButton("Lefty");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
DefaultAnimatable animatable = new DefaultAnimatable(animationPane, btn, importable, "Lefty");
Animator.INSTANCE.addAnimatable(animatable);
}
});
add(btn);
setBorder(new LineBorder(Color.DARK_GRAY));
}
public void setImportabale(IImportable target) {
this.importable = target;
}
#Override
public void importValue(String value) {
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
}
Maybe use mousePressed(),when you move the card,you press it until the target.And in the process, you get the information about JButton.getLocation() by the event,and than you need to solve the collision problem between two cards.So it's good!Of course, this is my advice ,you should have better idea!
I've been taking AP Computer Science this year as a sophomore in high school and we mainly cover material like loops, classes, methods, general CS logic, and some math stuff. I am missing what I really loved about coding in the first place, making games. Now every game I have made had some sort of way to manage it whether it was using timers in visual basic or a XNA plugin for c# that setup a update method for me. The problem is I have not learned how to do this for java in my course. I've read up a little on threads and implements runnable but i'm not really sure where I'm going with it.
Class 1
import java.awt.FlowLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
public class GFXScreen extends JFrame
{
/**
* #param screenHeigth
* #param screenHeigth
* #param The file name of the image. Make sure to include the extension type also
* #param The title at the top of the running screen
* #param The height of the screen
* #param The width of the screen
*/
public GFXScreen(String fileName, String screenTitle, int screenHeight, int screenWidth)
{
setLayout(new FlowLayout());
image1 = new ImageIcon(getClass().getResource(fileName));
label1 = new JLabel(image1);
this.add(label1);
//Set up JFrame
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setVisible(true);
this.setTitle(screenTitle);
this.setSize(screenWidth, screenHeight);
}
/**
* #param desired amount to move picture
*/
public void updatePic(int increment)
{
//update pos
label1.setBounds(label1.bounds().x, label1.bounds().y - increment,
label1.bounds().width, label1.bounds().height);
}
private ImageIcon image1;
private JLabel label1;
}
Class 2
public class MainClass implements Runnable {
public static void main(String[] args)
{
(new Thread(new MainClass())).start();
GFXScreen gfx = new GFXScreen("pixel_man.png", "pixel_Man", 1000, 1000);
}
public void run()
{
gfx.updatePic(1);
}
}
In this instance what I want to happen is, I want a picture that starts in the top to slowly move down smoothly to the bottom. How would i do this?
Suggestions:
Again, a Swing Timer works well for simple Swing animations or simple game loops. It may not be the greatest choice for complex or rigorous tame loops as its timing is not precise.
Most game loops will not be absolutely precise with time slices
And so your game model should take this into consideration and should note absolute time slices and use that information in its physics engine or animation.
If you must use background threading, do take care that most all Swing calls are made on the Swing event thread. To do otherwise will invite pernicious infrequent and difficult to debug program-ending exceptions. For more details on this, please read Concurrency in Swing.
I avoid using null layouts, except when animating components, as this will allow my animation engine to place the component absolutely.
When posting code here for us to test, it's best to avoid code that uses local images. Either have the code use an image easily available to all as a URL or create your own image in your code (see below for a simple example).
Your compiler should be complaining to you about your using deprecated methods, such as bounds(...), and more importantly, you should heed those complaints as they're there for a reason and suggest increased risk and danger if you use them. So don't use those methods, but instead check the Java API for better substitutes.
Just my own personal pet peeve -- please indicate that you've at least read our comments. No one likes putting effort and consideration into trying to help, only to be ignored. I almost didn't post this answer because of this.
For example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class GfxPanel extends JPanel {
private static final int BI_WIDTH = 26;
private static final int BI_HEIGHT = BI_WIDTH;
private static final int GAP = 6;
private static final Point INITIAL_LOCATION = new Point(0, 0);
private static final int TIMER_DELAY = 40;
public static final int STEP = 1;
private ImageIcon image1;
private JLabel label1;
private Point labelLocation = INITIAL_LOCATION;
private int prefW;
private int prefH;
private Timer timer;
public GfxPanel(int width, int height) {
// the only time I use null layouts is for component animation.
setLayout(null);
this.prefW = width;
this.prefH = height;
// My program creates its image so you can run it without an image file
image1 = new ImageIcon(createMyImage());
label1 = new JLabel(image1);
label1.setSize(label1.getPreferredSize());
label1.setLocation(labelLocation);
this.add(label1);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(prefW, prefH);
}
public void startAnimation() {
if (timer != null && timer.isRunning()) {
timer.stop();
}
labelLocation = INITIAL_LOCATION;
timer = new Timer(TIMER_DELAY, new TimerListener());
timer.start();
}
// My program creates its image so you can run it without an image file
private Image createMyImage() {
BufferedImage bi = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = bi.createGraphics();
g2.setColor(Color.red);
g2.fillRect(0, 0, BI_WIDTH, BI_HEIGHT);
g2.setColor(Color.blue);
int x = GAP;
int y = x;
int width = BI_WIDTH - 2 * GAP;
int height = BI_HEIGHT - 2 * GAP;
g2.fillRect(x, y, width, height);
g2.dispose();
return bi;
}
private class TimerListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
int x = labelLocation.x + STEP;
int y = labelLocation.y + STEP;
labelLocation = new Point(x, y);
label1.setLocation(labelLocation);
repaint();
if (x + BI_WIDTH > getWidth() || y + BI_HEIGHT > getHeight()) {
System.out.println("Stopping Timer");
((Timer) e.getSource()).stop();
}
}
}
private static void createAndShowGui() {
final GfxPanel gfxPanel = new GfxPanel(900, 750);
JButton button = new JButton(new AbstractAction("Animate") {
#Override
public void actionPerformed(ActionEvent arg0) {
gfxPanel.startAnimation();
}
});
JPanel buttonPanel = new JPanel();
buttonPanel.add(button);
JFrame frame = new JFrame("GFXScreen");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.getContentPane().add(gfxPanel);
frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_END);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
What I always use is an infinite loop that calls an update method each iteration, in that method, you would do whatever was required to update the state of the game or render a GUI.
Example
public static void main(String[] args){
// Initialise game
while(true){
updateGame();
}
}
public static void updateGame(){
// Update things here.
}
What I also do ,which is a little more complex, is create and interface called IUpdateListener and have certain classes that are specialised for a certain element of the game. I would example have an InputListener, an AIListener, each handling a certain element of game updating.
public interface IUpdateListener{
public void update();
}
public class Main{
public static ArrayList<IUpdateListener> listeners = new ArrayList<IUpdateListener>();
public static void main(String[] args){
listeners.add(new InputListener());
while(true){
for(IUpdateListener listener : listeners){
listener.update();
}
}
}
}
public class InputListener implements IUpdateListener{
public void update(){
// Handle user input here etc
}
}
That when painted for the first time, it is not painted correctly.
However, when I minimize the frame and restore it, it is painted correctly.
How will I fix this? I have tried repaint().
Here is the code
import javax.swing.JComponent;
import javax.swing.JFrame;
import com.sun.jna.Function;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
import com.sun.jna.Structure;
import com.sun.jna.platform.win32.WinDef.HWND;
import com.sun.jna.platform.win32.WinNT.HRESULT;
/**
* #author ex0b1t
*
*/
public class Aero {
public void enableAeroEffect(JFrame frame) {
NativeLibrary dwmapi = NativeLibrary.getInstance("dwmapi");
HWND aeroFrameHWND = new HWND(Native.getWindowPointer(frame));
MARGINS margins = new MARGINS();
margins.cxLeftWidth = -1;
margins.cxRightWidth = -1;
margins.cyBottomHeight = -1;
margins.cyTopHeight = -1;
Function extendFrameIntoClientArea = dwmapi
.getFunction("DwmExtendFrameIntoClientArea");
HRESULT result = (HRESULT) extendFrameIntoClientArea.invoke(
HRESULT.class, new Object[] { aeroFrameHWND, margins });
if (result.intValue() != 0)
System.err.println("Call to DwmExtendFrameIntoClientArea failed.");
frame.getRootPane().setDoubleBuffered(false);
frame.getRootPane().setOpaque(false);
if (frame.getRootPane().getContentPane() instanceof JComponent) {
JComponent content = (JComponent) frame.getRootPane().getContentPane();
content.setOpaque(false);
content.setDoubleBuffered(false);
}
}
/**
* #author ex0b1t
*
*/
public class MARGINS extends Structure implements Structure.ByReference {
public int cxLeftWidth;
public int cxRightWidth;
public int cyTopHeight;
public int cyBottomHeight;
}
}
import javax.swing.JFrame;
/**
* #author ex0b1t
*
*/
public class MediaManager extends JFrame {
private static final long serialVersionUID = -8440221168382362270L;
public MediaManager() {
setTitle("Media Manager");
setSize(800, 600);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
/**
* #param args
*/
public static void main(String[]args){
MediaManager mediamanager = new MediaManager();
mediamanager.setVisible(true);
new Aero().enableAeroEffect(mediamanager);
mediamanager.repaint();
}
}
Thank in advance.
What do you mean when you say it is not correctly painted?
I had a similar problem where when my frame was painted for the first time the contentPane was totally black. When i minimized the frame and then maximizing it,it was painted correctly (but not always- there were times i had to do it 2 or 3 times.) It turned out it was the drivers of my graphics card. I reinstalled them and it worked fine! (I had a Randeon)
also try
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
mediamanager.setVisible(true);
new Aero().enableAeroEffect(mediamanager);
mediamanager.repaint();
}
}
Threads and Swing
http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
SwingUtilities.invokeLater
setting the extended state of the frame to iconified and back to normal will paint the frame correctley. however when i add a component to the frame the backround is regrawn incorectley.
frame.setExtendedState(JFrame.ICONIFIED);
frame.setExtendedState(JFrame.NORMAL);