Scrolling programmatically - java

I would like the cell of my JTable to be aligned horizontally with the selected panels.Here is the a SSCCE to illustrate my problem. Thanks for any help.
public class TableCellAlignment {
private final static int MAX = 50;
private static SelectablePanel[] selectablePanels = new SelectablePanel[MAX];
private static JScrollPane slaveScrollPane = new JScrollPane();
private static JScrollPane masterScrollPane = new JScrollPane();
private static JTable slaveTable = new JTable();
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new TableCellAlignment().createGUI();
}
});
}
private static void createGUI() {
JFrame f = new JFrame("TableCellAlignment");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel masterPanel = new JPanel(new GridLayout(MAX, 1));
Integer[][] objs = new Integer[MAX][1];
for (int i = 0; i < MAX; i++) {
objs[i][0] = new Integer(i);
SelectablePanel masterSelectablePanel = new SelectablePanel();
masterSelectablePanel.setNum(i);
selectablePanels[i] = masterSelectablePanel;
masterPanel.add(masterSelectablePanel);
}
DefaultTableModel model = new DefaultTableModel(objs, new Object[]{"Column1"});
model.addTableModelListener(new TableModelListener() {
#Override
public void tableChanged(TableModelEvent e) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
slaveTable.setRowHeight(20);
}
});
}
});
model.addRow(objs);
slaveTable.setModel(model);
final JPanel p = new JPanel(new GridLayout(1, 2));
masterScrollPane.setViewportView(masterPanel);
slaveScrollPane.setViewportView(slaveTable);
p.add(masterScrollPane);
p.add(slaveScrollPane);
f.add(p);
f.setSize(400, 200);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static class SelectablePanel extends JPanel {
private PropertyChangeSupport cs;
private int num;
private boolean selected = false;
public SelectablePanel() {
cs = new PropertyChangeSupport(this);
cs.addPropertyChangeListener(new SelectedPropertyChangeListener());
addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
setSelected(true);
}
});
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public boolean isSelected() {
return selected;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (selected) {
Color c = g.getColor();
g.setColor(Color.blue);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.white);
FontMetrics fm = g.getFontMetrics();
g.drawString("" + getNum(), getWidth() / 2, (getHeight() + (fm.getAscent() - fm.getDescent())) / 2);
g.setColor(c);
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 20);
}
public void setSelected(boolean selected) {
boolean oldVal = isSelected();
this.selected = selected;
cs.firePropertyChange("selected", oldVal, selected);
repaint();
}
private class SelectedPropertyChangeListener implements PropertyChangeListener {
#Override
public void propertyChange(PropertyChangeEvent evt) {
if (evt.getPropertyName().equals("selected")) {
boolean selected = (boolean) evt.getNewValue();
if (selected) {
for (int i = 0; i < MAX; i++) {
SelectablePanel masterSelectablePanel = selectablePanels[i];
if (i != getNum() && masterSelectablePanel.isSelected()) {
masterSelectablePanel.setSelected(false);
}
}
slaveTable.setRowSelectionInterval(getNum(), getNum());
final JViewport viewport = slaveScrollPane.getViewport();
Rectangle rect = new Rectangle(getBounds().x, getBounds().y, 1, 1);
Rectangle r2 = viewport.getVisibleRect();
slaveTable.scrollRectToVisible(new Rectangle(rect.x, rect.y, (int)r2.getWidth(), (int)r2.getHeight()));
}
}
}
}
}
}

viewport.setViewPosition( pt ); as shown here.

It's basic math and it does not require access to the viewport:
// in the isSelected block of the propertyChangeListener:
JComponent current = (JComponent) evt.getSource();
slaveTable.setRowSelectionInterval(getNum(), getNum());
// get the cellRect of the selected cell
Rectangle cellRect = slaveTable.getCellRect(getNum(), 0, false);
// get the bounds of the selected panel
Rectangle panelRect = current.getBounds();
// get the visible rect of the selected panel's parent
Rectangle parentVisibleRect = ((JComponent) current.getParent()).getVisibleRect();
// the diff above the current (to the parent's visible rect)
int aboveCurrent = panelRect.y - parentVisibleRect.y;
// translate the cell rect
cellRect.y = Math.max(cellRect.y - aboveCurrent, 0);
// adjust size to slaveTable's visible height
cellRect.height = slaveTable.getVisibleRect().height;
slaveTable.scrollRectToVisible(cellRect);
Note that this snippet assumes that the view's viewport of both the panel's parent and the table have the same size, so either remove the header from the table, or add a header to the panel's scrollPane, or use a LayoutManager which can align the viewports of the two scrollPanes.

Related

Java drawing on sceen using mouse not working

