I am making a colour changer using RGB input, and I want to make sure the input's are integers whilst parsing. If one of the RGB values is not parsable, then it should clear that field but keep the fields that parsed fine. My code works but I have to use 3 try/catch statements but I want to reduce it to one. How would I merge all these three if possible?
How would I merge all these three if possible?
Move common code to helper method. I added value range check too.
private static int getChannelValue(JTextField field) {
String error;
try {
int value = Integer.parseInt(field.getText());
if (value >= 0 && value <= 255)
return value;
error = "Out of range";
} catch (NumberFormatException f) {
error = "Not an integer number";
}
JOptionPane.showMessageDialog(null, "No. " + error);
field.setText("");
return -1; // invalid
}
int r = getChannelValue(codeR);
int g = getChannelValue(codeG);
int b = getChannelValue(codeB);
if (r != -1 && g != -1 && b != -1)
centreName.setForeground(new Color(r, g, b));
I assume that you are having all of these values gather once a JButton is clicked? Well, instead of doing that why not store the values when the client is done writing to the TextFields and then use parseInt on that specific field?
field.addFocusListener(new FocusListener() {
#Override
public void focusGained(FocusEvent e) { }
#Override
public void focusLost(FocusEvent e) {
// parse and store int here
}
});
Since Color only accepts integers 0-255, you could instead use a regex
inputString.matches("[12]?\\d?\\d")
The regex accepts 1/2/nothing for the first digit, a number or nothing for the second digit, and requires the third digit
This works for 0-255, but also accepts numbers like 05, 00, and 260 (but not 005, unless you make it [012]), but Integer.parseInt() will figure them out
You may want to also exclude values like 260, which is covered in: Validate if input string is a number between 0-255 using regex
inputString.matches("1?[0-9]{1,2}|2[0-4][0-9]|25[0-5]")) will exclude values like 260, but not 05 or 00
Related
I have a JList that displays a filelist. The style I have it set to looks good with a FileFilter set to only show files and directories with names that are 15 characters long, however I still want to show the files that are longer than that, just show the first 15 characters or so. Basically, I want it to show this:
If I have a text file that says "1234567891234567.txt" - that has 20 characters including the ".txt" and it won't show up in the list. But I want it to show something like this:
"12345...567.txt" or something similar. Is there a way to do this?
Would I have to create a seperate array and copy everything over, and edit the value of the new array to be no longer than 15 characters? I tried looking for a function that would change the name of the file but I couldn't find any. Suggestions?
You can check the length of file name and abbreviate it if it contains more than 20 characters, like the method below:
private static String getShortName(String fileName){
if(fileName.length() <= 20){
return fileName;
}
String extension = fileName.substring(fileName.lastIndexOf("."));
String name = fileName.substring(0, fileName.lastIndexOf("."));
return name.substring(0, 5) + "..." + name.substring(name.length() - 4) + extension;
}
public static void main(String[] args) throws Exception {
System.out.println(getShortName("123.txt"));
System.out.println(getShortName("123rewe.txt"));
System.out.println(getShortName("123fdsfdsfdasfadsfdsgafgaf.txt"));
}
Please note that it won't work if the extension itself is more than 20 characters or file name does not have any extension. However, you can modify it as per your requirement.
Coming up with an abbreviated string that will fit in a certain amount of space isn’t as trivial as it may sound. Sure, you could just make sure your text is no longer than 15 characters, but all Swing look-and-feels assign a variable-width font to JLists. The system look-and-feel will use whatever font the underlying desktop uses for lists, which also is a variable-width font in all desktops I’m aware of.
Which means, the 20-character string IIIIIIIIIIIIIIII.txt and the 20-character string WWWWWWWWWWWWWWWW.txt are not the same width. Truncating each of them to fit in the JList’s space will not be as simple as making them 15 characters long.
Fortunately, you can use a FontMetrics to calculate a string’s visual size.
The simplest, though hardly most efficient, algorithm is to whittle down a string one character at a time until it fits in the JList’s width:
static <T> JList<T> createList(Collection<T> items) {
JList<T> list = new JList<T>(new Vector<T>(items)) {
private static final long serialVersionUID = 1;
#Override
public boolean getScrollableTracksViewportWidth() {
return true;
}
};
list.setCellRenderer(new DefaultListCellRenderer() {
private static final long serialVersionUID = 1;
private Insets insets = new Insets(0, 0, 0, 0);
#Override
public Component getListCellRendererComponent(JList<?> list,
Object value,
int index,
boolean selected,
boolean focused) {
insets = list.getInsets(insets);
int listWidth =
list.getWidth() - insets.left - insets.right - 4;
if (listWidth > 0 &&
value != null &&
!(value instanceof Icon)) {
FontMetrics metrics = list.getFontMetrics(list.getFont());
Graphics g = list.getGraphics();
String text = value.toString();
while (text.length() > 1 &&
metrics.getStringBounds(text, g).getWidth() > listWidth) {
int midpoint = text.length() / 2;
if (text.charAt(midpoint) != '\u2026') {
// Replace center character with ellipsis.
text = text.substring(0, midpoint) + '\u2026'
+ text.substring(midpoint + 1);
} else {
// Remove character before or after ellipsis.
if (text.length() % 2 == 0) {
midpoint--;
} else {
midpoint++;
}
text = text.substring(0, midpoint)
+ text.substring(midpoint + 1);
}
}
value = text;
g.dispose();
}
return super.getListCellRendererComponent(list, value, index,
selected, focused);
}
});
return list;
}
(Notice that “…” is not three period characters, but rather the ellipsis character. What’s the difference? The ellipsis is kerned differently, justified differently, read by screen readers differently, can’t be broken up by word-wrap, and is simply the correct punctuation. You wouldn’t use two apostrophes to represent a double-quote.)
I naïvely start by replacing the center character in each string, regardless of the width of the characters on either side of that character, but a more intelligent and possibly more visually pleasing approach would be to use the character visually located at the center, using TextLayout.hitTestChar.
I try to write a old maid.
After dealing cards,and sorting, i have two parts of card,one is playerDeck, one is computerDeck. now the pairs need to be removed.but i was stuck at this stage.
for example(just an example )
playerDeck:
'A♡', 'A♢', '8♡', '8♢', '8♠', 'Q♠', '2♠', '4♣', '7♢', '7♣', 'K♣', 'A♡', 'J♡', '9♣', '3♢'
computerDeck:
'3♡','3♣', '10♡','10♠','10♣', '6♡', 'K♡','K♢', 'A♣', 'A♠', '4♢', '7♡','7♠'
String q;
String p;
ArrayStringsTools AA=new ArrayStringsTools();//this is a class that i will use for removing item
for(int i=0;i<playerDeck.length-1;i++){
q=playerDeck[i];
q=q.substring(0,1);//i try to find the first character
p=playerDeck[i+1];//after finding first character, i can compare them,and if they are same, then i can remove them
p=p.substring(0,1);
if(q==p){
AA.removeItemByIndex(playerDeck,26,i);//this is the method that i used for removing same item,i will put this code below
AA.removeItemByIndex(playerDeck,26,i+1);//there are 51 cards in total,player has 26, computer has 25
}
}
public static int removeItemByIndex(String[] arrayOfStrings, int currentSize, int itemToRemove){//this is the method i used for removing item(first is the array of Deck, second is the size of Deck,third is the index of item to remove)
if( arrayOfStrings == null || currentSize > arrayOfStrings.length) {
System.out.println("ArrayStringsTools.removeItemByIndex: wrong call");
return currentSize;
}
if( itemToRemove < 0 || itemToRemove >= currentSize ) {
System.out.println("ArrayStringsTools.removeItem: item "
+ itemToRemove + " out of bounds. Array Unchanged.");
return currentSize;
}
int i;
for( i = itemToRemove; i < currentSize-1; i++){
arrayOfStrings[i] = arrayOfStrings[i+1];
}
arrayOfStrings[i]= null;
return currentSize-1;
i think i wrote correctly, but it doesnt show any difference compared with the origin.
the result should be:
playerDeck: '8♠', 'Q♠', '2♠', '4♣', 'K♣', 'A♡', 'J♡', '9♣', '3♢'
computerDeck:'10♣', '6♡', '4♢'
or is there another way to do this,because when a pair removed,there are two empty spaces, so... I've been struggling for a long time......
To compare the 1st character, change this line
if (q == p) {
to
if (q.charAt(0) == p.charAt(0)) {
Notice that q == p checks to see if the q and p refer to the same string, and do not look at the contents at all. If you want to compare full strings (or any other object that is not a char, an int, or so on) by content, you should use equals: q.equals(p) returns true only if both have the same content.
If you want to compare two strings,you can use 'equals',like
if(q.equals(p)){//q==p if true,they are save in the same location-this may not be what you want,and in this code it will be false forever.
}
basically I have a brute force password guesser(I realize it's not very efficient) I have a process I want to make into a recursive method that i can pass a length integer and it will run with that amount of characters.
here is the code:
public static void generatePassword(int length)
{
// should be a recusive function learn how to do that
// 1 interval
for(int i =32;i<127;i++)// ascii table length
{
System.out.println((char)i);
}
// 2 interval
for(int z =32;z<127;z++)// ascii table length
{
for(int q =32;q<127;q++)// ascii table length
{
System.out.println((char)z+""+(char)q);
}
}
// 3 interval
for(int w =32;w<127;w++)// ascii table length
{
for(int o =32;o<127;o++)// ascii table length
{
for(int g =32;g<127;g++)// ascii table length
{
System.out.println((char)w+""+(char)o+""+(char)g);
}
}
}
}
the intervals return a string with that length example: 3rd interval will return every possible string combination with a length of 3. if anyone can help me automate this process and explain(i would like to learn rather then copy and paste) that would be great ! :)
A recursive method is a method that calls itself, it has a base-condition (also called stop condition) which prevents it from going into an infinite loop.
Lets take the first interval as an example:
for(int i = 32; i < 127; i++) { // ascii table length
System.out.println((char)i);
}
we can create a recursive method that'll do the same thing:
private void interval1(int i) {
if (i < 32 || i >= 127) return;
System.out.println((char)i);
interval1(i + 1);
}
in order to use it for our use-case, we should call this method with i=32: interval(32)
Hope this helps!
The function
Note that this will be EXTREMELY INEFFICIENT. This shouldn't ever be done in practice, since the number of String objects created is MIND-BOGGLINGLY HUGE (see bottom of answer)
public void recursivePrint(String prefix, int levels) {
if (levels <= 1) {
for (int i = 33; i < 127; ++i) {
System.out.println(prefix+(char)i);
}
} else {
for (int i = 33; i < 127; ++i) {
recursivePrint(prefix+(char)i, levels-1);
}
}
}
Then you call it with:
recursivePrint("", 5); // for printing all possible combinations of strings of length 5
The way it works
Each call to a function has it's own memory, and is stored seperately. When you first call the function, there is a String called prefix with a value of "", and an int called 'levels' which has a value of 5. Then, that function calls recursivePrint() with new values, so new memory is allocated, and the first call will wait until this new call has finished.
This new call has a String called prefix with a value of (char)34+"", and a levels with a value of 4. Note that these are completely separate instances of these variables to the first function call because remember: each function call has it's own memory (the first call is waiting for this one to finish). Now this second call makes another call to the recursivePrint() function, making more memory, and waiting until this new call finishes.
When we get to levels == 1, there is a prefix built up from previous calls, and all that remains is to use that prefix and print all the different combinations of that prefix with the last character changing.
Recursive methods are highly inefficient in general, and in this case especially.
Why you should never use it
This method is not just inefficient, though; it's infeasible for anything useful. Let's do a calculation: how many different possibilities are there for a string with 5 characters? Well there's 127-33=94 different characters you want to choose, then that means that you have 94 choices for each character. Then the total number of possibilities is 94^5 = 7.34*10^9 [that's not including the 5+ bytes to store each one] (to put that in perspective 4GB of RAM is around 4*10^9 bytes)
Here is your method implemented using recursion:
public static void generatePassword(int length, String s) {
if (length == 0) {
System.out.println(s);
return;
}
for (int i = 32; i < 127; i++) {
String tmp = s+((char) i);
generatePassword(length - 1, tmp);
}
}
All you have to do is to pass length and initial String (ie "") to it.
At if statement there is checked, if recursion should be stopped (when length of generated password is equals to expected).
At for-loop there is new character added to actual String and the method is invoked with shorter length and a new String as an argument.
Hope it helps.
I am currently making a text adventure game in Java, but I have come across a problem:
I need the value of a String variable to change each time the value of a particular int variable changes.
I want the program to perform this task (then continue where it left off) each time the value of an int variable changes:
if (enemyposition == 1) {
enemyp = "in front of you";
}
else if (enemyposition == 2) {
enemyp = "behind you";
}
else if (enemyposition == 3) {
enemyp = "to your left";
}
else if (enemyposition == 4) {
enemyp = "to your right";
}
else {
enemyp = "WOAH";
}
Thanks! :D
You could make the code much shorter using an array.
String[] message = {"WOAH", // 0
"in front of you", // 1
"behind you", // 2
"to your left", // 3
"to your right"}; // 4
enemyp = (enemyposition > 0 && enemyposition < 5) ? message[enemyposition] :
message[0];
The question you're asking sounds like it might be answerable by creating a class to hold the enemyposition integer. Add a "setter" method to your class to set the integer. You can write your setter method so that when the integer is set, it also sets up a string. Then write a "getter" method to retrieve the string. That's one common way of making sure two variables change together.
public class EnemyPosition {
private int enemyposition;
private String enemyp;
public void setPosition(int n) {
enemyposition = n;
enemyp = [adapt your code to set this based on the position]
}
public String getEnemyp() {
return enemyp;
}
}
I'm sure there are a lot of details missing, but you get the idea. Then instead of int enemyposition in the rest of your code, use EnemyPosition enemyposition = new EnemyPosition(), and use the setPosition method instead of assigning to it.
That's not the only solution (an array or Map that maps integers to strings may be good enough), but it's one OOP way to do things.
i have a JFormattedTextField , and i want that when i try to enter a number, example 1002 , that i will rounded to the nearest multiple of 5
1002->1000
304->305
6->5
9->10
1->0
etc..
i've already setup a number format to cancel the grouping, and accepting only numbers
NumberFormat format=NumberFormat.getInstance();
format.setGroupingUsed(false);
pun1[i]=new JFormattedTextField(format); //pun1 and pun2 are the arrays of FIELDS
pun2[i]=new JFormattedTextField(format);
how can i resolve this problem?
I want this editing inside the field, while i'm writing the number, just as when the grouping character appears!
This works for int arguments:
public int roundToClosestFive(int num) {
return (int) (Math.round(num / 5.0) * 5);
}
Remember, to get the int value of the string you've entered you can do: Integer.valueOf(string); and pass that as an argument to the method. To have the text inside the JFormattedTextField change on focus change or enter, you could call the above method from the propertyChange() method of a PropertyChange listener that you can add to the JTextFormattedTextField. Something like this in the propertyChange() method:
public void propertyChange(PropertyChangeEvent e) {
Object source = e.getSource();
if (source == pun1[i]) {
((JFormattedTextField) source).setText(""
+ roundToClosestFive(((Number)pun1[i].getValue()).intValue()));
}
}