Java 我在JFrame中有几个JComboxes,它们在非常特定的情况下会减慢自定义绘图JPanel的速度。有人知道为什么会这样吗?
我正在为我正在进行的一个项目编写一个地图制作工具,最近我在JComboBox中加入了一个下拉选择器,用于选择可应用于平铺的纹理类型。我通过覆盖paintComponent()并为编辑器的图形部分调用repaint(),在扩展JPanel(标记为DrawPanel)上自定义绘图,并且还为菜单使用各种Swing组件。最近我开始注意到,单击并打开JComboBox会导致DrawPanel的性能下降到爬行状态。我将问题缩小了一点,并发现它只在某些用例下发生(稍后将解释)。当绘制画布变慢时,只能通过关闭窗口并重新启动来修复,或者有时在调整窗口大小时会间歇性地发生。我怀疑这是可行的,因为组件被调整大小并重新验证,但手动调用revalidate()似乎不起作用 在研究到底是什么在减速时,我加入了一些时间测量。我发现逻辑循环中的所有内容,即update()和window.repain(),都像正常一样启动:update方法的启动时间为10毫秒,repain()调用的启动时间为1毫秒,尽可能快。然而,当我在paintComponent()方法内部计时时,我发现该方法开始与下一次相同方法开始之间的时间从平均1毫秒增加到平均30-180毫秒,具体取决于窗口的大小。但完成绘图功能所需的时间没有改变。我对此进行了更多的研究,据我所知,AWT线程使用事件在组件调度上调用repaint(),以再次绘制组件,但最终取决于AWT线程何时真正执行重新绘制。这是为了保持它的并发性,也是不建议直接重写组件的paint()或update()方法的原因。我不是最擅长挥杆的,所以如果我弄错了,请纠正我 尽管有了这样的理解,AWT线程似乎在减速或专注于其他事情,并没有像我希望的那样快速地重新绘制画布。从现在起,我们将把整个问题称为经济放缓 关于用例。我发现JComboxes有许多用例会出现减速。在所有情况下,只有当JComboBox在JFrame之外绘制下拉列表时,才会发生这种情况。只有当JComboBox无法填充其周围区域时,才会发生这种情况,无论是直接设置setMaximumSize(),还是间接限制其大小(例如将其放置在JPanel中,并使其大小与内容的宽度和高度一致)。奇怪的是,如果显示的最大行数超过10,即使在JFrame之外显示,也不会出现减速 这里有一个我精心设计的测试类来展示我提到的行为。取决于你的硬件,它可能很明显,也可能不是那么明显。我试着给图形卡至少一点工作,以便在它发生时显示减速。我用Ryzen 3800x和RTX 2070在我的钻机上运行了这个Java 我在JFrame中有几个JComboxes,它们在非常特定的情况下会减慢自定义绘图JPanel的速度。有人知道为什么会这样吗?,java,swing,jcombobox,Java,Swing,Jcombobox,我正在为我正在进行的一个项目编写一个地图制作工具,最近我在JComboBox中加入了一个下拉选择器,用于选择可应用于平铺的纹理类型。我通过覆盖paintComponent()并为编辑器的图形部分调用repaint(),在扩展JPanel(标记为DrawPanel)上自定义绘图,并且还为菜单使用各种Swing组件。最近我开始注意到,单击并打开JComboBox会导致DrawPanel的性能下降到爬行状态。我将问题缩小了一点,并发现它只在某些用例下发生(稍后将解释)。当绘制画布变慢时,只能通过关闭窗
import javax.swing.*;
import java.awt.*;
public class TestClass{
public boolean running = true;
public long tickRegulator, displayTimer;
public long UPSFrameTimeMark, UPSFrameTime, FPSFrameTimeMark, FPSFrameTime, UPSDisplay, FPSDisplay;
public JFrame window;
public DrawPanel canvas;
public float time = 0;
public static void main(String[] args){new TestClass();}
public TestClass()
{
initialize();
logicLoop();
}
private void initialize()
{
//look and feel + defaulting the timings
UPSFrameTimeMark = UPSFrameTime = FPSFrameTime = FPSFrameTimeMark = System.currentTimeMillis();
try{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch(Exception e){e.printStackTrace();}
//below is the frame setup
window = new JFrame("Test Frame");
window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//DrawPanel extends JPanel and uses an overridden paintComponent() to draw
canvas = new DrawPanel();
canvas.setPreferredSize(new Dimension(400, 400));
window.add(canvas, BorderLayout.NORTH);
//below are all the use cases for the JComboBoxes
int itemCount = 20;
String[] options = new String[itemCount];
for(int i = 0; i < itemCount; i++){options[i]=""+i;}
//The first two JComboBoxes are tested in a toolbar
JToolBar toolBar = new JToolBar();
toolBar.setBackground(Color.WHITE);
toolBar.setFloatable(false);
window.getContentPane().add(toolBar, BorderLayout.PAGE_END);
//bottom left - max size not set (filling available space) - causes no issue
JComboBox mapTextureOptions = new JComboBox(options);
mapTextureOptions.setForeground(Color.BLUE);
toolBar.add(mapTextureOptions);
//bottom right - max size set to 15x15 (although only the height is respected) - causes issue
JComboBox mapTextureOptions2 = new JComboBox(options);
mapTextureOptions2.setForeground(Color.RED);
mapTextureOptions2.setMaximumSize(new Dimension(15, 15));
toolBar.add(mapTextureOptions2);
//the second two JComboBoxes are tested in a JPanel
JPanel panel = new JPanel();
window.add(panel, BorderLayout.CENTER);
//top left - max rows set to 11 + no max size is explicitly set - causes no issues
JComboBox mapTextureOptions3 = new JComboBox(options);
mapTextureOptions3.setForeground(Color.YELLOW);
mapTextureOptions3.setMaximumRowCount(11);
panel.add(mapTextureOptions3);
//top right - max rows set to 10 + no max size is explicitly set - causes issues
JComboBox mapTextureOptions4 = new JComboBox(options);
mapTextureOptions4.setForeground(Color.GREEN);
mapTextureOptions4.setMaximumRowCount(10);
panel.add(mapTextureOptions4);
window.pack();
window.setVisible(true);
}
private void logicLoop()
{
long timeMarker = System.currentTimeMillis();
while(running){
tickRegulator += (System.currentTimeMillis() - timeMarker);
displayTimer += (System.currentTimeMillis() - timeMarker);
timeMarker = System.currentTimeMillis();
if(displayTimer > 100)
{
FPSDisplay = FPSFrameTime;
UPSDisplay = UPSFrameTime;
displayTimer = 0;
}
try{
while(tickRegulator > 10)
{
UPSFrameTime = System.currentTimeMillis() - UPSFrameTimeMark;
UPSFrameTimeMark = System.currentTimeMillis();
update();
tickRegulator-=10;
}
window.repaint();
}catch(Exception e)
{
e.printStackTrace();
}
try{Thread.sleep(1);}catch(Exception e){e.printStackTrace();}
}
}
private void update()
{
time += 0.02f;
}
private void draw(Graphics2D g)
{
FPSFrameTime = System.currentTimeMillis() - FPSFrameTimeMark;
FPSFrameTimeMark = System.currentTimeMillis();
//draw background
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, window.getWidth(), window.getHeight());
float zoom = 0.05f;
for(int x = 0; x < Math.max((canvas.getWidth() * 1.2f) / zoom, 500); x += 100)
{
g.setColor(new Color(27, 255, 0, Math.round(80 * 0.8f)));
if((x - (0 - (0 % 100))) % 1000 != 0)
{
g.setColor(new Color(0, 255, 80, Math.round(28 * 0.8f)));
}
if((x - (0 - (0 % 100))) % 10000 == 0)
{
g.setColor(new Color(27, 255, 0, Math.round(128 * 0.8f)));
}
g.drawLine(Math.round((x + (0 % 100)) * zoom), 0, Math.round((x + (0 % 100)) * zoom), canvas.getHeight());
}
for(int y = 0; y < Math.max((canvas.getHeight() * 1.2) / zoom, 500); y += 100)
{
g.setColor(new Color(27, 255, 0, Math.round(80 * 0.8f)));
if((y - (0 - (0 % 100))) % 1000 != 0)
{
g.setColor(new Color(0, 255, 80, Math.round(28 * 0.8f)));
}
if((y - (0 - (0 % 100))) % 10000 == 0)
{
g.setColor(new Color(27, 255, 0, Math.round(128 * 0.8f)));
}
g.drawLine(0, Math.round((y + (0 % 100)) * zoom), canvas.getWidth(), Math.round((y + (0 % 100)) * zoom));
}
g.setColor(Color.RED);
g.fillOval((int)(Math.cos(time) * (canvas.getWidth() / 2 - 25)) + canvas.getWidth() / 2 - 25,
(int)(Math.sin(time) * (canvas.getHeight() / 2 - 25)) + canvas.getHeight() / 2 - 25,
50, 50);
g.drawString("UPS Frame Time: " + (UPSDisplay) + "ms", 5, 20);
g.drawString("FPS Frame Time: " + (FPSDisplay) + "ms", 5, 35);
}
class DrawPanel extends JPanel
{
public DrawPanel() {
setBorder(BorderFactory.createLineBorder(Color.black));
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
draw((Graphics2D) g);
}
}
}
import javax.swing.*;
导入java.awt.*;
公共类TestClass{
公共布尔运行=true;
公共长时间调节器,显示定时器;
公共长UpFrameTimemark、UpFrameTime、FPSFrameTimeMark、FPSFrameTime、UPSDisplay、FPSDisplay;
公共框架窗口;
公共绘图板画布;
公共浮动时间=0;
公共静态void main(字符串[]args){new TestClass();}
公共测试类()
{
初始化();
逻辑循环();
}
私有void初始化()
{
//外观+默认计时
upFrameTimeMark=upFrameTime=FPSFrameTime=FPSFrameTimeMark=System.currentTimeMillis();
请尝试{UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());}
catch(异常e){e.printStackTrace();}
//下面是框架设置
窗口=新JFrame(“测试框架”);
setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//DrawPanel扩展了JPanel并使用重写的paintComponent()进行绘制
canvas=新的DrawPanel();
canvas.setPreferredSize(新维度(400400));
添加(画布,BorderLayout.NORTH);
//下面是JComboxes的所有用例
int itemCount=20;
字符串[]选项=新字符串[itemCount];
对于(inti=0;i