I'm trying to write a panel with 3 vertical section in MigLayout: top growing, middle fixed and bottom growing.
The top is a JLabel with font-size-based-on-container-size. The middle is also a Jlabel, and the bottom is currently an empty JPanel.
Enlarging window is ok:
When I resize back the window, content doesn't resize back (note that the problem is not the font size, but the container width):
This problem exists only when in overrided method paint (see below) is called setFont on timer JLabel.
public class TabRace extends JPanel {
private JLabel timer;
public TabRace() {
super();
// Set the layout
this.setLayout(new MigLayout("","[grow]","[grow][][grow]"));
// Timer label
timer = new JLabel("00:00:00.000");
timer.setOpaque(true);
timer.setBackground(new Color(0, 0, 0));
timer.setForeground(new Color(255, 255, 255));
this.add(timer,"grow,wrap");
// Table label
JLabel tableCaption = new JLabel("Last Records:");
this.add(tableCaption,"wrap");
JPanel bottom = new JPanel();
this.add(bottom, "grow,wrap");
}
public void paint(Graphics g) {
super.paint(g);
// Thanks to coobird
// #see https://stackoverflow.com/questions/2715118/how-to-change-the-size-of-the-font-of-a-jlabel-to-take-the-maximum-size
Font labelFont = timer.getFont();
final int stringWidth = timer.getFontMetrics(labelFont).stringWidth(timer.getText());
final int componentWidth = timer.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double)componentWidth / (double)stringWidth;
int newFontSize = (int)(labelFont.getSize() * widthRatio);
int componentHeight = timer.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
// Set the label's font size to the newly determined size.
// REMOVING NEXT LINE AND RESIZING IS WORKING
timer.setFont(new Font(labelFont.getName(), Font.PLAIN, fontSizeToUse));
}
}
I've tried also to put JLabel inside JPanel. Any ideas?
I don't know why, but adding minimum width to first JLabel (or other row) resolves the issue:
this.add(timer,"grow,wrap,wmin 10");
Related
So what I'm trying to do is to resize the font of every component in a JFrame knowing that the fonts have different sizes at launch.
For example, I would have a JButton with a font size of 15 and a JLabel with a font size of 20 :
button1.setFont(new Font("Arial", Font.PLAIN, 15));
label1.setFont(new Font("Arial", Font.PLAIN, 20));
The result I want here is that if the window is resized to twice its width, the components should follow at the same rate, so the JButton would be 30 and the JLabel would be 40.
I'm using a ComponentListener on the JFrame but I can't find how to do it.
Here's what I currently have; if only I knew the window's size BEFORE it was resized it would already be working, but I don't think it's possible.
Here is the overridden componentResized method :
#Override
public void componentResized(ComponentEvent arg0) {
Component[] components = ((JFrame)arg0.getComponent()).getComponents();
System.out.println(((Component) arg0.getSource()).getSize().getWidth());//How do I find the window's size before it was resized ?
//Getting standard window size
Dimension dimScreen = Toolkit.getDefaultToolkit().getScreenSize();
Dimension dimBaseWindow = new Dimension(dimScreen.width/2,dimScreen.height/2);
double baseWidth = dimBaseWindow.getWidth();
//Getting current window size
Dimension dimCurrentWindow = ((JFrame)arg0.getComponent()).getSize();
double currentWidth = dimCurrentWindow.getWidth();
System.out.println(currentWidth);
//Rate at which the font will be resized
double resizeRate = currentWidth/baseWidth;
resizeComponentsFonts(components, resizeRate, (int)currentWidth, (int)baseWidth);
}
resizeComponentsFonts method :
public void resizeComponentsFonts(Component[] components, double resizeRate, int newWindowWidth, int baseWindowWidth) {
for(int i=0;i<components.length;i++) {
if(components[i] instanceof JPanel || components[i] instanceof JLayeredPane || components[i] instanceof JRootPane) {
resizeComponentsFonts(((Container)components[i]).getComponents(),resizeRate, newWindowWidth, baseWindowWidth);
}
else {
//System.out.println((double)components[i].getFont().getSize()/newWindowWidth*baseWindowWidth);
components[i].setFont(new Font(components[i].getFont().getFontName(),components[i].getFont().getStyle(),(int) (((double)components[i].getFont().getSize()/newWindowWidth*baseWindowWidth)*resizeRate)));
}
}
}
I have developed a Code which will display a panel & added a scrollpane which will scroll down if panel size is more than the visible region.
My code is
CT3= new CT3TycoDULocalPanel(anexflag1,anexflag2);
cnt =(JPanel)getContentPane ();
cnt.setLayout (null);
pane = new JPanel(new BorderLayout());
pane.add (CT3,BorderLayout.CENTER);
scPane = new JScrollPane(CT3);
scPane.setLayout(null);
scPane.setBackground(Color.GREEN);
scPane.setBounds(20,12,550,600);
scp=scPane.getVerticalScrollBar();
scp.setBounds (528,0,20,600);
scp.addAdjustmentListener (this);
scPane.setViewportView(CT3);
scPane.add(scp);
scPane.addMouseWheelListener(this);
scPane.add(CT3);
CT3.setBounds(10, 10, 510,CT3.y);
scPane.validate();
scPane.repaint();
cnt.add(scPane);
And in AdjustmentListener i have written following code:
public void adjustmentValueChanged(AdjustmentEvent e)
{
int y = (int)(e.getValue()*3.2);
CT3.reshape (10,(int)-Math.ceil(y)+25,510,CT3.y);
CT3.validate();
CT3.repaint();
}
And I have Dynmically calculated the size of CT3 as per following code
public void resize()
{
if(itemVect.size()<=17)
{
pnlAnex.setBounds(0, 50, 510, 700);
}
else
{
int size=itemVect.size();
y=(size*30)+90;
pnlAnex.setBounds(0, 50, 510, y+50);
pnlAnex.validate();
pnlAnex.repaint();
}
}
But I am not getting the desired output.
The CT3 panel is showing correct height but the scrollpane is getting more height as per shown below image.
The green part is of ScrollPane & the White part is of my desired output.
As you can see my scrollbar is still scrollable even if my desired output(White Panel) is dispalyed.
Please help me out to limit the scroll bar till my white panel is visible only(CT3 Panel)
Thanks in advance......
I'm working on some nesting of GUI objects. I've gotten most of it working so far but the latest part I haven't been able to figure out. It may be a simple problem and I don't think the depth of nesting is causing the issue but I'll list what I have in case it is.
So far I have a JFrame containing a JPanel, which has a JTabbedPane, this JTabbedPane has 2 JPanels in it. I am currently working on one of these JPanels - it contains a JSplitPane containing a JScrollPane and another JSplitPane. The second JSplitPane has two JScrollPanes. One of the JScrollPanes has a JPanel.
This is all working correctly up until the last JPanel, I've added a background just as a means of testing it to see if it's working right. My problem is that the background shows up basically as a border within the JScrollPane, the inside of the pane is gray, like there is no background.
Here is some of my code - I can provide more if anybody thinks it would be useful.
This is the JPanel that is within the JTabbedPane.
public class MapEditor extends JPanel{
int height, width;
final int DIVIDER_SIZE = 7;
final int HORIZONTAL_DIVIDER_PLACE = 300;
final int VERTICAL_DIVIDER_PLACE = 200;
//side bar divider separates main page and left (vertical divider)
//side bar division separates top and bottom of sidebar (horizontal divider)
JSplitPane sideBarDivider;
JSplitPane sideBar;
//scroll pane to hold tiles panel, map panel
JScrollPane toolContainer;
JScrollPane tileContainer;
JScrollPane mapContainer;
//panels held inside JScrollPanes above
JPanel toolPanel;
JPanel tilePanel;
JPanel mapPanel;
public MapEditor(int w, int h){
this.width = w;
this.height = h;
setLayout(new BorderLayout());
//we can just pass the final variables in here because it's in the top left
toolPanel = new ToolPanel(HORIZONTAL_DIVIDER_PLACE,
VERTICAL_DIVIDER_PLACE);
sideBar = splitScreen();
add(sideBar);
}
//main split between map and tools/tiles
public JSplitPane splitScreen(){
mapContainer = new JScrollPane();
sideBar = buildSideBar();
//add map container and sidebar
sideBarDivider = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,
sideBar, mapContainer);
sideBarDivider.setSize(width, height);
//set divider size and position
sideBarDivider.setDividerLocation(HORIZONTAL_DIVIDER_PLACE);
sideBarDivider.setDividerSize(DIVIDER_SIZE);
return sideBarDivider;
}
//small split between tools and tiles
public JSplitPane buildSideBar(){
toolContainer = new JScrollPane();
toolContainer.add(toolPanel);
tileContainer = new JScrollPane();
//add tile & tool containers
sideBar = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
toolContainer, tileContainer);
//set divider size and position
sideBar.setDividerSize(DIVIDER_SIZE);
sideBar.setDividerLocation(VERTICAL_DIVIDER_PLACE);
return sideBar;
}
}
This is the panel that is giving me problems.
public class ToolPanel extends JPanel{
int width, height;
public ToolPanel(int w, int h){
this.width = w;
this.height = h;
setLayout(new BorderLayout());
setSize(w, h);
setBackground(Color.BLACK);
}
}
Anybody see anything I'm doing wrong? I'm not too experienced with Java GUI components and would appreciate any help anybody has to offer.
toolContainer = new JScrollPane();
toolContainer.add(toolPanel);
You don't add components to a JScrollPane. The component is added to the "viewport" of the scroll pane.
You can use:
toolContainer = new JScrollPane( toolPanel );
or
toolContainer = new JScrollPane();
toolContainer.setViewportView(toolPanel);
Also, you should not be using:
setSize(w, h);
The layout manager of the component will determine the preferred size of the component based on the comopnents added to the panel.
If you are doing some kind of custom painting then you should override the getPreferredSize() method of the ToolPanel to return the appropriate size.
I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
However, they are overlapping with JButton on top.
Is there a way to have my Point always on top in the JPanel application window?
Here's a code snippet:
public leapPanel()
{
setLayout(null); //18-12-13
setBackground(Color.WHITE);
setVisible(true); //18-12-13
button = new JButton();
button.setBounds(100, 150, 100, 100);
button.setBackground(Color.BLACK);
add(button);
points[nPoints] = new Point(PWIDTH/2, PHEIGHT/2);
nPoints++;
listener = new leapListener(this);
controller = new Controller();
controller.addListener(listener);
}
public Dimension getPreferredSize()
{
return new Dimension(PWIDTH, PHEIGHT);
}
public void paintComponent(Graphics shape)
{
super.paintComponent(shape);
Graphics2D shaped = (Graphics2D)shape;
shaped.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for(int i=0; i<nPoints; i++)
{
shaped.setColor(Color.ORANGE);
shaped.fillOval(points[i].x, points[i].y, 12, 12);
}
}
private Point2D.Float calcScreenNorm(Hand hand, Screen screen)
/* The dot position is calculated using the screen position that the
user's hand is pointing at, which is then normalized to an (x,y)
value between -1 and 1, where (0,0) is the center of the screen.
*/
{
Vector palm = hand.palmPosition();
Vector direction = hand.direction();
Vector intersect = screen.intersect(palm, direction, true);
// intersection is in screen coordinates
// test for NaN (not-a-number) result of intersection
if (Float.isNaN(intersect.getX()) || Float.isNaN(intersect.getY()))
return null;
float xNorm = (Math.min(1, Math.max(0, intersect.getX())) - 0.5f)*2; // constrain to -1 -- 1
float yNorm = (Math.min(1, Math.max(0, (1-intersect.getY()))) - 0.5f)*2;
return new Point2D.Float(xNorm, yNorm);
} // end of calcScreenNorm()
I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
Not when components are on the same panel. The order of painting is to paint the component first (ie. your paintComponent() method is invoked). Then the child components of the panel are painted (ie. the button is painted). This is how Swing implements the parent/child relationship between components.
Try using two panels. The main panel will have a BorderLayout. Then you can use:
main.add(button, BorderLayout.NORTH);
main.add(leapPanel, BorderLayout.CENTER);
The other option is to try to use the OverlayLayout. It allows you to stack two components on top of one another, although I must admit I have problems controlling the exact location of components when using this layout. The basic code would be:
JPanel main = new JPanel();
main.setLayout( new OverlayLayout(main) );
JPanel buttonPanel = new JPanel();
buttonPanel.add( button );
main.add(buttonPanel);
main.add(leapPanel);
Using the OverlayLayout you may experience weird painting problems with the button. If so then check out the suggestion to override isOptimizedDrawingEnabled() from Overlap Layout.
JPanel main = new JPanel();
main.setLayout(new OverlayLayout(main));
//main.setBackground(Color.WHITE);
setSize(800, 600); //18-12-13
Container con = getContentPane();
con.setBackground(Color.WHITE);
BPanel = new buttonPanel();
panel = new leapPanel();
main.add(BPanel);
main.add(panel);
con.add(main);
This only allows me to show only BPanel on the application window.
What i need is to have both the point(panel) and button(BPanel) to be displayed on the application window with the point always on top.
Correct me if i am missing something here. Thanks!
I am trying to increase/decrease the font size of JButton text automatically (if JButton increases/stretches its text will also increase, if JButton decreases its text will also decrease). The default font of the JButtons will be Sans-Serif size 20 and it can never decrease below 20 (it can be 21, 30, 40 or anything above or equal to 20 but never anything below 20). I have a JPanel, called MenuJPanel, it uses the GridLayout to add 5 JButtons which will increase/decrease in size as the JPanel increases/deceases. I chose the GridLayout as it seems to be the best layout for this purpose, am I wrong? I also added a componentResized to the MenuJPanel. Below you can see my code which partially works.
public class MenuJPanel extends JPanel {
private JButton resizeBtn1;
private JButton resizeBtn2;
private JButton resizeBtn3;
private JButton resizeBtn4;
private JButton resizeBtn5;
public MenuJPanel() {
initComponents();
this.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
Font btnFont = resizeBtn1.getFont();
String btnText = resizeBtn1.getText();
int stringWidth = resizeBtn1.getFontMetrics(btnFont).stringWidth(btnText);
int componentWidth = resizeBtn1.getWidth();
// Find out how much the font can grow in width.
double widthRatio = (double) componentWidth / (double) stringWidth;
int newFontSize = (int) (btnFont.getSize() * widthRatio);
int componentHeight = resizeBtn1.getHeight();
// Pick a new font size so it will not be larger than the height of label.
int fontSizeToUse = Math.min(newFontSize, componentHeight);
// Set the label's font size to the newly determined size.
resizeBtn1.setFont(new Font(btnFont.getName(), Font.BOLD, fontSizeToUse));
}
});
}
private void initComponents() {
resizeBtn1 = new javax.swing.JButton();
resizeBtn2 = new javax.swing.JButton();
resizeBtn3 = new javax.swing.JButton();
resizeBtn4 = new javax.swing.JButton();
resizeBtn5 = new javax.swing.JButton();
setLayout(new java.awt.GridLayout(5, 0));
resizeBtn1.setText("Text to resize 1");
add(resizeBtn1);
resizeBtn2.setText("Text to resize 2");
add(resizeBtn2);
resizeBtn3.setText("Text to resize 3");
add(resizeBtn3);
resizeBtn4.setText("Text to resize 4");
add(resizeBtn4);
resizeBtn5.setText("Text to resize 5");
add(resizeBtn5);
}
}
Ordinarily, the ButtonUI delegate for a JButton calculates the button's preferred size based on the designer's chosen font and the platform's aesthetics. As your approach defeats this, it's up to you to decide how the text will scale with the button and accommodate button decorations.
Absent creating your own ButtonUI, you can simply scale the text. In this example, TextLayout is used to render the text in a BufferedImage at an arbitrarily large size that can be scaled down as needed. In this example, a single digit's glyph is rendered in a BufferedImage and scaled to fit the button's current size. If you need to deal with the relative positioning of an Icon, see SwingUtilities.layoutCompoundLabel(), examined here.