I am currently making a Twitter client, and I found some issue I couldn't solve myself.
I'm not sure what part of the code should I include, so I'll post a picture.
Picture
I have a JPanel in a JScrollPane, and then I add small JPanels (the tweets) to that JPanel. But there's always a space after those components.
Any advice about where is that space came from?
Thank You in advance.
Here are some pieces of code:
This is the main JPanel, that handles the Tweet JPanels:
package net.rothens.twitt3ns.gui;
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import javax.swing.*;
import net.rothens.twitt3ns.Twitt3ns;
import twitter4j.Status;
/**
*
* #author Rothens
*/
public class TweetsPanel extends JPanel {
public java.util.List<Long> timestamps;
public TweetsPanel() {
initUI();
}
public final void initUI() {
timestamps = new ArrayList<Long>();
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
}
public void addTwitt(Status s) {
if (!Twitt3ns.tw.mw.isScrollbarOnTop()) {
Twitt3ns.tw.mw.saveScrollbarPosition();
}
int pos = getPos(s.getCreatedAt().getTime()) + 1;
TweetPanel tp = new TweetPanel(s);
if (pos >= getComponentCount()) {
add(tp);
} else {
add(tp, pos);
}
validate();
if (!Twitt3ns.tw.mw.isScrollbarOnTop()) {
Twitt3ns.tw.mw.loadScrollbarPosition(tp.getHeight());
}
}
/**
* Update the time on the panels
*/
public void updatePanels() {
for (Component c : getComponents()) {
if (c instanceof TweetPanel) {
((TweetPanel) c).updateTime();
}
}
validate();
}
/**
* Gets the position of a new tweet
* #param what the time when the new component was created
* #return position of the new component
*/
public int getPos(long what) {
timestamps.add(what);
Collections.sort(timestamps);
return timestamps.size() - timestamps.indexOf(what) - 2;
}
public TweetsPanel(int id) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
TweetsPanel tl = new TweetsPanel();
tl.setVisible(true);
}
});
}
}
The Tweet JPanels code is this (I'll post in pastebin, it's way too big) : Pastebin
And in the Main JFrame, I create the tabbed pane, and the ScrollPanes in this way:
tabPane.setTabPlacement(javax.swing.JTabbedPane.BOTTOM);
tabPane.setAlignmentX(0.0F);
tabPane.setAlignmentY(0.0F);
spHome.setAlignmentX(0.0F);
spHome.setAlignmentY(0.0F);
spHome.setHorizontalScrollBar(null);
tabPane.addTab("Otthon", spHome);
tabPane.addTab("#", null, spMention, "Tweetek amik Téged említenek");
And this is how I add the JPanels to the JScrollPanes:
tpHome.setBorder(null);
tpHome.setFocusable(false);
spHome.setViewportView(tpHome);
tpMention.setBorder(null);
tpMention.setFocusable(false);
spMention.setViewportView(tpMention);
Related
package gameprojekt;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
//The GameWindow class holds the window
public class Game extends JFrame {
/*Global variable declaration*/
private int width;
private int height;
private int windowXPos;
private int windowYPos;
public static String p1 = "Player1";
public static String p2 = "Player2";
public static int playerScore = 0;
public static int oponentScore = 0;
public static int player1X;
public static int Player1Y;
public static int player2X;
public static int Player2Y;
private static boolean running = true;
public static int status = 0;
public static JFrame frame = new JFrame("Pong");
//public TestDrawPanel testPanel = new TestDrawPanel();
public static int getStatus() {
return status;
}
public static void setStatus(int status) {
Game.status = status;
}
// ------------------------------------------------------------
/**
* Creates a new JFrame window with the given size and
* center it based on the screen resolution
*/
public static final long serialVersionUID = 1L;
public Game() {
/*Local variable declaration*/
//JFrame frame = new JFrame("Pong");
Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
width = (int)dim.getWidth();
height = (int)dim.getHeight();
windowXPos = width / 2 - (width / 2) / 2;
windowYPos = height / 2 - (height / 2) / 2;
// ------------------------------------------------------------
// Set size, half of the screen resolution
frame.setSize(width/2, height/2);
// Allign the window to the users resolution
frame.setLocation(windowXPos, windowYPos);
frame.setVisible(true);
frame.setResizable(false);
// By exiting the window using "X" all relevant data is closed
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
/* zum Testen auskommentiert
#Override
public void paint(Graphics g) {
System.out.println("test");
this.drawPlayer(g);
}*/
/**
* Draw the Player on the given location and with the given size
* #param g Graphics object
*/
public void drawPlayer(Graphics g) {
}
private static void gameLoop() {
Menue m = new Menue();
m.loadMenue(frame);
while (running) {
if (m.isStartPressed()) {
System.out.println("test");
}
}
}
/**
* Create the game and initialize the gameplay
*/
public static void main(String[] args) {
/*Variable declaration*/
// ------------------------------------------------------------
Game game = new Game();
game.gameLoop();
}
}
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package gameprojekt;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.LayoutManager;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
/**
*
*
*/
public class Menue {
/* Global variable declaration */
private int widthMenue;
private int heightMenue;
private String start = "Start";
private String highscores = "Highscores";
private boolean startPressed = false;
public JButton bStart = new JButton(start);
public JButton bScore = new JButton(highscores);
// ----------------------------------------------------
public boolean isStartPressed() {
return startPressed;
}
public void setStartPressed(boolean startPressed) {
this.startPressed = startPressed;
}
public int getWidthMenue() {
return widthMenue;
}
public void setwidthMenue(int widthMenue) {
this.widthMenue = widthMenue;
}
public int getheightMenue() {
return heightMenue;
}
public void setheightMenue(int heightMenue) {
this.heightMenue = heightMenue;
}
public void loadMenue(JFrame j) {
JPanel menue = new JPanel();
LayoutManager border = new BorderLayout();
menue.setLayout(border);
menue.setBackground(Color.black);
bStart.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
setStartPressed(true);
}
});
menue.add(bStart, BorderLayout.LINE_START);
menue.add(bScore, BorderLayout.LINE_END);
j.getContentPane().add(menue);
}
}
Hi I'm having a problem that the variable startPressed seems to be getting ignored. If the button start is pressed the variable startPressed is set to true but the if statement in this while loop doesn't react to the new value:
while (running) {
if (m.isStartPressed()) {
System.out.println("test");
}
}
If I add System.out.println or Thread.sleep inside the loop then the if statement recognizes the value and is giving me the output.
I thought maybe there is a main problem in the programming structure or Java is too slow. Any ideas?
Thanks!
Your main problem is that your startPressed variable is not made volatile, and thus changing it in one thread may not be reflected in another thread. Change this and you'll see that your start button changes this variable appropriately:
private volatile boolean startPressed = false;
Your game loop shouldn't be as it flies in the face of Swing threading rules. Why not use a Swing Timer (my preference) or if you need your own roll-your own loop, then doing so in a background thread. Also consider making startPressed a "bound" variable, one that when changed tells any property change listeners that its state has been changed. This would be better than constantly polling its value.
Another comment: your code overuses statics and would be much better organized if you got rid of most of your static modifiers.
When you do something like
while(running) {
...
}
it means, that this loop is executed over and over again, nothing stops it, it gets executed as fast as your PC can do it. And therefore, it tends to block everything else. So yes, your program structure is the problem. Try to execute your game-loop in a separate thread. This thread can then update your view from time to time. Maybe think about to pause this thread from time to time or to schedule it in some way, so your view is only update every second (or whatever you want).
I am studying Java AWT to create GUI applications. I am working on the below code where I cannot make the panel visible inside the frame. Here is my code:
import java.awt.*;
import java.awt.event.*;
/**
*
* #author kiran
*/
public class UserInterface
{
Frame UI;
private static double UIWidth, UIHeight;
/**
* Constructs User Interface
*/
public UserInterface()
{
UI = new Frame("frame");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
UIWidth = screenSize.getWidth();
UIHeight = screenSize.getHeight();
buildFrame();
buildMessageInputArea();
}
/**
* returns the width of the UI
* #return returns the width of the UI
*/
public static double getUIWidth()
{
return UIWidth;
}
/**
* returns the width of the UI
* #return returns the width of the UI
*/
public static double getUIHeight()
{
return UIHeight;
}
/**
* Builds the frame
*/
private void buildFrame()
{
UI.setSize((int)UIWidth,(int)UIHeight*96/100);
UI.setVisible(true);
UI.setLayout(new FlowLayout());
UI.addWindowListener(new Actions());
}
private void buildMessageInputArea()
{
Panel current = new TextAreaPanel().getPanel();
current.setVisible(true);
UI.add(current);
}
}
class TextAreaPanel extends Frame
{
private Panel textAreaPanel;
TextArea msgInputArea;
public TextAreaPanel()
{
textAreaPanel = new Panel();
msgInputArea = new TextArea(1000,(int)UserInterface.getUIWidth() * 80/100);
}
private void addTextArea()
{
textAreaPanel.add(msgInputArea);
}
public Panel getPanel()
{
return textAreaPanel;
}
}
class Actions extends WindowAdapter
{
#Override
public void windowClosing(WindowEvent c)
{
System.exit(0);
}
}
How can I make the panel visible inside the frame?
How do I make a panel visible inside frame in Java AWT?
There were two fundamental problems with the code as seen, which can be fixed by changing the following:
Add the panel/text area to the GUI before setVisible(true) is called on the top level container.
While it is possible to add components to a container after it has been made visible, they require special handling, and it is not necessary in this case.
Add the text area to the panel!
Here is the code, turned into a Minimal, Complete, and Verifiable example by adding a main(String[]) method, with those two changes implemented, as well as more explanatory comments on other aspects of the code.
import java.awt.*;
import java.awt.event.*;
public class UserInterface {
Frame UI;
private static double UIWidth, UIHeight;
public static void main(String[] args) {
Runnable r = () -> {
new UserInterface();
};
EventQueue.invokeLater(r);
}
/**
* Constructs User Interface
*/
public UserInterface() {
UI = new Frame("frame");
// setting a GUI to full screen while accounting for the task
// bar can be achieved in a single line of code.
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
UIWidth = screenSize.getWidth();
UIHeight = screenSize.getHeight();
// these need to be called in the reverse order to ensure the
// components are added before the GUI is set visible.
buildMessageInputArea();
buildFrame();
}
/**
* returns the width of the UI
*
* #return returns the width of the UI
*/
public static double getUIWidth() {
return UIWidth;
}
/**
* returns the width of the UI
*
* #return returns the width of the UI
*/
public static double getUIHeight() {
return UIHeight;
}
/**
* Builds the frame
*/
private void buildFrame() {
UI.setSize((int) UIWidth, (int) UIHeight * 96 / 100);
UI.setVisible(true);
UI.setLayout(new FlowLayout());
UI.addWindowListener(new Actions());
}
private void buildMessageInputArea() {
Panel current = new TextAreaPanel().getPanel();
current.setVisible(true);
UI.add(current);
}
}
// does not need to be a fram
//class TextAreaPanel extends Frame {
class TextAreaPanel {
private Panel textAreaPanel;
TextArea msgInputArea;
public TextAreaPanel() {
textAreaPanel = new Panel();
// these number represent columns and rows, not pixels!
//msgInputArea = new TextArea(1000, (int) UserInterface.getUIWidth() * 80 / 100);
msgInputArea = new TextArea(40, 60);
// add the text area to the panel!
textAreaPanel.add(msgInputArea);
}
/** not called by anything else
private void addTextArea() {
textAreaPanel.add(msgInputArea);
}
**/
public Panel getPanel() {
return textAreaPanel;
}
}
// This can be achieved in a single line of code
class Actions extends WindowAdapter {
#Override
public void windowClosing(WindowEvent c) {
System.exit(0);
}
}
To add to / expand on the comments of #mKorbel & #camickr:
Why use AWT? See this answer for many good reasons to abandon AWT components in favor of Swing.
See Composition over inheritance.
The use of static in GUIs more commonly causes problems, than fixes them. Most (if not all) of the methods marked as static should be reduced to non-static with the code using an instance of the object to call the method.
EDIT: Everything displays correctly when either field or hunterField hold no objects in any location. field and hunterField both exclusively hold objects which extend the same class, so I guess it may have something to do with inheritance...?
I have created a simple Agent-Based Model using MASON. The back-end works find, but when I try displaying my agents only "wall" agents are displayed. (Wall Portrayal) My code is below... Any idea?
package sim.app.celai;
import java.awt.Color;
import javax.swing.JFrame;
import sim.app.tutorial3.Tutorial3WithUI;
import sim.display.Controller;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.portrayal.grid.SparseGridPortrayal2D;
import sim.util.Bag;
public class FieldWithGUI extends GUIState {
public Display2D display;
public JFrame frame;
SparseGridPortrayal2D hunterPortrayal = new SparseGridPortrayal2D();
SparseGridPortrayal2D wallPortrayal = new SparseGridPortrayal2D();
SparseGridPortrayal2D childPortrayal = new SparseGridPortrayal2D();
public FieldWithGUI() {
super(new Field(System.currentTimeMillis()));
}
public void setupPortrayals() {
childPortrayal.setField(((Field) state).field);
hunterPortrayal.setField(((Field) state).hunterField);
wallPortrayal.setField(((Field) state).wallField);
childPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.blue));
hunterPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.red));
wallPortrayal.setPortrayalForAll(new sim.portrayal.simple.OvalPortrayal2D(Color.green));
display.reset();
display.repaint();
}
public void quit()
{
super.quit();
if (frame!=null) frame.dispose();
frame = null; // let gc
display = null; // let gc
}
public static void main(String[] args)
{
new FieldWithGUI().createController();
}
public void start()
{
super.start();
// set up our portrayals
setupPortrayals();
}
public void init(Controller c)
{
super.init(c);
// Make the Display2D. We'll have it display stuff later.
display = new Display2D(400,400,this); // at 400x400, we've got 4x4 per array position
frame = display.createFrame();
c.registerFrame(frame); // register the frame so it appears in the "Display" list
frame.setVisible(true);
// specify the backdrop color -- what gets painted behind the displays
display.setBackdrop(Color.black);
// attach the portrayals
display.attach(childPortrayal, "children");
display.attach(hunterPortrayal, "hunter");
display.attach(wallPortrayal, "wall");
}
}
So this is my situation:
I have a timer and it updates values in the background until a value has reached a certain point.
But in order for me to see each update of value I currently have to add in a
"new ListWindow();" statement in my for loop.
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
/**
* Write a description of class Timing here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class Timing
{
/**
* Constructor for objects of class Timing
*/
public static void Timer()
{
Timer timer = new Timer(250, new TimerListener());
timer.start();
}
private static class TimerListener implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
while(valX != 100)
{
Timer();
MainProg.valX += 5;
// new ListWindow(); //statement goes here. it creates a new window
//each time it updates the value.
}
}
}
}
My problem is: I do not want a new window. I want the list that the value comes from (see below) to update its value and refresh the list in the current window. perhaps on a button click.
import javax.swing.*;
import javax.swing.event.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.Component.*;
/**
* Write a description of class ListWindow here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class ListWindow extends JFrame
{
private JPanel StatsPanel; //holds stats
private JPanel ButtonPanel; //holds stats
private JList StatList; //inventory
private JButton RefreshButton; // a button
private String[] Stats =
{"Stuff " + Stuff, "Value " + valX, "Test " + per};
/**
* Constructor
*/
public ListWindow()
{
setTitle("STATS");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
buildStatsPanel();
buildButtonPanel();
RefreshButton.addActionListener(new ButtonListener());
add(StatsPanel, BorderLayout.CENTER);
add(ButtonPanel, BorderLayout.SOUTH);
pack();
setVisible(true);
}
public void buildStatsPanel()
{
StatsPanel = new JPanel();
StatList = new JList(Stats);
StatList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
StatsPanel.add(StatList);
}
public void buildButtonPanel()
{
ButtonPanel = new JPanel();
RefreshButton = new JButton("Refresh");
ButtonPanel.add(RefreshButton);
}
private class ButtonListener
implements ActionListener
{
public void actionPerformed(ActionEvent e)
{
String actionCommand = e.getActionCommand();
if(actionCommand.equals("Refresh"))
{
pack();
invalidate();
validate();
}
}
}
public void RunMain(String[] args)
{
new ListWindow();
}
}
Also: this is my main method where I run things from. You should also notice that I have main methods in my other two snippets I pasted here. I did this so I could run things individually for quick debugging and future use.
/**
* Write a description of class MainProg here.
*
* #author (your name)
* #version (a version number or a date)
*/
public class MainProg
{
public static int stuff = 100;
public static int valX = 0;
public static int per = 100;
/**
* Constructor for objects of class Game
*/
public static void main()
{
new MoveWindow();
new ListWindow();
while (valX != 100)
{
Timing.Timer();
}
}
}
I am very new to java, i have looked for other solutions and was unable to find what I think i need. Perhaps I did find it, and did not recognize it as a solution.
All help is appreciated, thanks in advance.
Call a function that updates the list (the default JList ListModel used when supplying a Object array is rather inflexible and you may need to use a different ListModel rather than the default) with the new value.
I have a JDesktopPane containing some JInternalFrames. I want some menus on the menubar to be activated only when one of the JInternalFrames is selected. I've tried using VetoableChangeListener, with the following code in it:
JInternalFrame selectedFrame = desk.getSelectedFrame();
if ((selectedFrame != null)) {
imageMenu.setEnabled(Boolean.TRUE);
} else {
imageMenu.setEnabled(Boolean.FALSE);
}
But the results are not what I expected - for example, the menu is enabled only the second time I add a frame. when I close all frames, it remains enabled.
How can I make this work?
you have to read basic tutorial about JInternalFrames with link to the InternalFrameListener,
but another and look like as better way is programatically to know those event in all cases and evety times is by adding PropertyChangeListener as shows examples Getting All Frames in a JDesktopPane Container, by adding PropertyChangeListener you can listeng for these events
Add an InternalFrameListener to each internal frame added to the desktop pane, and each time an event is triggered, execute the code you have shown in your question.
This code could be better written though:
setEnabled takes a primitive boolean as argument, not a java.lang.Boolean. Use true and false rather than Boolean.TRUE and Boolean.FALSE.
The expression (selectedFrame != null) evaluates as a boolean. Just write
imageMenu.setEnabled(selectedFrame != null);
instead of
if ((selectedFrame != null)) {
imageMenu.setEnabled(Boolean.TRUE);
} else {
imageMenu.setEnabled(Boolean.FALSE);
}
I would just create a custom event and fire it when a JInternalFrame gets focus (isActivated).
The menu items would listen for this event, intercept it and set their status enabled or disabled accordingly.
The advantage here is that you don't have to handle what menu items should be available for which types of internal frames, just fire the appropriate event. It'll make your life easier if you add more internal frames in the future.
This answer is based on the answer by #mKorbel. This example shows one of the ways to detect focus between internal frames as is demonstrated here:
package com.apexroot.sandbox;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
/**
* author grants unlimited license to modify, reuse and redistribute. based on
* the suggestion by #mKorbel on stackoverflow at
* http://stackoverflow.com/questions/7219860/jinternalframe-selection
* please keep a URL to the original version in the source code.
* http://javajon.blogspot.com/2015/08/windowfocuslistener-for-jinternalframe.html
*
* #author Apexroot
*/
public class InternalFrameFocusListenerExample {
public static final String INTERNAL_FRAME_FOCUS_EVENT_PROPERTY = "selected";
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame jFrame = new JFrame();
final JDesktopPane jDesktopPane = new JDesktopPane();
final JInternalFrame[] jInternalFrames = new FocusInternalFrame[3];
for (int i = 0; i < jInternalFrames.length; i++) {
jInternalFrames[i] = new FocusInternalFrame();
}
jFrame.dispose();
jFrame.setContentPane(jDesktopPane);
jDesktopPane.setPreferredSize(new Dimension(400, 200));
jFrame.pack();
jFrame.setVisible(true);
for (int i = 0; i < jInternalFrames.length; i++) {
jDesktopPane.add(jInternalFrames[i]);
jInternalFrames[i].setLocation(10 + 60 * i, 10 + 40 * i);
jInternalFrames[i].setVisible(true);
}
}
});
}
public static class FocusInternalFrame extends JInternalFrame {
public FocusInternalFrame() {
final JLabel jLabel = new JLabel("placeholder for pack();");
setContentPane(jLabel);
pack();
this.addPropertyChangeListener(
INTERNAL_FRAME_FOCUS_EVENT_PROPERTY,
new LabelFocusListener(jLabel));
}
}
private static class LabelFocusListener implements PropertyChangeListener {
private final JLabel jLabel;
public LabelFocusListener(JLabel jLabel) {
this.jLabel = jLabel;
}
#Override
public void propertyChange(PropertyChangeEvent evt) {
// please keep a URL to the original version in the source code.
// http://javajon.blogspot.com/2015/08/windowfocuslistener-for-jinternalframe.html
if (INTERNAL_FRAME_FOCUS_EVENT_PROPERTY.equals(
evt.getPropertyName())) {
final Object oldValue = evt.getOldValue();
final Object newValue = evt.getNewValue();
if (oldValue instanceof Boolean
&& newValue instanceof Boolean) {
boolean wasInFocus = (Boolean) oldValue;
boolean isInFocus = (Boolean) newValue;
if (isInFocus && !wasInFocus) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
// focus gained
jLabel.setText("focus gained");
}
});
} else if (wasInFocus && !isInFocus) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
// focus lost
jLabel.setText("focus lost");
}
});
}
}
}
}
}
}