【问题标题】:Is it Better to Paint or Use a JLabel绘制或使用 JLabel 更好吗
【发布时间】:2013-10-27 17:51:48
【问题描述】:

我正在开发一个 Swing 应用程序,该应用程序将在背景中包含一些图像。我想知道以下哪种方法更有效(或更好),或者您是否有其他建议:

getGraphics().drawImage(t.getImage().getImage(), i * 16, j * 16, this);

JLabel tile = new JLabel(t.getImage());
tile.setBounds(i * 16, j * 16, t.getImage().getIconWidth(), t.getImage().getIconHeight());
add(tile);

编辑:

这就是事情发生的地方:

for (int j = 0; j < 3; j++) {
            for (int i = 0; i < 3; i++) {
                Tile t = map.getTiles()[j][i];
                if (t != null) {
                    // Draw it somehow.
                }
            }
        }

【问题讨论】:

  • 我认为(不确定)使用JLable 更安全,因为它会使用已初始化JLable 的线程绘制图像。
  • @user2511414:不,这两种技术都没有任何线程安全问题。但是,在要绘制图像时继续重新读取图像是错误的,但这不是线程安全问题,而是减慢程序问题。
  • @HovercraftFullOfEels 关于repainting the image 的好点,所以我弄错了。谢谢哥们:)

标签: java performance swing paint


【解决方案1】:

关于:

getGraphics().drawImage(t.getImage().getImage(), i * 16, j * 16, this);

您永远不应该使用通过在组件上调用getGraphics() 获得的 Graphics 对象进行绘图,因为这样获得的 Graphics 对象将是短暂的,并且您的绘图可能会变得不稳定。要明白我的意思,请尝试使用您的技术,然后在创建 GUI 后,最小化并恢复它,您可能会看到部分或全部图像已经消失。相反,您应该使用给定的 Graphics 对象在 JPanel(或其他 JComponent 派生类)的 paintComponent(...) 方法内部进行绘制。

也不要在每次绘制图像时都读取图像,因为这样做会导致程序不必要的变慢。相反,如果图像不是很大,则在程序启动时将它们读入一次,将它们放入 BufferedImage 或 ImageIcon 变量中(取决于需要),并在应用程序需要的时间和地点使用它们。


关于:

JLabel tile = new JLabel(t.getImage());
tile.setBounds(i * 16, j * 16, t.getImage().getIconWidth(), t.getImage().getIconHeight());
add(tile);

这很好,除了setBounds(...) 部分表明程序没有正确使用布局管理器。让 JLabel 及其 ImageIcon 设置自己的首选大小,并让布局管理器在设置组件和调整 GUI 大小时使用它。

请注意,您可以提供 JLabel 的布局管理器并向它们添加组件,就像它们是 JPanel 一样。主要区别在于 JLabels 默认不是不透明的。


关于哪个更好,使用 JLabel 保存图像或在paintComponent(...) 中绘图:通常取决于图像是否必须调整大小以适应组件。如果是这样,请绘制 JPanel 的paintComponent(...)。否则使用 JLabel。


编辑
根据您的 cmets:

关于第二部分,我没有使用布局管理器。

那么您的 GUI 在不同的操作系统上可能会变得丑陋,并且可能无法很好地扩展。布局管理器是 Swing 编程最强大的方面之一,如果您使用它们,您的 GUI 将更容易编码、更新、增强并在其他系统上运行良好。

关于第二部分,我将什么 Graphics 对象传递给 paintComponent()?

您不会将任何 Graphics 对象传递给 JPanel 的 paintComponent(Graphics g)。这是 JVM 的重绘管理器根据您的建议(通过调用 repaint())或操作系统的建议调用的方法。

最后,你是说我使用这两个选项中的哪一个并不重要?

不,我没有那样说。请重新阅读我在此编辑上方的建议。


编辑 2
关键链接:


编辑 3
对于瓦片地图,我将 ImageIcons 用于瓦片图像,然后将它们显示在 JLabels 网格中。这样,交换图块就像在感兴趣的 JLabel 上调用 setIcon(nextIcon) 一样简单。