I am trying to make a Digital Doily application using Swing and Graphics2D. I have never before used either Swing or done any 2d graphics. When you hold the mouse you should be able to draw stuff, but for some reason it is not working and I can't figure out why. I am not posting the GalleryPanel.java class, because it doesn't affect in any way the drawing. Here is my code:
Main.java
public class Main {
public static final int WINDOW_WIDTH = 1600;
public static final int WINDOW_HEIGHT = 800;
public static final int SIDE_MENU_WIDTH = WINDOW_WIDTH / 4;
public static final String TITLE = "Digital Doily";
public static final Font PANEL_TITLE_FONT = new Font("Arial", Font.BOLD, 16);
/**
* Just a main method used to run the JFrame window
* #param args
*/
public static void main(String[] args) {
WindowFrame frame = new WindowFrame(WINDOW_WIDTH, WINDOW_HEIGHT, TITLE);
}
}
WindowFrame.java
public class WindowFrame extends JFrame {
/**
* The width of the window
*/
private int width;
/**
* The height of the window
*/
private int height;
/**
* The main constructor of the window
* #param width - width of the window
* #param height - height of the window
* #param title - title of the window
*/
public WindowFrame(int width, int height, String title) {
super(title);
this.setSize(new Dimension(width, height));
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setFont(new Font("Times New Roman", Font.PLAIN, 12));
// Initializing the main GUI elements
initializeGUI();
this.setLocationRelativeTo(null);
this.setVisible(true);
}
/**
* The main GUI of the window frame
*/
private void initializeGUI() {
JPanel window = new JPanel(new BorderLayout());
this.setContentPane(window);
//Doily panel
DoilyPanel doilyPanel = new DoilyPanel();
doilyPanel.setBackground(Color.BLACK);
window.add(doilyPanel, BorderLayout.CENTER);
// Gallery panel
GalleryPanel galleryPanel = new GalleryPanel(doilyPanel);
galleryPanel.setBackground(Color.getColor("DDDDDD"));
window.add(galleryPanel, BorderLayout.EAST);
// Options panel
OptionsPanel optionPanel = new OptionsPanel(this, doilyPanel, galleryPanel);
optionPanel.setBackground(Color.getColor("DDDDDD"));
window.add(optionPanel, BorderLayout.WEST);
window.setVisible(true);
}
}
OptionsPanel.java
public class OptionsPanel extends JPanel {
/**
* An instance of the DoilyPanel class
*/
private DoilyPanel doilyPanel;
/**
* An instance of JFrame
*/
private JFrame frame;
private GalleryPanel galleryPanel;
public OptionsPanel(JFrame frame, DoilyPanel doilyPanel, GalleryPanel galleryPanel) {
this.doilyPanel = doilyPanel;
this.frame = frame;
this.galleryPanel = galleryPanel;
/**
* Start of GUI
*/
this.setPreferredSize(new Dimension(Main.SIDE_MENU_WIDTH, Main.WINDOW_HEIGHT));
setLayout(new BorderLayout());
//Initializing the panel GUI elements
initializeGUI();
setVisible(true);
/**
* End of GUI
*/
}
/**
* The main GUI of the panel
*/
private void initializeGUI() {
// Title panel
JPanel titlePanel = new JPanel();
titlePanel.setBackground(Color.WHITE);
this.add(titlePanel, BorderLayout.NORTH);
// Options title label
JLabel optionsTitle = new JLabel("Options");
optionsTitle.setFont(Main.PANEL_TITLE_FONT);
titlePanel.add(optionsTitle);
titlePanel.setVisible(true);
// Main panel
JPanel mainPanel = new JPanel(new FlowLayout(FlowLayout.CENTER,10,10));
mainPanel.setPreferredSize(new Dimension(Main.SIDE_MENU_WIDTH, Main.WINDOW_WIDTH - titlePanel.getHeight()));
this.add(mainPanel, BorderLayout.CENTER);
// Doily sector
JLabel sectorTitle = new JLabel("Sectors: ");
mainPanel.add(sectorTitle);
SpinnerModel sectorSpinnerModel = new SpinnerNumberModel(doilyPanel.getSectors(), 1,100,1);
JSpinner sectorSpinner = new JSpinner(sectorSpinnerModel);
mainPanel.add(sectorSpinner);
// Pen size
JLabel penSizeTitle = new JLabel("Pen size: ");
mainPanel.add(penSizeTitle);
SpinnerModel penSizeSpinnerModel = new SpinnerNumberModel(doilyPanel.getPenSize(), 1,100,1);
JSpinner penSizeSpinner = new JSpinner(penSizeSpinnerModel);
mainPanel.add(penSizeSpinner);
// Clear
JButton clearButton = new JButton("Clear");
mainPanel.add(clearButton);
// Undo
JButton undoButton = new JButton("Undo");
mainPanel.add(undoButton);
// Redo
JButton redoButton = new JButton("Redo");
mainPanel.add(redoButton);
// Delete
JButton deleteButton = new JButton("Delete");
mainPanel.add(deleteButton);
// Change pen color
JButton changePenColorButton = new JButton("Change pen color");
mainPanel.add(changePenColorButton);
// Save
JButton saveButton = new JButton("Save");
mainPanel.add(saveButton);
// Toggle sector lines
JButton toggleSectorLinesButton = new JButton("Sector lines: " + doilyPanel.getSectorLinesStatus());
mainPanel.add(toggleSectorLinesButton);
// Toggle reflections
JButton toggleReflectionButton = new JButton("Reflections: " + doilyPanel.getReflectedDrawingStatus());
mainPanel.add(toggleReflectionButton);
// Toggle eraser
JButton toggleEraserButton = new JButton("Eraser: ");
mainPanel.add(toggleEraserButton);
// Creating a new OptionsPanelListener
OptionsPanelListener optionsPanelListener = new OptionsPanelListener(
frame, doilyPanel, galleryPanel, penSizeSpinner, sectorSpinner, clearButton, undoButton, redoButton, deleteButton,
changePenColorButton, saveButton, toggleSectorLinesButton, toggleReflectionButton, toggleEraserButton
);
// Adding all listeners to the components
sectorSpinner.addChangeListener(optionsPanelListener);
mainPanel.setVisible(true);
}
}
OptionsPanelListener.java
public class OptionsPanelListener implements ActionListener, ChangeListener {
private JFrame frame;
private DoilyPanel doilyPanel;
private GalleryPanel galleryPanel;
private JSpinner sectorSpinner;
private JSpinner penSizeSpinner;
private JButton clearButton;
private JButton undoButton;
private JButton redoButton;
private JButton deleteButton;
private JButton changePenColorButton;
private JButton saveButton;
private JButton toggleSectorLinesButton;
private JButton toggleReflectionButton;
private JButton toggleEraserButton;
public OptionsPanelListener(
JFrame frame, DoilyPanel doilyPanel, GalleryPanel galleryPanel, JSpinner penSizeSpinner, JSpinner sectorSpinner, JButton clearButton, JButton undoButton, JButton redoButton,
JButton deleteButton, JButton changePenColorButton, JButton saveButton, JButton toggleSectorLinesButton, JButton toggleReflectionButton, JButton toggleEraserButton
) {
this.frame = frame;
this.doilyPanel = doilyPanel;
this.galleryPanel = galleryPanel;
this.penSizeSpinner = penSizeSpinner;
this.sectorSpinner = sectorSpinner;
this.clearButton = clearButton;
this.undoButton = undoButton;
this.redoButton = redoButton;
this.deleteButton = deleteButton;
this.changePenColorButton = changePenColorButton;
this.saveButton = saveButton;
this.toggleSectorLinesButton = toggleSectorLinesButton;
this.toggleReflectionButton = toggleReflectionButton;
this.toggleEraserButton = toggleEraserButton;
}
#Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == clearButton) {
doilyPanel.removeStrokes();
doilyPanel.repaint();
} else if(e.getSource() == undoButton) {
if (!doilyPanel.getStrokes().isEmpty()) {
doilyPanel.removeStrokes(doilyPanel.getStrokesSize());
doilyPanel.repaint();
}
// TO DO:
} else if (e.getSource() == redoButton) {
if (!doilyPanel.getStrokes().isEmpty()) {
doilyPanel.repaint();
}
} else if (e.getSource() == changePenColorButton) {
Color color = JColorChooser.showDialog(frame, "Change pen color", frame.getBackground());
if (color != null) {
doilyPanel.setStrokeColor(color);
doilyPanel.setColor(color);
}
doilyPanel.repaint();
} else if(e.getSource() == saveButton) {
if (galleryPanel.getDoilies().size() < 12) {
BufferedImage doily = DoilyPanel.resizeDoily(doilyPanel.saveDoily(doilyPanel), 100, 100);
galleryPanel.addDoily(new JLabel(new ImageIcon(doily)));
galleryPanel.revalidate();
} else {
JOptionPane.showMessageDialog(null, "The maximum number of doilies you can save is 12.");
}
} else if (e.getSource() == toggleSectorLinesButton) {
doilyPanel.toggleSectorLines();
doilyPanel.setSectorLinesStatus(doilyPanel.updateSectorLinesStatus());
doilyPanel.repaint();
} else if(e.getSource() == toggleReflectionButton) {
doilyPanel.toggleReflectDrawing();
doilyPanel.setReflectedDrawingStatus(doilyPanel.updateReflectDrawingStatus());
doilyPanel.repaint();
} else if (e.getSource() == toggleEraserButton) {
}
}
#Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() == penSizeSpinner) {
doilyPanel.setPenSize((int)penSizeSpinner.getValue());
doilyPanel.setStrokePenSize((int) penSizeSpinner.getValue());
doilyPanel.repaint();
//doilyPanel.repaint();
} else if (e.getSource() == sectorSpinner) {
doilyPanel.setSectors((int) sectorSpinner.getValue());
doilyPanel.setSectorsAngle(360.0 / doilyPanel.getSectors());
doilyPanel.repaint();
}
}
}
DoilyPanel.java
public class DoilyPanel extends JPanel {
/**
* How many sectors the doily has
*/
private int sectors;
/**
* The angle between each sector line
*/
private double sectorsAngle;
/**
* How big the size of the pen is
*/
private int penSize;
/**
* The color of the pen
*/
private Color color = Color.WHITE;
/**
* Whether sector lines are activated
*/
private boolean sectorLines = true;
private String sectorLinesStatus;
/**
* Whether reflected drawing is activated
*/
private boolean reflectedDrawing = false;
private String reflectedDrawingStatus;
/**
* The drawing area of the doily
*/
private BufferedImage canvas;
private Pen stroke;
private ArrayList<Pen> strokes;
/**
* |---------------------------------- Methods ----------------------------------|
*/
/**
* Get method for sectors property
* #return the number of sectors
*/
public int getSectors() {
return sectors;
}
/**
* Set method for sectors property
* #param sectors - new number of sectors
*/
public void setSectors(int sectors) {
this.sectors = sectors;
}
public void setSectorsAngle(double sectorsAngle) {
this.sectorsAngle = sectorsAngle;
}
public double getSectorsAngle() {
return sectorsAngle;
}
/**
* Get method for
* #return
*/
public int getPenSize() {
return penSize;
}
public void setPenSize(int penSize) {
this.penSize = penSize;
}
public Pen getStroke() {
return stroke;
}
public void setStroke(Pen stroke) {
this.stroke = stroke;
}
public void setStrokeColor(Color color) {
this.stroke.setColor(color);
}
public void setStrokePenSize(int size) {
this.stroke.setSize(size);
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
public void setCanvas(BufferedImage canvas) {
this.canvas = canvas;
}
public BufferedImage getCanvas() {
return canvas;
}
public boolean getSectorLines() {
return sectorLines;
}
public String getSectorLinesStatus() {
return sectorLinesStatus;
}
public void setSectorLinesStatus(String sectorLinesStatus) {
this.sectorLinesStatus = sectorLinesStatus;
}
public boolean getReflectDrawing() {
return reflectedDrawing;
}
public String getReflectedDrawingStatus() {
return reflectedDrawingStatus;
}
public void setReflectedDrawingStatus(String reflectedDrawingStatus) {
this.reflectedDrawingStatus = reflectedDrawingStatus;
}
public void addPoint(MouseEvent event) {
if (!(sectors % 2 == 0)) {
stroke.addPoint(new Point(event.getY() - this.getWidth() / 2, event.getX() - this.getWidth() / 2));
} else {
stroke.addPoint(new Point(event.getY() - this.getWidth() / 2, -event.getX() - this.getWidth() / 2));
}
repaint();
}
public ArrayList<Pen> getStrokes() {
return strokes;
}
public int getStrokesSize() {
return strokes.size() - 1;
}
public void removeStrokes(int index) {
this.strokes.remove(index);
}
public void removeStrokes() {
this.strokes.clear();
}
public String updateSectorLinesStatus() {
if (sectorLines) {
return "On";
}
return "Off";
}
public String updateReflectDrawingStatus() {
if (reflectedDrawing) {
return "On";
}
return "Off";
}
public DoilyPanel() {
setSectors(6);
setSectorsAngle(360.0 / getSectors());
setPenSize(2);
setColor(Color.BLUE);
stroke = new Pen(this);
strokes = new ArrayList<>();
canvas = new BufferedImage(800, 800, BufferedImage.TYPE_4BYTE_ABGR);
setSectorLinesStatus(updateSectorLinesStatus());
setReflectedDrawingStatus(updateReflectDrawingStatus());
this.setBackground(Color.BLACK);
this.addMouseListener(new DoilyPanelListener(this));
this.addMouseMotionListener(new DoilyPanelListener(this));
}
public void toggleSectorLines() {
sectorLines = !sectorLines;
}
public void toggleReflectDrawing() {
reflectedDrawing = !reflectedDrawing;
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D graphics2D = (Graphics2D) g;
graphics2D.setColor(Color.BLACK);
// Centering the image
graphics2D.translate(this.getWidth() / 2, this.getHeight() / 2);
if (sectorLines) {
for (int i = 0; i < sectors; i++) {
graphics2D.setColor(Color.WHITE);
graphics2D.setStroke(new BasicStroke(1));
graphics2D.drawLine(0, 0, 0, 364);
graphics2D.rotate(Math.toRadians(sectorsAngle));
}
}
graphics2D.setColor(Color.BLACK);
graphics2D.setStroke(new BasicStroke(penSize));
for (int i = 0; i < strokes.size(); i++) {
strokes.get(i).paint(graphics2D);
}
stroke.paint(graphics2D);
}
#Override
public void paint(Graphics g) {
super.paint(g);
}
public static BufferedImage resizeDoily(BufferedImage doily, int width, int height) {
BufferedImage resized = new BufferedImage(width, height, BufferedImage.TRANSLUCENT);
Graphics2D g2d = resized.createGraphics();
g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
g2d.drawImage(doily, 0, 0, width, height, null);
g2d.dispose();
return resized;
}
public BufferedImage saveDoily(JPanel panel) {
BufferedImage doily = new BufferedImage(panel.getWidth(), panel.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
panel.paint(doily.getGraphics());
return doily;
}
}
DoilyPanelListener.java
public class DoilyPanelListener implements MouseListener, MouseMotionListener {
private DoilyPanel doilyPanel;
public DoilyPanelListener(DoilyPanel doilyPanel) {
this.doilyPanel = doilyPanel;
}
#Override
public void mouseClicked(MouseEvent e) {
doilyPanel.addPoint(e);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
doilyPanel.getStrokes().add(doilyPanel.getStroke());
doilyPanel.setStroke(new Pen(doilyPanel));
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseDragged(MouseEvent e) {
doilyPanel.addPoint(e);
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
Pen.java
public class Pen {
private DoilyPanel doilyPanel;
private int size;
private Color color;
private boolean isReflectedOn;
private ArrayList<Point> points;
public void setSize(int size) {
this.size = size;
}
public int getSize() {
return size;
}
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
public void setReflectedOn(boolean reflectedOn) {
isReflectedOn = reflectedOn;
}
public void setPoints(ArrayList<Point> points) {
this.points = points;
}
public ArrayList<Point> getPoints() {
return points;
}
public Pen(DoilyPanel doilyPanel) {
this.doilyPanel = doilyPanel;
setSize(doilyPanel.getPenSize());
setColor(doilyPanel.getColor());
setReflectedOn(doilyPanel.getReflectDrawing());
points = new ArrayList<>();
}
public void addPoint(Point p) {
this.points.add(p);
}
public void paint(Graphics graphics) {
Graphics2D graphics2D = (Graphics2D) graphics;
graphics2D.setColor(color);
for (int i = 0; i < doilyPanel.getSectors(); i++) {
graphics2D.setStroke(new BasicStroke(size));
Point point1 = null;
if (points.size() == 1) {
point1 = points.get(0);
graphics2D.drawRect((int)point1.getX(), (int)point1.getY(), doilyPanel.getPenSize(), doilyPanel.getPenSize());
// Draw Reflections if they are on
if (isReflectedOn) {
graphics2D.drawRect(-(int)point1.getX(), (int)point1.getY(), doilyPanel.getPenSize(), doilyPanel.getPenSize());
}
graphics2D.rotate(Math.toRadians(doilyPanel.getSectorsAngle()));
} else if (points.size() > 1){
Iterator<Point> pointsIterator = points.iterator();
point1 = pointsIterator.next();
while (pointsIterator.hasNext()) {
Point point2 = pointsIterator.next();
graphics2D.drawRect((int)point1.getX(), (int)point1.getY(), (int)point2.getX(), (int)point2.getY());
// Draw Reflections if they are on
if (isReflectedOn) {
graphics2D.drawLine(-(int)point1.getX(), (int)point1.getY(), -(int)point2.getX(), (int)point2.getY());
}
point1 = point2;
}
graphics2D.rotate(Math.toRadians(doilyPanel.getSectorsAngle()));
}
}
}
}

CardLayout showing two panels, flashing

I'm trying to use CardLayout to show two JPanels, a main menu, and a controls screen. When I add two JPanels to my cards JPanel, it just shows two with flashing images. Here is my code:
package main;
public class MazeGame {
// Layout
public static JPanel cards = new JPanel();
// Window
public static JFrame window;
public static String windowLabel = "2D Maze Game - Before Alpha";
// Window Dimensions and Location
public static int WIDTH = 600;
public static int HEIGHT = 600;
public static Component center = null;
public static int exit = 3;
public static void main(String[] args) {
window = new JFrame(windowLabel);
window.setSize(new Dimension(WIDTH, HEIGHT));
window.setResizable(false);
window.setLocationRelativeTo(center);
window.setDefaultCloseOperation(exit);
cards.setLayout(new CardLayout());
cards.add(new MazeGamePanel(), "main");
cards.add(new MazeControlsPanel(), "controls");
window.add(cards);
CardLayout cl = (CardLayout) cards.getLayout();
cl.show(cards, "main");
window.setVisible(true);
}
}
MazeGamePanel:
public class MazeGamePanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Timer
public Timer timer;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public String option1 = "Play";
public String option2 = "Controls";
public String option3 = "Quit";
public MazeGamePanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeGameKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
ActionListener action = new ActionListener () {
public void actionPerformed (ActionEvent e) {
if(opacity != 0) {
opacity--;
} else {
timer.stop();
opacity = 0;
}
}
};
timer = new Timer(10, action);
timer.setInitialDelay(0);
timer.start();
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
if (selectedOption == 0) {
//Play
g.setColor(Color.BLACK);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 1) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.BLACK);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.GRAY);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
} else if (selectedOption == 2) {
//Play
g.setColor(Color.GRAY);
g.drawString(option1, WIDTH / 2 - 200, HEIGHT / 2);
//Controls
g.setColor(Color.GRAY);
g.drawString(option2, WIDTH / 2 - 200, HEIGHT / 2 + 50);
//Quit
g.setColor(Color.BLACK);
g.drawString(option3, WIDTH / 2 - 200, HEIGHT / 2 + 100);
}
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeGameKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_UP) {
if (selectedOption == 1) {
selectedOption = 0;
} else if (selectedOption == 2) {
selectedOption = 1;
}
}
if (e.getKeyCode() == KeyEvent.VK_DOWN) {
if (selectedOption == 0) {
selectedOption = 1;
} else if (selectedOption == 1) {
selectedOption = 2;
}
}
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
if(selectedOption == 1) {
MazeGame.window.removeAll();
MazeGame.window.add(new MazeControlsPanel());
MazeGame.window.validate();
}
}
}
}
}
MazeControlsPanel:
package screens;
public class MazeControlsPanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
// Font
public Font bitTrip;
public Thread thread;
public BufferedImage canvas;
public Graphics2D g;
public boolean running;
public int HEIGHT = MazeGame.HEIGHT;
public int WIDTH = MazeGame.WIDTH;
public int FPS = 30;
public int opacity = 255;
public int selectedOption = 0;
public MazeControlsPanel() {
this.setFocusable(true);
this.requestFocus();
addKeyListener(new MazeControlsKeyListener());
try {
bitTrip = Font.createFont(Font.TRUETYPE_FONT, new File(
"res/font/BitTrip7.TTF"));
} catch (FontFormatException | IOException e) {
e.printStackTrace();
}
/**
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
if (opacity != 0) {
opacity--;
} else {
timer.cancel();
opacity = 0;
}
}
}, 0, 4);
*/
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
}
public void run() {
running = true;
canvas = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) canvas.getGraphics();
long startTime = 0;
long millis = 0;
long waitTime = 0;
long targetTime = 1000 / FPS;
while (running) {
startTime = System.nanoTime();
update();
render();
draw();
millis = (System.nanoTime() - startTime) / 1000000;
waitTime = targetTime - millis;
try {
Thread.sleep(waitTime);
} catch (Exception e) {
}
}
}
// TODO
public void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0, WIDTH, HEIGHT);
bitTrip = bitTrip.deriveFont(40F);
g.setFont(bitTrip);
// Quit
g.setColor(Color.BLACK);
g.drawString("Main Menu", WIDTH / 2 - 200, HEIGHT / 2 + 100);
//g.setColor(new Color(0, 0, 0, opacity));
//g.fillRect(0, 0, WIDTH, HEIGHT);
}
public void update() {
}
public void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(canvas, 0, 0, null);
g2.dispose();
}
private class MazeControlsKeyListener extends KeyAdapter {
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
}
}
}
}
Here's a problem:
final Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
Don't use a java.util.Timer in a Swing program as you will have threading problems. Instead use a Swing Timer.
Also, you're making Swing calls in background threads and using Graphics object obtained by calling getGraphics() on a component, two no-nos for Swing programs.
EDIT
Here is a program that I worked on that swaps components with a CardLayout, but fades one component out as it fades the other one in. What it does:
The program adds all the swapping components to the CardLayout using JPanel.
It also adds a single SwappingImgPanel, a JPanel created to draw two images, one of the component that is fading out, and one of the component that is fading in.
When you swap components, you create images of the two components, the one currently visible, and the one that will next be visible.
You send the images to the SwappingImgPanel instance
You call swap() on the SwappingImgPanel instance.
The SwappingImgPanel will then draw both images but uses a Swing Timer to change the Graphic object's composite value. This is what causes an image to be partially visible.
When the SwappingImgPanel's Timer is done, a done() method is called which sets the SwappingImgPanel's State to State.DONE.
The main GUI is listening to the SwappingImgPanel's state value, and when it achieves State.DONE, the main GUI shows the actual next component (and not an image of it).
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.*;
#SuppressWarnings("serial")
public class DimmingPanelSwaps extends JPanel {
private static final int DELTA_TIME = 10;
private static final int ELAPSED_TIME = 3000;
private static final String SWAPPING_IMG_PANEL = "swapping img panel";
private CardLayout cardlayout = new CardLayout();
private JPanel cardHolderPanel = new JPanel(cardlayout);
private DefaultComboBoxModel<String> comboModel = new DefaultComboBoxModel<>();
private JComboBox<String> cardCombo = new JComboBox<>(comboModel);
private Map<String, JComponent> componentMap = new HashMap<String, JComponent>();
private String key = "";
private SwappingImgPanel swappingImgPanel = new SwappingImgPanel(DELTA_TIME, ELAPSED_TIME);
public DimmingPanelSwaps() {
registerComponent(createComponentOne(), "one");
registerComponent(createComponentTwo(), "two");
registerComponent(createComponentThree(), "three");
registerComponent(createComponentFour(), "four");
key = "one";
cardHolderPanel.add(swappingImgPanel, SWAPPING_IMG_PANEL);
JPanel southPanel = new JPanel();
southPanel.add(cardCombo);
setLayout(new BorderLayout());
add(cardHolderPanel, BorderLayout.CENTER);
add(southPanel, BorderLayout.SOUTH);
swappingImgPanel.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(PropertyChangeEvent pcEvt) {
if (pcEvt.getNewValue() == State.DONE) {
cardlayout.show(cardHolderPanel, key);
cardCombo.setEnabled(true);
}
}
});
cardCombo.addActionListener(new CardComboListener());
}
private JPanel createComponentFour() {
int rows = 4;
int cols = 4;
int gap = 5;
int tfColumns = 8;
JPanel panel = new JPanel(new GridLayout(rows, cols, gap, gap));
for (int i = 0; i < rows * cols; i++) {
JTextField textField = new JTextField(tfColumns);
JPanel tfPanel = new JPanel();
tfPanel.add(textField);
panel.add(tfPanel);
}
return panel;
}
private JLabel createComponentThree() {
int biWidth = 200;
BufferedImage img = new BufferedImage(biWidth, biWidth, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2.setPaint(new GradientPaint(0, 0, Color.red, 20, 20, Color.blue, true));
g2.fillOval(0, 0, biWidth, biWidth);
g2.dispose();
Icon icon = new ImageIcon(img);
JLabel label = new JLabel(icon);
return label;
}
private JScrollPane createComponentTwo() {
JTextArea textArea = new JTextArea(15, 40);
JScrollPane scrollpane = new JScrollPane(textArea);
scrollpane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
scrollpane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
return scrollpane;
}
private JPanel createComponentOne() {
JPanel innerPanel = new JPanel(new GridLayout(1, 0, 5, 0));
String[] btnTitles = {"One", "Two", "Three"};
for (String btnTitle : btnTitles) {
JButton btn = new JButton(btnTitle);
innerPanel.add(btn);
}
JPanel panel = new JPanel(new GridBagLayout());
panel.add(innerPanel);
return panel;
}
#SuppressWarnings("hiding")
private void registerComponent(JComponent jComp, String key) {
cardHolderPanel.add(jComp, key);
componentMap.put(key, jComp);
comboModel.addElement(key);
}
private class CardComboListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
final String oldKey = key;
key = (String) cardCombo.getSelectedItem();
cardCombo.setEnabled(false);
final JComponent firstComp = componentMap.get(oldKey);
final BufferedImage firstImg = extractComponentImg(firstComp);
final JComponent secondComp = componentMap.get(key);
final BufferedImage secondImg = extractComponentImg(secondComp);
cardlayout.show(cardHolderPanel, SWAPPING_IMG_PANEL);
swappingImgPanel.setFirstImg(firstImg);
swappingImgPanel.setSecondImg(secondImg);
swappingImgPanel.swap();
}
private BufferedImage extractComponentImg(final JComponent component) {
Dimension size = component.getSize();
BufferedImage img = new BufferedImage(size.width, size.height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = img.createGraphics();
component.paint(g2);
g2.dispose();
return img;
}
}
private static void createAndShowGui() {
DimmingPanelSwaps mainPanel = new DimmingPanelSwaps();
JFrame frame = new JFrame("Dimming Panel Swaps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
/**
* A JPanel that draws two images
* When swap is called, the first image is shown
* Then a Timer dims the first image while it reveals
* the second image.
* When the elapsed time is complete, it sets its state to State.DONE.
* #author Pete
*
*/
#SuppressWarnings("serial")
class SwappingImgPanel extends JPanel {
public static final String STATE = "state";
private BufferedImage firstImg;
private BufferedImage secondImg;
private int deltaTime;
private int elapsedTime;
// state is a "bound" property, one that is listened to via PropertyChangeSupport
private State state = State.PENDING;
private float alpha1;
private float alpha2;
public SwappingImgPanel(final int deltaTime, final int elapsedTime) {
this.deltaTime = deltaTime;
this.elapsedTime = elapsedTime;
}
public void swap() {
setState(State.STARTED);
if (firstImg == null || secondImg == null) {
done();
}
alpha1 = 1.0f;
alpha2 = 0.0f;
new Timer(deltaTime, new ActionListener() {
private int counter = 0;
private int max = elapsedTime / deltaTime;
#Override
public void actionPerformed(ActionEvent e) {
if (counter >= elapsedTime / deltaTime) {
((Timer)e.getSource()).stop();
done();
return;
}
// set new alpha composite values
alpha1 = ((float)max - counter) / (float) max;
alpha2 = (float) counter / (float) max;
// make sure alphas are within bounds
alpha1 = Math.min(1f, alpha1);
alpha1 = Math.max(0f, alpha1);
alpha2 = Math.min(1f, alpha2);
alpha2 = Math.max(0f, alpha2);
repaint();
counter++;
}
}).start();
}
private void done() {
firstImg = null;
secondImg = null;
setState(State.DONE);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (firstImg == null || secondImg == null) {
return;
}
// create a new Graphics2D object with g.create()
// to avoid any possible side effects from changing the
// composite of the JVM's Graphics object
Graphics2D g2 = (Graphics2D) g.create();
// set the first alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha1));
g2.drawImage(firstImg, 0, 0, this);
// set the second alpha composite, and draw the image
g2.setComposite(((AlphaComposite)g2.getComposite()).derive(alpha2));
g2.drawImage(secondImg, 0, 0, this);
g2.dispose(); // can get rid of this Graphics because we created it
}
public void setFirstImg(BufferedImage firstImg) {
this.firstImg = firstImg;
}
public void setSecondImg(BufferedImage secondImg) {
this.secondImg = secondImg;
}
public State getState() {
return state;
}
public void setState(State state) {
State oldValue = this.state;
State newValue = state;
this.state = state;
firePropertyChange(STATE, oldValue, newValue);
}
}
/**
* Modeled on SwingWorker.StateValue
* #author Pete
*
*/
enum State {
PENDING, STARTED, DONE
}

Java JScrollBar Design

I want customize the JScrollBar Design. I use Mac to develop the app with eclipse. I already tried to scrollPane.getVerticalScrollBar().setBackground(Color.BLACK); but nothing happen.
My code:
scrollPane = new JScrollPane(scriptView);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
scrollPane.getVerticalScrollBar().setUnitIncrement(6);
window.getContentPane().add(scrollPane);
The Object scriptView is from the class JEditorPane.
How it should look:
Thanks for every help.
I guess you are looking for a transparent scrollbar.
This is just presented as an idea(NOT tested code):
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
public class TranslucentScrollBarTest {
public JComponent makeUI() {
JTextArea cmp = new JTextArea();
String str = "1234567890abcdefghijklmnopqrstuvwxyz";
for(int i=0; i<20; i++) {
cmp.append(str+str+"\n");
}
cmp.setForeground(Color.WHITE);
cmp.setBackground(Color.BLACK);
cmp.setOpaque(true);
JScrollPane scrollPane = new JScrollPane(
cmp, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setComponentZOrder(scrollPane.getVerticalScrollBar(), 0);
scrollPane.setComponentZOrder(scrollPane.getViewport(), 1);
scrollPane.getVerticalScrollBar().setOpaque(false);
scrollPane.setLayout(new ScrollPaneLayout() {
#Override
public void layoutContainer(Container parent) {
JScrollPane scrollPane = (JScrollPane)parent;
Rectangle availR = scrollPane.getBounds();
availR.x = availR.y = 0;
Insets insets = parent.getInsets();
availR.x = insets.left;
availR.y = insets.top;
availR.width -= insets.left + insets.right;
availR.height -= insets.top + insets.bottom;
Rectangle vsbR = new Rectangle();
vsbR.width = 12;
vsbR.height = availR.height;
vsbR.x = availR.x + availR.width - vsbR.width;
vsbR.y = availR.y;
if(viewport != null) {
viewport.setBounds(availR);
}
if(vsb != null) {
vsb.setVisible(true);
vsb.setBounds(vsbR);
}
}
});
scrollPane.getVerticalScrollBar().setUI(new BasicScrollBarUI() {
private final Dimension d = new Dimension();
#Override protected JButton createDecreaseButton(int orientation) {
return new JButton() {
#Override public Dimension getPreferredSize() {
return d;
}
};
}
#Override protected JButton createIncreaseButton(int orientation) {
return new JButton() {
#Override public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar)c;
if(!sb.isEnabled() || r.width>r.height) {
return;
}else if(isDragging) {
color = new Color(200,200,100,200);
}else if(isThumbRollover()) {
color = new Color(255,255,100,200);
}else {
color = new Color(220,220,200,200);
}
g2.setPaint(color);
g2.fillRoundRect(r.x,r.y,r.width,r.height,10,10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x,r.y,r.width,r.height,10,10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
});
return scrollPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TranslucentScrollBarTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Here is an improved version I did for a private project. It also supports horizontal scrollbar.
Code:
import javax.swing.*;
import javax.swing.plaf.basic.BasicScrollBarUI;
import java.awt.*;
/**
* This is an implementation of a JScrollPane with a modern UI
*
* #author Philipp Danner
*
*/
public class ModernScrollPane extends JScrollPane {
private static final long serialVersionUID = 8607734981506765935L;
private static final int SCROLL_BAR_ALPHA_ROLLOVER = 100;
private static final int SCROLL_BAR_ALPHA = 50;
private static final int THUMB_SIZE = 8;
private static final int SB_SIZE = 10;
private static final Color THUMB_COLOR = Color.Black;
public ModernScrollPane(Component view) {
this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
public ModernScrollPane(int vsbPolicy, int hsbPolicy) {
this(null, vsbPolicy, hsbPolicy);
}
public ModernScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
setBorder(null);
// Set ScrollBar UI
JScrollBar verticalScrollBar = getVerticalScrollBar();
verticalScrollBar.setOpaque(false);
verticalScrollBar.setUI(new ModernScrollBarUI(this));
JScrollBar horizontalScrollBar = getHorizontalScrollBar();
horizontalScrollBar.setOpaque(false);
horizontalScrollBar.setUI(new ModernScrollBarUI(this));
setLayout(new ScrollPaneLayout() {
private static final long serialVersionUID = 5740408979909014146L;
#Override
public void layoutContainer(Container parent) {
Rectangle availR = ((JScrollPane) parent).getBounds();
availR.x = availR.y = 0;
// viewport
Insets insets = parent.getInsets();
availR.x = insets.left;
availR.y = insets.top;
availR.width -= insets.left + insets.right;
availR.height -= insets.top + insets.bottom;
if (viewport != null) {
viewport.setBounds(availR);
}
boolean vsbNeeded = isVerticalScrollBarfNecessary();
boolean hsbNeeded = isHorizontalScrollBarNecessary();
// vertical scroll bar
Rectangle vsbR = new Rectangle();
vsbR.width = SB_SIZE;
vsbR.height = availR.height - (hsbNeeded ? vsbR.width : 0);
vsbR.x = availR.x + availR.width - vsbR.width;
vsbR.y = availR.y;
if (vsb != null) {
vsb.setBounds(vsbR);
}
// horizontal scroll bar
Rectangle hsbR = new Rectangle();
hsbR.height = SB_SIZE;
hsbR.width = availR.width - (vsbNeeded ? hsbR.height : 0);
hsbR.x = availR.x;
hsbR.y = availR.y + availR.height - hsbR.height;
if (hsb != null) {
hsb.setBounds(hsbR);
}
}
});
// Layering
setComponentZOrder(getVerticalScrollBar(), 0);
setComponentZOrder(getHorizontalScrollBar(), 1);
setComponentZOrder(getViewport(), 2);
viewport.setView(view);
}
private boolean isVerticalScrollBarfNecessary() {
Rectangle viewRect = viewport.getViewRect();
Dimension viewSize = viewport.getViewSize();
return viewSize.getHeight() > viewRect.getHeight();
}
private boolean isHorizontalScrollBarNecessary() {
Rectangle viewRect = viewport.getViewRect();
Dimension viewSize = viewport.getViewSize();
return viewSize.getWidth() > viewRect.getWidth();
}
/**
* Class extending the BasicScrollBarUI and overrides all necessary methods
*/
private static class ModernScrollBarUI extends BasicScrollBarUI {
private JScrollPane sp;
public ModernScrollBarUI(ModernScrollPane sp) {
this.sp = sp;
}
#Override
protected JButton createDecreaseButton(int orientation) {
return new InvisibleScrollBarButton();
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new InvisibleScrollBarButton();
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
int alpha = isThumbRollover() ? SCROLL_BAR_ALPHA_ROLLOVER : SCROLL_BAR_ALPHA;
int orientation = scrollbar.getOrientation();
int x = thumbBounds.x;
int y = thumbBounds.y;
int width = orientation == JScrollBar.VERTICAL ? THUMB_SIZE : thumbBounds.width;
width = Math.max(width, THUMB_SIZE);
int height = orientation == JScrollBar.VERTICAL ? thumbBounds.height : THUMB_SIZE;
height = Math.max(height, THUMB_SIZE);
Graphics2D graphics2D = (Graphics2D) g.create();
graphics2D.setColor(new Color(THUMB_COLOR.getRed(), THUMB_COLOR.getGreen(), THUMB_COLOR.getBlue(), alpha));
graphics2D.fillRect(x, y, width, height);
graphics2D.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
sp.repaint();
}
/**
* Invisible Buttons, to hide scroll bar buttons
*/
private static class InvisibleScrollBarButton extends JButton {
private static final long serialVersionUID = 1552427919226628689L;
private InvisibleScrollBarButton() {
setOpaque(false);
setFocusable(false);
setFocusPainted(false);
setBorderPainted(false);
setBorder(BorderFactory.createEmptyBorder());
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(400, 400));
JPanel content = new JPanel();
content.setBackground(Color.WHITE);
content.setPreferredSize(new Dimension(500, 500));
content.add(new JLabel("test"));
frame.add(new ModernScrollPane(content));
frame.pack();
frame.setVisible(true);
}
}
Custom scrollbar preview :
Custom scrollbar code :
public class CustomScrollBarUI extends BasicScrollBarUI {
private final Dimension d = new Dimension();
#Override
protected JButton createDecreaseButton(int orientation) {
return new JButton() {
private static final long serialVersionUID = -3592643796245558676L;
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new JButton() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar) c;
if (!sb.isEnabled() || r.width > r.height) {
return;
} else if (isDragging) {
color = Color.DARK_GRAY; // change color
} else if (isThumbRollover()) {
color = Color.LIGHT_GRAY; // change color
} else {
color = Color.GRAY; // change color
}
g2.setPaint(color);
g2.fillRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
}
Then use it like this:
YOUR_COMPONENT.getVerticalScrollBar().setUI(new CustomScrollBarUI());
Sadly the proposed solutions will break JTable and won't display the table header, but I found this solution that seems to work.

Very slow scrolling in JScrollPane when using per-pixel transparency

I am using per-pixel transparency using AWTUtilities.setWindowOpaque() on JFrame, that contains JScrollPane. When transparency is on, the scrolling in that pane is very slow and laggy, without it is not. Trying this on Windows 7 and JDK 6.
public class MainFrame extends JFrame {
super();
setUndecorated(true);
AWTUtilities.setWindowOpaque(this, false); //this turns JScrollPane inside of this JFrame slow and laggy
}
Have anyone issued this? Thanks!
I can't see any scrolling issue, nor to create testing scenario for code that is based on good Swing rules, this code is quite too hard for processor(s) and GPU, Java6, Win7 64b
from code
import com.sun.awt.AWTUtilities;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableModel;
public class ViewPortFlickeringOriginal {
private JFrame frame = new JFrame("Table");
private JViewport viewport = new JViewport();
private Rectangle RECT = new Rectangle();
private Rectangle RECT1 = new Rectangle();
private JTable table = new JTable(50, 3);
private javax.swing.Timer timer;
private int count = 0;
private GradientViewPortOriginal tableViewPort;
private static boolean loggerOpacity;
private JPanel panel = new JPanel();
private static JButton button;
public ViewPortFlickeringOriginal() {
tableViewPort = new GradientViewPortOriginal(table);
viewport = tableViewPort.getViewport();
viewport.addChangeListener(new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (tableViewPort.bolStart) {
RECT = table.getCellRect(0, 0, true);
RECT1 = table.getCellRect(table.getRowCount() - 1, 0, true);
Rectangle viewRect = viewport.getViewRect();
if (viewRect.intersects(RECT)) {
System.out.println("Visible RECT -> " + RECT);
tableViewPort.paintBackGround(new Color(250, 150, 150));
} else if (viewRect.intersects(RECT1)) {
System.out.println("Visible RECT1 -> " + RECT1);
tableViewPort.paintBackGround(new Color(150, 250, 150));
} else {
System.out.println("Visible RECT1 -> ???? ");
tableViewPort.paintBackGround(new Color(150, 150, 250));
}
}
}
});
frame.add(tableViewPort);
button = new JButton("Change Opacity for Java6 / Win7");
button.setBounds(100, 100, 50, 50);
button.setVisible(true);
panel.add(button);
loggerOpacity = true;
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent evt) {
Object src = evt.getSource();
if (src == button && loggerOpacity) {
AWTUtilities.setWindowOpacity(frame, 0.80f);
}
}
});
frame.add(panel, BorderLayout.SOUTH);
frame.setPreferredSize(new Dimension(600, 300));
frame.pack();
frame.setLocation(50, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
RepaintManager.setCurrentManager(new RepaintManager() {
#Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
Container con = c.getParent();
while (con instanceof JComponent) {
if (!con.isVisible()) {
return;
}
if (con instanceof GradientViewPortOriginal) {
c = (JComponent) con;
x = 0;
y = 0;
w = con.getWidth();
h = con.getHeight();
}
con = con.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
});
frame.setVisible(true);
start();
}
private void start() {
timer = new javax.swing.Timer(100, updateCol());
timer.start();
}
public Action updateCol() {
return new AbstractAction("text load action") {
private static final long serialVersionUID = 1L;
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("updating row " + (count + 1));
TableModel model = table.getModel();
int cols = model.getColumnCount();
int row = 0;
for (int j = 0; j < cols; j++) {
row = count;
table.changeSelection(row, 0, false, false);
timer.setDelay(100);
Object value = "row " + (count + 1) + " item " + (j + 1);
model.setValueAt(value, count, j);
}
count++;
if (count >= table.getRowCount()) {
timer.stop();
table.changeSelection(0, 0, false, false);
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
table.clearSelection();
tableViewPort.bolStart = true;
}
});
}
}
};
}
public static void main(String[] args) {
java.awt.EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
ViewPortFlickeringOriginal viewPortFlickering = new ViewPortFlickeringOriginal();
}
});
}
}
class GradientViewPortOriginal extends JScrollPane {
private static final long serialVersionUID = 1L;
private final int h = 50;
private BufferedImage img = null;
private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
private JViewport viewPort;
public boolean bolStart = false;
public GradientViewPortOriginal(JComponent com) {
super(com);
viewPort = this.getViewport();
viewPort.setScrollMode(JViewport.BLIT_SCROLL_MODE);
viewPort.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
viewPort.setScrollMode(JViewport.SIMPLE_SCROLL_MODE);
paintBackGround(new Color(250, 150, 150));
}
public void paintBackGround(Color g) {
Graphics2D g2 = shadow.createGraphics();
g2.setPaint(g);
g2.fillRect(0, 0, 1, h);
g2.setComposite(AlphaComposite.DstIn);
g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h,
new Color(0.1f, 0.8f, 0.8f, 0.5f)));
g2.fillRect(0, 0, 1, h);
g2.dispose();
}
#Override
public void paint(Graphics g) {
if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2 = img.createGraphics();
super.paint(g2);
Rectangle bounds = getViewport().getVisibleRect();
g2.scale(bounds.getWidth(), -1);
int y = (getColumnHeader() == null) ? 0 : getColumnHeader().getHeight();
g2.drawImage(shadow, bounds.x, -bounds.y - y - h, null);
g2.scale(1, -1);
g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h + y, null);
g2.dispose();
g.drawImage(img, 0, 0, null);
}
}
but I'm able to demonstrating lazy scrolling for JScrollPane contains others JComponents as is JTable or JList or JTextArea or JTextPane
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import javax.swing.*;
public class ListPanel extends JFrame {
private static final long serialVersionUID = 1L;
public ListPanel() {
setLayout(new GridLayout(0, 2, 10, 10));
DefaultListModel model = new DefaultListModel();
model.addElement(createButtons("one"));
model.addElement(createButtons("two"));
model.addElement(createButtons("three"));
model.addElement(createButtons("four"));
model.addElement(createButtons("five"));
model.addElement(createButtons("six"));
model.addElement(createButtons("seven"));
model.addElement(createButtons("eight"));
model.addElement(createButtons("nine"));
model.addElement(createButtons("ten"));
model.addElement(createButtons("eleven"));
model.addElement(createButtons("twelwe"));
JList list = new JList(model);
list.setCellRenderer(new PanelRenderer());
JScrollPane scroll1 = new JScrollPane(list);
final JScrollBar scrollBar = scroll1.getVerticalScrollBar();
scrollBar.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("JScrollBar's current value = " + scrollBar.getValue());
}
});
add(scroll1);
JScrollPane scroll2 = new JScrollPane(createPanel());
add(scroll2);
final JScrollBar scrollBar1 = scroll2.getVerticalScrollBar();
scrollBar1.addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(AdjustmentEvent e) {
System.out.println("JScrollBar's current value = " + scrollBar1.getValue());
}
});
}
public static JPanel createPanel() {
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1, 1, 1));
panel.add(createButtons("one"));
panel.add(createButtons("two"));
panel.add(createButtons("three"));
panel.add(createButtons("four"));
panel.add(createButtons("five"));
panel.add(createButtons("six"));
panel.add(createButtons("seven"));
panel.add(createButtons("eight"));
panel.add(createButtons("nine"));
panel.add(createButtons("ten"));
panel.add(createButtons("eleven"));
panel.add(createButtons("twelwe"));
return panel;
}
public static JButton createButtons(String text) {
JButton button = new JButton(text);
return button;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
ListPanel frame = new ListPanel();
frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
//frame.pack();
frame.setSize(270, 200);
frame.setVisible(true);
}
});
}
class PanelRenderer implements ListCellRenderer {
#Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
JButton renderer = (JButton) value;
renderer.setBackground(isSelected ? Color.red : list.getBackground());
return renderer;
}
}
}

