我正在使用swing制作游戏画布并决定使用JTextField
来输入用户名和密码到面板中。
我正在缓冲图像,然后将其渲染到屏幕上,而不是将所有内容直接绘制到面板上。
我遇到了一个问题,我画了一个背景并将我的两个文本字段都设置为不透明,但似乎每当我在那些文本字段中输入内容时它会闪烁一个黑框,其中{{1是的。
它出现在我的用户名和密码字段中。知道原因可能是什么?
其他有用的信息:每当我点击一个文本框时,两个组件都会在第一个字符的位置闪烁黑色。
编辑 - 我刚注意到登录按钮在JTextField
和MOUSE_ENTERED
时也闪烁黑色。
MOUSE_EXIT
这是文本字段:(来自使用getPanel()完全调用GamePanel的单独类...)
public class GamePanel extends JPanel implements Runnable {
public GamePanel(int width, int height) {
this.pWidth = width;
this.pHeight = height;
setController(new LoginGameController(this));
setPreferredSize( new Dimension(pWidth, pHeight));
setBackground(Color.BLACK);
setFocusable(true);
requestFocus(); // the JPanel now has focus, so receives key events
// create game components
addMouseListener(this);
addKeyListener(this);
setLayout(null);
startGame();
}
private void startGame()
// initialise and start the thread
{ if (animator == null) {
animator = new Thread(this);
animator.start();
}
}
public void run() {
while(true) {
gameUpdate();
if(getGraphics() != null){
gameRender(); // render the game to a buffer
paintScreen(); // draw the buffer on-screen
}
try {
Thread.sleep(28);
} catch (InterruptedException e) {}
}
}
private void paintScreen() {
Graphics2D g = (Graphics2D) getGraphics();
if ((g != null) && (img != null))
g.drawImage(img, 0, 0, null);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
private void gameRender() {
if(getWidth() > 0 && getHeight() > 0)
img = createImage(getWidth(), getHeight());
if(img != null) {
Graphics2D g = (Graphics2D) img.getGraphics();
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
g.setColor(Color.BLACK);
g.fillRect(0, 0, pWidth, pHeight);
getController().render(img);
paintComponents(img.getGraphics());
}
}
}
谢谢!
答案 0 :(得分:3)
基本问题是,当你更新你的图形时,你绕过了Swings重绘过程并且不尊重EDT。
JComponent#getGraphics
是一个临时/临时缓冲区,将在下次重绘时重新绘制。此外,如果您没有创建图形,则不应将其丢弃!
public void run() {
while(true) {
gameUpdate();
if(getGraphics() != null){
gameRender(); // render the game to a buffer
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
paintScreen(); // draw the buffer on-screen
}
});
} catch (Exception exp) {
exp.printStackTrace(); // please clean this up
}
}
try {
Thread.sleep(28);
} catch (InterruptedException e) {}
}
}
我不知道这是否会解决它,但它不会伤害。 (这会影响你的FPS,你应该考虑画画需要多长时间以及你想等多久)
另外,而不是调用paintScreen()
,您可以调用repaint
(或让paintScreen
执行此操作)并覆盖paintComponent
方法来绘制缓冲区。
这将允许Swing正确地恢复对绘制过程的控制。
答案 1 :(得分:2)
窗口或组件至少有三种重绘方式。
通常,以下途径是有效的:
操作系统可以请求更新特定矩形。这是由工具包提取的。此外,组件也可以通过其repaint
方法向工具箱发出变化信号。该工具包持续收集合并传入重绘请求一段时间,然后要求窗口重新绘制特定矩形。窗口的默认操作是通过调用其paintComponent
方法来绘制自身,其中它不与实心子项重叠,然后递归绘制其组件。
如果你自己进行渲染,工具包也是这样做的。由于您没有覆盖paintComponent
,因此当此方法运行时,它将作为默认值。默认操作是什么都不做。然后工具包拾取空帧缓冲区并在其上绘制按钮(不会绘制背景)。
您可以禁用工具包的渲染过程并自行渲染(抓取缓冲区,绘制到其中,然后提交)。您可以调用setIgnoreRepaint(true)
方法忽略操作系统的请求。