有很多要理解的,所以坚持我。我在 JScrollPane 中有一个 JPanel,它在 JTabbedPane 中,而 JTabbedPane 在 JFrame 中。在这个过程中的某个地方,我失去了添加关键听众的能力。
我用这个来设置我的 JFrame
public class Cartographer {
private final JFrame frmMyWorld = new JFrame();
/**
* set up our toolbar
*/
private final JButton addTabb = new JButton("Create New Workspace");
//this is where I create the new tabbed pane
private static JTabbedPane tabbedPane;
private int numberOfTabbs;
public static boolean isScrolling;
private static JSlider zoomer;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Cartographer window = new Cartographer();
window.frmMyWorld.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Cartographer() {
initialize();
createEvents();
}
然后我初始化:
private void initialize() {
frmMyWorld.setTitle("My World");
frmMyWorld.setBounds(0, 0, 1450, 805);
frmMyWorld.getContentPane().setBackground(new Color(100,100,100));
frmMyWorld.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
newTab();
isScrolling = true;
//this sets up my slider which I'm using to zoom
zoomer = new JSlider();
zoomer.setMinimum(-1000);
zoomer.setMaximum(1000);
zoomer.setValue(1000);
zoomer.setOrientation(SwingConstants.VERTICAL);
zoomer.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if(isScrolling) {
hPortion = getHPortion();
vPortion = getVPortion();
}
isScrolling = false;
int hScale = (int) getSelectedPane().getHorizontalScrollBar().getMaximum();
int vScale = (int) getSelectedPane().getVerticalScrollBar().getMaximum();
getSelectedSpace().setZoomFactor(Math.pow(2, (double) zoomer.getValue()/250 - 4));
getSelectedSpace().setZoomerValue(zoomer.getValue());
getSelectedSpace().repaint();
getSelectedPane().getHorizontalScrollBar().setValue((int) Math.round(hPortion*hScale - (hVisible()/2)));
getSelectedPane().getVerticalScrollBar().setValue((int) Math.round(vPortion*vScale - (vVisible()/2)));
getSelectedPane().addNotify();
getSelectedPane().revalidate();
getSelectedPane().setDoubleBuffered(true);
getSelectedPane().getHorizontalScrollBar().revalidate();
getSelectedPane().getVerticalScrollBar().revalidate();
getSelectedSpace().repaint();
}
});
/**and using a group layout, we add a new tab to our JFrame
* my original code was using buttons I'm just simplifying the code to make it . */easier to read,that's why I'm using group layour ,
GroupLayout groupLayout = new GroupLayout(frmMyWorld.getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 1335, GroupLayout.PREFERRED_SIZE))
.addGap(28))
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 624, GroupLayout.PREFERRED_SIZE)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 642, GroupLayout.PREFERRED_SIZE))
.addGap(18))
);
groupSettingManager(groupLayout);
}
newTab() 函数是我们创建新标签时所做的
void newTab() {
//We first create a new workspace with the given dimentions
Workspace workSpace = new Workspace(1295*256, 592*256);
//request focus so we can add key listeners
workSpace.requestFocus();
//Our workspace sits inside a scroll pane
JScrollPane scrollPane = new JScrollPane(workSpace);
numberOfTabbs++;
//our scroll pane sits inside a tabbed pane
tabbedPane.addTab("Workspace " + numberOfTabbs, scrollPane);
tabbedPane.setSelectedIndex(numberOfTabbs-1);
scrollPane.getHorizontalScrollBar().addMouseListener(new MouseListener(){
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
@Override
public void mouseClicked(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}
});
scrollPane.getVerticalScrollBar().addMouseListener(new MouseListener(){
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
@Override
public void mouseClicked(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}
});
}
您可能已经注意到,我们在新工作区创建后立即请求焦点,但是,这似乎并没有给它焦点
我试过将关键监听器添加到工作区,就像这样
public class Workspace extends JPanel implements KeyListener{
//we keep every landmass that will appear in the workspace stored in this array
public ArrayList<Node> protoLandmass = new ArrayList<Node>();
private static Color backGroundColor;
private int zoomerValue;
private static double zoomFactor;
private static int width;
private static int height;
private static boolean zooming = false;
/**
*
*/
private static final long serialVersionUID = 1L;
public Workspace(int w, int h) {
eventHandlers();
this.setPreferredSize(new Dimension(w,h));
backGroundColor = new Color(0,120,255);
this.setBackground(backGroundColor);
zoomFactor = 1;
width = w;
height = h;
zoomerValue = 1000;
this.setFocusable(true);
//I've also tried to request focus here, that didn't work either
//this.requestFocus();
this.addKeyListener(this);
//this.requestFocusInWindow();
repaint();
}
...
@Override
public void keyTyped(KeyEvent e) {
...
}
@Override
public void keyPressed(KeyEvent e) {
...
}
}
@Override
public void keyReleased(KeyEvent e) {
...
}
这里的关键监听器不起作用,即使我已经尝试在多个地方请求焦点
当我在这里创建事件时,鼠标监听器似乎起作用了:
private void eventHandlers() {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
...
repaint();
}
public void mouseClicked(MouseEvent e) {
...
}
public void mouseReleased(MouseEvent e) {
...
}
public void mouseExited(MouseEvent e) {
...
repaint();
}
public void mouseEntered(MouseEvent e) {
...
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
repaint();
}
public void mouseDragged(MouseEvent e) {
repaint();
}
public void mouseWheelMoved(MouseEvent e) {
// this one doesn't work either
Cartographer.isScrolling = true;
}
});
this.addKeyListener(new KeyAdapter(){
@Override
public void keyTyped(KeyEvent e) {
...
}
@override
public void keyPressed(KeyEvent e) {
...
}
}
@override
public void keyReleased(KeyEvent e) {
...
}
}
我尝试在这里添加关键监听器,但它们也没有用。我从来没有尝试过同时在两个地方都有主要的听众,我只是展示他们去过的所有地方,让你更容易。
最小可重现示例:
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.JSlider;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeListener;
import javax.swing.event.ChangeEvent;
public class Cartographer {
private final JFrame frmMyWorld = new JFrame();
/**
* set up our toolbar
*/
double hPortion = 0;
double vPortion = 0;
//the space that will contain everything that is drawn
private static JTabbedPane tabbedPane;
private int numberOfTabbs;
public static boolean isScrolling;
private static JSlider zoomer;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Cartographer window = new Cartographer();
window.frmMyWorld.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Cartographer() {
initialize();
}
/**
* Initialise the contents of the frame.
*/
private void initialize() {
frmMyWorld.setTitle("My World");
frmMyWorld.setBounds(0, 0, 1450, 805);
frmMyWorld.getContentPane().setBackground(new Color(100,100,100));
frmMyWorld.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
newTab();
isScrolling = true;
/**
* give everything its position in the window, we're using a group layout
*/
zoomer = new JSlider();
zoomer.setMinimum(-1000);
zoomer.setMaximum(1000);
zoomer.setValue(1000);
zoomer.setOrientation(SwingConstants.VERTICAL);
zoomer.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if(isScrolling) {
hPortion = getHPortion();
vPortion = getVPortion();
}
isScrolling = false;
int hScale = (int) getSelectedPane().getHorizontalScrollBar().getMaximum();
int vScale = (int) getSelectedPane().getVerticalScrollBar().getMaximum();
getSelectedSpace().setZoomFactor(Math.pow(2, (double) zoomer.getValue()/1000 - 1));
getSelectedSpace().setZoomerValue(zoomer.getValue());
getSelectedSpace().repaint();
getSelectedPane().getHorizontalScrollBar().setValue((int) Math.round(hPortion*hScale - (hVisible()/2)));
getSelectedPane().getVerticalScrollBar().setValue((int) Math.round(vPortion*vScale - (vVisible()/2)));
getSelectedPane().addNotify();
getSelectedPane().revalidate();
getSelectedPane().setDoubleBuffered(true);
getSelectedPane().getHorizontalScrollBar().revalidate();
getSelectedPane().getVerticalScrollBar().revalidate();
getSelectedSpace().repaint();
}
});
GroupLayout groupLayout = new GroupLayout(frmMyWorld.getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 1335, GroupLayout.PREFERRED_SIZE))
.addGap(28))
);
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 624, GroupLayout.PREFERRED_SIZE)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 642, GroupLayout.PREFERRED_SIZE))
.addGap(18))
);
groupSettingManager(groupLayout);
}
void groupSettingManager(GroupLayout groupLayout) {
frmMyWorld.getContentPane().setLayout(groupLayout);
}
void newTab() {
//We first create a new workspace with the given dimentions
Workspace workSpace = new Workspace(1295*4, 592*4);
//we need to focus on this new workspace for key listeners to work
//Our workspace sits inside a scroll pane
JScrollPane scrollPane = new JScrollPane(workSpace);
numberOfTabbs++;
//our scroll pane sits inside a tabbed pane
tabbedPane.addTab("Workspace " + numberOfTabbs, scrollPane);
workSpace.requestFocus();
tabbedPane.setSelectedIndex(numberOfTabbs-1);
scrollPane.getHorizontalScrollBar().addMouseListener(new MouseListener(){
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
@Override
public void mouseClicked(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}
});
scrollPane.getVerticalScrollBar().addMouseListener(new MouseListener(){
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
@Override
public void mouseClicked(MouseEvent e) {}public void mouseReleased(MouseEvent e) {}public void mouseEntered(MouseEvent e) {}public void mouseExited(MouseEvent e) {}
});
}
static Workspace getSelectedSpace() {
return ((Workspace) ((JScrollPane) tabbedPane.getSelectedComponent()).getViewport().getView());
}
JScrollPane getSelectedPane() {
return (JScrollPane) tabbedPane.getSelectedComponent();
}
Workspace getSpace(int i) {
return ((Workspace) ((JScrollPane) tabbedPane.getComponent(i)).getViewport().getView());
}
JScrollPane getPane(int i) {
return (JScrollPane) tabbedPane.getComponent(i);
}
static void setZoomerValue(int i) {
if(-1000 <= i && i <= 1000)
zoomer.setValue(i);
}
int getZoomerValue() {
return zoomer.getValue();
}
public double getHPortion() {
int m = getSelectedPane().getHorizontalScrollBar().getMaximum();
int v = getSelectedPane().getHorizontalScrollBar().getValue();
double a = getSelectedPane().getHorizontalScrollBar().getVisibleAmount()/2;
return (v + a)/m;
}
public double getVPortion() {
int m = getSelectedPane().getVerticalScrollBar().getMaximum();
int v = getSelectedPane().getVerticalScrollBar().getValue();
double a = getSelectedPane().getVerticalScrollBar().getVisibleAmount()/2;
return (v +a)/m;
}
public int hVisible() {
return getSelectedPane().getHorizontalScrollBar().getVisibleAmount();
}
public int vVisible() {
return getSelectedPane().getVerticalScrollBar().getVisibleAmount();
}
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.LayoutManager;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JPanel;
public class Workspace extends JPanel implements KeyListener{
//we keep every landmass that will appear in the workspace stored in this array
private static Color backGroundColor;
private static Color foreGroundColor;
private int zoomerValue;
private static double zoomFactor;
private static int width;
private static int height;
/**
*
*/
private static final long serialVersionUID = 1L;
public Workspace(int w, int h) {
eventHandlers();
this.setPreferredSize(new Dimension(w,h));
backGroundColor = Color.BLACK;
foreGroundColor = Color.WHITE;
this.setBackground(backGroundColor);
zoomFactor = 1;
width = w;
height = h;
zoomerValue = 1000;
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
//this.requestFocusInWindow();
repaint();
}
public Workspace(LayoutManager layout) {
super(layout);
}
public Workspace(boolean isDoubleBuffered) {
super(isDoubleBuffered);
}
public Workspace(LayoutManager layout, boolean isDoubleBuffered) {
super(layout, isDoubleBuffered);
}
public double getZoomFactor() {
return zoomFactor;
}
public void setZoomFactor(double z) {
zoomFactor = z;
repaint();
}
public void adjustZoomFactor(int z) {
zoomFactor = Math.pow(2, z);
repaint();
}
public int getZoomerValue() {
return zoomerValue;
}
public void setZoomerValue(int i) {
zoomerValue = i;
}
/**
* Paint Function and supplement functions
*/
public void paint(Graphics g)
{
Graphics2D g2= (Graphics2D) g;
zoom(g2);
//a for loop to run the same function on each of the landmasses to draw them all
for(int i = 0; i < 35; i++)
for(int j = Math.floorMod(i, 2); j < 16; j+=2) {
g2.setColor(foreGroundColor);
g2.fillRect(148*i, 148*j, 148, 148);
g2.setColor(Color.GREEN);
g2.drawString("(" + i + "," + j + ")",148*i+66,148*j+72);
}
this.setBackground(backGroundColor);
}
private void zoom(Graphics2D g) {
//if(zooming) g.translate(-getMousePosition().x, -getMousePosition().y);
g.scale(zoomFactor,zoomFactor);
this.setPreferredSize(new Dimension((int) Math.round(width*zoomFactor), (int) Math.round(height*zoomFactor)));
this.validate();
//if(zooming) g.translate(getMousePosition().x, getMousePosition().y);
}
/**
* Any events that occur within the workspace happen here
*/
private void eventHandlers() {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
foreGroundColor = Color.BLUE;
repaint();
}
public void mouseClicked(MouseEvent e) {
backGroundColor = Color.GRAY;
repaint();
}
public void mouseReleased(MouseEvent e) {
foreGroundColor = Color.WHITE;
repaint();
}
public void mouseExited(MouseEvent e) {
backGroundColor = Color.BLACK;
repaint();
}
public void mouseEntered(MouseEvent e) {
Cartographer.setZoomerValue(zoomerValue);
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
repaint();
}
public void mouseDragged(MouseEvent e) {
repaint();
}
public void mouseWheelMoved(MouseEvent e) {
Cartographer.isScrolling = true;
}
});
this.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
foreGroundColor = Color.RED;
}
});
}
public int mousePositionX() {
return (int) Math.round(getMousePosition().x/zoomFactor);
}
public int mousePositionY() {
return (int) Math.round(getMousePosition().y/zoomFactor);
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case 38 : if(zoomerValue < 1000) { zoomerValue+=5; Cartographer.setZoomerValue(zoomerValue);}
repaint();
break;
case 40 : if(zoomerValue > -1000) {zoomerValue-=5; Cartographer.setZoomerValue(zoomerValue);}
System.out.println(zoomerValue);
repaint();
break;
default: repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
}
因此,使用您的代码,我可以证明键绑定确实在嵌套组件内部起作用,这里的绑定位于 g 键上,表示“绿色”。按下该键时,组件的前景色变为绿色。
绑定:
private void eventHandlers() {
// .......
// add some key bindings to test that they work
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
// when the g-key is pressed, the foreground color is set to green
KeyStroke gDownKey = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false);
KeyStroke gUpKey = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, true);
inputMap.put(gDownKey, "gDown");
actionMap.put("gDown", new ForeGroundColorAction(Color.GREEN));
inputMap.put(gUpKey, "gUp");
actionMap.put("gUp", new ForeGroundColorAction(Color.WHITE));
}
private class ForeGroundColorAction extends AbstractAction {
private Color color;
public ForeGroundColorAction(Color color) {
this.color = color;
}
@Override
public void actionPerformed(ActionEvent e) {
foreGroundColor = color;
repaint();
}
}
还有我的MRE演示程序:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.*;
public class Cartographer {
private final JFrame frmMyWorld = new JFrame();
double hPortion = 0;
double vPortion = 0;
private JTabbedPane tabbedPane;
private int numberOfTabbs;
public boolean isScrolling;
private JSlider zoomer;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Cartographer window = new Cartographer();
window.frmMyWorld.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public Cartographer() {
initialize();
}
private void initialize() {
frmMyWorld.setTitle("My World");
frmMyWorld.setBounds(0, 0, 1450, 805);
frmMyWorld.getContentPane().setBackground(new Color(100, 100, 100));
frmMyWorld.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
tabbedPane = new JTabbedPane(JTabbedPane.TOP);
newTab();
isScrolling = true;
zoomer = new JSlider();
zoomer.setMinimum(-1000);
zoomer.setMaximum(1000);
zoomer.setValue(1000);
zoomer.setOrientation(SwingConstants.VERTICAL);
zoomer.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
if (isScrolling) {
hPortion = getHPortion();
vPortion = getVPortion();
}
isScrolling = false;
int hScale = (int) getSelectedPane().getHorizontalScrollBar().getMaximum();
int vScale = (int) getSelectedPane().getVerticalScrollBar().getMaximum();
getSelectedSpace().setZoomFactor(Math.pow(2, (double) zoomer.getValue() / 1000 - 1));
getSelectedSpace().setZoomerValue(zoomer.getValue());
getSelectedSpace().repaint();
getSelectedPane().getHorizontalScrollBar()
.setValue((int) Math.round(hPortion * hScale - (hVisible() / 2)));
getSelectedPane().getVerticalScrollBar()
.setValue((int) Math.round(vPortion * vScale - (vVisible() / 2)));
getSelectedPane().addNotify();
getSelectedPane().revalidate();
getSelectedPane().setDoubleBuffered(true);
getSelectedPane().getHorizontalScrollBar().revalidate();
getSelectedPane().getVerticalScrollBar().revalidate();
getSelectedSpace().repaint();
}
});
GroupLayout groupLayout = new GroupLayout(frmMyWorld.getContentPane());
groupLayout.setHorizontalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 85, GroupLayout.PREFERRED_SIZE)
.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 1335,
GroupLayout.PREFERRED_SIZE))
.addGap(28)));
groupLayout.setVerticalGroup(
groupLayout.createParallelGroup(Alignment.LEADING)
.addGroup(groupLayout.createSequentialGroup()
.addContainerGap()
.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
.addComponent(zoomer, GroupLayout.PREFERRED_SIZE, 624,
GroupLayout.PREFERRED_SIZE)
.addComponent(tabbedPane, GroupLayout.PREFERRED_SIZE, 642,
GroupLayout.PREFERRED_SIZE))
.addGap(18)));
groupSettingManager(groupLayout);
}
void groupSettingManager(GroupLayout groupLayout) {
frmMyWorld.getContentPane().setLayout(groupLayout);
}
void newTab() {
// We first create a new workspace with the given dimentions
Workspace workSpace = new Workspace(1295 * 4, 592 * 4, this);
// we need to focus on this new workspace for key listeners to work
// Our workspace sits inside a scroll pane
JScrollPane scrollPane = new JScrollPane(workSpace);
numberOfTabbs++;
// our scroll pane sits inside a tabbed pane
tabbedPane.addTab("Workspace " + numberOfTabbs, scrollPane);
workSpace.requestFocus();
tabbedPane.setSelectedIndex(numberOfTabbs - 1);
scrollPane.getHorizontalScrollBar().addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
});
scrollPane.getVerticalScrollBar().addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
isScrolling = true;
}
});
}
Workspace getSelectedSpace() {
return ((Workspace) ((JScrollPane) tabbedPane.getSelectedComponent()).getViewport().getView());
}
JScrollPane getSelectedPane() {
return (JScrollPane) tabbedPane.getSelectedComponent();
}
Workspace getSpace(int i) {
return ((Workspace) ((JScrollPane) tabbedPane.getComponent(i)).getViewport().getView());
}
JScrollPane getPane(int i) {
return (JScrollPane) tabbedPane.getComponent(i);
}
void setZoomerValue(int i) {
if (-1000 <= i && i <= 1000)
zoomer.setValue(i);
}
int getZoomerValue() {
return zoomer.getValue();
}
public double getHPortion() {
int m = getSelectedPane().getHorizontalScrollBar().getMaximum();
int v = getSelectedPane().getHorizontalScrollBar().getValue();
double a = getSelectedPane().getHorizontalScrollBar().getVisibleAmount() / 2;
return (v + a) / m;
}
public double getVPortion() {
int m = getSelectedPane().getVerticalScrollBar().getMaximum();
int v = getSelectedPane().getVerticalScrollBar().getValue();
double a = getSelectedPane().getVerticalScrollBar().getVisibleAmount() / 2;
return (v + a) / m;
}
public int hVisible() {
return getSelectedPane().getHorizontalScrollBar().getVisibleAmount();
}
public int vVisible() {
return getSelectedPane().getVerticalScrollBar().getVisibleAmount();
}
}
class Workspace extends JPanel implements KeyListener {
// we keep every landmass that will appear in the workspace stored in this array
private Color backGroundColor;
private Color foreGroundColor;
private int zoomerValue;
private Cartographer cartographer;
private double zoomFactor;
private int width;
private int height;
private static final long serialVersionUID = 1L;
public Workspace(int w, int h, Cartographer cartographer) {
this.cartographer = cartographer;
eventHandlers();
this.setPreferredSize(new Dimension(w, h));
backGroundColor = Color.BLACK;
foreGroundColor = Color.WHITE;
this.setBackground(backGroundColor);
zoomFactor = 1;
width = w;
height = h;
zoomerValue = 1000;
this.setFocusable(true);
this.requestFocus();
this.addKeyListener(this);
setBackground(backGroundColor); // !!s
}
public Workspace(LayoutManager layout) {
super(layout);
}
public Workspace(boolean isDoubleBuffered) {
super(isDoubleBuffered);
}
public Workspace(LayoutManager layout, boolean isDoubleBuffered) {
super(layout, isDoubleBuffered);
}
public double getZoomFactor() {
return zoomFactor;
}
public void setZoomFactor(double z) {
zoomFactor = z;
repaint();
}
public void adjustZoomFactor(int z) {
zoomFactor = Math.pow(2, z);
repaint();
}
public int getZoomerValue() {
return zoomerValue;
}
public void setZoomerValue(int i) {
zoomerValue = i;
}
@Override // must override paintComponent, not paint
protected void paintComponent(Graphics g) {
super.paintComponent(g); // never forget this!
// best to only scale a copy of the Graphics object so as not to break the painting chain
Graphics2D g2 = (Graphics2D) g.create();
zoom(g2);
for (int i = 0; i < 35; i++) {
for (int j = Math.floorMod(i, 2); j < 16; j += 2) {
g2.setColor(foreGroundColor);
g2.fillRect(148 * i, 148 * j, 148, 148);
g2.setColor(Color.GREEN);
g2.drawString("(" + i + "," + j + ")", 148 * i + 66, 148 * j + 72);
}
}
g2.dispose(); // dispose of copy
// this.setBackground(backGroundColor); // !! does not belong in painting method
}
private void zoom(Graphics2D g) {
// if(zooming) g.translate(-getMousePosition().x, -getMousePosition().y);
g.scale(zoomFactor, zoomFactor);
this.setPreferredSize(
new Dimension((int) Math.round(width * zoomFactor), (int) Math.round(height * zoomFactor)));
this.validate();
// if(zooming) g.translate(getMousePosition().x, getMousePosition().y);
}
/**
* Any events that occur within the workspace happen here
*/
private void eventHandlers() {
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
foreGroundColor = Color.BLUE;
repaint();
}
public void mouseClicked(MouseEvent e) {
backGroundColor = Color.GRAY;
repaint();
}
public void mouseReleased(MouseEvent e) {
foreGroundColor = Color.WHITE;
repaint();
}
public void mouseExited(MouseEvent e) {
backGroundColor = Color.BLACK;
repaint();
}
public void mouseEntered(MouseEvent e) {
cartographer.setZoomerValue(zoomerValue);
repaint();
}
});
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
repaint();
}
public void mouseDragged(MouseEvent e) {
repaint();
}
public void mouseWheelMoved(MouseEvent e) {
cartographer.isScrolling = true;
}
});
this.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
foreGroundColor = Color.RED;
}
});
// add some key bindings to test that they work
InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = getActionMap();
// when the g-key is pressed, the foreground color is set to green
KeyStroke gDownKey = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false);
KeyStroke gUpKey = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, true);
inputMap.put(gDownKey, "gDown");
actionMap.put("gDown", new ForeGroundColorAction(Color.GREEN));
inputMap.put(gUpKey, "gUp");
actionMap.put("gUp", new ForeGroundColorAction(Color.WHITE));
}
private class ForeGroundColorAction extends AbstractAction {
private Color color;
public ForeGroundColorAction(Color color) {
this.color = color;
}
@Override
public void actionPerformed(ActionEvent e) {
foreGroundColor = color;
repaint();
}
}
public int mousePositionX() {
return (int) Math.round(getMousePosition().x / zoomFactor);
}
public int mousePositionY() {
return (int) Math.round(getMousePosition().y / zoomFactor);
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case 38:
if (zoomerValue < 1000) {
zoomerValue += 5;
cartographer.setZoomerValue(zoomerValue);
}
repaint();
break;
case 40:
if (zoomerValue > -1000) {
zoomerValue -= 5;
cartographer.setZoomerValue(zoomerValue);
}
System.out.println(zoomerValue);
repaint();
break;
default:
repaint();
}
}
@Override
public void keyReleased(KeyEvent e) {
}
}
注意我删除了许多静态修饰符。另外,你不应该在 paint 中绘制,而应该在 paintComponent 中绘制,并且不要忘记调用 super 的方法来进行内务绘制。此外,缩放通常应该在 JVM 提供的 Graphics 对象的副本上完成。