I'm writing a simple color chooser in java and I added a few JTextFields
to get user input. I added the text fields to a JPanel
, but for some reason, they don't appear when I override the paint method. When I run the program without overriding the paint method, though, the text fields show up. I know that they exist though, since the cursor changes when I hover over them, and if I add tool tip text, it shows up too. How do I get the text fields to show up? Here is the code:
public class ColorSlider extends JPanel {
private ColorChooser parent;
private int sliderX = 0;
private JTextField textField = new JTextField();
public ColorSlider(ColorChooser parent, int x, int y, String toolTip) {
this.parent = parent;
parent.add(this);
setBounds(x, y, 96, 16);
setVisible(true);
setOpaque(false);
setFocusable(true);
addMouseListener(this);
addMouseMotionListener(this);
setToolTipText(toolTip);
setLayout(null);
textField.setBounds(80, 0, 16, 16); // Yes, I know this is way too small
textField.setText("Text");
add(textField);
}
@Override
public void paint(Graphics g) {
g.setColor(new Color(0xDDDDE1));
g.fillRect(0, 4, 80, 8);
g.setColor(new Color(0x444448));
g.fillRect(sliderX, 0, 8, 16);
}
Start by taking a look at Performing Custom Painting and Painting in AWT and Swing
Essentially what you've done is broken the paint chain. Painting is made up of a series of chained method calls, each method adding something to the process, background, border, children...etc.
By overriding paint
and failing to call super.paint
, you've prevented the panel from painting it's children.
Now, you could override paintComponent
instead (ensuring that you call super.paintComponent
), you could still end up with issues, as the painting is done behind the child components.
A better (and simpler) solution would be to create two JPanel
s and use there background
color properties to simply change the color as you need.
Don't use null
layouts, pixel perfect layouts are an illusion in modern GUI design, you don't control how the rendering works on different platforms, in particular how fonts are rendered.
Make use of appropriate layout managers
Additional...
Separate the areas of responsibility. The "slider" is responsible for ... sliding. Create a component which does nothing but provides that functionality. Then create another component which uses this slider and a JTextField
to introduce extended functionality...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;
public class ColorSliderTest {
public static void main(String[] args) {
new ColorSliderTest();
}
public ColorSliderTest() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ColorSliderPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class ColorSliderPane extends JPanel {
private final ColorSliderControl colorSliderControl;
private final JTextField field;
public ColorSliderPane() {
field = new JTextField(5);
colorSliderControl = new ColorSliderControl();
setLayout(new BorderLayout());
add(colorSliderControl);
JPanel filler = new JPanel();
filler.add(field);
add(filler, BorderLayout.SOUTH);
}
}
public class ColorSliderControl extends JPanel {
private int sliderX;
public ColorSliderControl() {
setOpaque(false);
setBorder(new EmptyBorder(4, 4, 4, 4));
}
@Override
public Dimension getPreferredSize() {
Insets insets = getInsets();
int width = 80 + (insets.left + insets.right);
int height = 16 + (insets.top + insets.bottom);
return new Dimension(width, height);
}
@Override
public void paint(Graphics g) {
Insets insets = getInsets();
int y = getHeight() / 2;
int x = insets.left;
int width = getWidth() - (insets.left + insets.right);
g.setColor(new Color(0xDDDDE1));
g.fillRect(x, y - 4, width, 8);
g.setColor(new Color(0x444448));
g.fillRect(sliderX + x, y - 8, 8, 16);
}
}
}
Before you say "but I want the field to the right", change
add(filler, BorderLayout.SOUTH);
to
add(filler, BorderLayout.EAST);
I might also mention JSlider
I think you've painted over them.
This is a singularly awful way to treat your UI code; just what is it you are trying to accomplish by having two rectangles with hard-coded colors at hard-coded positions in your panel?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.