I am trying to do something pretty common with GWT - creating a button behavior with an image and a text by positioning the text on top of the image.
I have used the HTML widget but how can I make the text not selectable?
I recently had the same need for a GWT button which allows to add image AND text. So I coded one myself since the already available implementations didn't work. I wrote a post on my blog but I also copy the code here:
Here's the code for my custom button
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Image;
public class CustomButton extends Button {
private String text;
public CustomButton(){
super();
}
public void setResource(ImageResource imageResource){
Image img = new Image(imageResource);
String definedStyles = img.getElement().getAttribute("style");
img.getElement().setAttribute("style", definedStyles + "; vertical-align:middle;");
DOM.insertBefore(getElement(), img.getElement(), DOM.getFirstChild(getElement()));
}
#Override
public void setText(String text) {
this.text = text;
Element span = DOM.createElement("span");
span.setInnerText(text);
span.setAttribute("style", "padding-left:3px; vertical-align:middle;");
DOM.insertChild(getElement(), span, 0);
}
#Override
public String getText() {
return this.text;
}
}
Usage with UiBinder XML definition
...
<!-- ImageBundle definition -->
<ui:with field="res" type="com.sample.client.IDevbookImageBundle" />
...
<d:CustomButton ui:field="buttonSave" text="Save" resource="{res.save}"></d:CustomButton>
The screenshot of such a button:
Do you mean to get rid of the text select cursor, or make the text completely unselectable?
To make it look like something clickable, you can use the cursor CSS rule.
.widget_style {cursor: pointer;}
Actually making it unselectable is not well supported from what I understand. It is in the CSS3 specs with user-select.
.widget_style {user-select:none;}
I would use the Button-Widget and call the setHTML() function.
You could use this code:
public class Custombutton extends Button {
public CustomButton(String text, String img) {
this.setHTML(text + "<br><img src=\"" + img + "\">");
}
}
You just have to provide the text and the img url when you create the button.
Did you try the CustomButton class of gwt?
here is the link:
http://projectpossibility.org/projects/word_prediction/gwt-linux-1.4.60/doc/javadoc/com/google/gwt/user/client/ui/CustomButton.html
A class that allows the addition of arbitrary widgets to a Button:
import java.util.ArrayList;
import java.util.Iterator;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
public class ButtonWithWidgets extends Button implements HasWidgets
{
private ArrayList<Widget> widgets = new ArrayList<Widget>();
#Override
public void add(Widget w)
{
DOM.insertChild(getElement(), w.getElement(), widgets.size());
}
#Override
public void clear()
{
for (Widget widget : widgets)
{
DOM.removeChild(getElement(), widget.getElement());
}
widgets.clear();
}
#Override
public Iterator<Widget> iterator()
{
return widgets.iterator();
}
#Override
public boolean remove(Widget w)
{
if (widgets.indexOf(w) != -1)
{
widgets.remove(w);
DOM.removeChild(getElement(), w.getElement());
return true;
}
else
return false;
}
}
with UiBinder:
...
<customwidgets:ButtonWithWidgets>
<g:Label>Whatever</g:Label>
<g:Image url="etc.png"/>
</customwidgets:ButtonWithWidgets>
Related
Minimal classes to reproduce the issue:
import static com.gluonhq.charm.glisten.application.AppManager.*;
import javafx.application.Application;
import javafx.stage.Stage;
import com.gluonhq.charm.glisten.application.AppManager;
import com.gpsdemo.view.View1;
import com.gpsdemo.view.View2;
public class MyApplication extends Application {
AppManager appManager = AppManager.initialize();
public static final String VIEW1 = HOME_VIEW;
public static final String VIEW2 = "View2";
#Override
public void init() {
appManager.addViewFactory(VIEW1, View1::get);
appManager.addViewFactory(VIEW2, View2::get);
}
#Override
public void start(Stage stage) throws Exception {
appManager.start(stage);
if (com.gluonhq.attach.util.Platform.isDesktop()) {
stage.setHeight(600);
stage.setWidth(360);
stage.centerOnScreen();
}
}
public static void main(String args[]) {
launch(args);
}
}
import javafx.scene.control.Label;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
import com.gpsdemo.MyApplication;
public class View1 extends View {
private static View1 INSTANCE;
public static View1 get() {
return INSTANCE != null ? INSTANCE : (INSTANCE = new View1());
}
private View1() {
setCenter(new Label("Nothing to see here"));
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setTitleText("View1");
var optionsButton = MaterialDesignIcon.MENU.button(e -> getAppManager().switchView(MyApplication.VIEW2));
appBar.getActionItems().add(optionsButton);
}
}
import java.util.Set;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.scene.Node;
import com.gluonhq.charm.glisten.control.AppBar;
import com.gluonhq.charm.glisten.control.SettingsPane;
import com.gluonhq.charm.glisten.control.settings.DefaultOption;
import com.gluonhq.charm.glisten.mvc.View;
import com.gluonhq.charm.glisten.visual.MaterialDesignIcon;
public class View2 extends View {
private static View2 INSTANCE;
public static View2 get() {
return INSTANCE != null ? INSTANCE : (INSTANCE = new View2());
}
private View2() {
var settingsPane = new SettingsPane();
var option = new DefaultOption<>("Title", "Description", "Category", new SimpleDoubleProperty(), true);
settingsPane.getOptions().add(option);
setCenter(settingsPane);
setOnShown(e -> {
System.out.println("On shown");
Set<Node> lookup = settingsPane.lookupAll(".secondary-graphic");
System.out.println(lookup);
});
}
#Override
protected void updateAppBar(AppBar appBar) {
appBar.setTitleText("View2");
var backButton = MaterialDesignIcon.ARROW_BACK.button(e -> getAppManager().switchToPreviousView().get());
appBar.setNavIcon(backButton);
}
}
Launch the application normally, View1 will show.
Click on the button to show View2. The first time View2 is loaded the output is
On shown
[]
So the lookup fails in the onShown event.
Click on the back button and then show View2 again. The output is
On shown
[HBox#2c8d8a10[styleClass=secondary-graphic]]
which is correct.
If View2 is set as HOME_VIEW, the lookup will find the nodes correctly on the first onShown event. This looks like a bug to me. Regardless, I would like the lookup to succeed on the first time so I can configure the view correctly.
Using:
<javafx-maven-plugin-version>0.0.8</javafx-maven-plugin-version>
<gluonfx-maven-plugin-version>1.0.14</gluonfx-maven-plugin-version>
<java-version>17</java-version>
<javafx-version>18.0.1</javafx-version>
<charm-version>6.1.0</charm-version>
As mentioned in the comments, the issue is that the SHOWN event does not happen after a css pass is applied, therefore the lookup fails. A fix can be to manually do a css pass before the lookup, inside the SHOWN handler:
setOnShown(e -> {
System.out.println("On shown");
settingsPane.applyCss();
Set<Node> lookup = settingsPane.lookupAll(".secondary-graphic");
System.out.println(lookup);
});
This is confusing because the SHOWN event does not actually happen after the view is fully shown (in which case a css pass has happened). The event also behaves differently than JavaFX's dialog DIALOG_SHOWN event, that does happen after the dialog is fully shown (including a css pass).
Its been a while since i built a desktop JAVA application.. after lots of documentation and doing implementation tests, i still have not found an image grid solution.
Either Java lacks such a ready-to-use component (?!) or you tell me to brush up my google-fu. :)
I have a very simple technical premises: a JDialog that allows the user to pick an image. Input is a Map<Integer, String> list that holds filenames. Output is the Integer key the user chose. GUI also is simple: user chooses 1 image using mouse or keyboard, and dialog closes. All images are 80x80px and loaded from filename, not a resource.
I tried several approaches so far this morning:
Search for components/widgets that show scrollable imagegrid that can flow to the left. (no dice)
Search for components/widgets that show scrollable imagegrid (no dice)
Search for any components/widgets/gui-libs (no dice .. do these even exist?!)
Try and implement myJList.setModel(), but i cant get it to just take my Map<> and show thumbnails. (overcomplicates!)
Try and implement myJPanel.setlayout(new FlowLayout(..)) with several myJPanel.add(new JButton(..)) which just creates a bunch of JButton on a JPanel, which each need a event handler. I wonder how scrolling and keyboard input is going to work out, and how i'm supposed to keep/reference my Map<> key values. (overcomplicates?)
In lieu of your answer, i am now working on the latter, which should work but i cant believe everyone needs to reinvent the same GUI wheel here. How to have the user select an image from my Map<Integer, String>? Are there JAVA libraries/widgets/components that i should look to avoid this?
I hope this isn't being modded down, i have no working implementation with error to show you guys.. this question is about how/where to find the components or what approaches would be better. Its 2014 and i cant believe that JAVA still requires me to build my own "GUI component" just to see some images.. not even Delphi or Mono does that.
If all you want is a grid of images, and having them selectable, consider using a JList, filling it with appropriate ImageIcons, and giving it a ListSelectionListener. In the Listener you can close the enclosing dialog when a selection has been made.
You state:
Try and implement myJList.setModel(), but i cant get it to just take my Map<> and show thumbnails. (overcomplicates!)
You need to use your Map to populate your ListModel, and set that Model to the JList's model.
For example:
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dialog.ModalityType;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
#SuppressWarnings("serial")
public class ImageGridPanel extends JPanel {
public static final String PATH = "http://images-2.drive.com.au/2011/";
public static final String[] CARS = {
"04/15/2308961/giulietta_1024-80x80.jpg",
"11/18/2781958/audi-a1-sportback_600-80x80.jpg",
"12/23/2856762/fiat-500-80x80.jpg",
"01/12/2129944/Honda-Civic-Sedan-concept-1_600-80x80.jpg",
"12/23/2856581/mini-roadster-80x80.jpg",
"12/23/2856571/hyundai-veloster-80x80.jpg",
"12/23/2856771/hyundai-i30-80x80.jpg",
"12/23/2856580/mini-coupe-80x80.jpg" };
private DefaultListModel<Car> carModel = new DefaultListModel<>();
final JTextField textField = new JTextField(20);
public ImageGridPanel() {
for (String carPath : CARS) {
String path = PATH + carPath;
try {
URL imgUrl = new URL(path);
BufferedImage img = ImageIO.read(imgUrl);
ImageIcon icon = new ImageIcon(img);
String name = carPath.substring(carPath.lastIndexOf("/"));
name = name.substring(1, name.lastIndexOf("-"));
carModel.addElement(new Car(name, icon));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
ShowGridAction showAction = new ShowGridAction("Car Grid", carModel);
JButton showGridBtn = new JButton(showAction);
add(showGridBtn);
add(textField);
}
private class ShowGridAction extends AbstractAction {
private CarGridPanel carGridPanel;
public ShowGridAction(String name, DefaultListModel<Car> carModel) {
super(name);
carGridPanel = new CarGridPanel(carModel);
}
public CarGridPanel getCarGridPanel() {
return carGridPanel;
}
#Override
public void actionPerformed(ActionEvent e) {
Window win = SwingUtilities.getWindowAncestor((Component) e.getSource());
JDialog dialog = new JDialog(win, "Cars", ModalityType.APPLICATION_MODAL);
dialog.add(carGridPanel);
dialog.pack();
dialog.setLocationRelativeTo(null);
int x = dialog.getLocation().x;
int y = dialog.getLocation().y - 150;
dialog.setLocation(x, y);
dialog.setVisible(true);
Car selectedCar = carGridPanel.getSelectedCar();
if (selectedCar != null) {
textField.setText(selectedCar.getName());
}
}
}
private static void createAndShowGui() {
JFrame frame = new JFrame("ImageGrid");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ImageGridPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
class Car {
String name;
Icon icon;
public Car(String name, Icon icon) {
this.name = name;
this.icon = icon;
}
public String getName() {
return name;
}
public Icon getIcon() {
return icon;
}
}
#SuppressWarnings("serial")
class CarGridPanel extends JPanel {
private JList<Car> carList = new JList<>();
private Car selectedCar;
public CarGridPanel(ListModel<Car> model) {
carList.setModel(model);
carList.setLayoutOrientation(JList.HORIZONTAL_WRAP);
carList.setVisibleRowCount(2);
carList.setCellRenderer(new DefaultListCellRenderer() {
#Override
public Component getListCellRendererComponent(JList<?> list,
Object value, int index, boolean isSelected, boolean cellHasFocus) {
if (value != null) {
Car carValue = (Car) value;
value = carValue.getIcon();
} else {
value = "";
}
return super.getListCellRendererComponent(list, value, index,
isSelected, cellHasFocus);
}
});
setLayout(new BorderLayout());
add(new JScrollPane(carList));
carList.addListSelectionListener(new ListListener());
}
public Car getSelectedCar() {
return selectedCar;
}
private class ListListener implements ListSelectionListener {
#Override
public void valueChanged(ListSelectionEvent e) {
selectedCar = carList.getSelectedValue();
Window win = SwingUtilities.getWindowAncestor(CarGridPanel.this);
win.dispose();
}
}
}
No, Java doesn't have what you want.
Java is a general-purpose programming language, not a toolset, particularly not a specialized desktop GUI toolset. This is not a denigration of the language, just a statement of a purpose that it was not developed to fulfill.
If Delphi or Mono or anything has your particular widget, then I suggest you program in that, instead. This is not a denigration of you, just an observation that, if you do not want to put together the widget you want from lower-level components and code, then Java is not the right language/tool for you to use to do it.
As for not believing that Java "still requires" you to build your own component, I can only say that you don't get to choose which languages provide which features. I'm just as glad Java isn't littered with your component and the hundreds of others that people like you would come up with that they think Java should provide. It's big enough as it is.
I would like to create a new Swing JComponent based on an existing one, but with a different API. In other words, I don't want to extend the existing component, because I don't want it's API to be accessible.
Here an example to clarify my needs:
A replacement of the JCheckBox which show two buttons ON/OFF. This could be based on a pre-configured JCommandButtonStrip (some info here) but exposing exactly the same API of JCheckBox. The configuration of the JCommandButtonStrip must not be altered.
What is the best approach for such a problem?
Clarifications:
As someone pointed out, what I wrote about API is not clear.
Of course JComponent have a number of public fields and methods which will be available for each sub-class. Then each sub-class of JComponent may add its own public fields and methods. For example, AbstractButton adds the isSelected() method, while JCommandButtonStrip adds the getButtonCount() method.
So, what I meant is: I want to create a new JComponent sub-class MyJComponent, which is based on an existing one ExistingJComponent. I don't want the public methods of ExistingJComponent, except those of JComponent, to be exposed by my class MyJComponent. Then I want to add some public methods to MyJComponent.
Please note that I'm not looking for an alternative to the JCommandButtonStrip/JCheckBox example. I'm interested in a general approach to such a problem.
You can create a new class which extends JComponent then inside the constructor insert a checkbox into itself.
public class MyCoolCheckbox extends JComponent{
private JCheckBox checkbox;
public MyCoolCheckbox(String label) {
checkbox= new JCheckBox(label);
this.setLayout(new BorderLayout());
this.add(checkbox, BorderLayout.CENTER);
}
}
This is obviously incomplete and you may need to delegate certain methods to the child. It might get messy. IDEs like IntelliJ IDEA will generate all this for you if you hit alt-ins (by default) then delegate, then select the checkbox member and pick the entries you want to delegate. For example:
public void setForeground(Color fg) {
checkbox.setForeground(fg);
}
public void setBackground(Color bg) {
checkbox.setBackground(bg);
}
public Color getForeground() {
return checkbox.getForeground();
}
public Color getBackground() {
return checkbox.getBackground();
}
Keep in mind that because the child is within the Swing component tree, other code will have access to the children even though they are marked private.
((JCheckBox)myCoolCheckbox.getComponents()[0]).setSelected(true);
As shown here, you can use two instances of JToggleButton in a ButtonGroup to "show two buttons ON / OFF." The ButtonGroup causes only one button in the group to be selected at a time. The following change is illustrated:
private final JLabel label = new JLabel(" \u2713 ");
Based on this picture of JCommandButtonStrip:
I think you are looking for JToggleButton as #trashgod suggested, but I'm not sure about buttons group given the current description of your "problem". If you need buttons group then use it.
Anyway my answer points to this line:
This could be based on a pre-configured JCommandButtonStrip (some info
here) but exposing exactly the same API of JCheckBox.
Once again it's not clear if you're trying to do a buttons bar such as JCommandButtonStrip or you want to do something else. However you can make your own component extending from JComponent and delegate only those methods that are needed from the outside. For example let's say you want to do a buttons bar such as JCommandButtonStrip. Then you can have:
One class extending from JComponent: your buttons bar.
Another one providing an API to add "commands" to the buttons bar.
Note: There's already a JToolBar component which can perfectly be used without reinvent the wheel. The example below is just to show you that you can control the API offered to the developers.
MyCommandBar.java
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import javax.swing.AbstractButton;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JToggleButton;
import javax.swing.event.ChangeListener;
public class MyCommandBar extends JComponent {
private final JPanel content;
private final Map<String, CommandItem> map = new HashMap<>();
public MyCommandBar() {
super();
content = new JPanel(new GridLayout(1, 0));
content.setOpaque(false);
setLayout(new FlowLayout());
add(content);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics graphics = g.create();
graphics.setColor(getBackground());
graphics.fillRect(0, 0, getWidth(), getHeight());
graphics.dispose();
}
public void addCommandItem(String actionCommand, CommandItem commandItem) {
if(map.get(actionCommand) != null) {
removeCommandItem(actionCommand);
}
content.add(commandItem.getComponent());
map.put(actionCommand, commandItem);
}
public void removeCommandItem(String actionCommand) {
CommandItem commandItem = map.get(actionCommand);
if(commandItem != null) {
content.remove(commandItem.getComponent());
content.revalidate();
content.repaint();
map.remove(actionCommand);
}
}
public CommandItem getCommandItem(String actionCommand) {
return map.get(actionCommand);
}
public static class CommandItem {
public static final int TOGGLE_BUTTON_STYLE = 0;
public static final int CHECK_BOX_STYLE = 1;
public static final int DEFAULT_BUTTON_STYLE = 2;
private final AbstractButton component;
public CommandItem(String text, boolean state, Icon icon, int style) {
switch(style) {
case TOGGLE_BUTTON_STYLE : component = new JToggleButton(text, icon, state); break;
case CHECK_BOX_STYLE : component = new JCheckBox(text, icon, state); break;
default: component = new JButton(text, icon);
}
}
protected AbstractButton getComponent() {
return component;
}
public void addActionListener(ActionListener listener) {
component.addActionListener(listener);
}
public void addChangeListener(ChangeListener listener) {
component.addChangeListener(listener);
}
public void setAction(Action action) {
component.setAction(action);
}
}
}
Example of use
This code snippet shows how MyCommandBar class should be used:
MyCommandBar commandBar = new MyCommandBar();
commandBar.setBorder(BorderFactory.createLineBorder(Color.black, 1));
commandBar.addCommandItem("BOLD", new MyCommandBar.CommandItem("<html><b>Bold</b></html>", true, null, MyCommandBar.CommandItem.TOGGLE_BUTTON_STYLE));
commandBar.addCommandItem("ITALICS", new MyCommandBar.CommandItem("<html><i>Italics</i></html>", false, null, MyCommandBar.CommandItem.CHECK_BOX_STYLE));
commandBar.addCommandItem("UNDERLINE", new MyCommandBar.CommandItem("<html><u>Underline</u></html>", false, null, MyCommandBar.CommandItem.DEFAULT_BUTTON_STYLE));
And you'll see something like this:
You can create MyJComponent subclass of JComponent with a private field that references a forwarding class for ExistingComponent.
The interactions with ExistingComponent are done with the forwarding class through methods of MyJComponent, and you are free to add more methods to MyJComponent.
Please see Effective Java item 16, for the delegation pattern used with the forwarding class.
I have one org.eclipse.ui.dialogs.CheckedTreeSelectionDialog like below code.
final CheckedTreeSelectionDialog checkedTreeSelectionDialog = new
CheckedTreeSelectionDialog(new Shell(),new ActionLabelProvider(), new
ActionContentProvider());
ActionLabelProvider implements org.eclipse.jface.viewers.ILabelProvider and ActionContentProvider implements org.eclipse.jface.viewers.ITreeContentProvider
I have some elements initially selected and some are not in the CheckedTreeSelectionDialog.
When dialog is open, if I check the unchecked element, I want to show one message.
How can I do this?
Create a subclass of CheckedTreeSelectionDialog and add addCheckStateListener, use the below code.
// When user checks a checkbox in the tree
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.CheckedTreeSelectionDialog;
public class MyCheckedTreeSelectionDialog extends CheckedTreeSelectionDialog {
public MyCheckedTreeSelectionDialog(Shell parent, ILabelProvider labelProvider, ITreeContentProvider contentProvider) {
super(parent, labelProvider, contentProvider);
}
#Override
protected CheckboxTreeViewer getTreeViewer() {
CheckboxTreeViewer treeViewer = super.getTreeViewer();
treeViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
if (event.getChecked()) {
// Given element is checked
} else {
// Given element is un-checked
// Your message here
}
}
});
return treeViewer;
}
}
I would like to create my own Look and Feel and have derived the MetalLookAndFeel. I have setup a very basic configuration where all files are in the same directory and have not a package declaration:
MyLookAndFeel.java
import javax.swing.UIDefaults;
import javax.swing.plaf.basic.BasicLookAndFeel;
import javax.swing.plaf.metal.MetalLookAndFeel;
public class MyLookAndFeel extends MetalLookAndFeel {
public MyLookAndFeel() {
setCurrentTheme(new DefaultMetalTheme());
}
#Override
protected void initClassDefaults(UIDefaults table) {
super.initClassDefaults(table);
table.put( "ButtonUI", "MyButtonUI");
}
#Override
public String getName() {
return "MyLookAndFeel";
}
#Override
public String getID() {
return "MyLookAndFeel";
}
#Override
public String getDescription() {
return "MyLookAndFeel";
}
#Override
public boolean isNativeLookAndFeel() {
return false;
}
#Override
public boolean isSupportedLookAndFeel() {
return true;
}
}
And we also have the MyButtonUI.java:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import javax.swing.AbstractButton;
import javax.swing.JComponent;
import javax.swing.plaf.metal.MetalButtonUI;
public class MyButtonUI extends MetalButtonUI {
#Override
public void paint(Graphics g, JComponent c) {
}
#Override
protected void paintButtonPressed(Graphics g, AbstractButton b) {
g.fillRect(0, 0, 40, 40);
}
#Override
protected void paintText(Graphics g, AbstractButton b, Rectangle textRect,
String text) {
}
}
With the above code I expect that a weird button is going to be painted (or no button at all since the paint method is empty) when I run the TestUI JFrame class with this constructor, but the button looks quiet normal:
public TestUI() throws UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(new MyLookAndFeel());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(200,200);
setLayout(new FlowLayout());
add(new JButton("Press"));
add(new JLabel("Text"));
setVisible(true);
}
Have I forgotten something important?
"MyButtonUI" should be full path (same as for Icon packaged in jar) or valid class name e.g. UIManager.put("ButtonUI", MyButtonUI.class.getName());
override BasicButtonUI, with interfaces to another LaFs, can be empty, without override all methods for all System LaFs, instead of MetalButtonUI, your custom MetalButtonUI is so LaF sensitive, breakable, in the case that is registred in UIManager
maybe will help you partial workaround for MetalButtonUI, maybe there isn't reason to register custom UI to UIManager, sure final decision is up tu you
In your class MyButtonUI you have to implement a public static method createUI(). Like this:
public static ComponentUI createUI(JComponent c)
{
return new MyButtonUI ();
}
Or return one shared instance for all the buttons.