I'm trying to create a networked poker server client program, I'm currently writing the client side which includes the graphics part, However when I try to add a component to a JPanel in my code when a certain condition is met in the run method, add method doesn't seem to work, however other methods that manipulates the JPanel under the same condition works.
public class PokerClient {
BufferedReader in;
PrintWriter out;
JFrame frame = new JFrame("Poker");
JPanel playerHandPanel;
String serverAddress = "localhost";
String playerName;
Card playerHand1, playerHand2;
public PokerClient() {
// Layout GUI
frame.setSize(1100, 700);
frame.setResizable(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
playerHandPanel = new JPanel(new GridLayout(1, 2));
playerHandPanel.setPreferredSize(new Dimension(600, 300));
playerHandPanel.add(new CardComponent(new Card(3, Suit.CLUB))); //it works here
playerHandPanel.setVisible(true);
frame.add(playerHandPanel, BorderLayout.NORTH);
frame.setVisible(true);
}
/**
* Prompt for and return the desired screen name.
*/
private String getName() {
return JOptionPane.showInputDialog(
frame,
"Choose a screen name:",
"Screen name selection",
JOptionPane.PLAIN_MESSAGE);
}
private Card constructCard(String line){
int seperator = line.indexOf('/');
int cardNum = Integer.parseInt(line.substring(0, seperator));
Card card;
if(line.substring(seperator+1).startsWith("S")){
card = new Card(cardNum, Suit.SPADE);
} else if(line.substring(seperator+1).startsWith("C")){
card = new Card(cardNum, Suit.CLUB);
} else if(line.substring(seperator+1).startsWith("D")){
card = new Card(cardNum, Suit.DIAMOND);
} else{
card = new Card(cardNum, Suit.HEART);
}
System.out.println(card.toString());
return card;
}
/**
* Connects to the server then enters the processing loop.
*/
private void run() throws IOException {
Socket socket = new Socket(serverAddress, 9050);
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
// Process all messages from server, according to the protocol.
while (true) {
String line = in.readLine();
System.out.println(line);
if (line.startsWith("SUBMITNAME")) {
// String name = getName();
// playerName = name;
// out.println(name);
} else if (line.startsWith("p1")) {
playerHandPanel.add(new CardComponent(new Card(4, Suit.SPADE)));//this doesn't work i can't figure out why
playerHandPanel.setBackground(Color.WHITE);//this worked
playerHandPanel.add(new JLabel("is this added"));//this doesn't work either
playerHandPanel.repaint();
}
}
}
public static void main(String[] args) throws Exception {
PokerClient client = new PokerClient();
client.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
client.frame.setVisible(true);
client.run();
}
}
Several problems jump out:
You're not calling revalidate() on the playerHandPanel after adding or removing a component -- probably a major contributor to your problem.
You're constraining the playerHandPanel's size artificially
And not putting it into a JScrollPane
Your code flaunts Swing threading rules by making major Swing component state changes off of the Swing event thread or EDT
You're using a constraining layout, new GridLayout(1, 2)
Possible solutions:
Yes, do call revalidate() on the playerHandPanel after adding or removing a component. This will tell its layout managers to do their thing.
If you want to use GridLayout, do so in a more flexible way, such as, new GridLayout(1, 0) or new GridLayout(1, 0), depending on if you want to specify the number of columns or rows (the 0 meaning a variable number of columns or rows)
Consider using a JList or JTable, two components that are much easier to add things to.
Do learn and follow Swing threading rules, including only making Swing state changes (such as adding or removing components, changing background color...) on the Swing event thread.
Related
I am making a Library for my pupils to create a GUI easy in Java,
but if they press a button in the Interface it should run a method created by them.
Is there any way to do this?
I am not really into Java, but the curriculum wants me to:(
You can use reflection to run their class without requiring they implement an interface although you would still have to provide instructions to limit the argument types. This works only for methods with no arguments.
java.awt.EventQueue.invokeLater(() -> {
JFrame frm = new JFrame();
JPanel pnl = new JPanel();
frm.add(pnl);
pnl.setLayout(new BoxLayout(pnl, BoxLayout.Y_AXIS));
pnl.add(new JLabel("Class"));
JTextField classField = new JTextField();
pnl.add(classField);
pnl.add(new JLabel("Method"));
JTextField methodField = new JTextField();
pnl.add(methodField);
JTextArea area = new JTextArea();
area.setPreferredSize(new Dimension(300, 300));
JButton btn = new JButton("Run");
pnl.add(btn);
pnl.add(area);
System.setOut(new PrintStream(new OutputStream() {
#Override
public void write(int b) throws IOException {
area.append(new String(new byte[]{(byte) b}));
}
}));
btn.addActionListener(e -> {
try {
Class cls = Class.forName(classField.getText());
Method m = null;
Method ma[] = cls.getDeclaredMethods();
String methodName = methodField.getText().trim();
m = cls.getMethod(methodName,new Class[]{});
Object o = cls.newInstance();
Object mr = m.invoke(o);
if(null != mr) {
area.append("\nreturned "+mr.toString()+"\n");
}
} catch (Exception ex) {
ex.printStackTrace();
area.append("\nException "+ex.getMessage()+"\n");
}
});
frm.pack();
frm.setVisible(true);
});
given a class like:
public class StudentClass {
public void print10() {
int sum= 0;
for(int i = 0; i< 10; i++ ) {
System.out.println("i = "+i);
sum+=i;
}
}
}
The fields would be need to be filled with StudentClass and print10 and the compiled class needs to be on your classpath.
Perhaps a better option would be to teach Processing (https://processing.org/). This is essentially java since the Processing code gets pasted into a java class behind the scenes but is much more oriented to get beginners drawing graphical sketches. I guess you'd have to ask your administration if they would go for it and at some point the students would need to be able to write the code the processing tools are generating for them.
Currently developing a GUI in Java that communicates through Ethernet. It is designed to send data through one port and receive data through the other. The data received is used to populate a dynamic section of the GUI that changes with the data received that unfortunately must also be scaled to fit on the screen. My question is how using Java would I go about populating part of the GUI with a scaled version of the Ethernet data received?
Using swing for the display and awt for the listener. Data is received from java socket. Still unclear on exact way received data is packaged but trying to get a base idea on how to populate the virtual screen. separate thread to populate the screen most likely but also how to actually populate the screen with scaled version.
The GUI is designed to emulate a physical display unit with physical buttons and graphical display (colored words as well as arrows and other graphics, original idea was to just map it pixel for pixel but scaling throws me off).
Here is a snippet of the code, the virtual screen is not populated at the moment, just white outline and the communication port is not opened yet (all McduPanel does is paint static image to the screen, and setKey just sets a String variable based on the button pressed and sends it through the open port):
private McduPanel mPanel;
public McduGui() {
mPanel = new McduPanel();
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice vc = env.getDefaultScreenDevice();
JFrame window = new JFrame();
window.addMouseListener(new MouseClickHandler());
window.add(mPanel);
window.setUndecorated(true);
window.setResizable(false);
vc.setFullScreenWindow(window);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
try {
getPorts();
} catch (IOException ex) {
System.out.println(ex);
}
}
public static class MouseClickHandler implements MouseListener {
#Override
public void mousePressed(MouseEvent me) {
int screenX = me.getXOnScreen();
int screenY = me.getYOnScreen();
System.out.println("screen(X,Y) = " + screenX + "," + screenY);
setKey(screenX,screenY);
}
#Override
public void mouseReleased(MouseEvent e) {
}
#OverrideDo
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
}
public static void getPorts() throws IOException {
String screen = "host"; //host name
String charData = "host"; //host name
int screenPort = 71;//Integer.parseInt(71);
int charPort = 72;//port number
Socket echoSocket = new Socket(screen, 71);
PrintWriter out = new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
}
To further clarify:
A static image is painted to the screen with Strings mapped to positions on the screen that will send the String associated to that position every time it sees a mouse press. There is a virtual screen within the GUI that will change based on data received from port. It is up in the air what that data will be right now, but by design it is supposed to be the exact same as what physical screen looks like.
Best example I can give is think of a gameboy, the gameboy image is static on the panel, but virtual screen keeps updating based on the data received from the port. That box needs to be refreshed and more than likely scaled from the original size.
OK. I really tried hard to understand your problem. I am still not sure if your problem is painting, threads or reading from a socket, but I made a runnable example. The code is super ugly, but you can execute it as it is. The code create a "test server" which writes to a port every some seconds and a "test client" which reads from this port every some seconds. After the client read some text, it will print it on the screen.
Note that this is just an example - super ugly as I said, but it runs right out of the box. Also not that I strongly recommend to not paint any stuff! Use JButtons to display buttons and JTextFields (or JTextAreas) to display text. Do not print it by painting on the screen!
import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class RemoteConsole extends JPanel {
private String text = "Start";
public static void main(String[] args) throws Exception {
// your class is called McduPanel
RemoteConsole remoteConsole = new RemoteConsole();
// JFrame which contains all components
JFrame frame = new JFrame();
frame.setSize(400, 500);
frame.setVisible(true);
frame.getContentPane().add(remoteConsole);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
ServerSocket serverSocket = new ServerSocket(4564);
// this is a test server which just writes "test"
// to a port every 1 seconds
new Thread() {
public void run() {
try {
Socket socket = new Socket("localhost", 4564);
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
while (true) {
System.out.println("send");
out.println("test");
sleep(1000);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
// a test client which checks the port every 1.5 seconds
// and paints the text to a JPanel
new Thread() {
public void run() {
try {
Socket socket = serverSocket.accept();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while (true) {
String message = in.readLine();
System.out.println("received: " + message);
remoteConsole.appendText(message);
remoteConsole.repaint();
sleep(1500);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString(text, 75, 100);
}
public void appendText(String text) {
this.text += text;
}
}
I am currently in a programming course in highschool and we are focusing on Java, one of the programs required to be built is a Rock Paper Scissors game. I have done this easily and it works but i decided to try and figure out how to make it work in a window of its own. this led me to research JFrames and how to use them. I have loked up many tutorials to introduce it and I have 5 different examples from the oracle site saved to use for reference, yet i have not be able to figure out why this program won't work.
package rps;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
/**
* Name: Steven Biro
* Course Code: ICS3U
* Teacher: Mr.Carron
* Date: 23-Apr-2014
* Program Description:
*/
public class RPS
implements ActionListener {
static JPanel text,buttons;
/**
* #param args the command line arguments
*/
public void RPS() {
JButton Rock,Paper,Scissors;
buttons = new JPanel();
Rock = new JButton("Rock");
Paper = new JButton("Paper");
Scissors = new JButton("Scissors");
Rock.setMnemonic(KeyEvent.VK_D);
Paper.setMnemonic(KeyEvent.VK_M);
Scissors.setMnemonic(KeyEvent.VK_E);
Rock.setActionCommand("Rock");
Paper.setActionCommand("Paper");
Scissors.setActionCommand("Scissors");
Rock.addActionListener(this);
Paper.addActionListener(this);
Scissors.addActionListener(this);
buttons.add(Rock);
buttons.add(Paper);
buttons.add(Scissors);
}
public void actionPerformed(ActionEvent e) {
String PC,Player;
int outcome;
PC="";
Player=(e.getActionCommand());
int computer = (int)(Math.random()*3+1);
if (computer==1) {
PC="Rock";
} else if (computer==2) {
PC="Paper";
} else {
PC="Scissors";
} if (Player.equals(PC)) {
outcome=0; //tied
} else {
if ("Rock".equals(PC)) {
if ("Paper".equals(Player)) {
outcome=1; //win
} else {
outcome=2; //lose
}
} else if ("Paper".equals(PC)) {
if ("Scissors".equals(Player)) {
outcome=1; //win
} else {
outcome=2; //lose
}
} else {
if ("Rock".equals(Player)) {
outcome=1; //win
} else {
outcome=2; //lose
}
}
}
JLabel r;
if (outcome==0) {
r = new JLabel ("You Tied.");
} else if (outcome==1) {
r = new JLabel ("You Win.");
} else if (outcome==2) {
r = new JLabel ("You Lose.");
} else {
System.exit(2);
r = new JLabel ("wont ever execute");
}
text = new JPanel();
text.add(r);
}
public static void GUI() {
//Create and set up the window.
JFrame frame = new JFrame("RockPaperScissors");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
frame.add(buttons);
frame.add(text);
//Display the window.
frame.pack();
frame.setVisible(true);
frame.setSize(250,150);
}
public static void main(String[] args) {
GUI();
}
}
If you can help me figure out why the JPanels called "buttons" and "text" wont add I would be very grateful.
If I remove
//Create and set up the content pane.
frame.add(buttons);
frame.add(text);
from my program, then it runs without a problem and is just a blank window as would be expected, so i am at a loss of what to do.
EDIT:
The error i get after i make the correction of removing void from public void RPS() {
Exception in thread "main" java.lang.NullPointerException
at java.awt.Container.addImpl(Container.java:1091)
at java.awt.Container.add(Container.java:1003)
at javax.swing.JFrame.addImpl(JFrame.java:564)
at java.awt.Container.add(Container.java:415)
at rps.RPS.GUI(RPS.java:102)
at rps.RPS.main(RPS.java:114)
Picked up _JAVA_OPTIONS: -Djava.net.preferIPv4Stack=true
Java Result: 1
If i remove static from static JPanel text,buttons; then netbeans "corrects" each method so it never says static for any of them including Main so it says it cant find main.
sorry if im coming across as stupid, but if anyone could please help me figure this out i would be very appreciative.
You never create a RPS instance anywhere via new RPS().
You have a "pseudo-constructor" in your RPS class. i.e., this, public void RPS() { is not a constructor. Get rid of the void return type as constructors should have no return type: public RPS() {
Your Swing component fields should most definitely not be static.
You're adding components to a JFrame without respect for its layout manager, the BorderLayout. Your current code is adding null components, but if they weren't null, they'd both be added BorderLayout.CENTER, the last one covering up the previous one.
Create a master JPanel in the RPS class, and then add that to the JFrame in the main method, via non-static methods.
For example, RPS could potentially extend JPanel, and if that's the case, then you'd add it to the JFrame like so:
JFrame frame = new JFrame("RPS");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(new RPS());
Other suggestions:
Check out enums as Rock Paper Scissors lends itself well to this, including giving the enum methods to test for win
By using an enum, it would be easier to modify the code later to allow for additional states, such as Lizard and Spock.
Try to separate the logic portion of your program from the view -- the GUI portion.
Avoid having your GUI classes implement your listener interfaces as this leads to creation of "switch-board" listeners, kind of like you're writing -- a bear to debug or enhance. Instead experiment with anonymous inner classes, or private inner classes here.
This is probably because
public void RPS() {
is not the constructor, but a method (because it has a return type), and so is never called.
Remove the void and you should be good.
I'm in the process of writing a game. The game plays background music while it is running. This works fine, and I've decided to add a main menu, as their are three types of this game:
Single Player
Two Player
Online
When I run these classes individually (which have their own main methods - obviously), they work perfectly fine. However, in my Welcome Menu class, which is responsible for the main menu (all necessary imports are there, just not shown here):
public class WelcomeMenu implements ActionListener {
public void setButtonBG(JButton button, String imgPath) throws IOException //this method is reponsible for setting images to their corresponding JButton(s)
{
BufferedImage img = ImageIO.read(ClassLoader.getSystemResource(imgPath));
ImageIcon sp = new ImageIcon(img);
button.setIcon(sp);
button.setBorderPainted(false);
}
private JFrame welcomeWindow = new JFrame("Tic-Tac-Toe");
private JButton singlePlayerButton = new JButton();
private JButton twoPlayerButton = new JButton();
private JButton onlineButton = new JButton();
public WelcomeMenu() throws IOException
{
//START OF CONSTRUCTOR
//Main window is being sized, default way to close, and internal layout
welcomeWindow.setSize(600, 420);
welcomeWindow.setLayout(new CardLayout());
//Object res = this.getClass().getResource("/");
//System.out.println(res);
BufferedImage bf = ImageIO.read(ClassLoader.getSystemResource("images/mainMenuBG.jpg"));
welcomeWindow.setContentPane(new backImage(bf)); // adding created component to the JFrame using the backImage class
welcomeWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
welcomeWindow.setLocationRelativeTo(null);
welcomeWindow.setResizable(false);
welcomeWindow.setVisible(true);
//setting the icon
try
{
java.net.URL url = ClassLoader.getSystemResource("images/icon.png");
Toolkit kit = Toolkit.getDefaultToolkit();
Image img = kit.createImage(url);
welcomeWindow.setIconImage(img);
}
catch(NullPointerException n)
{
System.out.println("Image could not be fetched.");
}
//adding custom buttons
//ImageIcon singlePlayer = new ImageIcon("images/singlePlayerButton.jpg");
//setting sizes
singlePlayerButton.setSize(387, 72);
twoPlayerButton.setSize(387, 72);
onlineButton.setSize(387, 72);
//setting background images to buttons
setButtonBG(singlePlayerButton, "images/sPlayerButton.jpg");
setButtonBG(twoPlayerButton, "images/tPlayerButton.jpg");
setButtonBG(onlineButton, "images/mPlayerButton.jpg");
//adding listeners
singlePlayerButton.addActionListener(this);
twoPlayerButton.addActionListener(this);
onlineButton.addActionListener(this);
//adding the custom buttons
welcomeWindow.add(singlePlayerButton);
welcomeWindow.add(twoPlayerButton);
welcomeWindow.add(onlineButton);
//setting locations and visibility
singlePlayerButton.setLocation(110, 90);
singlePlayerButton.setVisible(true);
twoPlayerButton.setLocation(110, 182);
twoPlayerButton.setVisible(true);
onlineButton.setLocation(110, 274);
onlineButton.setVisible(true);
//END OF CONSTRUCTOR
}
public static TicTacToeTP spg;
//All actions are done here
#Override
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == singlePlayerButton)
{
System.out.println("<LOG> SINGLE PLAYER GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
if(e.getSource() == twoPlayerButton)
{
System.out.println("<LOG> TWO PLAYER GAME REQUESTED");
try
{
//spg = new TicTacToeTP("images/black-squareMod_RED.jpg");
//spg.playBackgroundSong();
TicTacToeTP.main(null);
}
catch(IOException io)
{
System.out.println("IO EXCEPTION!");
}
welcomeWindow.setVisible(false);
welcomeWindow.dispose();
}
if(e.getSource() == onlineButton)
{
System.out.println("<LOG> ONLINE GAME REQUESTED");
JOptionPane.showMessageDialog(welcomeWindow, "This game mode has not been implemented yet.");
}
}
public static void main(String[] args) throws IOException
{
EventQueue.invokeLater(new Runnable()
{
#Override
public void run()
{
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex)
{
}
}
});
new WelcomeMenu();
}
}
... if I click the Two Player button, for example, it plays the audio ONLY. None of my other components load. Just an empty JFrame. Notice how in the actionPerformed() method, I tried both TicTacToeTP.main(null) and (commented out, now) instantiating a new TicTacToeTP object AND calling the playBackgroundSong() method. If I eliminate this methods call, and just instantiate the object, it works fine - but no music.
Why is this happening, and how can I fix it?
Here is the playBackgroundSong() method:
private Player p = null;
//private InputStream fis = null;
public void playBackgroundSong() //responsible for playing background music
{
//PausablePlayer p = null;
InputStream fis = null;
ArrayList<InputStream> stream = new ArrayList<InputStream>(); //this ArrayList contains multiple audio files that the method will loop through >> defined below
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Basic space - The XX - Instrumental.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Mirrors [ Upbeat Electronic Instrumental ] Spence Mills HQ Free Beat Download 2012.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/Static [ Aggressive Dark Pop Hip Hop Rap Instrumental ] Spence Mills Free Beat Download Link 2012 HD.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 soundtrack Med Sci 1.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/System Shock 2 Soundtrack Ops 2.mp3"));
stream.add(ClassLoader.getSystemResourceAsStream("resources/01 Intro.mp3"));
Collections.shuffle(stream);
for(int i = 0; i < stream.size(); i++)
{
try
{
fis = stream.get(i);
}
catch (NullPointerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p = new Player(fis);
}
catch (JavaLayerException ex)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ex);
}
try
{
p.play();
}
catch (JavaLayerException ee)
{
Logger.getLogger(TicTacToeTP.class.getName()).log(Level.SEVERE, null, ee);
}
}
playBackgroundSong();
}
You appear to be playing a long-running bit of code, playBackgroundSong(), on the Swing event dispatch thread or EDT. This thread is responsible for painting the GUI and interacting and responding to user input, and if it gets tied up, the program essentially freezes. This might not have been an issue when you called this method in the main method -- basically off of the Swing event thread, but is an issue when it is specifically called on the event dispatch thread. A possible solution: play your music in a background thread. A SwingWorker might work well for you, and there are decent tutorials on the use of these and the EDT. Google "Concurrency in Swing", and check out what will likely be the first hit for more.
As an aside: you usually don't want to call another class's main method. Instead create an instance of the other class and use it.
Edit You state:
Thanks. Looking at this part: docs.oracle.com/javase/tutorial/uiswing/concurrency/simple.html Seems to explain what I want to do, correct? I am reading it all, by the way
Actually you could go even simpler. Since you're not waiting for a result from your playBackgroundSong(), you could possibly just call it in its own simple thread by just wrapping it in a Runnable and then putting that in a Thread:
new Thread(new Runnable() {
public void run() {
playBackgroundSong();
}
}).start();
Before coming here, I have searched all over the web and read dozens of topic talking about this but I can't fix my problem.
I want to show the progress of an upload. In the following code, everything works, except that my JFrame does not update. I am using a technique I found on another topic, but it doesn't seem to work. I think it will be more simple if you take a look at my code (I erased the instructions that aren't related to the problem).
/*
* Correct imports have been done
*/
class GUI extends JFrame {
public JPanel pan;
public GUI(JPanel panel) {
super("Uploading...");
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
setPreferredSize(new Dimension(600, 500));
setMinimumSize(new Dimension(600, 500));
setMaximumSize(new Dimension(600, 500));
setDefaultCloseOperation(this.DO_NOTHING_ON_CLOSE);
setLocationRelativeTo(null);
pan = panel;
pan.setLayout(new BoxLayout(pan, BoxLayout.Y_AXIS));
setContentPane(pan);
setVisible(true);
}
}
public class GUIUpload {
private static GUI ui;
public static void main(String args[]) {
JPanel main = new JPanel();
ui = new GUI(main); // create and display GUI
uploadLoop(args, main); // start the upload loop
/*
* After upload is finished
*/
JButton jb = new JButton("Ok");
jb.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent arg0) {
ui.setVisible(false);
}
});
ui.getContentPane().add(jb);
ui.getContentPane().repaint();
}
private static void uploadLoop(String[] paths, JPanel monitor) {
/*
* Upload starts here
*/
long transfered;
long size;
InputStream inputStream;
FTPClient ftpClient = new FTPClient();
try {
ftpClient.connect("xxxxxx", 21);
boolean success = ftpClient.login("xxxxxx", "xxxxxx");
/*
* Sending
*/
for (int i = 0; i < 4; i++){
if (paths[i] != null){
File localFile = new File(paths[i]);
String remoteFile = "/public_html/papers/" + i + ".pdf";
JLabel label = new JLabel("Uploading...");
ui.getContentPane().add(label);
ui.repaint();
inputStream = new FileInputStream(localFile);
// Monitoring misc
size = localFile.length();
transfered = 0;
int percentage = 0;
// Progress bar
JProgressBar pgb = new JProgressBar();
pgb.setValue(0);
ui.getContentPane().add(pgb);
ui.repaint();
// Upload routine
OutputStream outputStream = ftpClient.storeFileStream(remoteFile);;
byte[] bytesIn = new byte[4096];
int read = 0;
while ((read = inputStream.read(bytesIn)) != -1) {
outputStream.write(bytesIn, 0, read);
transfered += read;
percentage = (int)(transfered * 100.0 / size + 0.5);
System.out.println(percentage);
pgb.setValue(percentage);
ui.repaint();
}
inputStream.close();
outputStream.close();
boolean completed = ftpClient.completePendingCommand();
/*
* End of upload
*/
}
}
} // end try
catch (Exception e){
// Do nothing}
} // end catch
} // end upload method
}
The percentage works fine. The file transfer works fine. The GUI frame only updates after when I repaint it in the main method of the GUIUpload class. When it repaints, I can see that all the labels and progressbars have been correctly added and updated (the progress bars are showing the maximum value.
So.. it's been quite a while that I'm searching how to do this, and I've tried using threads, I've tried a lot of things, but none worked (or I did something wrong when trying them).
Thanks a lot to anyone who will be able to help me out.
Best regards.
Swing is single-threaded. When you perform resource heavy tasks such as file download, you prevent Swing from repainting.
It's unsurprising that raw Threads didn't work as Swing has it's own concurrency features that provide a means of dealing with time-consuming background tasks. Threads were not designed to interact with swing components.
Use a SwingWorker.