I want to be able to Enter Text that will appear on the window and then if I were to re-size the window then the text could change with its size. The problem is that I'm not entirely sure how to implement this. Since I will to writing to the Jpanel I'm thinking I would have to use a Jlabel to add the text onto the window, but then resizing the window might not affect the Jlabel? Am I suppose to directly write on the Jpanel somehow, or get the size of the window(length and width) and use that to increase or decrease the size of the text? Any help would be appreciated.
If I understand your question correctly that you are trying to re-size some label type text you could try something along these lines:
public class ResizeTextTest extends JFrame{
public ResizeTextTest() {
add(new MyPanel());
}
public static void main(String[] args) {
ResizeTextTest t = new ResizeTextTest();
t.setSize(400,300);
t.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
t.setVisible(true);
}
class MyPanel extends JPanel {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//Using a multiplier like this on the width and height of the
//Panel will give you a text size that correlates with the size
//of the window.
Font f = new Font("Arial", Font.PLAIN,
(int) (.0005 * this.getWidth() * this.getHeight()));
g.setFont(f);
g.drawString("Hello World", 50, 100);
}
}
The paintComponent method is automatically called when the window is resized. You can also call it explicitly using the component's repaint() method.
Use a text area, not a label. Make sure the 'line wrap' property is selected/true.
Related
I'm beginner in Java and I'm trying to make a simple text editor where the font and text size can be changed. It works although it has an issue that it seems that the text area size is fixed to the font and text size when something is changed.
I want the text area size all time be the same. I was debugging and I realize that rows and columns of text area never change.
Image before change font:
Image after change font:
Full code:
public class Run {
public static void main(String args[]) {
MainFrame main_frame = new MainFrame();
}
}
public class MainFrame extends JFrame{
private TextAreaPanel text_area_panel = new TextAreaPanel(60, 20);
private ComboBoxesPanel combo_boxes_panel = new ComboBoxesPanel(this.text_area_panel);
public MainFrame() {
this.initUI();
}
private void initUI() {
setLayout(new BorderLayout());
add(combo_boxes_panel, BorderLayout.NORTH);
add(text_area_panel, BorderLayout.CENTER);
setSize(getToolkit().getScreenSize().width / 2, getToolkit().getScreenSize().height / 2);
setLocation(getToolkit().getScreenSize().width / 4, getToolkit().getScreenSize().height / 4);
setTitle("Simple Text Editor");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
}
}
public class TextAreaPanel extends JPanel{
private JTextArea text_area = new JTextArea();
private JScrollPane scroll_text_area = new JScrollPane(text_area);
public TextAreaPanel(int width, int height) {
this.addComponets();
setTextAreaSize(width, height);
}
private void addComponets() {
add(scroll_text_area);
}
public void setTextAreaSize(int width, int height) {
text_area.setRows(height);
text_area.setColumns(width);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//setTextAreaSize(getWidth() / 15, getHeight() / 20);
}
public JTextArea getArea() {
return this.text_area;
}
}
public class ComboBoxesPanel extends JPanel{
private String[] system_fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
private Object[] sizes = {8,10,12,14,16,20,24,36, 48};
private JComboBox font_box = new JComboBox(system_fonts);
private JComboBox size_box = new JComboBox(sizes);
private TextAreaPanel text_area_panel;
public ComboBoxesPanel(TextAreaPanel text_area_panel) {
this.text_area_panel = text_area_panel;
font_box.addActionListener(font_listener);
size_box.addActionListener(size_listener);
add(font_box);
add(size_box);
}
private ActionListener font_listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
(text_area_panel.getArea()).setFont(new Font((String)font_box.getSelectedItem(),
Font.PLAIN, (int)size_box.getSelectedItem()));
}
};
private ActionListener size_listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
(text_area_panel.getArea()).setFont(new Font((String)font_box.getSelectedItem(),
Font.PLAIN, (int)size_box.getSelectedItem()));
}
};
}
Anyone knows how to solve this issue? Any idea how to solve this?
Also all the code in my GitLab repository if anyone wants to help.
https://gitlab.com/RichardCG/simpletexteditor
Thanks. :)
First of all I will rant a little about your variable names.
When you create a JTextArea you specify the "rows/columns" of the text area:
why do you use "width/height" as the variable names in your class? In Swing "width/height" are used to represent pixel values.
why did you change the order of the variables? You specify the "row, column" as the parameters of the text area. Why would you change your parameter order to "width, height". The "width" does NOT correlate to "rows".
It is confusing when the API is not consistent.
it seems that the text area size is fixed to the font and text size
Correct, all Swing components are responsible for determining their own preferred size. The size is based on the properties of the component. So when you change the font or font size the component will recalculate its preferred size.
This is a good thing as it allows:
the layout mangers to work properly
the scroll pane to work properly as the scrollbars will appear when needed.
I want the text area size all time be the same
You can control the size of the scroll pane, which in turn will keep the text area size the size while showing/hiding scrollbars as required.
In the constructor of you class you can add:
int scrollBarSize = UIManager.getInt("ScrollBar.width");
Dimension d = text_area.getPreferredSize();
d.width += scrollBarSize;
d.height += scrollBarSize;
scroll_text_area.setPreferredSize(d);
This works because the FlowLayout respects the preferred size of any component added to the panel.
However, this is NOT a good solution. Instead you should design your editor to be more user friendly.
For any editor I've used the editor component takes up all the available space in the frame. So you may have a tool bar (at the top), or status bar (at the bottom) and the editor takes up the remaining space. This allows the editor size to change as the user resizes the frame.
So typically you would just set the row/columns of the JTextArea when you create the text area and add the text area to a JScrollPane. Then the scroll pane is added to the CENTER of the BorderLayout on the. frame and you then pack() the frame BEFORE making the frame visible.
There is no need for the TextAreaPanel class.
I have added webcam to my software using com.github.sarxos.webcam. It has a JPanel named WebcamPanel and has predefined webcam sizes while I need my custom size of pictures. I managed to crop the images taken from webcam at 640 x 480. I want to put a red rectangle over the WebcamPanel to show that this part of the image will be saved.
public class CardPanel {
Dimension panelDim = new Dimension(640, 480);
public Cardpanel(){
//....Button Defined earlier
btnTakePhoto.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
webcameFrame();
}
});
}
private void webcamFrame(){
imageFrame = new JFrame("Photo Capture");
// Did some calculations to put window at center
imageFrame.setBounds(screenSize.width / 2 - frameWidth / 2, screenSize.height / 2 - frameHeight / 2, frameWidth,
frameHeight);
imageFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
imageFrame.setContentPane(contentPane);
JPanel webcamWindow = new JPanel();
RedHighlighter redHighlighter = new RedHighlighter();
Webcam webcam = Webcam.getDefault();
webcam.setViewSize(WebcamResolution.VGA.getSize());
webcamPanel = new WebcamPanel(webcam);
webcamPanel.setFillArea(true);
webcamPanel.setMirrored(false);
webcamPanel.setPreferredSize(panelDim);
webcamWindow.add(webcamPanel);
webcamWindow.add(redHighlighter);
hBox.add(webcamWindow);
}
// Sub Class just for drawing the rectangle
public class RedHighlighter extends JPanel{
public RedHighlighter() {
// If you delete the following line, nothing will appear
setPreferredSize(new Dimension(400, 400));
}
#Override
public void paint(Graphics g) {
g.setColor(Color.RED);
g.drawRect(100, 100, 200, 200);
}
}
}
I used JLayeredPanes but no matter what you do it will cover whole size and will show only one item at a time.
Overriding paint method helped me draw the rectangle but it's on side and not on top.
As you can see the rectangle has pushed WebcamPanel towards left. I want webcamPanel to remain in it's position while the rectangle on top of it at center. Please suggest an efficient approach to this problem. Thanks!
The one JPanel is being pushed over due to the layout managers that you are using. If you want one JPanel to overly another, you'll want to consider using a JLayeredPane, with the video images in the lower level, perhaps the JLayeredPane.DEFAULT layer, and the drawing JPanel above it.
Other options and issues:
You could potentially draw in the same JPanel that the image is being displayed in by displaying the image in a paintComponent method as well as the drawing (in lines of code after the image is displayed.
Look into use of a JLayer as a way of adding a drawing "decoration" over your image.
Always override paintComponent, not paint
Always call the super's painting method within your override.
It worked!
public class MyWebcamPanel extends WebcamPanel {
/**
*
*/
private static final long serialVersionUID = 2808353446021354508L;
public MyWebcamPanel(Webcam webcam) {
super(webcam);
}
#Override
protected void paintComponent(Graphics g) {
int x = 180;
int y = 87;
super.paintComponent(g);
g.setColor(Color.RED);
g.drawRect(x, y, 640-2*x, 480-2*y);
}
}
im trying to insert a gif as a background for my app. I cut all frames and renamed them f1/f2/f3/f4/f5/f6/..... I would use a timer to change the frame so it looks like an animation.
There is a total of 42 frames, so f42.png is the last frame. The code seems to be fine, but there is no result. Any help?
Global variables:
private String backgroundFile;
public JPanel backgroundPanel, areaImage;
private BufferedImage background;
private javax.swing.Timer timerBackground;
Constructor where the Timer is initialized:
public Game()
{
entryWindow();
this.setLayout(null);
timerBackground = new javax.swing.Timer(100,this);
timerBackground.stop();
}
Animation method code:
private void backgroundAnimation()
{
backgroundFile = "f"+backgroundNum+".png";
try{
background=ImageIO.read(new File(backgroundFile));
}
catch(IOException e)
{
}
backgroundPanel = new JPanel()
{
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(background, 0, 0, 1100,800,null);
}
};
backgroundPanel.setBackground(Color.BLACK);
backgroundPanel.setBounds(0, 0, 1100, 800);
if (backgroundNum>42)backgroundNum++;
else backgroundNum=1;
add(backgroundPanel);
backgroundPanel.setVisible(true);
}
Action Listener for timer:
if (ae.getSource() == timerBackground)
{
backgroundAnimation();
}
In order to show JPanel, you need to add it to something like JFrame with an BorderLayout for instance, then you need to show the JFrame. JFrame is a application window, the JPanel can be only added and drawn on Window, it can't be viewed without something on which it can draw (like app Window). Beside that you don't need to create new JPanel each time the animation changes, just make a setter for the current image to show, and after assigning the image call repaint(), the ImagePanel could be like this:
public class ImagePanel extends JPanel {
private volatile BufferedImage image;
public void showImage(BufferedImage image) {
this.image=image;
repaint();
}
public void paintComponent(Graphics g) {
g.drawImage(image, 0,0,getWidth(),getHeight(),null);
}
}
add it to your JFrame at application start, also set the LayoutManager of JFrame to BorderLayout preferably, because without that your panel will have size(0,0) since you didn't set it, and it could be one of reasons why you don't see it (you can't see something which is 0 pixel in size, can you?).
Then in your timer just call the ImagePanel method public void showImage(BufferedImage image) with the image to show. If that's don't solve your problem, then post your entire code. As without that i'm just guessing, but those are common problems, so there's big chance you hit something from this.
I can see a few issues here
1. Assuming your Game class is extending JFrame, You need to add the JPanel to the ContentPane of the JFrame. Use one of the approaches setContentPane(backgroundPanel); or getContentPane().add(backgroundPanel)
You are not using a LayoutManager. So either use a LayoutManager or set the Size of the 'JFrame' and 'JPanel' explicitly using setBounds() method. I would recommend using a LayoutManager.
The JPanel or any Component for that matter does not automatically refresh itself. Once you change the image, you need to call repaint() on your JPanel.
You dont need to create a new JPanel every time you change the image. Just extend the JPanel and override the paintComponent()like you have done. Use the Timer to change the image of that single instance and call repaint() with every change.
The complete example, with hat output you are seeing will help understand the problem better and give you a solution. Please see How to create a Minimal, Complete, and Verifiable example
There are multiple problems here, but first let me answer your question:
You are creating a new JPanel and add it to the Game on every run through. That is wrong, since you add infinite panels to your Game
Also in your if/else you have a wrong condition. You increase the iterator when it is greater 42. You probably mean lesser than 42.
Here is how I would do it:
public class BackgroundPanel extends JPanel {
private int currImage = 0;
private BufferedImage[] backgroundImages;
public BackgroundPanel() {
int numberOfImages = 42;
backgroundImages = new BufferedImage[42];
for(int i = 1; i <= numberOfImages; i++) {
String backgroundFile = "f" + i + ".png";
backgroundImages[i] = ImageIO.read(new File(backgroundFile));
}
}
public void nextImage() {
/*if(currImage <= 42) currImage++;
else currImage = 1;*/
if(currImage++ > 42) currImage = 1;
repaint();
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(backgroundImages[currImage], 0, 0, getWidth(), getHeight(), null);
}
}
You need to add this panel ONCE to your "Game":
//Somewhere in your Game
private BackgroundPanel backgroundPanel;
...
...
public Game() {
entryWindow();
this.setLayout(null);
backgroundPanel = new backgroundPanel();
backgroundPanel.setSize(getWidth(), getHeight());
add(backgroundPanel);
timerBackground = new javax.swing.Timer(100,this);
timerBackground.stop();
}
Your timer:
if (ae.getSource() == timerBackground) {
backgroundPanel.nextImage();
}
It's easier to put the background on JLabel. It requires only 3 lines of code and works fine! :) Hope it helps for anyone that will have the same problem :)
All you have to do is copy this code, change the name (i have all pictures in a folder called "Images") with any kind of Java supported picture/video/.... (just change the suffix .gif to your file format) and at last the size. Good luck! :)
public JLabel backgroundGIF;
backgroundGIF = new JLabel(new ImageIcon(getClass().getResource("Images/background.gif")));
backgroundGIF.setBounds(0,0,1100,800);
add(backgroundGIF);
I've been coding a simulation for a traffic flow network in Java, and the class that is supposed to graphically model the network looks as follows:
public class Map extends JPanel {
BufferedImage truck1;
public Map() throws IOException{
truck1 = ImageIO.read(getClass().getResource("Truck.png"));
}
protected void paintcomponent (Graphics g) {
super.paintComponent(g);
g.drawImage(truck1, 50, 100, 300, 300, this);
}
}
In my main() function, I instance the object as follows at the very beginning of the function:
Frame F1 = new Frame();
F1.setLayout(new FlowLayout());
F1.setSize(500,500);
F1.setVisible(true);
Map map = new Map();
map.setOpaque(true);
F1.add(map);
F1.setVisible(true);
However, when I run the program, the only output is a blank window with a slightly darker grey small square exactly in the middle at the top of the window. I've added Truck.png to the project, and I can't see any reason why it shouldn't display properly. What am I doing wrong?
Components should be added to the frame before the frame is made visible.
You are using a FlowLayout for your frame. A FlowLayout respects the preferred size of all components. Your Map class doesn't have a preferred size so the size defaults to (0, 0) so there is nothing to paint. Override the getPreferredSize() method of the Map class to return the appropriate size for the component.
Ok i have a JPanel such as this one :
public class GUI {
JFrame frame = new JFrame("Net");
JPanel panel = new JPanel();
public GUI()
{
frame.setSize(835,650);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setVisible(true);
frame.add(panel);
panel.setSize(600,600);
panel.setLocation(215,5);
panel.add(new DrawPlanes(300,300,200,Color.BLACK));}
There are some other panels in there tables etc. My main is this one :
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
#Override
public void run(){
//new GUI();
new GUI().buildTable();
}
});
And there i another class this one :
public class DrawPlanes extends JPanel
{
private static int centreX, centreY, radius;
private Color colour;
public DrawPlanes()
{
centreX = 300;
centreY = 300;
radius = 200;
colour = Color.BLACK;
}
public DrawPlanes(int centreX,int centreY, int radius, Color colour)
{
this.centreX = centreX;
this.centreY = centreY;
this.radius = radius;
this.colour = colour;
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
System.out.println("ppp");
Graphics2D g2D = (Graphics2D) g;
g2D.setStroke(new BasicStroke(2F));
g.setColor(Color.BLACK);
g.drawOval(centreX - radius , centreY - radius, radius * 2 , radius * 2);
......
}
}
Ok so i ve setted the background colour of my panel red to see whats going on the whole panel its red but there is a small grey square where i believe the drawings are. I ve tried to change opaque as there might be an incompatibility issue but nothing changed at all.Any suggestions,is there anything that i m missing?
link of what is the result of
panel.add(new DrawPlanes(300,300,200,Color.BLACK))
http://dc626.4shared.com/img/FeYopZC1/s7/142d22f1be0/2013-12-08_142846.png?async&rand=0.9010817544924218
what does the DrawPlanes class draws when i checked it having the main and a panel etc in the DrawPlanes itself http://dc626.4shared.com/img/NPDkiQRJ/s7/142d22f23b0/1451491_586878858047235_191988.jpg?async&rand=0.27479583155781395 .When i apply a layout manager that grey square just moves to the center when i use getPreferredSize overriden or not the whole red panel appears grey.
frame.add(component) function eventually add your component to frame's content pane which has BorderLayout as default layout manager.
A JPanel uses FlowLayout as default layout which respect component's preferred size.
As your 'panel' and 'frame' is satisfying above two as a default, size hint with setSize(Dimension) or setBounds(Dimenstion) to component won't have effect.
You should provide size hint using setPreferredSize(Dimenstion)(to DrawPanel instance of your context) and if specifying minimum/maximum size is needed setMinimumSize(Dimenstion) and setMaximumSize(Dimenstion).
However it is considered as a better practice to override getXXXSize(Dimenstion): xxx represents Preferred/Minimmum/Maximum always which allows to adjust size of component with it's content.
Instead of calling setSize(Dimension) on a window it is preferable to call pack() at the end of addition of child components.
We should call setVisible(true) after finishing addition of all of the child components and following above point, after pack().
Please, start with the tutorial: Laying Out Components Within a Container
Edit:
Let us edit your GUI() constructor code and see what happens:
public GUI()
{
frame.setSize(835,650);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//frame.setVisible(true); // <<--- call it at the end of the code
frame.add(panel);
//panel.setSize(600,600); <<--- removing set size
panel.add(new DrawPlanes(300,300,200,Color.BLACK));
frame.setVisible(true);
}
And the DrawPnales will extend JComponent:
public class DrawPlanes extends JComponent{
public DrawPlanes(int centreX,int centreY, int radius, Color colour)
{
this.centreX = centreX;
this.centreY = centreY;
this.radius = radius;
this.colour = colour;
}
#Override
public Dimension getPreferredSize() {
return new Dimenstion(width, height);
// ^ provide your required size
}
}
If this still doesn't make any sense to you, then please try learning Swing layout managers a little bit further. Otherwise no matter how hard we hit our head on the table, possibly we won't be able to achieve any thing.
You're missing the fact that panels are laid out inside their container using a LayoutManager. The default layout manager of JPanel is a FlowLayout. The FlowLayout uses the preferred width and height of the components it lays out to decide where to place them in the container, and which size they should have. But your DrawPlanes panel doesn't override getPreferredSize(), so its preferred size is the default one.
Every time you use setSize() on a component or frame, you have a 99.9% probability of doing something wrong. Learn layout managers. If you design a custom component like your DrawPlanes component, which is not just a container for other components, but has a custom paintComponent() method, then override getPreferredSize(), getMaximumSize() and getMinimumSize() to tell the layout managers how they should display your component, and to make sure your custom component always has the appropriate size. You never set the size of a JButton, right? That's because the JButton itself decides, based on the text and icon it contains, which size it should have.