I am trying to fetch data from the database and publish the result on a JPanel.
Here is the simplified code:
public class LedgerView extends JPanel {
public LedgerView() {
super();
this.setLayout(new FlowLayout());
this.add(new JLabel("ITEMS:"));
String JDBC_DRIVER = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://localhost/gnufinance";
String USERNAME = "gnufinance";
String PASSWORD = "gnuisnotunix";
Connection conn = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
String query = "SELECT * FROM transactions";
try {
PreparedStatement ps = conn.prepareStatement(query);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
String desc = rs.getString(3);
System.out.println(desc);
this.add(new JLabel(desc));
}
} catch (SQLException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
JFrame view = new JFrame();
view.setVisible(true);
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
}
Nothing is displayed except a blank grayed frame, but when I remove the JDBC code, the first JLabel(ITEMS) is displayed. There is nothing on the screen but the System.out.println in the while loop prints all the data properly on the console. There are no exceptions.
You have to create the panel on the Event Dispatch Thread, or EDT.
Swing is not Thread Safe; any changes that you make to swing controls (such as creating new JLabels), must occur on the EDT (which is not the thread your main method starts on. You use EventQueue.invokeLater() to tell Java to move the work onto the Swing drawing thread.
Note that most of the time you do not want your work (like accessing a database) to occur on the EDT because it will make your user interface unresponsive. In other words, your program will be doing the work of accessing the database when it could, instead, be drawing your screen.
This code will fix your immediate problem, but you should consider accessing the database somewhere else (perhaps, for now, in your main method), storing the result in a List, and then passing the List to your LedgerView, which will result in a more responsive user interface.
public static void main(String[] args) {
final JFrame view = new JFrame();
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
view.setSize(300, 300);
view.add(new LedgerView(), BorderLayout.CENTER);
view.setVisible(true);
}
}
}
Related
I'm quite the beginner when it comes to java & coding in general, so I apologise for any overly obvious questions asked. I've just completed part of an application which reads data from an SQL database, then sends some stuff to print to socket depending on what information is read. I'm now trying to learn swing and get a GUI working with the application. Currently I have 2 forms, the first is used to select a printer, then the second will (hopefully) work as a log/ console which tells the user what and when stuff is happening. I've got the code and the forms together in a project.
I was wanting to find out how I can make the class which has my code in run when a Jbutton is pressed on a GUI, as well as how I can stop it from running when a different JButton is pressed.
The code from the Swing Form (Form2.java) is as follows:
package com.company;
import javax.swing.*;
public class Form2
{
private JTextArea jtaConsole;
private JPanel Jframer;
private JButton stopButton;
private JButton startButton;
public Form2(String message)
{
JFrame frame = new JFrame("Print Application");
frame.setContentPane(this.Jframer);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setResizable(true);
frame.setVisible(true);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
jtaConsole.append(" Printer selected: " + message + "\n");
}
}
And the code from the class I want the JButton to run is as follows:
package com.company;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.sql.*;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ZebraCode
{
public static void main(String[] args)
{
{
while (true)
{
//SQL login.
String connectionString = "jdbc:sqlserver://:;database=;user=;password=!!;";
//Select Data.
String SQL = "SELECT TOP 2 [PK_PrintQueueID],[FK_PrinterID],[FK_BarcodeTypeID],[Barcode],[Quantity],[QueueDate],[ProcessedDate] FROM [Brad].[dbo].[PrintQueue] -- WHERE ProcessedDate IS NULL";
//Connection Variable & Time Settings.
Connection connection = null;
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date();
try
{
connection = DriverManager.getConnection(connectionString);
Statement stmt = connection.createStatement();
Statement stmt2 = null;
ResultSet rs = stmt.executeQuery(SQL);
while (rs.next())
{
// Get barcode value to split & Set date.
String FK_BarcodeTypeID = rs.getString("FK_BarcodeTypeID");
String barcode = rs.getString("Barcode");
String[] parts = barcode.split("-");
String part1 = parts[0];
String SQL2 = "UPDATE PrintQueue SET ProcessedDate = '" + dateFormat.format(date) + "' WHERE PK_PrintQueueID = '" + rs.getString("PK_PrintQueueID")+"'";
stmt2 = connection.createStatement();
stmt2.executeUpdate(SQL2);
// Action based on type of barcode.
if (FK_BarcodeTypeID.equals("1"))
{
// Type 128 barcode.
String zpl = "^XA^BY2,3,140^FT80,200^BCN,Y,N,N^FD>:" + rs.getString("Barcode") + "^FS^FT200,250^A0N,42,40^FH^FD" + part1 + "^FS^XZ";
printlabel(zpl);
System.out.println("New serialized barcode added.\nPrinting: " + (rs.getString("Barcode")));
System.out.println("Process date: " + dateFormat.format(date) + ".\n");
}
else
{
// Type 39 barcode.
String zpl = "CT~~CD,~CC^~CT~ ^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR4,4~SD15^JUS^LRN^CI0^XZ^XA^MMT^PW674^LL0376 ^LS0 ^BY2,3,151^FT84,249^BCN,,Y,N^FD>:" + rs.getString("Barcode") + "^FS ^PQ1,0,1,Y^XZ";
printlabel(zpl);
System.out.println("New un-serialized barcode added.\nPrinting: " + (rs.getString("Barcode")));
System.out.println("Process date: " + dateFormat.format(date) + ".\n");
}
}
} catch (SQLException e)
{
e.printStackTrace();
}
try
{
//Makes execution sleep for 5 seconds.
Thread.sleep(5000);
}
catch (InterruptedException ez)
{
}
}
}
}
//Printer Info.
public static void printlabel(String zpl)
{
try
{
Socket clientSocket;
clientSocket = new Socket("", );
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
outToServer.writeBytes(zpl);
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Any tutorials or direction as to how I can learn this would be appreciated.
Thanks!
You want to add an action listener.. here is an example. Below are two examples on how to do so using lambdas and not using one.
JButton button = new JButton("Click Me!");
// Without lambda
button.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
// Code to execture when clicked
}
});
//With lambda
button.addActionListener(e -> {
//code to execute when clicked
});
I'd also advise you to do a little reading, http://www.tutorialspoint.com/design_pattern/mvc_pattern.htm
Your question is a bit broad but let me offer some suggestions:
First off, you really don't want to have a JButton run the database code unchanged as doing this would be shoehorning a linear console program into an event-driven GUI, a recipe for disaster. Note that as written all your database code is held within a single static main method, and so there would be no way for the GUI to be able to control the running of that code. Either it runs or it doesn't, that's it, and no easy way for the database code to return its data to the GUI.
Instead first change that database code so that it is much more modular and OOP-friendly, including creating proper classes with state (instance fields) and behavior (instance methods), and getting almost all that code out of the static main method.
What I'm asking you to do is to create a proper model for your GUI, aka your view. Only after doing this would you have your GUI create a model object and call its methods on button push within your ActionListener. You will also want to call any long-running code within a background thread such as can be obtained with a SwingWorker.
Other issues:
You never initialize your JPanel or JTextArea variables, and so you're both adding a null variable as your JFrame's JPanel and calling methods on a null JTextArea variable, both of which will throw NullPointerExceptions.
Here's a part of code I developed to better understand Java gui. I'm also a begginer.
It's three classes: starter class, ongoing non gui processes, gui with the swingworker method. Simple, works, can safely update a lot of gui components from Swingworkers process method (passes a class instance as argument). Whole code so it can be copy/pasted:
package structure;
public class Starter {
public static void main(String[] args) {
Gui1 thegui = new Gui1();
}
}
LOGIC
package structure;
public class Logical {
String realtimestuff;
public String getRealtimestuff() {
return realtimestuff;
}
public void setRealtimestuff(String realtimestuff) {
this.realtimestuff = realtimestuff;
}
//MAIN LOGICAL PROCESS..
public void process(){
// do important realtime stuff
if (getRealtimestuff()=="one thing"){
setRealtimestuff("another thing");
}else{setRealtimestuff("one thing");
}
// sleep a while for readibility of label in GUI
//System.out.println(getRealtimestuff());
try {
Thread.sleep(250);
} catch (InterruptedException e) {
System.out.println("sleep interrupted");
return;
}
}
}
GUI CLASS with Swingworker
package structure;
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JLabel;
import java.util.List;
import javax.swing.*;
public class Gui1 {
final class Dataclass{
String stringtosend;
public Dataclass(String jedan){
//super();
this.stringtosend = jedan;
}
}
// EDT constructor
JFrame frame;
public Gui1(){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
initialize();
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void initialize() {
// JUST A FRAME WITH A PANEL AND A LABEL I WISH TO UPDATE
frame = new JFrame();
frame.setBounds(100, 100, 200, 90);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.NORTH);
JLabel lblNovaOznaka = new JLabel();
panel.add(lblNovaOznaka);
frame.setVisible(true);
SwingWorker <Void, Dataclass> worker = new SwingWorker <Void, Dataclass>(){
#Override
protected Void doInBackground() throws Exception {
Logical logic = new Logical();
boolean looper = true;
String localstring;
while (looper == true){
logic.process();
localstring = logic.getRealtimestuff();
publish(new Dataclass(localstring));
}
return null;
}
#Override
protected void process(List<Dataclass> klasa) {
// do a lot of things in background and then pass a loto of arguments for gui updates
Dataclass xxx = klasa.get(getProgress());
lblNovaOznaka.setText(xxx.stringtosend);
}
};
worker.execute();
}
}
I have a main JFrame and three java class that contains different pie charts and these piechart are in panel. I want to call the three pie classes in main jframe. How can l do that?
// I have three of these Chart classes creating different charts inside panels
public class PiePanel extends Observer {
Singleton connCC = Singleton.getInstance();
Connection con = null;
Statement stm = null;
PiePanel(Subject s) {
panel = new JPanel();
sub = s;
}
#Override
public void update() {
try {
con = connCC.getDBconnection();
stm = con.createStatement();
ResultSet rs = stm.executeQuery("Select pet_name as pet, count(pet_ID) AS 'count' from Pet group by pet_name");
DefaultPieDataset dataset = new DefaultPieDataset();
while (rs.next()) {
dataset.setValue(rs.getString("pet"), Integer.parseInt(rs.getString("count")));
}
JFreeChart pieChart = ChartFactory.createPieChart("Header", dataset, true, true, false);
PiePlot plot = (PiePlot) pieChart.getPlot();
plot.setSimpleLabels(true);
PieSectionLabelGenerator gen = new StandardPieSectionLabelGenerator(
"{0}: {1} ({2})", new DecimalFormat("0"), new DecimalFormat("0%"));
plot.setLabelGenerator(gen);
panel.add(new ChartPanel(pieChart) {
#Override
public Dimension getPreferredSize() {
return new Dimension(335, 235);
}
});
panel.validate();
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
}
//below is a class that puts all the panels inside a list
public class Subject {
private List<Observer> panel = new ArrayList<Observer>();
public Subject(){
panel.add(new BarPanel(this));
panel.add(new AreaPanel(this));
panel.add(new PiePanel(this));
}
public List<Observer> getChart(){
return panel;
}
}
//main
public class Main {
public static void main(String[] args) {
Subject s = new Subject();
while (true) {
String input = JOptionPane.showInputDialog(null, "Input value:");
if ("d".equals(input) || "w".equals(input)) {
try {
//String value = Integer.parseInt(input);
s.setState(input);
} catch (Exception e) {
System.exit(0);
}
} else {
System.out.println("Wrong Input!");
System.exit(0);
}
}
}
}
Now i want to pass this list in another JFrame class just as in the picture.
Your problem is that you're adding three components in a default fashion to a container that uses BorderLayout, and this results in each added component in the BorderLayout.CENTER covering all the other components added previously. If you want to display three components you can:
Use BorderLayout constants to add the components to different locations within the BorderLayout-using container, or
use a different layout, here perhaps a GridLayout(3, 1), or
if you want a more complex GUI that shows more components, then nest JPanels, each using its own layout manager.
For example, if you want to display the pie charts to the side for instance, then I'd put them into a JPanel that uses a GridLayout, and then add that GridLayout using JPanel to the BorderLayout-using main GUI in the BorderLayout.LINE_END position, or whatever location you desire.
If on the other hand your goal is to swap out one JPanel for another in response to an event, then use a CardLayout to allow easy and efficient swapping of components.
I am trying to learn ProgressMonitor in Java Swing.
I created this simple test code -
public class ProgressMonitorTest extends JFrame
{
private JPanel contentPane;
private ProgressMonitor progressMonitor;
private JButton button;
private static ProgressMonitorTest frame;
private static boolean isFrameReady;
public JButton getButton()
{
return button;
}
public ProgressMonitor getProgressMonitor()
{
return progressMonitor;
}
/**
* Launch the application.
*/
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
try
{
frame = new ProgressMonitorTest();
frame.setVisible(true);
isFrameReady = true;
}
catch (Exception e)
{
e.printStackTrace();
}
}
});
while(!isFrameReady)
{
//
}
frame.getButton().addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e)
{
try
{
for(int i=0;i<=10;i++)
{
final int percent = i;
SwingUtilities.invokeAndWait(new Runnable()
{
#Override
public void run()
{
frame.getProgressMonitor().setProgress(percent * 10);
frame.getProgressMonitor().setNote("Completed " + percent*10 + "%.");
}
});
try
{
Thread.sleep(1000);
}
catch(Exception ee)
{
//
}
}
}
catch(Exception es)
{
//
}
}
});
}
/**
* Create the frame.
*/
public ProgressMonitorTest()
{
isFrameReady = false;
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
setTitle("Progress Monitor");
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
progressMonitor = new ProgressMonitor(frame, "Update in progress...", "", 0, 10);
button = new JButton("Click Here");
contentPane.add(button);
setContentPane(contentPane);
}
}
A few questions regarding this-
If I remove the isFrameReady check, the program says a NullPointerException at the line where I assign the button's action listener.
If I keep the above check, then clicking on the button does nothing.
Keeping the above check and then debugging this, I let it wait for some time before it gets to the line where the action listener. In this case, it works but immediately quits saying it can't call invokeAndWait from the event handling thread.
What am I missing in all this ? Can someone explain how to get this to work.
If I remove the isFrameReady check, the program says a
NullPointerException at the line where I assign the button's action
listener.
your use of isFrameReady ensures that you have created your frame successfully. inside your main, your posted request to event dispatch thread(EDT) using call EventQueue.invokeLater(new Runnable(){}): removing the check isFrameReady, you were going to call frame.getButton() in main thread but the frame have not been yet created by frame = new ProgressMonitorTest(); in the EDT and thus a NullPointerException occurs.
If I keep the above check, then clicking on the button does nothing.
you should understand by now, that above check is nothing to do with button click. The button is not doing anything because the GUI got freezed for violating swing's single threading rule. Put your incrementing for loop of the actionPerformed method inside another thread as the following code fragement shows and execute it from there. you will see that it works fine.
new Thread(){
public void run()
{
for(int i=0; i<10; i++)
{
//whatever you were doing.
}
}
}.start();
Keeping the above check and then debugging this, I let it wait for
some time before it gets to the line where the action listener. In
this case, it works but immediately quits saying it can't call
invokeAndWait from the event handling thread.
SwingUtitlies.invokeAndWait() blocks the current thread and waits until the EDT is done executing the task given to it. As actionPerformed() function is already running inside EDT, so calling SwingUtitlies.invokeAndWait() from the current thread:EDT would block the current thread:EDT which should not be allowed. Don't use invokeAndWait for this case. you should call SwingUtilities.invokeLater() instead.
However I don't think you will get anything until you understand Swing threading model. Read the javadoc and some internet resource. DO HAVE The book Filthy Rich Clients and try the example the book offered: You will have a greater knowledge in graphical effects then any other resource can provide.
I want to write a program that allows user to connect,view and add or delete values from database. I'm stuck with the swing part. When i select a combobox option nothing happens but i want to create a view like mysql workbench. It suppose to be like that; user picks a table name from combobox and can see column names from that table and textfields to add new values or existing values above column names.
My code is this so far:
public class DBC extends JFrame{
static String tablo;
static JTextField tf = new JTextField(20);
static int columnCount;
static JPanel tfPanel = new JPanel();
static JLabel depName = new JLabel("Name");
static JLabel depLocation = new JLabel("Location");
static Box box = new Box(BoxLayout.Y_AXIS);
public static void main(String[] args) throws Exception {
Class.forName("com.mysql.jdbc.Driver");
Connection connect = DriverManager.getConnection("jdbc:mysql://localhost:3306/project"
,"root","123456789");
final Statement statement = connect.createStatement();
JLabel tabloSec = new JLabel("Tablo Seçin:");
final JComboBox<String> tablolar = new JComboBox<String>();
DatabaseMetaData md = connect.getMetaData();
final ResultSet rs = md.getTables(null, null, "%", null);
while (rs.next()) {
tablolar.addItem(rs.getString(3));
}
tablolar.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
tablo = tablolar.getSelectedItem().toString();
try {
columnCount = rs.getMetaData().getColumnCount();
for(int i=0;i<=columnCount;i++ ){
box.add(tf);
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
JButton ekle = new JButton("Ekle");
ekle.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent e) {
try {
switch(tablo){
case "department":
statement.executeUpdate("INSERT INTO department(Name,Location) VALUES('"+tf.getText()+"')");
case "employee":
statement.executeUpdate("INSERT INTO employee(Id,FirstName,LastName,Sex,Address,Email,Salary,BirthDate,JoinDate) VALUES('"+tf.getText()+"')");
case "engineer":
statement.executeUpdate("INSERT INTO engineer(EngineerType) VALUES('"+tf.getText()+"')");
case "manager":
statement.executeUpdate("INSERT INTO manager(Department) VALUES('"+tf.getText()+"')");
case "project":
statement.executeUpdate("INSERT INTO project(Name,Number,Value) VALUES('"+tf.getText()+"')");
case "secretary":
statement.executeUpdate("INSERT INTO secretary(TypingSpeed) VALUES('"+tf.getText()+"')");
}
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
});
JButton cik = new JButton("Çık");
cik.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
JPanel panel = new JPanel(new GridLayout(4,3));
panel.add(tabloSec);
panel.add(tablolar);
panel.add(box);
panel.revalidate();
panel.add(ekle);
panel.add(cik);
JFrame frame = new JFrame("Deneme");
frame.setSize(600,600);
frame.setLocationRelativeTo(null);
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
}
Looks like you're adding the same text field when iterating over the metadata of the result set: box.add(tf);. This will add the same text field only once. You also need to validate() and repaint() the box container after adding new controls to it. Note that you also need to remove all controls from the box container when selecting new table. You may need to introduce scroll pane. In addition, SQL statement execution refers to the same text field. Unless of course there is only one column and one value that is always should be updated.
All in all, unless this is a very specific solution for a very specific set of tables, you may consider using friendlier controls for this, perhaps a list or a table. Maybe something similar to a properties table where first column specifies the name of the property, and the second column the value of that property. The value column is editable. You can repopulate the properties table once new SQL table is selected. Then on statement execution, just collect all the necessary values. As an alternative, you can also show the relevant view of a SQL table and let user tweak whatever values and then update SQL once done. Look at Table From Database by #camickr.
Also note that you should not execute SQL statements on Event Dispatch Thread, this may freeze your UI as long operations will block EDT. These operations should be handled on an auxiliary worker thread. See Event Dispatch Thread. It is common to use SwingWorker to handle such lengthy tasks.
i really need to find better ways to word my questions.
Basically I've created a program that takes information from a webpage and displays it nicely across the screen.
When the user closes the program, they actually hide it.
I also have another method which constantly loops checking for information to see if tis been updated.
unfortunately the problem im having is that it loops to fast, i only want it to check for information every 40 seconds or so.
What i tried was inserting a wait(1000,1000) in the method itself and in the main of the program. but both of these cause IllegalMonitorStateException.
Is this the correct way to make the thread wait properly? or is there a better way?
note: the only thread i have is the main.
MAIN
class Marquee
{
public static void main(String[] args) throws InterruptedException
{
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
while(true)
{
// this doesnt work
frame.wait(1000,1000);
frame.notifyAll();
frame.checkForNewUpdate();
System.out.println(" ____________________________next line _______________________________");
}
}
}
CHECK FOR UPDATES
public String[] checkForNewUpdate()
{
//setVisible(true);
String tempUpdate = getEngineersUpdate();
if (latestUpdate[0] != tempUpdate)
{
// do nothign
setVisible(false);
}
else if(latestUpdate[0]==tempUpdate)
{
latestUpdate[0] = tempUpdate;
//show the page again
setVisible(true);
}
else if(latestUpdate[0]!= "NULL")
{
// do nothing
//latestUpdate[0] = tempUpdate;
}
else
{
latestUpdate[0] = tempUpdate;
}
return latestUpdate;
}
1: WHat am i doing wrong to get this exception
2: Is there any other way to make a gap of time in a method
3: Am i going to have to put all these methods into another thread? Please say no
// my constructor which I failed to mention has a timer in it. only i dont know hwo to use it
class MyFrame extends JFrame implements ActionListener
{
private ActionListener listener;
private Timer t1;
private String [] latestUpdate = new String[1];
public MyFrame()
{
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();// gets the maximum size of the screen
setSize(d.width,(d.height/100)*10);//sets it to max. need to change this
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int)rect.getMinX();
int y = (int)rect.getMaxY()-getHeight();
setLocation(x,y-30);
setTitle("ALERT::OUTAGE");
MyPanel panel = new MyPanel();
add(panel);
listener = this;
t1 = new Timer(50,listener);
t1.start();
}
by request, here is getEngineersUpdate()
public String getEngineersUpdate() //gets data from page and sets it to string.
{
String update = "blank";
final WebClient webClient = new WebClient();
webClient.setJavaScriptEnabled(false);// javascript causes some serious problems.
webClient.setCssEnabled(false);
String forChecking;
HtmlPage page;
try
{
URL outageURL = new URL("file:\\C:\\Users\\0vertone\\Desktop\\version control\\OUTAGE\\Outages.html"); //local drive at home
page = webClient.getPage(outageURL);
//All this crap can be gone if we just give the table an id
Object[] dates = page.getByXPath("//span[#id='date']/text()").toArray();
Object[] sites = page.getByXPath("//span[#id='site']/text()").toArray();
Object[] issues = page.getByXPath("//span[#id='issue']/text()").toArray();
System.out.println("" + dates[0].toString());
System.out.println("" + sites[0].toString());
System.out.println("" + issues[0].toString());
update = (dates[0].toString() + " " + sites[0].toString() + " " +issues[0].toString());
forChecking = dates[0].toString();
/**some examples of the getCellAt() method*/
//update = table.getCellAt(0,0).asText(); // This returns DATE/Time
//update = table.getCellAt(1,0).asText(); // This return the actual date
//update = table.getCellAt(0,1).asText(); // This returns, SITE/Sector
//update = table.getCellAt(1,1).asText(); // This returns the actual site issue
}
catch (FailingHttpStatusCodeException a)
{
System.out.println("Failing HTTP Status Execution");
a.printStackTrace();
}
catch (MalformedURLException b)
{
System.out.println("Malformed URL");
b.printStackTrace();
}
catch (IOException c)
{
System.out.println("IO PROBLEMS!");
c.printStackTrace();
}
webClient.closeAllWindows();
return update;
}
I've changed your code so it should work as you intended. I'm not clear on what getEngineersUpdate() does, so I can't say for sure if it will work, but I've given you a start. I've included 2 options for how to handle it, with explanation in the comments. You can see how to use a Timer properly in the constructor, also. Finally, I don't have your full code, so I had to rig something together to simulate it.
class Marquee {
public static void main(String[] args) throws InterruptedException {
MyFrame frame = new MyFrame();
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setVisible(true);
frame.setAlwaysOnTop(true);
frame.setBackground(Color.BLACK);
frame.setResizable(true);
}
}
class MyFrame extends JFrame {
private String [] latestUpdate = new String[1];
private static final int DISPLAY_TIME = 3000;
private Timer displayTimer;
/*
* Option #1:
* Ideally, you'd have the thread that generates the "Engineers Update" messages call this
* method. If you can't make this event based, then you should use option #2
*/
public void newUpdate(String message) {
setVisible(true);
// change this to whatever you need to.
text.setText(message);
displayTimer.restart();
}
// I used this to test it
private JTextField text;
public MyFrame() {
// gets the maximum size of the screen
Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
//sets it to max. need to change this
setSize(d.width, (d.height / 100) * 10);
// this shit find the max size of screen and puts it bottom left
GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
GraphicsDevice defaultScreen = ge.getDefaultScreenDevice();
Rectangle rect = defaultScreen.getDefaultConfiguration().getBounds();
int x = (int) rect.getMinX();
int y = (int) rect.getMaxY() - getHeight();
setLocation(x, y - 30);
setTitle("ALERT::OUTAGE");
//MyPanel panel = new MyPanel();
//add(panel);
text = new JTextField("Initial Text");
add(text);
// this creates a timer that when it goes off, will hide the frame
displayTimer = new Timer(DISPLAY_TIME, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setVisible(false);
}
});
// sets the timer not to repeat
displayTimer.setRepeats(false);
//This code is for option #2:
updateTimer = new Timer(UPDATE_INTERVAL, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
checkForNewUpdate();
}
});
updateTimer.start();
}
// This is for option #2
private static final int UPDATE_INTERVAL = 1000;
private Timer updateTimer;
/*
* Option #2:
* Not ideal, but this should work.
*/
public String[] checkForNewUpdate() {
// I don't know how getEngineersUpdate() works
// which would have made it much easier to help you.
String tempUpdate = getEngineersUpdate();
// String comparison doesn't work like this in java.
// you also had a sleeping NullPointerException here
if (!tempUpdate.equals(latestUpdate[0])) {
// this is when you have a new update, correct?
newUpdate(tempUpdate);
latestUpdate[0] = tempUpdate;
} else if (tempUpdate.equals(latestUpdate[0])) {
// it's the same update as last time, so do nothing
} else if (tempUpdate.equals("NULL")) {
// You need to handle this according to what getEngineersUpdate() does
}
return latestUpdate;
}
// This code is rigged to show how it would work
private static int i = 0;
private String getEngineersUpdate() {
// 1 in 6 chance of returning "NULL"
if (Math.random() * 6 - 1 < 0)
return "NULL";
// probability of 1 in 4 of generating a new update
if(Math.random() * 4 - 1 < 0)
return "UPDATE #"+i++;
else
return "UPDATE #"+i;
}
}
I think you can't call wait() on an JFrame, but I am not sure.
You have to call wait() within a snychronized-block. (Example below)
Thread.sleep(1000l) can be used, if it runs in a Thread, but look for the class Timer
It would be much better design, if you create a thread, which checks for updates. You can notify the GUI (JFrame) with some kind of event-listener about the new date to display.
Take a look at the Timer and Callable.
You should create another thread, you should call checkforNewUpdate method from this thread. And also do not forget use SwingUtilities.invokeLater method to update your UI inside checkforNewUpdate method. here is the some part of the code;
public class Marque {
private JFrame frame;
class CheckForUpdate implements Runnable {
public void run() {
while(true) {
checkForNewUpdate();
try {
Thread.sleep(40000);
} catch (InterruptedException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
} }
}
public String[] checkForNewUpdate() {
//your code
// user interface interaction code
SwingUtilities.invokeLater(new Runnable() {
public void run() {
frame.setVisible(true);
}
});
}
}
public Marque() {
frame = new JFrame();
//....frame related code
new Thread(new CheckForUpdate()).start();
}
public static void main(String[] arg) {
Marque marque = new Marque();
}