I'm writign a POS system(point of sale) for fun. A typical feature of a POS system is buttons that have different background colors for different products. But I don't mean the background behind the button's image, i mean like in this random picture I got off google images:
Edit: Note I changed the look and feel to the system one
I need to do something like THAT with my buttons. I know a few ways this COULD be possible:
Creating a look and feel for my buttons?
Completely overriding the paintComponenet method in my JButtons(But that's a pretty pathetic way to do it... and the border + text isn't drawn when I override that... obviously a bad idea)
Using button.setContentAreaFilled(false);, and putting a JPanel of the same size as the button behind the button.
I don't really know how to create my own look and feel, and it sounds like a pain, especially just for 1 button, and I heard something about breaking the look and feel which scared me away from that idea. The 3rd way sounds plausible, and not extremely difficult, but I what is the very best way to do what I am trying to do?
Right now my code for creating butons is this:
JButton b = new JButton(text);
b.addActionListener(this);
b.setFont(Main.f);
b.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
buttons.add(b);
return b;
I've messed around with this code(Mostly for fun, not practicality):
JButton b = new JButton(text){
public void paintComponent(Graphics g){
super.paintComponent(g);
Color bg = getBackground();
int borderchange = -50;
g.setColor(new Color(
Math.max(0,bg.getRed()+borderchange),
Math.max(bg.getGreen()+borderchange,0),
Math.max(bg.getBlue()+borderchange,0)));
g.fillRect(0,0,getWidth(),getHeight());
g.setColor(getBackground());
int border = 4;
g.fillRect(border,border,getWidth()-border,getHeight()-border);
g.setColor(Color.BLACK);
g.setFont(getFont());
g.drawString(getText(),getWidth()/2,getHeight()/2);
}
};
Creating a look and feel for my buttons?
Look and Feel is something like as theme,
by default this ColorScheme has a one, two, three Colors, this theme is applied for all Swing JComponents,
then all Swing JComponents have got the same Color, ColorScheme
not something that you looking for
Completely overriding the paintComponenet method in my JButtons(But
that's a pretty pathetic way to do it... and the border + text isn't
drawn when I override that... obviously a bad idea)
JButton has array of Colors
you can to override paintComponent, fills whole area, Rectangle with one Color (not something that you looking for) or to use GradientPaint
you can to override BasicButtonUI
override proper key in UIManager and put there arrays of Colors
Using button.setContentAreaFilled(false);, and putting a JPanel of
the same size as the button behind the button.
this could be easiest of ways, prepare Icons (or download set of Icons)
use proper methods, implemented (Mouse & Key & KeyBindings) events
in the JButton API
override ButtonModel (by using ChangeListener)
Have you tried:
yourButton.setBackground(COLOR)
?
Related
I'm trying to add some polish to a small game I made and, every time a round finishes, I'd like the whole JFrame to flash white and quickly lose opacity until you can see the game again. How would I do this?
Note: I'm thinking about hiding all the components and adding a JPanel on top that loses opacity quickly but this doesn't seem right (and I'd like to be able to see the components behind the white flash as it goes from opaque to transparent).
You could probably use the JLayer class. Take a look at the section from the Swing tutorial on How to Decorate Components with the JLayer Class.
The tutorial has examples that:
paint translucent layers
do animation
Put the examples together and you should have a solution.
You can use fading out image to achieve the same. AlphaComposite is used for fading effect.
Graphics2D g2d = (Graphics2D) g;
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
Refer Fade Out Image to access the sample code.
I have an assignment where I am supposed to create a prototype drawing program to display and manipulate faces. It is supposed to use 2 windows, one to draw the face and the other to control the drawing. It is supposed to initially show the image of a face (drawn with shapes).
The face consists of a head, two eyes, a nose, and a mouth. Each of these parts is selected by clicking the mouse within the border of the object. The eyes are selected as a pair, so clicking either eye selects them both. when one face part is selected, all previous selections are forgotten.
The control window operates only upon the selected object. A click on the Change image button performs the following tasks (depending on the selected face part):
Head: Head changes from green to yellow to purple to purple, and back to green
Nose: The nose image changes another of three possible nose images
Mouth: Mouth image changes to another of three possible mouth images
Eyes: eye image changes to another of four possible eye images
Include a scroll bar with behavior:
Selected Head: Head gets wider and narrower with scroll bar value change
Selected Nose: Nose image moves up or down with scroll bar value change
Selected Mouth: Mouth gets wider or narrower with scroll bar value change
Selected Eyes: Eyes move closer together or farther apart with scroll bar value change
My problem is, I have no idea where to even start. I have watched many a tutorial on swing and awt and have even tried playing around with the palette manager in NetBeans. Can anyone point me in the right direction or maybe walk me through the code?
Your question is not a good fit here. Also, despite your instructors alleged inaccuracies, it is still conceivably possible for a person to do the research on their own to go from the rather nice set of specific requirements you have to a functioning program. I don't mean that to be as critical as it may sound.
However, out of appreciation of the fact that you approached your instructor, and also out of pity, maybe I can give you some starting points and hints.
First of all, Swing is the right way to start. Read through the relevant sections of the tutorial at http://zetcode.com/tutorials/javaswingtutorial/ and follow along with some of the projects.
You can code Swing interfaces by hand quite easily, and for your relatively simple application, and for the learning experience, it is a reasonable option. However, for future reference, many IDEs have GUI editors (NetBeans ships with the feature I think, Eclipse has the WindowBuilder plugin) - the caveat being that you have to add learning how to use the IDE to your task list (of course, this will ultimately save you time in the long run).
In any case, your first step should be to design your software. Determine what actions you need to perform, what user actions you need to respond to and how, and what information you are working with. You give the following requirements:
The control window operates only upon the selected object. A click on
the Change image button performs the following tasks (depending on the
selected face part):
Head: Head changes from green to yellow to purple to purple, and back
to green
Nose: The nose image changes another of three possible nose
images
Mouth: Mouth image changes to another of three possible mouth
images
Eyes: eye image changes to another of four possible eye images
Include a scroll bar with behavior:
Selected Head: Head gets wider and narrower with scroll bar value
change
Selected Nose: Nose image moves up or down with scroll bar
value change
Selected Mouth: Mouth gets wider or narrower with scroll
bar value change
Selected Eyes: Eyes move closer together or farther
apart with scroll bar value change
The basic component you are working with here is a face, so let's make a design decision here to have a face be an object with other properties (you could take a different approach and have the different parts of the face be your basic units). Based on your description of scroll bars, a face has the following modifiable properties:
Head width.
Vertical nose position.
Mouth width.
Distance between eyes.
A face also, of course, has other constant characteristics that are pretty much up to you to arbitrarily decide the value of, for example the diameter of the eyes, the color of the skin, etc. You will have to work those out.
In addition to modifying the above properties, there are a few things you need to be able to do with a face, also based directly on your requirements:
Draw (paint) the face.
Redraw (repaint) the face when a property changes.
Allow the user to select a part by clicking, which breaks down into:
Responding to mouse clicks.
Determining the component under the cursor given an XY location.
Providing information about the selection to the application.
The last part "providing information about the selection" is an implementation detail that you have a few options for, and you will have to decide. For example, you could create some type of event listener interface and tell the face about it, and let it call methods on that interface when the selection changes -- this is a very swing way to do it. You could also have the face internally maintain which property is currently selected, in which case you need to give it the ability to get/set the value of the currently selected property. You could also have the face directly call methods on your editor UI window. All of these ways have distinct advantages and disadvantages, and I'll leave it as an exercise to the reader to experiment.
Now, you also, as per your requirements, need to provide a scroll bar for the user to edit properties with, in a separate window. So now, think about what UI components you need and how you want them to tie together:
Face Window
Contains a single face component (or more if you want).
Editor Window
Contains a scroll bar.
Might contain a label describing the current selection, if you'd like.
Swing already provides most of these components. A window is a JFrame. A scroll bar is a JScrollBar. A label is a JLabel. Swing doesn't provide a face, so you'll need to write a custom component yourself.
As for how they tie together:
Changing the object selection in the face could:
Update the scrollbar to the current value, if you'd like.
Update the scrollbar range to appropriate values.
Update the label to describe the current selection, if you'd like.
Changing the scrollbar must:
Update the currently selected property on the face.
Ultimately cause the face to be redrawn.
The major task now, then, is to implement a Swing component that draws a face and responds to mouse clicks.
Since you are creating a new component, you'll want to pick an appropriate base, perhaps a JComponent or a JPanel, up to you. Exactly how to create new components can be easily found in many tutorials on Google (including some basics in the one I linked to above), and that is up to you to research. Essentially, though, reiterating what was said above, your custom face component has the following custom behaviors:
Draw a face.
Receive mouse events.
Determine clicked component from mouse X,Y coordinates. At its most basic level, this will require some math. If your head, eyes, mouth, and nose are ellipses, for example, it will be up to you to compute whether or not a given X,Y coordinate is within the bounds of one of those ellipses. However, you will want to look into Shape, which will allow you to easily define shapes and provides bounds checking methods already.
I think this is enough for you to get started and put it all together. The following general tasks are at hand:
Read that tutorial I linked to, a lot of basics should become clear. Try writing some simple "hello world" style applications.
Try writing some custom components; your requirements are basic and much of it is covered in the "Painting" section of that tutorial.
Check out a tutorial or some examples on how to use Shape and experiment.
If you have specific questions about code you've written, with a specific problem you may be trying to solve, you can always come back and post that on SO.
I hope this helps. More importantly, I hope this gives you at least some idea of how to go from requirements to implementation in general.
Edit:
It's been a while since I played with Shape so I put together this tiny example. Click / drag over the two shapes to select them, which will turn them yellow:
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
#SuppressWarnings("serial")
public class ShapeSelect extends JPanel {
private final Shape firstShape = new Rectangle2D.Float(60, 40, 70, 70);
private final Shape secondShape = new Ellipse2D.Float(30, 30, 90, 50);
private Shape selected = null;
public ShapeSelect () {
// set up the component
setPreferredSize(new Dimension(200, 200));
addMouseMotionListener(new MouseMotionAdapter() {
#Override public void mouseDragged (MouseEvent event) {
selectShapeUnder(event.getX(), event.getY());
}
});
addMouseListener(new MouseAdapter() {
#Override public void mousePressed (MouseEvent event) {
selectShapeUnder(event.getX(), event.getY());
}
});
}
// draw our shapes, selected shape is yellow.
#Override protected void paintComponent (Graphics g) {
Graphics2D graphics = (Graphics2D)g;
graphics.setColor((selected == firstShape) ? Color.YELLOW : Color.RED);
graphics.fill(firstShape);
graphics.setColor((selected == secondShape) ? Color.YELLOW : Color.GREEN);
graphics.fill(secondShape);
}
// updates 'selected' based on x,y coordinate and redraws component on change.
public void selectShapeUnder (int x, int y) {
Shape oldSelected = selected;
// note that since second shape is draw on top of first, we give second preference.
// for overlapping shapes the selection should be consistent with the gui display.
if (secondShape.contains(x, y))
selected = secondShape;
else if (firstShape.contains(x, y))
selected = firstShape;
else
selected = null;
if (selected != oldSelected)
repaint();
}
public static final void main (String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override public void run () {
JFrame frame = new JFrame("Shape Select");
frame.getContentPane().add(new ShapeSelect(), BorderLayout.CENTER);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I'm writing a plugin for a Swing application which I don't own or have access to the source code for. In parts of my UI, I want to use specific colors in order to match my icons.
In this case, I want to create a JPanel with a specific background color.
final JPanel panel = new JPanel();
panel.setBackground(new Color(101, 102, 103));
It appears that no matter what color I use, I get the same result. I suspect it's the look and feel that is changing the color on me.
All of the solutions I've found discuss changing the look and feel or setting new defaults. I don't want to take this approach because:
It's very dependent on the current look and feel
It would affect all panels in the application, and not just the one I'm interested in
The application supports several different themes (look and feels), so even if I were to use the UIManager to figure out exactly what they are, this would break as soon as they added a new theme.
I'm not too experienced with Swing, but I feel like the look and feel should set the defaults, but anything I set manually should still take effect. Is there any way to set the panel's background to a specific color regardless of the look and feel?
I'm chalking this up to a bug (or maybe a feature) in the application's custom look and feel. If I load a new look and feel the panel is displayed correctly.
As a work around you could create a custom JPanel that overrides paintComponent(Graphics g) to draw the background color.
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLUE);
g.fillRect(0, 0, getWidth(), getHeight());
}
Are you getting the problem while using Nimbus Look-and-Feel. Then please check my answer for more or less same problem at
Changing the Look and Feel changes the color of JTextPane?
I need to implement font size switching in my app. But when I increase font's size RadioButtons remain same size and on small screen with high resolution my customer just can't hit it easily. Is there a way to resize RadioButton's round thing programmatically without diging into L&F and redrawing Icons manually (it's complicated since app targets multiple platforms with different UIs and each of them must have 7 icons).
Perfect solution could look like this:
Extraction of native UI icon.
Resizing it
Setting resized icon as component's icon.
How to implement step 1? Is it possible?
EDIT: this is what i tried so far
public class IconImageSaver extends JFrame{
public IconImageSaver() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setBounds(0,0,100,100);
setVisible(true);
JRadioButton rad1 = new JRadioButton();
rad1.setBounds(10,10,40,40);
add(rad1);
Icon icon = UIManager.getIcon("RadioButton.icon");//(1) trying to get icon
int w = icon.getIconWidth(),h = icon.getIconHeight();
Image i = rad1.createImage(w, h);
Image i2 = rad1.createImage(w,h);
Graphics g = i.getGraphics();
Graphics g2 = i2.getGraphics();
g.setColor(Color.CYAN);
g.fillRect(0, 0, w, h);
rad1.setIcon(new ImageIcon(i));//setting icons
g2.setColor(Color.RED);
g2.fillRect(0, 0, w, h);
rad1.setPressedIcon(new ImageIcon(i2));//setting icons
}
public static void main(String[] args) {
new IconImageSaver();
}
}
At position (1) i'm trying to get icon image, but it returns only background color.
Can't understand why.
Setting icons for various states works as intended.
Some L&Fs (e.g. Nimbus, Aqua) support a large JComponent.sizeVariant, as discussed in Resizing a Component and Using Client Properties.
Addendum: I must use pure native L&F.
The rendering of a JRadioButton is determined by its associated ButtonUI delegate. The internals of delegates supplied by the native L&F are generally inaccessible and rely on host platform APIs. You have to use the available feature(s) of the user's chosen L&F or supply your own. If you can explain more about the underlying problem, it may help to suggest better alternatives.
Addendum: Absent developing a complete L&F, it may be possible to work with the radio button's parent, JToggleButton. Such buttons work well in a ButtonGroup, as shown here, and they can be decorated arbitrarily, as outlined here.
is very L&F sensitive, by default you can
use proper L&F (only Nimbus has implemented auto_whatever) but we talking about Custom L&F
to override keys in UIManager, but these keys can, could (be presented or with value) or missing in compare with another L&F
create own (J)Component, to overide important methods and
a) put to the UIManger (one def. valid for whole JVM instace)
b) add to the selected, desired or part of (J)Components, e.i. .... in the visible GUI
notice for (I need to implement font size switching in my app) there is very important to test if is required to change (we'll talking about) Font or FontUIResources, part of implemented methods for part of (J)Components to pretty ignore Font and required FontUIResources, now not sure if vice versa too
IMPORTANT NOTE: This was only tested with the default 'Metal' look and feel. I do not guarantee that this will work for any other look and feel. Also I am not entirely sure how it works because it is admittedly a bit of a hack.
I was able to solve this a little bit differently.
I Was scaling my font globally using the UIManager defaults and so I wanted my radio buttons to scale with the font.
I found I could do this by extracting the Icon for the radio button from the UIManager, buffering them, re-sizing them and then deriving a new icon from the graphics of the buffered icons.
I ended up with this function:
public static void scaleRadioButtonIcon(JRadioButton rb){
boolean previousState = rb.isSelected();
rb.setSelected(false);
FontMetrics boxFontMetrics = rb.getFontMetrics(rb.getFont());
Icon radioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage radioImage = new BufferedImage(
radioIcon.getIconWidth(), radioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics graphics = radioImage.createGraphics();
try{
radioIcon.paintIcon(rb, graphics, 0, 0);
}finally{
graphics.dispose();
}
ImageIcon newRadioImage = new ImageIcon(radioImage);
Image finalRadioImage = newRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(true);
Icon selectedRadioIcon = UIManager.getIcon("RadioButton.icon");
BufferedImage selectedRadioImage = new BufferedImage(
selectedRadioIcon.getIconWidth(), selectedRadioIcon.getIconHeight(),BufferedImage.TYPE_INT_ARGB
);
Graphics selectedGraphics = selectedRadioImage.createGraphics();
try{
selectedRadioIcon.paintIcon(rb, selectedGraphics, 0, 0);
}finally{
selectedGraphics.dispose();
}
ImageIcon newSelectedRadioImage = new ImageIcon(selectedRadioImage);
Image selectedFinalRadioImage = newSelectedRadioImage.getImage().getScaledInstance(
boxFontMetrics.getHeight(), boxFontMetrics.getHeight(), Image.SCALE_SMOOTH
);
rb.setSelected(previousState);
rb.setIcon(new ImageIcon(finalRadioImage));
rb.setSelectedIcon(new ImageIcon(selectedFinalRadioImage));
}
What it does is get the size of the font from the radiobuttons's font metrics. Using those metrics, it derives a new icon based on the icon found in the 'Look and Feel' and sizing it to the font's height.
One thing that I am not able to explain is how the icon for the radiobutton coming out of the UIManager changes to the 'selected' icon when I am accessing the same property to get both icons.
I start by saving the state of the control so I can restore it at the end. This is done because in order for the icons to be set properly, the state needs to be unchecked when you first request the icon from the UIManager and then it will need to be checked when you request the icon the second time to get the 'selected' icon.
Again, I am not entirely sure how the UIManager works or why the icon changes when we call the same property just by setting the 'selected' value of a single radiobutton, but that is what is required in order to get both the necessary icons.
If you did not want to use the font to size the controls, you could easily just pass in the height and width as parameters and use them instead of the font's height when setting the buffered image size.
I might mention that this same methodology works with checkboxes
I've just started coding video games and I've heard that doing all your drawing on a JPanel and attaching that panel onto a JFrame is better than simply drawing onto the JFrame. I was just wondering why is this better?
It is better for various reasons, including:
In most Swing components, custom painting is achieved by overriding the paintComponent(Graphics) method. Top-level Swing containers (e.g. JFrame, JApplet, JWindow) have only paint(Graphics). As a result of the common method for painting, people who answer often forget about this difference between common and top-level components, and therefore suggest silly advice. ;)
A JComponent can be added to a JFrame, or a JApplet, or a JDialog, or a constraint of a layout in a JPanel, or a JInternalFrame, or a.. Just when you think your GUI is complete, the client says "Hey, wouldn't it be great to throw in a tool-bar & offer it as an applet as well?" The JComponent approach adapts easily to that.
As explained (complete with code!) by Richante, it is easier to calculate the co-ordinates required for painting the custom component, and if it has a preferred size, to size the JFrame to be 'exactly the right size' to contain the GUI (using pack()). That is especially the case when other components are added as well.
Now, two minor disagreements with the advice offered.
If the entire component is custom painted, it might be better to simply put a BufferedImage inside an ImageIcon/JLabel combo. Here is an example of painting to an image. When it comes time to update it:
Call getGraphics() for a Graphics or createGraphics() for a Graphics2D
Draw the custom painting to that graphics instance
Dispose of the graphics instance
Call repaint() on the label.
It is an easy way to do Double Buffering.
Let me elaborate a bit. In video games, to avoid the flicker caused by redrawing and display smoother graphics, people usually use double buffering. They create an offscreen surface, draw everything on that and then display the entire off-screen surface on the screen in one go.
In Java2D and Swing, the easiest way to do this, is to simply do your game sprite drawing on a JPanel, and then add the JPanel to a JFrame.
Secondly, by drawing things on a JPanel, you allow more GUI widgets and other graphical objects to be displayed on the JFrame without having to paint them manually in the game loop. For example buttons, menus, other panels, even other rendering JPanels.
Thirdly, it allows you to use automatically translated co-ordinates for your game. You can draw everything from the top-left to the bottom-right without having to worry about the window manager specific things like window border-widths, task panes, titles etc.!
Moreover, this is not just a convention only used by Game Programmers in Java. Creating a separate Game Board, Render Panel or Graphics Widget is quite popular when programming games using a library with an internal mainloop such as a GUI Toolkit. You can use a User Form in Windows Forms and a Drawing Board in GTK+.
The JFrame includes things like the menu, title bar and border. Therefore, when you refer to coordinates you have to account for these. You might also decide to add a menu bar, or some other components, to the frame. If your painting is all in a JPanel, then this won't change how you need to refer to coordinates.
For example, try:
public class Test extends JFrame {
public Test() {
super();
setVisible(true);
setBounds(100, 100, 200, 100);
}
#Override
public void paint(Graphics g) {
g.fillRect(0, 0, 50, 50);
}
public static void main(String[] args) {
new Test();
}
}
and you will see that the black square is not square! Because (0, 0) is the top left corner of the entire frame, not the corner of the visible area.