Repaint Aero JFrame - java

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);

Related

Adding mouseevent to circle

i'm trying to make an AimTrainer where you click a circle and it makes another appear which I can do but I can not figure out how to make it so when you click a circle it registers a mouseevent. I have no idea where to start. Right now my code just draws circles and they get smaller and smaller over time until they disappear. I want to make my circles clickable. Any help appreciated.
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package testingapplication;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.MouseInfo;
import java.awt.Point;
import java.util.Timer;
import java.util.TimerTask;
/**
*
* #author 18086
*/
public class GameForm2 extends javax.swing.JFrame {
private ConstantsAndLogic constantsandlogic;
public void UpdateBoard(){
// Cursor();
ConstantsAndLogic.circlesize();
repaint();
if (ConstantsAndLogic.iDiameterX == 0){
ConstantsAndLogic.main();
ConstantsAndLogic.resetdiameter();
}
}
public GameForm2 (){
myTimer.scheduleAtFixedRate(task, 0, 50);
this.setSize(100, 100);
this.setVisible(true);
constantsandlogic = new ConstantsAndLogic();
ConstantsAndLogic.main();
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.setColor(Color.RED);
g.fillOval(ConstantsAndLogic.iCircleX,ConstantsAndLogic.iCircleY,ConstantsAndLogic.iDiameterX,ConstantsAndLogic.iDiameterY);
System.out.println(ConstantsAndLogic.iCircleX);
System.out.println(ConstantsAndLogic.iCircleY);
}
public void Cursor() {
Point cursor = MouseInfo.getPointerInfo().getLocation();
}
Timer myTimer = new Timer();
TimerTask task = new TimerTask() {
#Override
public void run() {
UpdateBoard();
}
};
}

Load a new JPanel into an existing JPanel

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

Java Jframe ICONIFIED closing failure

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);
}
}
}

JFrame repaint() and revalidate() only updating when window is resized on Mac os

