如何等待 JComponent 完全绘制?

发布于 2024-08-03 14:28:44 字数 621 浏览 3 评论 0原文

我需要一种方法来等待(Swing)JComponent 完全绘制。这个实际问题源自 openmap 应用程序:任务是绘制具有几个图层的地图 (mapBean) 并从该地图创建图像。

不幸的是,有明确记录,图像格式化程序从地图中获取当前状态来创建图片,并且有可能(尤其是当地图变得复杂时)在绘制 mapBean(一个 JComponent)之前调用格式化程序。

尽管用这个 openmap 应用程序进行了解释,但该问题非常普遍,并且据说与 Swing 相关。现在,我只是等待固定时间(一秒),但这并不能消除创建不完整地图的风险...

编辑

更多细节 - 我必须从构建一个(OpenMap)MapPanel 开始,其中internallz创建一个MapBean(JComponent子类)和一个MapHandler。然后,我向 MapHandler 提供地理层,框架开始在 JComponent 类型 MapBean 上绘制地理数据。

将所有图层添加到地图后,我使用另一个框架类来创建 JPG 图像(或:保存图像数据的 byte[])。如果我不等待,可能会导致问题:这个“图像创建者”从地图 bean 的当前状态创建图像,如果我提前调用这个“图像创建者”,一些地图图层未绘制且丢失。相当烦人...

I need a way to wait until a (Swing) JComponent is fully painted. This actual problem arises from an openmap application: The task is to draw a map (mapBean) with a couple of layers and create an image from that map.

Unfortunatly, and it's clearly documented, the image formatter takes the current state from the map to create the picture, and there's a chance, especially when maps become complex, that the formatter ist called before the mapBean, a JComponent, is painted.

Although explained with this openmap application, the problem is quite general and supposedly Swing related. Right now, I just wait a fixed time (one second) but that does not eliminate the risk of creating incomplete maps...

Edit

Some more details - I have to start with constructing a (OpenMap) MapPanel, which internallz creates a MapBean (JComponent subclass) and a MapHandler. Then I feed the MapHandler with geographical Layers and the Framework starts painting the geographical data 'on' the JComponent type MapBean.

After adding all layers to the Map, I use another framework class to create a JPG image (or: the byte[] that holds the image data). And this can cause problem, if I don't wait: this 'image creator' creates the image from the current state of the map bean, and if I call this 'image creator' to early, some map layers are not painted and missing. Pretty annoying...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

稚气少女 2024-08-10 14:28:44

java.awt.EventQueue.invokeLater 将允许您在绘制操作完成后运行任务。如果它正在执行某种异步加载,那么它将是特定于 API 的(就像 MediaTracker 对于 Image 所做的那样)。

java.awt.EventQueue.invokeLater will allow you to run a task after the paint operation has finished. If it is doing some kind of asynchronous load, then it will be API specific (as MediaTracker does for Image).

夏末染殇 2024-08-10 14:28:44

您还可以尝试使用离屏缓冲区来渲染图像:

 MapBean map = new MapBean();
 map.setData(...);

 BufferedImage bi = new BufferedImage(...);
 map.paintComponent(bi.getGraphics());

 writeToFile(bi);

You might also try using an off screen buffer to render your image in:

 MapBean map = new MapBean();
 map.setData(...);

 BufferedImage bi = new BufferedImage(...);
 map.paintComponent(bi.getGraphics());

 writeToFile(bi);
顾冷 2024-08-10 14:28:44

听起来您需要将 JComponent 的底层数据更新与 Swing 的绘制周期同步。您可以对 JComponent 进行子类化并装饰 paintComponent() 方法,您也可以查看 ImageObserver.imageUpdate(),尽管我不确定这是否能说明问题你想要什么。

public class DrawingCycleAwareComponent extends MyOtherJComponent {

    private final Object m_synchLock = new Object();

    protected void paintComponent(Graphics g) {
        synchronized (m_synchLock) {
            super.paintComponent(g);
        }
    }

    protected void updateData(Object data) {
        if (SwingUtilities.isEventDispatchThread()) {
            reallySetMyData(data);  // don't deadlock yourself if running in swing
        }
        else {
            synchronized (m_synchLock) {
                reallySetMyData(data);
            }
        }
    }
}

It sounds like you need to synchronize updating your JComponent's underlying data with Swing's paint cycle. You can subclass your JComponent and decorate the paintComponent() method, you might also look at ImageObserver.imageUpdate(), though I'm not sure if that is going to tell you what you want.

public class DrawingCycleAwareComponent extends MyOtherJComponent {

    private final Object m_synchLock = new Object();

    protected void paintComponent(Graphics g) {
        synchronized (m_synchLock) {
            super.paintComponent(g);
        }
    }

    protected void updateData(Object data) {
        if (SwingUtilities.isEventDispatchThread()) {
            reallySetMyData(data);  // don't deadlock yourself if running in swing
        }
        else {
            synchronized (m_synchLock) {
                reallySetMyData(data);
            }
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文