Layering multiple GlassPane's in a Root Container

Is it possible to add multiple GlassPanes for a single JFrame, or do I have to use the uncomfortable LayeredPane with the Opacity attribute.
I have attached some code that shows what I want to do (provided by #camickr).
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
public class MultiplayGlassPane {
private static final long serialVersionUID = 1L;
private JFrame frame = new JFrame("frameTitle");
private JPanel fPanel = new JPanel();
private Random random = new Random();
private final static Border MESSAGE_BORDER = new EmptyBorder(10, 10, 10, 10);
private JLabel message = new JLabel();
private ArrayList<Star> stars = new ArrayList<Star>();
public MultiplayGlassPane() {
MyGlassPane glass = new MyGlassPane();
for (int i = 0; i < 35; i++) {
Star star = new Star(new Point(random.nextInt(580), random.nextInt(550)));
star.setColor(Color.orange);
star.setxIncr(-3 + random.nextInt(7));
star.setyIncr(-3 + random.nextInt(7));
glass.add(star);
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(glass, BorderLayout.CENTER);
frame.setLocation(20, 20);
frame.pack();
frame.setVisible(true);
DisabledGlassPane1 glassPane = new DisabledGlassPane1();
JRootPane rootPane = SwingUtilities.getRootPane(frame);
rootPane.setGlassPane(glassPane);
glassPane.activate("");
}
private class MyGlassPane extends JLabel {
private static final long serialVersionUID = 1L;
private ArrayList<Star> stars = new ArrayList<Star>();
private javax.swing.Timer timer = new javax.swing.Timer(20, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Star star : stars) {
star.move();
}
repaint();
}
});
public void stopAnimation() {
if (timer.isRunning()) {
timer.stop();
}
}
public void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
#Override
public void addNotify() {
super.addNotify();
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(new Dimension(620, 620));
}
public MyGlassPane() {
this.setPreferredSize(new Dimension(620, 620));
}
public void add(Star star) {
stars.add(star);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Star star : stars) {
g.setColor(star.getColor());
g.fillPolygon(star);
}
}
}
class DisabledGlassPane1 extends JComponent implements KeyListener {
private static final long serialVersionUID = 1L;
public DisabledGlassPane1() {
setOpaque(false);
Color base = UIManager.getColor("inactiveCaptionBorder");
Color background = new Color(base.getRed(), base.getGreen(), base.getBlue(), 128);
setBackground(background);
setLayout(new GridBagLayout());
add(message, new GridBagConstraints());
message.setOpaque(true);
message.setBorder(MESSAGE_BORDER);
addMouseListener(new MouseAdapter() {
});
addMouseMotionListener(new MouseMotionAdapter() {
});
addKeyListener(this);
setFocusTraversalKeysEnabled(false);
Random random = new Random();
for (int i = 0; i < 50; i++) {
Star star = new Star(new Point(random.nextInt(490), random.nextInt(490)));
star.setColor(Color.magenta);
star.setxIncr(-3 + random.nextInt(7));
star.setyIncr(-3 + random.nextInt(7));
add(star);
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
((Graphics2D) g).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
for (Star star : stars) {
g.setColor(star.getColor());
g.fillPolygon(star);
}
}
#Override
public void setBackground(Color background) {
super.setBackground(background);
Color messageBackground = new Color(background.getRGB());
message.setBackground(messageBackground);
}
public void keyPressed(KeyEvent e) {
e.consume();
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
e.consume();
}
public void activate(String text) {
if (text != null && text.length() > 0) {
message.setVisible(true);
message.setText(text);
message.setForeground(getForeground());
} else {
message.setVisible(false);
}
setVisible(true);
//setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
requestFocusInWindow();
}
public void deactivate() {
setCursor(null);
setVisible(false);
}
private javax.swing.Timer timer = new javax.swing.Timer(15, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
for (Star star : stars) {
star.move();
}
repaint();
}
});
public void stopAnimation() {
if (timer.isRunning()) {
timer.stop();
}
}
public void startAnimation() {
if (!timer.isRunning()) {
timer.start();
}
}
#Override
public void addNotify() {
super.addNotify();
timer.start();
}
#Override
public void removeNotify() {
super.removeNotify();
timer.stop();
}
public void add(Star star) {
stars.add(star);
}
}
private class Star extends Polygon {
private static final long serialVersionUID = 1L;
private Point location = null;
private Color color = Color.YELLOW;
private int xIncr, yIncr;
static final int WIDTH = 600, HEIGHT = 600;
Star(Point location) {
int x = location.x;
int y = location.y;
this.location = location;
this.addPoint(x, y + 8);
this.addPoint(x + 8, y + 8);
this.addPoint(x + 11, y);
this.addPoint(x + 14, y + 8);
this.addPoint(x + 22, y + 8);
this.addPoint(x + 17, y + 12);
this.addPoint(x + 21, y + 20);
this.addPoint(x + 11, y + 14);
this.addPoint(x + 3, y + 20);
this.addPoint(x + 6, y + 12);
}
public void setColor(Color color) {
this.color = color;
}
public void move() {
if (location.x < 0 || location.x > frame.getContentPane().getWidth() - 20) {
xIncr = -xIncr;
}
if (location.y < 0 || location.y > frame.getContentPane().getHeight() - 20) {
yIncr = -yIncr;
}
translate(xIncr, yIncr);
location.setLocation(location.x + xIncr, location.y + yIncr);
}
public void setxIncr(int xIncr) {
this.xIncr = xIncr;
}
public void setyIncr(int yIncr) {
this.yIncr = yIncr;
}
public Color getColor() {
return color;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MultiplayGlassPane Mpgp = new MultiplayGlassPane();
}
});
}
}
Look at http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html for an explanation on Root panes and what the Glass pane actually is.
The glass pane is just a convenient way to add a component which has the size of the Root Pane, and which blocks all input events. This allows you to catch any interaction with your components to create a "Please wait..." screen.
There is only a single glass pane per root container. You cannot layer glass panes.
You can replace the contents of the glass pane by something else if you want to layer something over the current glass pane. You can also set a JPanel as a glass pane, which allows you to layout multiple components in the glass pane.
Usually, you should only use the glass pane to block user input (and, if necessary, display some kind of "please wait" message). Can you provide a use case of why you want to put glass panes on top of one another?

Categories