I use this class for my school app projects. It is how I set the application up and it extends JFrame and implements Runnable. Now whenever I use this in school on a Windows computer and everything works and the screen updates, but at home on a Mac it doesn't. I use Eclipse neon with JDK 1.8.0_101
Please help me out, I can't test any projects at home cause of this.
import java.awt.Graphics;
import javax.swing.JFrame;
public abstract class GUIApplication extends JFrame implements Runnable{
private Screen currentScreen;
//no main, cant instentiate an abstract class
public GUIApplication(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
int x=40;
int y=40;
int width=1000;
int height=640;
setBounds(x,y,width,height);
initScreen();
setVisible(true);
}
//this is a method for creating the starting screen
protected abstract void initScreen();
public void setScreen(Screen screen){
//stop controls from previous screen
removeListeners();
setCurrentScreen(screen);
//add new controls
addListeners();
}
private void removeListeners(){
if(getCurrentScreen() != null){
if(getCurrentScreen().getMouseListener() != null) removeMouseListener(getCurrentScreen().getMouseListener());
if(getCurrentScreen().getMouseMotionListener() != null) removeMouseMotionListener(getCurrentScreen().getMouseMotionListener());
if(getCurrentScreen().getKeyListener() != null) removeKeyListener(getCurrentScreen().getKeyListener());
// if(currentScreen.getMouseWheelListener() != null) removeMouseWheelListener(currentScreen.getMouseWheelListener());
}
}
private void addListeners(){
if(getCurrentScreen() != null){
if(getCurrentScreen().getMouseListener() != null)addMouseListener(getCurrentScreen().getMouseListener());
if(getCurrentScreen().getMouseMotionListener() != null) addMouseMotionListener(getCurrentScreen().getMouseMotionListener());
if(getCurrentScreen().getKeyListener() != null){
addKeyListener(getCurrentScreen().getKeyListener());
}
// if(currentScreen.getMouseWheelListener() != null) addMouseWheelListener(currentScreen.getMouseWheelListener());
}
}
public void paint(Graphics g){
g.drawImage(getCurrentScreen().getImage(), 0, 0, null);
}
public void run(){
while(true){
getCurrentScreen().update();
repaint();
try {
Thread.sleep(30);
repaint();
revalidate();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public Screen getCurrentScreen() {
return currentScreen;
}
public void setCurrentScreen(Screen currentScreen) {
this.currentScreen = currentScreen;
}
}
This is how a game would start:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.util.ArrayList;
import javax.swing.JFrame;
import game.mainScreenTeam.Dragon;
import game.mainScreenTeam.HomeScreen;
import game.miniGameTeam.GameInstructions;
import game.miniGameTeam.GameScreen;
import game.miniGameTeam.HighScoreScreen;
import game.shopScreen.BuyScreenWendy;
import game.shopScreen.HomeShopScreen;
import game.shopScreen.SellShopZheng;
import guiPractice.GUIApplication;
import guiPractice.Screen;
import guiPractice.components.AnimatedComponent;
/**
* #author Kat
*
*/
public class DragonLand extends GUIApplication {
public static DragonLand game;
public static int coins = 1500;
public static HomeScreen homeScreen;
public static Screen shopMain; // shop 1
public static Screen sellScreen; // shop 2
public static Screen buyScreen; // shop 3
public static Screen highscoreScreen; // high score
public static GameScreen miniGameScreen; // minigame
public static Screen gameInstructionsScreen;
public static Screen HelpScreen;
public static Color NAVY;
public static Color BRIGHT_PINK;
public static Color LIGHT_PINK;
public static Color LIGHT_NUDE;
public static Color DARKER_NUDE;
/**
*
*/
// public static void addDragon(AnimatedComponent a){
// dragonList.add(a);
// }
public DragonLand() {
}
/* (non-Javadoc)
* #see guiPractice.GUIApplication#initScreen()
*/
#Override
protected void initScreen() {
initColors();
miniGameScreen = new GameScreen(getWidth(),getHeight());
shopMain = new HomeShopScreen(getWidth(),getHeight());
sellScreen = new SellShopZheng(getWidth(),getHeight());
homeScreen = new HomeScreen(getWidth(),getHeight());
buyScreen = new BuyScreenWendy(getWidth(),getHeight());
highscoreScreen = new HighScoreScreen(getWidth(),getHeight());
HomeScreen.jenCode = new game.mainScreenTeam.HomeJenniber();
gameInstructionsScreen = new GameInstructions(getWidth(), getHeight());
setScreen(homeScreen);
}
private void initColors() {
NAVY = new Color(62,74,99);
BRIGHT_PINK = new Color(224,102,102);
LIGHT_PINK = new Color(248,186,182);
LIGHT_NUDE = new Color(244,215,183);
DARKER_NUDE = new Color(230,195,147);
}
/**
* #param args
*/
public static void main(String[] args) {
game = new DragonLand();
Thread go = new Thread(game);
go.start();
}
//public coin getter + setter
public void setCoins(int x){
coins = x;
}
public int getCoins(){
return coins;
}
}
This is the home screen
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import game.DragonLand;
import guiPractice.ClickableScreen;
import guiPractice.components.Action;
import guiPractice.components.AnimatedComponent;
import guiPractice.components.Button;
import guiPractice.components.Graphic;
import guiPractice.components.TextLabel;
import guiPractice.components.Visible;
import guiPractice.sampleGames.MouseFollower;
/**
* #author Kat
* #author Jenniber
*
*/
public class HomeScreen extends ClickableScreen implements Runnable{
private Graphic background;
public static HomeJenniber jenCode;
public HomeScreen(int width, int height) {
super(width, height);
Thread play = new Thread(this);
play.start();
}
#Override
public void initAllObjects(ArrayList<Visible> viewObjects) {
background=new Graphic(0,0,getWidth(),getHeight(),"img/Grassland.png");
viewObjects.add(background);
HomeKat katCode=new HomeKat(viewObjects, getWidth(), getHeight());
}
#Override
public void run() {
}
}
katCode adds buttons to the screen and image annimations
public void paint(Graphics g){
g.drawImage(getCurrentScreen().getImage(), 0, 0, null);
}
Don't override paint() on a JFrame.
The proper way to do custom painting is to override paintComponent(...) on a JPanel (or JComponent) and then you can set the content pane of the frame to this panel. And don't forget to invoke super.paintComponent(...) as the first statement in the method. Read the section from the Swing tutorial on Custom Painting for more information and working examples.
However if you do get lazy, then at minimum you need to invoke super.paint(...) as the first statement in the paint(...) method.
Also, I doubt you need the revalidate(), since you don't appear to be adding/removing components from the frame.
But in general the order should be:
revalidate(); // to invoke the layout manager
repaint(); // paint components in new location.
I also don't know why you are invoking the update() method. That seems like old AWT code which you don't use in Swing. I suggest you take a look at the tutorial link I gave you and look at the table of contents for other Swing basics.

Creating a java method that can continuously update variables

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
}
}

Categories