I have a JTable wrapped into a JScrollPane. When I scroll to the top or bottom and continue to scroll, I want to be able to detect that in order to possibly load more items at the beginning or end since it is too expensive/not practical to load all items at once. The AdjustmentListener is not fired when the JScrollPane does not move (e.g. when it is already at the top or bottom):
scrollPane.getVerticalScrollBar().addAdjustmentListener(adjustmentEvent ->
{
int value = adjustmentEvent.getValue();
System.out.println(value); // Prints 0 e.g. when the top has been reached
});
However, I need to know when the user scrolls even though the end/start has already been reached.
How can this be done?
I suggest using a change listener on the JViewport of the scroll pane. The following example shows how to proceed. Please note that shouldCheck might be used to prevent false notifications (in my sample top is printed three times upon startup. If you run the sample and move the slider to the top and bottom a corresponding text is printed.
package com.thomaskuenneth;
import javax.swing.*;
public class Main {
static boolean shouldCheck = true;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame("Demo");
f.getContentPane().add(createUI());
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.setVisible(true);
});
}
static JComponent createUI() {
String[][] rowData = new String[200][10];
String[] columnNames = new String[10];
for (int i = 0; i < 200; i++) {
for (int j = 0; j < 10; j++) {
if (i == 0) {
columnNames[j] = String.format("#%d", j);
}
rowData[i][j] = String.format("%d - %d", i, j);
}
}
JTable t = new JTable(rowData, columnNames);
JScrollPane sp = new JScrollPane(t);
JScrollBar sb = sp.getVerticalScrollBar();
JViewport vp = sp.getViewport();
vp.addChangeListener((l) -> {
if (!shouldCheck) {
return;
}
if (sb.getValue() == sb.getMinimum()) {
System.out.println("top");
} else if (sb.getValue() + sb.getVisibleAmount() == sb.getMaximum()) {
System.out.println("bottom");
}
});
return sp;
}
}
Related
I am trying to create a grid (5*5) size like GUI. I tried and made a very basic grid, which is working quite fine, but I am trying to change the background colour of each JPanel when user click and drop over it. But I am not aware of the GUI in Java yet. So wondering if someone could help me please.
This my code to the grid and matching the both files(Sentiment word analyzing)
public static TwitterSystem getObject()
{
if (Object==null)
Object = new TwitterSystem();
return Object;
}
long startTime = System.currentTimeMillis();
long endTime = System.currentTimeMillis();
long totalTime = endTime - startTime;
//read jason from file into String
//create a lot of tweet objects
//run the tweetSystem
public void Run()
{
double r;
for (int i = 0; i < 5; i++)
for (int j = 0; j < 5; j++)
DataGrid[i][j] = 0.0;
// trying to load the wordlist and tweets
try
{
WordList = new Sentiment_Analysis("E:\\JAVA\\src\\wordlist.txt");
Tweet = new Tweet_Reader("E:\\JAVA\\tweets.json");
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
tweets = Tweet.getTweets();
// for each tweet, we getting the rating and working out where it is in the grid.
for(Tweet t : tweets) {
r = WordList.getRating(t);
if((int)t.getCoordinate().getLatitude() == 24 && (int)t.getCoordinate().getLongitude() == 54 ) {
DataGrid[2][2] += r;
}
if((int)t.getCoordinate().getLatitude() == 25 && (int)t.getCoordinate().getLongitude() == 54 ) {
DataGrid[0][1] += r;
}
}
// printing out the score for each square.
for (int i = 0; i < 5; i ++)
for (int j = 0; j < 5; j++)
System.out.format("[%4d][%4d] = %.4f\n", i, j, DataGrid[i][j]);
System.out.println("Finish calculating");
System.out.println("STATS - TIME: Analysis took "
+ TimeUnit.SECONDS.convert(totalTime, TimeUnit.MILLISECONDS)
+ " seconds");
}
}
Thank you in advance! i'm quite new to Programming
So far got the grid working but i want make the grid in GUI
HELP PLEASE!!!!
Starting from this complete example, I've added an ActionListener to each ButtonPanel in the grid. The listener updates the enclosing panel's background color. Note that each button uses its own instance of the same anonymous class. Comment out the timer's start() invocation to see the effect better. As an exercise, try changing class ButtonPanel to a factory method such as createButtonPanel(), as shown here for createGridPanel().
private static class ButtonPanel extends JPanel {
public ButtonPanel(int i) {
this.setBackground(new Color(rnd.nextInt()));
JButton b = new JButton("Button " + String.valueOf(i));
b.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
JButton b = (JButton) e.getSource();
ButtonPanel.this.setBackground(new Color(rnd.nextInt()));
}
});
this.add(b);
}
}
I have a button. If I click this button, a popup appears. The popup asking me to write a word. if I write a word 6 letter, 6 jlabels appear, but if I enter another word shorter, the JLabels do not disappear
I want my JLabels may decrease according to a shorter word, but i don't know :(
thx for your great help !
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
//BUTTON 1 WORD
Controller c = new Controller();
try {
final JFrame popup = new JFrame();
//display popup
word = JOptionPane.showInputDialog(popup, "Enter one word", null);
//control the length of the word
c.controleW(word);
//display jlabel lenght of word
keyNumber.setText(String.valueOf(word.length()));
//JLabels displays depending on the word length
int pixels = 50;
for (int i = 0; i < word.length(); i++) {
label = new JLabel("_");
label.setBounds(pixels, 200, 30, 30);
add(label);
label.repaint();
pixels += 20;
}
} catch (Exception e) {
System.out.println(e);
}
}
And my class to control the length of the word
public String controleW(String word) {
boolean flag = false;
final JFrame popup = new JFrame();
while (flag == false) {
if (word.length() <= 3) {
word = JOptionPane.showInputDialog(popup, "Enter one word", null);
} else {
flag = true;
}
};
return null;
}
You are always adding labels in your method, never removing any, thus running the code twice will indeed add labels twice. To fix it, you can simply add a removeAll(); in jButton1ActionPerformed before you add any labels. This makes sure that any previously added components will be removed.
The code below is supposed to create and object instance for a specific type (say color) JButton I want to represent in a grid. When I iterate through the for-loop to add the buttons to the jframe it adds nothing. But if I add a single instance variable it will add that. Anybody have an idea?
public class Grid {
protected JButton [][] board;
private JButton player;
private JButton openCell;
private JButton wall;
private JButton closedCell;
public Grid(String [] args) { // args unused
// Instantiation
board = new JButton [6][6];
layout = new String [6][6];
blueCell = new JButton("BLUE CELL");
redCell = new JButton("RED CELL");
greenCell = new JButton("GREEN CELL");
whiteCell = new JButton("WHITE CELL");
// Configuration (add actions later)
// Decoration
blueCell.setBackground(Color.blue);
redCell.setBackground(Color.red);
greenCell.setBackground(Color.green);
whiteCell.setBackground(Color.white);
for (int rows = 0; rows < 6; rows++) {
for (int cols = 0; cols < 6; cols++) {
if ((layout[rows][cols]).equals('*')) {
board[rows][cols] = blueCell;
}
else if ((layout[rows][cols]).equals('.')) {
board[rows][cols] = redCell;
}
else if ((layout[rows][cols]).equals('x')) {
board[rows][cols] = greenCell;
}
else {
board[rows][cols] = whiteCell;
}
}
}
JFrame game = new JFrame();
game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
game.setLayout(new GridLayout (6, 6));
game.setSize(500, 500);
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board.length; j++) {
if ((board[i][j]).equals(blueCell)) {
grid.add(blueCell);
}
else if ((board[i][j]).equals(redCell)) {
grid.add(redCell);
}
else if ((board[i][j]).equals(greenCell)) {
grid.add(greenCell);
}
else {
grid.add(whiteCell);
}
}
}
grid.setVisible(true);
} // end of constructor
} // end of Grid class
You can add a component to your GUI only once. If you add it to another component, it will be removed from the previous component. You're trying to add the same JButtons several times, and that won't work. Instead you're going to have to create more JButtons. Consider having your buttons share Actions which is allowed.
If you need more help, consider posting compilable code (your current code is not), a small runnable, compilable program that demonstrates your problem, in other words, an sscce.
Edit
You comment:
But don't these count as instances of a JButton not the same JButton? (I don't understand what your answer meant...)
Think of it mathematically... how many JButtons do you create in your code above? Well, this is easy to figure, exactly 4:
blueCell = new JButton("BLUE CELL");
redCell = new JButton("RED CELL");
greenCell = new JButton("GREEN CELL");
whiteCell = new JButton("WHITE CELL");
So, now ask yourself, how many JButtons are you trying to display in your GUI with these four JButtons? If it's four, then you're possibly OK (as long as you use each button), but if it's more, then you're in trouble. From your 6x6 grid, board = new JButton [6][6];, it looks like you're trying to display 36 JButtons, and if this is true, you've got problems.
But again, if still stuck, please consider creating and posting an sscce.
Is there a way, to highlight or change the color of a string that gets added from a String[] to a JTextArea?
Currently I'm using the DefaultHighlighter with the addHighlighter(from, to, highlighter) method, but that does not work the way ' want it to.
The String[] comes from a list that records key imput, and ' want every singlecharacter string to be highlighted to colored.
Example what the JTextArea looks like: A B C D E F G [SPACE] H I J K L [ENTER].
By the way, I add one string at a time to the textArea with a for loop like that:
for(int cnt = 0; cnt <= strings.length; cnt++){
if(strings[cnt].length() != 1){
text.append("[" + strings[cnt] + "] ");
}
else{
text.append(strings[cnt]);
//tryed to do it like that, but obviously did not work the way it wanted it to
// text.getHighlighter().addHighlight(cnt, cnt + 1, highlightPainter);
}
}
The color for a JTextArea applys to the entire JTextComponent's Document text foreground color rather than to individual characters. You can use JTextPane instead
Here is a simple example:
public class ColoredTextApp {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame("Colored Text");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
StyledDocument doc = new DefaultStyledDocument();
JTextPane textPane = new JTextPane(doc);
textPane.setText("Different Colored Text");
Random random = new Random();
for (int i = 0; i < textPane.getDocument().getLength(); i++) {
SimpleAttributeSet set = new SimpleAttributeSet();
StyleConstants.setForeground(set,
new Color(random.nextInt(256), random.nextInt(256),
random.nextInt(256)));
StyleConstants.setFontSize(set, random.nextInt(12) + 12);
StyleConstants.setBold(set, random.nextBoolean());
doc.setCharacterAttributes(i, 1, set, true);
}
frame.add(new JScrollPane(textPane));
frame.pack();
frame.setVisible(true);
}
});
}
}
You can't. A JTextArea is plain unformatted text. All the text can be the same font or foreground color, but that's about it. You'll need to use a JTextPane or JEditorPane instead.
Check out the JTextPane / JEditorPane Tutorial.
I'm trying to place a JList inside of a JScrollPane and have it alphabetically list the entries in vertical columns like this:
A D G
B E H
C F
However when the JList runs out of space to display more entries, I'd like the JScrollPane to scroll only in the vertical direction.
This works when I use VERTICAL_WRAP. However, it seems like when I use vertical wrap I get a horizontal scrollbar and when I use HORIZONTAL_WRAP I get the scrollbar I want, but the items get placed in an order that I don't like. Can I have my cake and eat it too? Here's a simple example of what I'm trying to do.
This is the closest I could get, but I'd like to be able to scroll vertically while maintaining the vertical alphabetical ordering.
public class ScrollListExample {
static List<String> stringList = new ArrayList<String>();
static {
for (int i = 0; i < 500; i++) {
stringList.add("test" + i);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame();
final Container contentPane = frame.getContentPane();
final JList list = new JList(stringList.toArray());
list.setLayoutOrientation(JList.VERTICAL_WRAP);
list.setVisibleRowCount(0);
final JScrollPane scrollPane = new JScrollPane(list);
contentPane.add(scrollPane);
frame.setPreferredSize(new Dimension(800, 400));
frame.pack();
frame.setVisible(true);
}
}
One solution I've though of is:
If the cell size is known I can create a component listener, and listen for a resize event. When that event is triggered I can calculate the desired row count in order to prevent horizontal scrolling. This just seems like a hack, and I'm not sure how it could work with variable sized text components.
I think your solution is just fine, and not a hack at all. Any built-in feature would have to do basically the same thing anyways.
Here's a modification to your example that does what you want.
public class ScrollListExample {
static List<String> stringList = new ArrayList<String>();
static {
for (int i = 0; i < 500; i++) {
stringList.add("test" + i);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame();
final Container contentPane = frame.getContentPane();
final JList list = new JList(stringList.toArray());
list.setLayoutOrientation(JList.VERTICAL_WRAP);
final JScrollPane scrollPane = new JScrollPane(list);
contentPane.add(scrollPane);
frame.setPreferredSize(new Dimension(800, 400));
frame.pack();
list.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
fixRowCountForVisibleColumns(list);
}
});
fixRowCountForVisibleColumns(list);
frame.setVisible(true);
}
private static void fixRowCountForVisibleColumns(JList list) {
int nCols = computeVisibleColumnCount(list);
int nItems = list.getModel().getSize();
// Compute the number of rows that will result in the desired number of
// columns
int nRows = nItems / nCols;
if (nItems % nCols > 0) nRows++;
list.setVisibleRowCount(nRows);
}
private static int computeVisibleColumnCount(JList list) {
// It's assumed here that all cells have the same width. This method
// could be modified if this assumption is false. If there was cell
// padding, it would have to be accounted for here as well.
int cellWidth = list.getCellBounds(0, 0).width;
int width = list.getVisibleRect().width;
return width / cellWidth;
}
}
Is this what you're going for? (Might need to change the preferred size...)
public class ScrollListExample {
static List<String> stringList = new ArrayList<String>();
static {
for (int i = 0; i < 500; i++) {
stringList.add("test" + i);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame();
final Container contentPane = frame.getContentPane();
final JList list = new JList(stringList.toArray());
final JScrollPane scrollPane = new JScrollPane(list);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
contentPane.add(scrollPane);
frame.setPreferredSize(new Dimension(200,200));
frame.pack();
frame.setVisible(true);
}
}
Brilliant Code #Kevin K... I suggest a small modification to avoid ArithmeticException (Divide by zero)
private int computeVisibleColumnCount(JList list)
{
int cellWidth = list.getCellBounds(0, 0).width;
int width = list.getVisibleRect().width;
return width == 0 ? 1 : width / cellWidth;
}