有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何获取数据库中的图像,并将其设置为特定行的表的“tooltipText()

我正在创建一个程序,上面有一个JTable,由我的数据库数据填充。每一行上都有相应的图片,所以我想做的是,当我将鼠标光标放在那一行上时,它会弹出一个包含图片的ToolTiptText

 tblListOfInmates = new JTable(){                       
                private static final long serialVersionUID = 8240878564742150750L;
                public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                        Component c = super.prepareRenderer(renderer, row, column);                     
                        if (c instanceof JComponent)  {
                            try{
                                    JComponent jc = (JComponent) c;    

                                    Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");                                                                          
                                    con = DriverManager.getConnection("jdbc:odbc:RIM");
                                    st = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);

                                    String x = tblListOfInmates.getModel().getValueAt(row, 6).toString();
                                    String sql = "select * from records where ID ='"+x+"'";
                                    rs = st.executeQuery(sql);
                                    java.net.URL url = new File(rs.getString("ID")).toURI().toURL();





                                     final String html = "<html><body>" + "<img src='"+ url + "' width=160 height=120> ";

                                    jc.setToolTipText(html + "<br/>"
                                            + getValueAt(row, column).toString()
                                            + ":  row, col (" + row + ", " + column + ")");                                     
                            }catch(Exception e){e.printStackTrace();}
                        }
                        return c;
                    }
            };

我犯了这个错误

 at RecordManagementSystem.MainFrame$18.prepareRenderer(MainFrame.java:860)
at javax.swing.plaf.basic.BasicTableUI.paintCell(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paintCells(Unknown Source)
at javax.swing.plaf.basic.BasicTableUI.paint(Unknown Source)
at javax.swing.plaf.ComponentUI.update(Unknown Source)
at javax.swing.JComponent.paintComponent(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JViewport.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at javax.swing.JLayeredPane.paint(Unknown Source)
at javax.swing.JComponent.paintChildren(Unknown Source)
at javax.swing.JComponent.paintToOffscreen(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)
at javax.swing.RepaintManager$PaintManager.paint(Unknown Source)
at javax.swing.RepaintManager.paint(Unknown Source)
at javax.swing.JComponent.paint(Unknown Source)
at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
at java.awt.Container.paint(Unknown Source)
at java.awt.Window.paint(Unknown Source)
at javax.swing.RepaintManager$3.run(Unknown Source)
at javax.swing.RepaintManager$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)
at javax.swing.RepaintManager.access$1100(Unknown Source)
at javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$200(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

我不知道如何正确地做到这一点,我也不知道我的想法是否正确。请告诉我你是否有比这个更好的主意=)


共 (2) 个答案

  1. # 1 楼答案

    我猜您试图加载到工具提示中的图像是数据库中的blob。问题是不能从数据库对象生成url。您可以将url存储在数据库中,指向文件系统中的url,但我认为这可能是不可能的,因为您不希望数据库和文件系统中都有图像

    也许您应该做的是在加载TableModel时,将所有相应的图像保存到文件系统(临时)。你可以用File.createTempFile来做这件事。您可以从该img获取URL

    还请注意,您将希望在后台线程中执行此操作。见Concurrency with Swing

    然后,您可以从文件系统访问这些图像,这将比尝试一次一个从db访问要高效得多。然后可以使用File.getUri().getUrl()在html字符串中使用文件系统中的url

    您可以使用一种方法来清除这些映像的文件系统。您可能希望在每次加载一组新的表数据和/或程序关闭时调用它

    您可以从db blob加载一个图像,然后像这样将其写入文件

    Blob blob = rs.getBlob("img");
    int blobLength = (int) blob.length();  
    
    byte[] bytes = blob.getBytes(1, blobLength);
    blob.free();
    BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
    ImageIO.write(img, "png", new File("..."));
    

    下面是一个包含上述大部分要点的示例。除了背景线程。有两种方法可以做到这一点,但每次从数据库更新表模型时都需要这样做

    enter image description here

    import java.awt.Component;
    import java.awt.image.BufferedImage;
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.net.URL;
    import java.sql.Blob;
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.ResultSetMetaData;
    import java.util.HashMap;
    import java.util.Map;
    import javax.imageio.ImageIO;
    import javax.swing.JComponent;
    import javax.swing.JFrame;
    import javax.swing.JScrollPane;
    import javax.swing.JTable;
    import javax.swing.SwingUtilities;
    import javax.swing.table.DefaultTableModel;
    import javax.swing.table.TableCellRenderer;
    
    public class TableToolTip {
    
        private Map<String, URL> fileMap;
    
        public TableToolTip() {
            fileMap = new HashMap<>();
            JTable table = createTable();
    
            JFrame frame = new JFrame();
            frame.add(new JScrollPane(table));
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    
        private JTable createTable() {
            JTable table = new JTable(createModel()) {
    
                public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
                    Component c = super.prepareRenderer(renderer, row, column);
                    if (c instanceof JComponent) {
                        JComponent jc = (JComponent) c;
                        URL url = fileMap.get((String) getValueAt(row, column));
                        String html = "<html><body>"
                                + "<img src='"
                                + url
                                + "' width=150 height=150> ";
    
                        jc.setToolTipText(html + "<br/>"
                                + getValueAt(row, column).toString()
                                + ":  row, col (" + row + ", " + column + ")"
                                + "</body></html>");
                    }
                    return c;
                }
            };
            return table;
        }
    
        private DefaultTableModel createModel() {
            DefaultTableModel model = null;
            try {
                Class.forName("com.mysql.jdbc.Driver");
                Connection conn = DriverManager.getConnection(
                        "jdbc:mysql://localhost/mario", "root", "password");
                PreparedStatement ps = conn.prepareStatement("select * from characters");
                ResultSet rs = ps.executeQuery();
                ResultSetMetaData rsMeta = rs.getMetaData();
                String colTitle = rsMeta.getColumnName(1);
    
                model = new DefaultTableModel(new String[]{colTitle}, 0);
    
                while (rs.next()) {
                    String name = rs.getString("NAME");
                    model.addRow(new Object[]{name});
                    File temp = File.createTempFile(name, ".png");
                    Blob blob = rs.getBlob("IMG");
                    int blobLength = (int) blob.length();
                    byte[] bytes = blob.getBytes(1, blobLength);
                    blob.free();
                    BufferedImage img = ImageIO.read(new ByteArrayInputStream(bytes));
                    ImageIO.write(img, "png", temp);
    
                    URL fileURL = temp.toURI().toURL();
                    fileMap.put(name, fileURL);
                }
    
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return model;
        }
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    new TableToolTip();
                }
            });
        }
    }
    
  2. # 2 楼答案

    • TableCellRenderer中的每个键和鼠标事件都会立即触发,然后长时间繁重的JDBC任务会生成RepaitManager异常,不要这样做,也不要打开JDBC连接,会生成一堆键和鼠标事件,尤其是每像素的鼠标事件

    • 将所有图像作为图标/图像图标、事件加载到局部变量。到Icon/ImageIcon的数组,