2012-09-14 31 views
6

Tôi đã có một ứng dụng máy tính để bàn Java mà làm việc, trong số khác, trên OS X.Swing và bitmap trên màn hình thường

Bây giờ mới MacBook Pro có một màn hình võng mạc và tôi quan tâm: làm thế nào là nó sẽ để làm việc liên quan đến Swing?

Điều gì sẽ xảy ra khi một ứng dụng Java sử dụng cả các thành phần Swing và một số đồ họa bitmap (như biểu tượng tùy chỉnh/ImageIcon)?

Tất cả các ứng dụng Java trên máy tính để bàn được tự động thay đổi kích thước (ví dụ bằng cách tăng gấp bốn lần pixel) hoặc tôi cần phải tạo hai phiên bản biểu tượng của mình (ví dụ: biểu tượng 24x24 và biểu tượng khác có biểu tượng 96x96) xác định rằng ứng dụng đang chạy trên màn hình võng mạc?

+3

Vui lòng chỉnh sửa câu hỏi của bạn để bao gồm [sscce] (http://sscce.org/) minh họa khu vực bạn quan tâm; chủ sở hữu màn hình mới của MacBook Pro có thể đăng ảnh [screenshot] (http://meta.stackexchange.com/questions/99734/how-do-i-create-a-screenshot-to-illustrate-a-post). – trashgod

+0

BTW, biểu tượng 24x24 của bạn chỉ cần trở thành biểu tượng 48x48. Retina tăng gấp đôi độ phân giải trong mỗi kích thước, biến mỗi pixel thành bốn pixel. – MiguelMunoz

Trả lời

0

này như thế nào biểu tượng trông giống như trên võng mạc macbook của tôi '12:

enter image description here

Trên biểu tượng phía bên trái trong IntelliJ IDEA 11 (ứng dụng xoay) và ở phía bên IDEA đúng 12 mà là tuyên bố được được retinized. Như bạn có thể thấy các biểu tượng tự động thay đổi kích cỡ (ở bên trái) trông khá xấu xí.

Theo như tôi biết, họ, just like the guys from Chrome team, đã tạo bằng cách cung cấp các biểu tượng có kích thước gấp đôi.

4

Trên Java 6 của Apple, bạn có thể cung cấp nhiều phiên bản của cùng một hình ảnh. Tùy thuộc vào màn hình (võng mạc hay không), một hoặc hình ảnh khác được chọn và rút ra.

Tuy nhiên, những hình ảnh phải được nạp trong một cách đặc biệt:

Toolkit.getDefaultToolkit().getImage("NSImage://your_image_name_without_extension"); 

Ví dụ, nếu (độ phân giải thường xuyên) hình ảnh của bạn được gọi là: "scissor.png", bạn phải tạo ra một phiên bản độ phân giải cao "[email protected]" (theo sau Apple naming conventions) và đặt cả hai hình ảnh trong thư mục Resources của gói ứng dụng của bạn (có, bạn cần phải bundle your app). Sau đó gọi:

Image img = Toolkit.getDefaultToolkit().getImage("NSImage://scissor"); 

Bạn có thể sử dụng hình ảnh dẫn đến các nút của bạn và nó sẽ được rút ra với độ phân giải đúng một cách kỳ diệu.

Có hai "thủ thuật" khác mà bạn có thể sử dụng:

  1. Sử dụng một AffineTransform của (0.5, 0.5) trên đối tượng Graphics2D của bạn trước khi vẽ một hình ảnh. Xem thêm this java-dev message
  2. Tạo một phiên bản dpi cao hình ảnh của bạn lập trình sử dụng this hack

Các "lừa" đầu tiên (0,5 gỉ) bây giờ cũng hoạt động trên của Oracle Java 7/8. I.e. nếu bạn vẽ một hình ảnh với 0,5 tỷ lệ trực tiếp đến đối tượng Đồ họa của thành phần, nó sẽ được hiển thị ở độ phân giải cao trên màn hình Retina (và cũng bằng một nửa kích thước ban đầu).

+0

Có thể ai đó không phải là người trả lời, hãy bỏ phiếu này hoặc chấp nhận nó nếu nó thực sự hoạt động, không thể đóng các bản sao đối với câu hỏi này cho đến khi điều này được thực hiện. –

7

Sử dụng thư viện IconLoader. Nó hỗ trợ hình ảnh HiDPI http://bulenkov.com/iconloader/ Nó cũng cung cấp cách làm việc với hình ảnh HiDPI (bản vẽ, vv)

1

Tôi có thể xác nhận rằng việc chia tỷ lệ hình ảnh của bạn hoạt động trên Oracle Java 1.8. Tôi không thể nhận được NSImage hack để làm việc trên java 1.7 hoặc 1.8.Tôi nghĩ rằng đây chỉ hoạt động với Java 6 từ Mac ...

Trừ khi ai đó có một giải pháp tốt hơn, những gì tôi làm là như sau:

Tạo hai bộ biểu tượng. Nếu bạn có biểu tượng chiều rộng 48pixel, hãy tạo một số 48px @normal DPI và một số khác tại 96px với 2x DPI. Đổi tên hình ảnh 2xDPI thành @2x.png để phù hợp với tiêu chuẩn đặt tên của apple.

Phân lớp ImageIcon và gọi số RetinaIcon hoặc bất kỳ thứ gì. Bạn có thể kiểm tra cho một màn hình Retina như sau:

public static boolean isRetina() { 

boolean isRetina = false; 
GraphicsDevice graphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice(); 

try { 
       Field field = graphicsDevice.getClass().getDeclaredField("scale"); 
     if (field != null) { 
      field.setAccessible(true); 
      Object scale = field.get(graphicsDevice); 
      if(scale instanceof Integer && ((Integer) scale).intValue() == 2) { 
       isRetina = true; 
      } 
     } 
    } 
    catch (Exception e) { 
     e.printStackTrace(); 
    } 
    return isRetina; 
} 

Hãy chắc chắn để @Override chiều rộng và chiều cao của lớp mới ImageIcon như sau:

@Override 
public int getIconWidth() 
{ 
    if(isRetina()) 
    { 
     return super.getIconWidth()/2; 
    } 
    return super.getIconWidth(); 
} 

@Override 
public int getIconHeight() 
{ 
    if(isRetina()) 
    { 
     return super.getIconHeight()/2; 
    } 
    return super.getIconHeight(); 
} 

Một khi bạn có một bài kiểm tra cho màn hình võng mạc và tùy chỉnh phương pháp chiều rộng/chiều cao của bạn ghi đè bạn có thể tùy chỉnh các phương pháp painIcon như sau:

@Override 
public synchronized void paintIcon(Component c, Graphics g, int x, int y) 
{ 
    ImageObserver observer = getImageObserver(); 

    if (observer == null) 
    { 
     observer = c; 
    } 

    Image image = getImage(); 
    int width = image.getWidth(observer); 
    int height = image.getHeight(observer); 
    final Graphics2D g2d = (Graphics2D)g.create(x, y, width, height); 

    if(isRetina()) 
    { 
     g2d.scale(0.5, 0.5); 
    } 
    else 
    { 

    } 
    g2d.drawImage(image, 0, 0, observer); 
    g2d.scale(1, 1); 
    g2d.dispose(); 
} 

tôi không biết làm thế nào điều này sẽ làm việc với nhiều màn hình mặc dù là có ai khác có thể giúp đỡ với điều đó?

Hy vọng mã này sẽ giúp bạn!

Jason Barraclough.

Dưới đây là một ví dụ của việc sử dụng rộng như đã đề cập ở trên: RetinaIcon is on the left. ImageIcon is on the right

+0

Cảm ơn giải pháp này. Nó hoạt động độc đáo. – user3396583

0

Dưới đây là một giải pháp, mà làm việc cũng có khi các biểu tượng được sử dụng trong menu táo. Có biểu tượng được tự động chuyển sang màu xám. Vì vậy, tôi đã thực hiện một lớp DenseIcon sơn dày đặc:

public synchronized void paintIcon(Component c, Graphics g, int x, int y) { 
    if(getImageObserver() == null) { 
     g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), c); 
    } else { 
     g.drawImage(getImage0(), x, y, getIconWidth(), getIconHeight(), getImageObserver()); 
    } 
} 

Làm thế nào để móc vào màu xám Tôi chưa tìm ra. Vì vậy, khi một kludge chúng tôi trở lại một hình ảnh độ phân giải thấp để trình đơn có thể làm thay đổi nó:

public Image getImage() { 
    Image image = getImage0().getScaledInstance(
      getIconWidth(), 
      getIconHeight(), 
      Image.SCALE_SMOOTH); 
    ImageIcon icon = new ImageIcon(image, getDescription()); 
    return icon.getImage(); 
} 

Bạn tìm ra quy tắc ứng đầy đủ các lớp học ở đây trên gist. Bạn cần khởi tạo lớp biểu tượng với một URL đến một hình ảnh có kích thước gấp đôi. Làm việc cho màn hình 2K.

Các vấn đề liên quan