Проблемы с градиентом в Java
В моей программе я хотел иметь полупрозрачный белый до прозрачного градиента на моем JFrame, чтобы наложить желтый фон. Это прекрасно работает, и оно должно быть от белого до прозрачного, потому что мои настройки для программы работают для пользователя. Тем не менее, когда я беру программу в колледж (JRE7 на мой JRE6), градиент становится белым до черноватого, тогда прозрачным... Это не так плохо, пока вы не начнете увеличивать непрозрачность белого цвета... есть ли в любом случае я может это исправить?
вот соответствующий код из верхней части моего кода JFrame.
public class DictionaryGUI extends JFrame
{
protected JPanel pGradientPane;
//Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180
protected int iDegreeBlack = 0
DictionaryGUI(int iWidth, int iHeight)
{
/*General definitions*/
super(String.format("French Verb Conjugator - Version %s", MainLauncher.version));
setSize(iWidth, iHeight);
new Menu(this);
this.iWidth = iWidth;
this.iHeight = iHeight;
getContentPane().setBackground(pInterfaceColour);
pGradientPane = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
pGradientPane.setPreferredSize(new Dimension(iWidth - 16, iHeight - 62));
/*components added to pGradientPane here!*/
add(pGradientPane);
}
И основной класс также:
public class MainLauncher
{
static int iHeight = 400;
static int iWidth = 730;
static String version = "0A3B6";
public static void main(String[] args)
{
try
{
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {e.printStackTrace();}
DictionaryGUI window = new DictionaryGUI(iWidth, iHeight);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setVisible(true);
}
Разве это просто разница между JRE6 и JRE7? должен ли я сделать нижний цвет до белого? (было черное, что люди хотят затемнить цвет внизу.)
Я могу опубликовать некоторые скриншоты завтра, если кому-то это понадобится....
![What the gradient should look like]()
![What the gradient actually looks like for some]()
Спасибо
Джейми
EDIT:
Я изменил второй (прозрачный) цвет в градиенте на белый, и он исправил проблему. Однако меня все еще беспокоит, почему прозрачный черный цвет проходит сквозь середину? это должно быть чем-то связано с JRE7, потому что там, где это происходит... возможно, они что-то изменили с тем, как работает прозрачность в градиентах. Кто-нибудь знает, как устранить эту проблему, сохраняя цвет черным?
Ответы
Ответ 1
Проблема с кодом - это строка:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
должно быть следующим:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 245, 62, iDegreeWhite));
Оглядываясь на ваш вопрос, я вижу, что вы в основном нашли решение, но это немного другое. Вот почему:
При смешивании цветов в градиенте, вы смешиваете все аспекты цвета: RBGA
Вы видите, пока не достигнете полного второго цвета, вы смешаете черный цвет с градиентом цвета, и этот микс не будет полностью прозрачным. Таким образом, на 20% вниз по странице вы получите этот цвет: 204,204,204,144 (это 80% белого, 20% черного и 56% непрозрачного).
Самое простое решение - полностью избегать полупрозрачности, если вы не используете его - просто смешайте светло-желтый сверху с темно-желтым внизу. Это также требует меньше ресурсов.
Но поскольку вы используете прозрачность, решение, которое я предоставил, также использует прозрачность. Вы будете смешивать от белого до желтого, используя прозрачную прозрачность.
Если вы смешиваете белый с белым (прозрачный), у вас будет такая же проблема, как и раньше, только с белым (что будет менее заметно, так как это один из цветов, который вы используете): градиент будет иметь белый цвет "полоса", пока второй цвет не достигнет полной прозрачности.
Насколько он отличается от разных JVM, я бы предположил, что Oracle, возможно, изменил способ смешивания альфа. Кажется, что лучшая альфа-поддержка - это то, над чем они работали некоторое время, и это логичный шаг в этом направлении. У меня нет никаких доказательств этого утверждения, но он основан только на других изменениях, которые я видел с альфой (например, прозрачным окном).
ИЗМЕНИТЬ
Этот SSCCE демонстрирует как проблему, так и решение:
import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class TransparencyDemo extends Box{
protected JPanel pGradientPane;
//Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180;
protected int iDegreeBlack = 0;
public TransparencyDemo() {
super(BoxLayout.X_AXIS);
setOpaque(true);
//Incorrect Solution
pGradientPane = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0, iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
add(pGradientPane);
//Correct Solution
JPanel pGradientPane2 = new JPanel(new GridBagLayout())
{
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics)
{
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 245, 62, iDegreeWhite));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane2.setOpaque(false);
add(pGradientPane2);
setBackground(pInterfaceColour);
}
public static void main(String[] args){
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TransparencyDemo());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
Ответ 2
Вот моя версия вашего кода как sscce:
import java.awt.*;
import javax.swing.*;
import javax.swing.UIManager.LookAndFeelInfo;
public class MainLauncher {
static int iHeight = 400;
static int iWidth = 730;
static String version = "0A3B6";
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
DictionaryGUI window = new DictionaryGUI(iWidth, iHeight);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setVisible(true);
}
}
class DictionaryGUI extends JFrame {
protected JPanel pGradientPane;
// Interface gradient specification
private Color pInterfaceColour = new Color(255, 245, 62);
protected int iDegreeWhite = 180;
protected int iDegreeBlack = 0;
DictionaryGUI(int iWidth, int iHeight) {
/* General definitions */
super(String.format("French Verb Conjugator - Version %s",
MainLauncher.version));
setSize(iWidth, iHeight);
getContentPane().setBackground(pInterfaceColour);
pGradientPane = new JPanel() {
private static final long serialVersionUID = 1L;
protected void paintComponent(Graphics pGraphics) {
Graphics2D pGraphicsGradientRender = (Graphics2D) pGraphics;
pGraphicsGradientRender.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255,
255, 255, iDegreeWhite), 0, getHeight(), new Color(0, 0, 0,
iDegreeBlack));
pGraphicsGradientRender.setPaint(pGradient);
pGraphicsGradientRender.fillRect(0, 0, getWidth(), getHeight());
super.paintComponent(pGraphics);
}
};
pGradientPane.setOpaque(false);
pGradientPane.setPreferredSize(new Dimension(iWidth - 16, iHeight - 62));
/* components added to pGradientPane here! */
add(pGradientPane);
}
}
Но опять же это не демонстрирует вашу проблему. Я предполагаю, что ваша проблема заключается в использовании прозрачных фонов с графическим интерфейсом Swing, где артефакты живописи полностью не исправлены. Если да, прочитайте, что Роб Камик должен сказать об этом в своем блоге: Фон с прозрачностью
Ответ 3
Я предполагаю, что это касается "графического конвейера", который используется на разных компьютерах.
В Java есть несколько разных конвейеров, вот некоторая информация о них.
На моем компьютере я могу использовать конвейер X11 или конвейер OpenGL. С трубой X11 происходит темнота; на OpenGL это не так.
В Windows вы можете выбрать один из трех разных конвейеров, и даже тогда (смотря на ссылку выше) могут быть различия.
Я не могу сразу представить, какая у вас конфигурация вашей школы и почему она отличается, но вы можете попытаться расследовать.
Возможно, вы захотите записать эту разницу в качестве ошибки.
Ответ 4
У меня есть fatamorgana, я уверен, что GradientPaint темнее и темнее и темнее, phaaa crazy eye illusion, brrrr
//http://stackoverflow.com/questions/13748810/gradient-problems-in-java/13806210#comment18995490_13806210
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.RepaintManager;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
public class MainLauncher {
private JFrame window = new JFrame();
public MainLauncher() {
GradientPane pane = new GradientPane();
pane.setLayout(new GridLayout(6, 4, 15, 15));
for (int i = 1; i <= 24; i++) {
pane.add(createButton(i));
}
pane.setOpaque(false);
window.add(pane);
RepaintManager.setCurrentManager(new RepaintManager() {
@Override
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
Container con = c.getParent();
while (con instanceof JComponent) {
if (!con.isVisible()) {
return;
}
if (con instanceof GradientPane) {
c = (JComponent) con;
x = 0;
y = 0;
w = con.getWidth();
h = con.getHeight();
}
con = con.getParent();
}
super.addDirtyRegion(c, x, y, w, h);
}
});
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setLocationByPlatform(true);
window.setSize(400, 300);
//window.pack();
window.setVisible(true);
}
private JButton createButton(final int text) {
JButton button = new JButton(Integer.toString(text));
return button;
}
class GradientPane extends JPanel {
private static final long serialVersionUID = 1L;
private final int h = 150;
private BufferedImage img = null;
private BufferedImage shadow = new BufferedImage(1, h, BufferedImage.TYPE_INT_ARGB);
public GradientPane() {
paintBackGround(new Color(150, 250, 150));
}
public void paintBackGround(Color g) {
Graphics2D g2 = shadow.createGraphics();
g2.setPaint(g);
g2.fillRect(0, 0, 1, h);
g2.setComposite(AlphaComposite.DstIn);
g2.setPaint(new GradientPaint(0, 0, new Color(0, 0, 0, 0f), 0, h, new Color(0.1f, 0.8f, 0.8f, 0.5f)));
g2.fillRect(0, 0, 1, h);
g2.dispose();
}
@Override
public void paintComponent(Graphics g) {
if (img == null || img.getWidth() != getWidth() || img.getHeight() != getHeight()) {
img = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB);
}
Graphics2D g2 = img.createGraphics();
super.paintComponent(g2);
Rectangle bounds = this.getVisibleRect();
g2.scale(bounds.getWidth(), -1);
g2.drawImage(shadow, bounds.x, -bounds.y - h, null);
g2.scale(1, -1);
g2.drawImage(shadow, bounds.x, bounds.y + bounds.height - h, null);
g2.dispose();
g.drawImage(img, 0, 0, null);
}
}
public static void main(String[] args) {
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
MainLauncher ml = new MainLauncher();
}
});
}
}
Ответ 5
Как заметил Ник, проблема в том, что вы используете прозрачный черный, а не прозрачный белый. Таким образом, полупрозрачные цвета представляют собой оттенок между белым и черным.
Попробуйте заменить эту строку в коде:
GradientPaint pGradient = new GradientPaint(0, 0, new Color(255, 255, 255, iDegreeWhite), 0, getHeight(), new Color(255, 255, 255, iDegreeBlack));