例如,请参阅 TrashGod 和我对这个问题的回答:jlabel images array

关于:

就布局管理器而言,我有充分的理由。我用布局管理器制作了许多 GUI,但这个很特别 ;)。

这样做需要您自担风险,而且我愿意打赌您的推理不正确。


编辑 4

我不使用布局管理器的原因是因为我想用 Swing 制作一个小型 RPG 游戏。

然后,最好将图块保存在使用 GridLayout 的容器中,并且该容器可能保存在 JScrollPane 中,以便您可以向任何方向滚动。然后,您可以让您的精灵位于 JLabels 中(通过为它们提供适当的布局),或者通过使用 JLayeredPane 在顶部。

我不希望任何 cmets 告诉我我不能或我不应该,因为如果不可能,我会自己找出答案。

  • 当然,我们并不是要告诉您您不能做任何事情,否则您无法规定我们应该或不应该告诉您的内容。您来这里寻求我们的建议,我们有义务告诉您我们认为最有效的方法。你有权听从我们的建议,因为这是你的节目,但同样,你不能规定我们可以或不能告诉你什么,除了你不应该容忍或允许粗鲁或冒犯性的陈述(标记版主如果你看到这个,他们会处理的)。

【讨论】:

  • 关于第二部分,我没有使用布局管理器。关于第二部分,我将什么Graphics 对象传递给paintComponent()?最后,您是说我使用这两个选项中的哪一个并不重要?
  • 另外,感谢关​​于不每次加载的部分;我修好了。
  • 就布局管理器而言,我有充分的理由。我用布局管理器制作了许多 GUI,但这个很特别;)。至于paintComponent(),我假设你的意思是覆盖它,但我之前很困惑。以这种方式绘制的所有图像将始终具有相同的大小(16 像素 x 16 像素)。
  • 我看不出与以前相比...,隧道尽头的任何光线,答案都是基于您的努力,以获得更好的帮助尽快发布SSCCE,简短,可运行,可编译跨度>
  • +1 表示所有编辑,@PogoStick29 I have no reason to move the tiles, as they are static background images. - 少数潜力之一。不使用布局管理器的原因(在我看来)是当您有随机动态移动的图像时。但是,由于您使用的是静态图像,因此应该使用 LayoutManager 来定位它们。基本上,您正在编写的代码无论如何都在复制布局管理器的功能。编程规则之一是不要重新发明轮子。
【解决方案2】:

使用 JLabel 会占用容器空间。

在容器上绘图不会占用容器空间。

【讨论】:

  • 您确定不能将组件放在 JLabel 上吗?即使你给它一个像样的布局管理器?
  • 你可以将兄弟组件放在 JLabel 上,但是许多布局管理器会限制它!现在不要告诉我 JLabel 也是容器,并且可以包含组件!或者使用 Z-Order,将同级组件放在一起。 JLabel 的目的是标记一些东西!
  • 确实,JLabel 的 主要 目的是“标记某些东西”,但它可以像 JPanel 一样用作容器,不,布局管理器不会只要正确使用它们,就不会对此进行任何限制。我们中的许多 Swing 爱好者多年来一直在这样做。
  • 是的,这就是我的意思,我们可以做任何事情,我可以在 5 分钟内为您提供放置在 JLabel 上或包含在 JLabel 中的组件,但我使用 JLabel 来标记某些东西,或者就像 OP , 使用 JLabel 显示一些徽标。并且以这种正常方式使用标签会占用空间,但使用Graphics绘制不会占用容器空间。
  • 酷,我从未见过那个页面。关于这个问题,我通常参考我的Background Panel 链接,其中包含允许 OP 做出选择的两种解决方案,希望它可以帮助人们更好地理解 Swing 的工作原理。是的,标签通常用于标记某事,但我也喜欢挑战人们在解决问题时要“跳出框框思考”。
猜你喜欢
  • 1970-01-01
  • 2017-01-10
  • 2012-04-09
  • 2017-01-19
  • 2010-09-22
  • 2011-11-16
  • 2011-12-02
  • 1970-01-01
  • 2020-01-01
相关资源
最近更新 更多