我有一个非常基本的小JFrame与JToggleButtons和子类JPanels知道如何绘制我想要他们绘制的东西。选择按钮会使椭圆出现在相应的面板中。取消选择按钮会使图形消失。
不幸的是,最小化(图标化)然后恢复(取消图像化)会导致任何绘制的形状消失。所以我需要手动触发重绘。问题是,如果我首先显示一个消息框,我只能完成重绘(即,我只是看它)。
以下是JFrame的deiconify事件:
private void formWindowDeiconified(java.awt.event.WindowEvent evt)
{
//having this message makes everything work
JOptionPane.showMessageDialog(null, "Useless message this is.");
//but if I skip it, I'm SOL
//what's going on?
drawAll();
}
此方法遍历我的所有按钮,并在必要时请求重绘:
public void drawAll()
{
for (int i=0; i<channels; i++)
{
if (buttons[i].isSelected())
{
lightboxes[i].drawMe();
}
}
}
这是我的子类JPanel:
class MyJPanel extends JPanel {
public void drawMe()
{
Graphics myGraphics = this.getGraphics();
myGraphics.fillOval(0, 0, this.getWidth(), this.getHeight());
}
public void unDraw()
{
this.invalidate();
this.repaint();
}
}
答案 0 :(得分:4)
RepaintManager
恢复后,窗口应自动重新绘制。问题是你没有像你应该那样进行自定义绘画......
这不是如何做自定义绘画...
public void drawMe()
{
Graphics myGraphics = this.getGraphics();
myGraphics.fillOval(0, 0, this.getWidth(), this.getHeight());
}
getGraphics
可以返回null
,并且最多只是图形状态的快照。
Swing中的绘画可以随时出现,原因有很多,其中大多数都是你无法控制的(你也不应该关心)。
您的工作只是响应这些重新绘制请求并更新组件状态。
Swing有一个详细的绘画链,可以自动调用,你可以使用它。
你应该覆盖paintComponent
并在此方法中执行所有绘画
答案 1 :(得分:1)
首先,对于速度我会使用双缓冲。最好在屏幕上绘制图形并在绘图完成后将其显示在屏幕上。以下内容应该排除你。
public class MyPanel extends JPanel {
private BufferedImage buffer;
private Graphics2D canvas;
@Override
public void paintComponent(Graphics g) {
if(buffer == null) {
buffer = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB);
canvas = buffer.createGraphics();
}
canvas.fillOval(0, 0, this.getWidth(), this.getHeight());
g.drawImage(buffer, 0, 0, this);
}
}
答案 2 :(得分:1)
我只是提供这个答案,以便人们可以看到我最终做的事情。每个人都指出的主要教训是使用组件的paintComponent。请参阅您自己可能遇到的问题的评论。
修改:已更新以反映MadProgrammer的评论。
//with help from Slihp and MadProgrammer on StackOverflow
//http://stackoverflow.com/q/17331986/1736461
class MyJPanel extends JPanel {
private boolean buttonSelected = false;
@Override
public void paintComponent(Graphics g) {
//make sure the background gets painted (wacky results otherwise)
super.paintComponent(g);
//now if the corresponding toggle button is on, plop on the circle
if (buttonSelected)
{
g.fillOval(0, 0, this.getWidth(), this.getHeight());
}
}
//an action listener for the button calls this
public void setButtonSelected(boolean buttonStateIn)
{
buttonSelected = buttonStateIn;
}
}
我也将按钮子类化了,所以我可以从事件处理程序中获取它的“ID”:
class MyJToggleButton extends JToggleButton
{
private int whoAmI;
public MyJToggleButton(int whoAmIn)
{
//the string given to the constructor becomes the button's label
//("1", "2", "3", etc..)
super(Integer.toString(whoAmIn + 1));
whoAmI = whoAmIn;
}
public int getWho()
{
return whoAmI;
}
}
制作按钮的JFrame代码:
private void makeButtons(int howMany)
{
buttons = new MyJToggleButton[howMany];
for (int i=0; i<howMany; i++)
{
buttons[i] = new MyJToggleButton(i);
buttons[i].addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
//find out which button this is
MyJToggleButton button = (MyJToggleButton) evt.getSource();
int which = button.getWho();
//send the button state to the corresponding lightbox
lightboxes[which].setButtonSelected(button.isSelected());
//trigger its redrawing
lightboxes[which].invalidate();
lightboxes[which].repaint();
}
});
this.add(buttons[i]);
}
}
这是我必须做的唯一手动重绘 - 调整大小和重新显示,所有其他有趣的东西最终都会击中paintComponent,它只需要知道它的按钮是否被推动以知道该怎么做。超级干净,正是我想要的。