In my GUI program, I have a thread with a while loop that resizes the text = to fit into the various JLabels and JButtons that are on it. But sometimes = when the text is a certain width it will get bigger and smaller. For exampl= e, it will have text in the font size 26, it loops and resizes it to 20. Th= en it loops again and changes it back to 26, creating a "jiggling" effect. Here is what I have: public static Font getMaxFontSize(Component comp, String text) { Font compFont =3D comp.getFont(); String compText =3D text; int stringWidth =3D questionLabel.getFontMetrics(compFont).stringWidth(com= pText); int compWidth =3D comp.getWidth()-75; =09 if (stringWidth =3D=3D 0) { stringWidth++; } double widthRatio =3D (double)compWidth / (double)stringWidth; =09 int newFontSize =3D (int)(compFont.getSize() * widthRatio); int compHeight =3D comp.getHeight(); =09 int fontSizeToUse =3D Math.min(newFontSize, compHeight); =09 if (fontSizeToUse < 1) { return new Font(compFont.getName(), Font.PLAIN, 1); } return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); } Does anyone know why it is doing this, and how I could fix it? Thanks!
![]() |
0 |
![]() |
On 12/6/2016 17:21, The Kreepy Gamer wrote: > In my GUI program, I have a thread with a while loop that resizes the text to fit into the various JLabels and JButtons that are on it. But sometimes when the text is a certain width it will get bigger and smaller. For example, it will have text in the font size 26, it loops and resizes it to 20. Then it loops again and changes it back to 26, creating a "jiggling" effect. > > Here is what I have: > > public static Font getMaxFontSize(Component comp, String text) { > Font compFont = comp.getFont(); > String compText = text; > int stringWidth = questionLabel.getFontMetrics(compFont).stringWidth(compText); > int compWidth = comp.getWidth()-75; > > if (stringWidth == 0) { > stringWidth++; > } > double widthRatio = (double)compWidth / (double)stringWidth; > > int newFontSize = (int)(compFont.getSize() * widthRatio); > int compHeight = comp.getHeight(); > > int fontSizeToUse = Math.min(newFontSize, compHeight); > > if (fontSizeToUse < 1) { > return new Font(compFont.getName(), Font.PLAIN, 1); > } > return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); > } > > Does anyone know why it is doing this, and how I could fix it? > > Thanks! > An SSCCE might get you some answers. -- Knute Johnson
![]() |
0 |
![]() |
If this is what you meant, I have added more code so it can be more easily compiled. public static void main(String[] args) { JFrame window = new JFrame(); JLabel label = new JLabel("Hey! That's pretty good!"); window.add(label); window.setSize(300,300); label.setFont(getMaxFontSize(label,label.getText())); window.setVisible(true); } public static Font getMaxFontSize(Component comp, String text) { Font compFont = comp.getFont(); String compText = text; int stringWidth = questionLabel.getFontMetrics(compFont).stringWidth(compText); int compWidth = comp.getWidth()-75; if (stringWidth == 0) { stringWidth++; } double widthRatio = (double)compWidth / (double)stringWidth; int newFontSize = (int)(compFont.getSize() * widthRatio); int compHeight = comp.getHeight(); int fontSizeToUse = Math.min(newFontSize, compHeight); if (fontSizeToUse < 1) { return new Font(compFont.getName(), Font.PLAIN, 1); } return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); }
![]() |
0 |
![]() |
On 12/8/2016 14:48, The Kreepy Gamer wrote: > If this is what you meant, I have added more code so it can be more easily compiled. > > public static void main(String[] args) { > JFrame window = new JFrame(); > JLabel label = new JLabel("Hey! That's pretty good!"); > window.add(label); > window.setSize(300,300); > label.setFont(getMaxFontSize(label,label.getText())); > window.setVisible(true); > } > > public static Font getMaxFontSize(Component comp, String text) { > Font compFont = comp.getFont(); > String compText = text; > int stringWidth = questionLabel.getFontMetrics(compFont).stringWidth(compText); > int compWidth = comp.getWidth()-75; > > if (stringWidth == 0) { > stringWidth++; > } > double widthRatio = (double)compWidth / (double)stringWidth; > > int newFontSize = (int)(compFont.getSize() * widthRatio); > int compHeight = comp.getHeight(); > > int fontSizeToUse = Math.min(newFontSize, compHeight); > > if (fontSizeToUse < 1) { > return new Font(compFont.getName(), Font.PLAIN, 1); > } > return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); > } > That can't be compiled and that's one reason you aren't getting any answers. See http://mindprod.com/jgloss/sscce.html. Since your code above won't compile as it is, I'm not sure if the fact that you appear to be creating your GUI on a thread other than the Event Dispatch Thread (EDT) is the problem. Swing components must be created and most component methods must be called from the EDT. Not doing so can cause unending problems with your program. So give us an SSCCE and I'm sure that you will get an answer to your problem. -- Knute Johnson
![]() |
0 |
![]() |
On Thu, 08 Dec 2016 12:48:44 -0800, The Kreepy Gamer wrote: > If this is what you meant, I have added more code so it can be more > easily compiled. > What Knute meant was that it helps if you post code written to the conventions described here: http://stackoverflow.com/help/mcve The idea is to provide a minimal amount of code that illustrates the problem you're trying the solve or demonstrate that, when cut from the NNTP post and pasted into a *.java file, will compile and run without the need to add imports, class wrappers, etc. This is a reasonable requirement: requiring your would-behelper to mess around making your code compile before they can see what you're asking for help with is just taking the piss. Traditionally this has been known as providing an SSCCE (Short, Self Contained, Correct Example) but when I looked for it just now the well- known sscce.org domain, which used to explain how to make an SSCCE, now points at https://coderanch.com/ - which apparently doesn't say what an SSCCE is. ========= The only online SSCCE definition I can find at present is on Roedy's site at http://mindprod.com/jgloss/sscce.html I notice that Stackoverflow now seems to be pushing the use of the very similar MCVE http://stackoverflow.com/help/mcve as its replacement. -- martin@ | Martin Gregorie gregorie. | Essex, UK org |
![]() |
0 |
![]() |
On 12/8/2016 5:17 PM, Martin Gregorie wrote: > On Thu, 08 Dec 2016 12:48:44 -0800, The Kreepy Gamer wrote: >> If this is what you meant, I have added more code so it can be more >> easily compiled. > Traditionally this has been known as providing an SSCCE (Short, Self > Contained, Correct Example) but when I looked for it just now the well- > known sscce.org domain, which used to explain how to make an SSCCE, now > points at https://coderanch.com/ - which apparently doesn't say what an > SSCCE is. https://coderanch.com/sscce/ Arne
![]() |
0 |
![]() |
On 06/12/16 23:21, The Kreepy Gamer wrote: > In my GUI program, I have a thread with a while loop that resizes the text to fit into the various JLabels and JButtons that are on it. But sometimes when the text is a certain width it will get bigger and smaller. For example, it will have text in the font size 26, it loops and resizes it to 20. Then it loops again and changes it back to 26, creating a "jiggling" effect. > > Here is what I have: > > public static Font getMaxFontSize(Component comp, String text) { > Font compFont = comp.getFont(); > String compText = text; > int stringWidth = questionLabel.getFontMetrics(compFont).stringWidth(compText); > int compWidth = comp.getWidth()-75; > > if (stringWidth == 0) { > stringWidth++; > } > double widthRatio = (double)compWidth / (double)stringWidth; > > int newFontSize = (int)(compFont.getSize() * widthRatio); > int compHeight = comp.getHeight(); > > int fontSizeToUse = Math.min(newFontSize, compHeight); > > if (fontSizeToUse < 1) { > return new Font(compFont.getName(), Font.PLAIN, 1); > } > return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); > } > > Does anyone know why it is doing this, and how I could fix it? Presumably, somewhere in the code you haven't shown us, you set the font of comp to the new font, and then sometime later do the same again. It's bound to oscillate because you calculate the new font size pretty much entirely based on the current font size. It's up to you to determine which part of your code logic is broken. We have no idea what the intent of the code is supposed to be. To see it in action (some unusable aspects of your method reworked to make it executable): package fonts; import java.awt.Component; import java.awt.Font; import javax.swing.JTextField; public class Fonts { static Font aFont = new Font("default", Font.PLAIN, 20); static int fontSize = aFont.getSize(); static JTextField component = new JTextField(""); public static void main(String[] args) { Font f = aFont; component.setFont(f); for (int i = 0; i < 10; i++) { f = getMaxFontSize(component, "a test string"); component.setFont(f); System.out.println(f); } } public static Font getMaxFontSize(Component comp, String text) { Font compFont = comp.getFont(); String compText = text; int stringWidth = comp.getFontMetrics(compFont).stringWidth(compText); int compWidth = 140; if (stringWidth == 0) { stringWidth++; } double widthRatio = (double) compWidth / (double) stringWidth; int newFontSize = (int) (aFont.getSize() * widthRatio); int compHeight = 30; int fontSizeToUse = Math.min(newFontSize, compHeight); if (fontSizeToUse < 1) { return new Font(aFont.getName(), Font.PLAIN, 1); } return new Font(aFont.getName(), Font.PLAIN, fontSizeToUse); } }
![]() |
0 |
![]() |
On Thu, 8 Dec 2016 22:17:06 -0000 (UTC), Martin Gregorie <martin@address-in-sig.invalid> wrote: [snip] >Traditionally this has been known as providing an SSCCE (Short, Self >Contained, Correct Example) but when I looked for it just now the well- >known sscce.org domain, which used to explain how to make an SSCCE, now >points at https://coderanch.com/ - which apparently doesn't say what an >SSCCE is. I just tried sscce.org, and it worked for me. Sincerely, Gene Wirchenko
![]() |
0 |
![]() |
Thanks for your help! I hope I got it right this time. :) In my GUI program, I have a thread with a while loop that resizes the text = to fit into the various JLabels and JButtons that are on it. But sometimes = when the text is a certain width it will get bigger and smaller. For exampl= e, it will have text in the font size 26, it loops and resizes it to 20. Th= en it loops again and changes it back to 26, creating a "jiggling" effect. import java.awt.Component; import java.awt.Font; import javax.swing.JFrame; import javax.swing.JLabel; public class Fonts {=20 static JLabel label =3D new JLabel("text that \"jiggles\" = ");=20 public Fonts() { JFrame window =3D new JFrame("Test"); window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setSize(300,300); =20 label.setHorizontalAlignment(JLabel.CENTER); =20 window.add(label); window.setVisible(true); } public static void main(String[] args) {=20 new Fonts(); Thread thread =3D new Thread(new Runnable() { public void run() { while (true) { label.setFont(getMaxFontSize(label,label.getText())); } } }); thread.run(); }=20 public static Font getMaxFontSize(Component comp, String text) {=20 Font compFont =3D comp.getFont();=20 String compText =3D text;=20 int stringWidth =3D comp.getFontMetrics(compFont) .stringWidth(compText);=20 int compWidth =3D comp.getWidth()-75;=20 =20 if (stringWidth =3D=3D 0) {=20 stringWidth++;=20 } =20 while (compWidth < 0) { compWidth++; } =20 double widthRatio =3D (double)compWidth / (double)stringWidth;=20 =20 int newFontSize =3D (int)(compFont.getSize() * widthRatio);=20 int compHeight =3D comp.getHeight();=20 =20 int fontSizeToUse =3D Math.min(newFontSize, compHeight);=20 if (fontSizeToUse < 1) {=20 return new Font(compFont.getName(), Font.PLAIN, 1);=20 }=20 return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse);=20 } } Does anyone know why it is doing this, and how I could fix it?
![]() |
0 |
![]() |
On Fri, 09 Dec 2016 09:07:42 -0800, Gene Wirchenko wrote: > On Thu, 8 Dec 2016 22:17:06 -0000 (UTC), Martin Gregorie > <martin@address-in-sig.invalid> wrote: > > [snip] > >>Traditionally this has been known as providing an SSCCE (Short, Self >>Contained, Correct Example) but when I looked for it just now the well- >>known sscce.org domain, which used to explain how to make an SSCCE, now >>points at https://coderanch.com/ - which apparently doesn't say what an >>SSCCE is. > > I just tried sscce.org, and it worked for me. > Now the sscce.org domain is working from here as well. I also see that the domain is now owned by the folks behind javaranch.com and that the domain details were updated on the 7th of this month. So, it looks as though the SSCCE description page was recently moved to javaranch.com and the domain details updated so recently that the details were still propagating through the DNS hierarchy when I tried to access it yesterday. -- martin@ | Martin Gregorie gregorie. | Essex, UK org |
![]() |
0 |
![]() |
On 12/9/2016 2:35 PM, The Kreepy Gamer wrote: > Thanks for your help! I hope I got it right this time. :) > > > In my GUI program, I have a thread with a while loop that resizes the text to fit into the various JLabels and JButtons that are on it. But sometimes when the text is a certain width it will get bigger and smaller. For example, it will have text in the font size 26, it loops and resizes it to 20. Then it loops again and changes it back to 26, creating a "jiggling" effect. A few random observations, scattered throughout: > import java.awt.Component; > import java.awt.Font; > > import javax.swing.JFrame; > import javax.swing.JLabel; > > public class Fonts { > > static JLabel label = new JLabel("text that \"jiggles\" "); You've already been warned that Swing is not thread-safe, and that almost all manipulation of Swing things must happen on the event dispatching thread, or EDT. Here, you construct a Swing component while *not* running on the EDT. I don't know whether this contributes to your trouble, but it would certainly be a good idea to fix the known errors before attacking the mysteries. > public Fonts() { > JFrame window = new JFrame("Test"); > window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > window.setSize(300,300); > > label.setHorizontalAlignment(JLabel.CENTER); > > window.add(label); > window.setVisible(true); > } > > public static void main(String[] args) { > new Fonts(); The constructor builds and manipulates several Swing things, but is not running on the EDT. Hence, everything it does is suspect. > Thread thread = new Thread(new Runnable() { > public void run() { > while (true) { > label.setFont(getMaxFontSize(label,label.getText())); > } > } > }); > thread.run(); You probably meant start() rather than run(), but it's pointless either way. Also, it's wrong either way: It manipulates a Swing thing from a non-EDT thread, whether that thread is the original main thread (as shown here) or a different thread (if you used start() instead). Also, `while(true)' looks like a poor idea: Instead of trying to set and reset and re-reset the component's font over and over and over again as rapidly as a dedicated core can do it, you ought to be setting the font in response to some kind of event. If you're trying to make text fit in a predefined space, set the font when the text and/or the space changes. Just sitting in a tight loop going SET-SET-SET-SET-SET is silly (especially if you intend most SET's to use the same font). > } > > public static Font getMaxFontSize(Component comp, String text) { > Font compFont = comp.getFont(); > String compText = text; > int stringWidth = comp.getFontMetrics(compFont) > .stringWidth(compText); > int compWidth = comp.getWidth()-75; Still more Swing stuff while not running on the EDT. > if (stringWidth == 0) { > stringWidth++; > } > > while (compWidth < 0) { > compWidth++; > } > > double widthRatio = (double)compWidth / (double)stringWidth; > > int newFontSize = (int)(compFont.getSize() * widthRatio); Just a thought: It might be just a little better if you used Math.round() instead of just throwing the fraction away. (Then again, it might not be better.) > int compHeight = comp.getHeight(); Not running on the EDT. (Is there an echo in here?) > int fontSizeToUse = Math.min(newFontSize, compHeight); > if (fontSizeToUse < 1) { > return new Font(compFont.getName(), Font.PLAIN, 1); > } > return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); > } > } > > Does anyone know why it is doing this, and how I could fix it? Fonts don't shrink and stretch in infinitely fine gradations, so it's quite possible to arrive at an oscillation. Let's say you start with font size S and discover that the string is a little wider than you want. Okay, so you change to size S-epsilon -- and now you find that the string is shorter than you'd like. So you run through your calculation again and settle on (S-epsilon)+epsilon, and now the text is too wide, so ... Putting it all together, I'd encourage the following approach: 1) Fix up the EDT business. I don't know that it *is* contributing to your trouble, but it certainly *could* be. (For example, changing a font while not on the EDT will probably interact poorly with Swing's painting of the screen.) Something is amiss, this aspect of your code is wrong, fix what's know to be wrong and then see what problems remain. 2) Restructure your program so it knows *when* a font change is needed and makes the change *once*, instead of making it over and over and over again in a tight loop. When you decide a change is needed, make a "best effort" to fit the text, knowing that the fit will almost never be exact. (Because of granularity, if nothing else: You can't fill a one-and-a-half car-length gap with cars.) -- esosman@comcast-dot-net.invalid "Nobody ever went broke underestimating the intelligence of the American public." -- HLM (paraphrased)
![]() |
0 |
![]() |
When I've needed to do something like this, my outermost GUI container (a JPanel) has been sized to fit the screen (size expressed in pixels). All labels, Text areas, etc are auto-scaled to match by expressing their sizes as percentages of the outermost container and the font scaled to match: during initialisation I construct a font with that size and use it everywhere, the benefit being that I don't need to resize and fonts after the program has been initialised. Modified Font construction is easy: import java.awt.Font; public class MyFont extends Font { private int fontsize; /* in pts */ public EditFont(int fontsize) { super("Monospaced", PLAIN, fontsize); this.fontsize = fontsize; } } ....and add any other methods you need in order to size a JLabel, etc, to contain a given string. -- martin@ | Martin Gregorie gregorie. | Essex, UK org |
![]() |
0 |
![]() |
On 12/9/2016 2:35 PM, The Kreepy Gamer wrote: > public class Fonts { > public Fonts() { > JFrame window = new JFrame("Test"); > window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); > window.setSize(300,300); > > label.setHorizontalAlignment(JLabel.CENTER); > > window.add(label); > window.setVisible(true); > } > > public static void main(String[] args) { > new Fonts(); See Eric Sosman's comments about EDT. And fix it. The behavior of the code is unpredictable. I don't think it impact this problem though. > Font compFont = comp.getFont(); > String compText = text; > int stringWidth = comp.getFontMetrics(compFont) > .stringWidth(compText); > int compWidth = comp.getWidth()-75; > > if (stringWidth == 0) { > stringWidth++; > } > > while (compWidth < 0) { > compWidth++; > } > > double widthRatio = (double)compWidth / (double)stringWidth; > > int newFontSize = (int)(compFont.getSize() * widthRatio); > int compHeight = comp.getHeight(); > > int fontSizeToUse = Math.min(newFontSize, compHeight); > if (fontSizeToUse < 1) { > return new Font(compFont.getName(), Font.PLAIN, 1); > } > return new Font(compFont.getName(), Font.PLAIN, fontSizeToUse); There is any guarantee that this algorithm will be stable. And in fact it keeps jumping (between 17 and 18 on my PC). There are a couple of possible fixes: 1) replace: int newFontSize = (int)(compFont.getSize() * widthRatio); with: int newFontSize = (int)(compFont.getSize() * widthRatio + 0.5); (or use Math.round) It solves the problem on my PC. But I don't think it guarantees stability either. 2) replace: int newFontSize = (int)(compFont.getSize() * widthRatio); with: int newFontSize = (int)(compFont.getSize() * (widthRatio/2 + 0.5)); I think this is a good change as I believe it in general should make it more stable, but I still don't think it guarantees. 3) But maybe with an extra check. replace: int newFontSize = (int)(compFont.getSize() * widthRatio); with: int newFontSize = (int)(compFont.getSize() * (widthRatio/2 + 0.5)); if(newFontSize == oldFontSize) newFontSize = compFont.getSize(); oldFontSize = compFont.getSize(); I don't know if it is guaranteed to be stable, but I am rather confident that it will be in practice. Arne
![]() |
0 |
![]() |
On Fri, 09 Dec 2016 21:22:17 +0000, Martin Gregorie wrote: > When I've needed to do something like this, my outermost GUI container > (a JPanel) has been sized to fit the screen (size expressed in pixels). > All labels, Text areas, etc are auto-scaled to match by expressing their > sizes as percentages of the outermost container and the font scaled to > match: during initialisation I construct a font with that size and use > it everywhere, the benefit being that I don't need to resize and fonts > after the program has been initialised. > > Modified Font construction is easy: > > import java.awt.Font; > > public class MyFont extends Font { > private int fontsize; /* in pts */ > > public EditFont(int fontsize) > { > super("Monospaced", PLAIN, fontsize); > this.fontsize = fontsize; > } > } > > ...and add any other methods you need in order to size a JLabel, etc, to > contain a given string. Faulty editing (my bad): replace EditFont with MyFont. -- martin@ | Martin Gregorie gregorie. | Essex, UK org |
![]() |
0 |
![]() |
Thank you for taking your time to look at my code, I fixed my original prob= lem but I am having trouble with another one. Sometimes, but not every time= when I change the text in a JTextField programmatically or manually, a Nul= lPointerException is thrown without any info on what line it comes from. I = believe this might be fixed by having all my Swing code run on the EDT, but= this is the only way I have ever written my GUIs and before this I had nev= er heard of the EDT. I looked it up but I couldn't figure out how to do thi= s. Could you go more in depth about how to run my code on the EDT?
![]() |
0 |
![]() |
On 12/12/2016 2:18 PM, The Kreepy Gamer wrote: > Thank you for taking your time to look at my code, I fixed my original problem but I am having trouble with another one. Sometimes, but not every time when I change the text in a JTextField programmatically or manually, a NullPointerException is thrown without any info on what line it comes from. I believe this might be fixed by having all my Swing code run on the EDT, but this is the only way I have ever written my GUIs and before this I had never heard of the EDT. I looked it up but I couldn't figure out how to do this. Could you go more in depth about how to run my code on the EDT? http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html -- esosman@comcast-dot-net.invalid "Nobody ever went broke underestimating the intelligence of the American public." -- HLM (paraphrased)
![]() |
0 |
![]() |
On 12/12/2016 2:18 PM, The Kreepy Gamer wrote: > Thank you for taking your time to look at my code, I fixed my > original problem but I am having trouble with another one. Sometimes, > but not every time when I change the text in a JTextField > programmatically or manually, a NullPointerException is thrown > without any info on what line it comes from. I believe this might be > fixed by having all my Swing code run on the EDT, but this is the > only way I have ever written my GUIs and before this I had never > heard of the EDT. I looked it up but I couldn't figure out how to do > this. Could you go more in depth about how to run my code on the > EDT? You should be able to get line number by compiling the right way and print stack trace somewhere. Regarding how to use EDT then that should be covered in practically all Swing tutorials. Arne
![]() |
0 |
![]() |