Unexpected change in background of header of custome jcombobox in swing - java

I try to make a custom jcombobox for my menu sidebar
my jcombobox has JButton as items because I found it easy to insert and align icon and text.
But my problem is when I choose a item in dropdown, the color of the header changes unexpectedly to the default color of component.
public class MyComboBoxRenderer extends JLabel implements ListCellRenderer<Object> {
private String _title;
private JButton header;
public MyComboBoxRenderer(String title) {
_title = title;
}
#Override
public Component getListCellRendererComponent(JList<?> list, Object value,
int index, boolean isSelected, boolean hasFocus) {
JButton item = new JButton();
item.setOpaque(true);
item.setBorderPainted(false);
item.setFocusPainted(false);
item.setBackground(isSelected ? Frame.LIGHTER_COLOR : Frame.LIGHT_COLOR );
ImageIcon dot = new ImageIcon("image/icon/orange_dot.png");
if (index == -1){
item.setText(_title);
header=item;
return item;
}
else{
item.setIcon(dot);
item.setIconTextGap(30);
item.setText(value.toString());
return item;
}
}
public JButton getHeader(){
return header;
}
}
public static class MyComboBoxUI extends BasicComboBoxUI {
final JButton button= new JButton(EXPAND_ARROW);
protected void installDefaults() {
super.installDefaults();
}
#Override
protected JButton createArrowButton() {
button.setContentAreaFilled(false);
button.setBorder(null);
return button;
}
#Override
public void configureArrowButton() {
super.configureArrowButton();
}
public JButton getArrowButton(){
return button;
}
}
public class ComboBox extends JComboBox{
public boolean isExpanded = false;
private MyComboBoxRenderer renderer;
public ComboBox(){
super();
this.setUI(new MyComboBoxUI());
}
public ComboBox(String[] list){
super(list);
renderer = new MyComboBoxRenderer("Lists Of Vocab");
this.setUI(new MyComboBoxUI());
this.setFont(Frame.I_FONT);
this.setForeground(Frame.FONT_COLOR);
this.setBackground(Frame.LIGHT_COLOR);
this.setRenderer(renderer);
MyComboBoxUI ui = (MyComboBoxUI) this.getUI();
JButton arrowButton = ui.getArrowButton();
arrowButton.addActionListener((ActionEvent e)->{
isExpanded = !isExpanded;
if(isExpanded == true){
arrowButton.setIcon(COLLAPSE_ARROW);
}
else{
arrowButton.setIcon(EXPAND_ARROW);
}
});
}
public MyComboBoxRenderer getRenderer(){
return renderer;
}
I add this combobox to the sideBar
private void addCheckBoxToSideBar(){
ComboBox lists = new ComboBox(listNames);
lists.setAlignmentX(Component.LEFT_ALIGNMENT); // have to have
lists.addItemListener(new ItemListener(){
#Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
CardLayout cl = (CardLayout)(mainPane.getLayout());
cl.show(mainPane, (String)e.getItem());[enter image description here][1]
}
}
});
sideBar.add(lists);
}
This is first:
https://i.stack.imgur.com/ctVnT.png
But when I click to choose an item, it changes to default color:
https://i.stack.imgur.com/KkhhO.png
Those are what I tried but they didn't work:
to set the background of the header in the itemStateChanged
get the JTextfield of BasicComboBoxEditor of it
I wonder whether updating UI causes this problem but I don't understand much about it.

In your MyComboBoxUI, try overriding this method :
#Override
public void paintCurrentValueBackground(Graphics g,Rectangle bounds,boolean hasFocus)
{
Color t = g.getColor();
g.setColor(your_color);
g.fillRect(bounds.x,bounds.y,bounds.width,bounds.height);
g.setColor(t);
}

Related

How to add a button inside a table cell in java netbeans? (I am using the drag and drop method.)

I am trying to add a button inside a table cell. I am using the drag and drop method of netbeans since I know nothing about coding and will appreciate if you can teach me to code it. Thanks!
If you are using drag&drop in netbean for swing,
I highly advise you to touch the fundamental of swings , get your hands dirty so that you will know what is going on and how does the code work.
let me run through how you can achieve this. it will consist of 3 classes so that you will have a better understanding on what is going on and it practices oop too but of cause you can modify it to your preferred design pattern.
_main.java
public class _main extends JFrame{
private static final long serialVersionUID = 1L;
// Create new JFrame
_main(){
new JFrame("Main");
setLayout(new BorderLayout());
setSize(500,300);
add(new JLabel("Table Example ", SwingUtilities.CENTER) , BorderLayout.PAGE_START);
// ---------------- Call the method you have created in tableView.java ------------
add(new JScrollPane(new tableView(this).sampleTable()), BorderLayout.CENTER);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args){
//Run Program
new _main();
}
}
tableView.java
public class tableView {
JFrame frame = new JFrame();
public tableView(JFrame frame) {
this.frame = frame;
}
//Create columnTitle & Table Model
String[] columnTitle = { "Data 1", "Data 2", "Data 3", "Buttons " };
DefaultTableModel model = new DefaultTableModel(columnTitle, 0);
public JTable sampleTable(){
JTable _dataTable = new JTable(model) {
#Override
public void updateUI() {
super.updateUI();
setRowHeight(34);
setAutoCreateRowSorter(true);
//------------ Placing button at your desired column ------------
TableColumn column;
column = getColumnModel().getColumn(3);
column.setCellRenderer(new tableModel(frame).new viewRenderer());
column.setCellEditor(new tableModel(frame).new ButtonsEditorView(this));
}
};
DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer();
centerRenderer.setHorizontalAlignment(JLabel.CENTER);
//-------- Adding data to your table row , use for loop for multiple data ---------
model.addRow(new Object[]{"1","2","3"});
return _dataTable;
}
}
tableModel.java
public class tableModel extends tableView{
public tableModel(JFrame frame) {
super(frame);
}
class viewButton extends JPanel {
public JButton viewbtnp = new JButton("View");
protected viewButton() {
setOpaque(true);
setFocusable(false);
add(viewbtnp);
}
}
class viewRenderer implements TableCellRenderer {
private final viewButton panel = new viewButton() {
#Override
public void updateUI() {
super.updateUI();
setName("Table.cellRenderer");
}
};
#Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
panel.setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return panel;
}
}
class ViewAction extends AbstractAction {
private final JTable table;
protected ViewAction(JTable table) {
super("view");
this.table = table;
}
#Override
public void actionPerformed(ActionEvent e) {
//--------------------------- Create your own function on what you want the button to do when button is clicked -------------
System.out.println("Clicked ");
}
}
class ButtonsEditorView extends AbstractCellEditor implements TableCellEditor {
protected final viewButton panel = new viewButton();
protected final JTable table;
protected ButtonsEditorView(JTable table) {
super();
this.table = table;
panel.viewbtnp.setAction(new ViewAction(table));
}
#Override
public Component getTableCellEditorComponent(JTable tbl, Object value, boolean isSelected, int row,
int column) {
panel.setBackground(tbl.getSelectionBackground());
return panel;
}
#Override
public Object getCellEditorValue() {
return "";
}
}
}
Output
Hope it helps.
Cheers

How to set image and text on JRadioButton?

I am using Swing and JRadioButton in my application. I need to set image and text on my button. For that I am using this:
JRadioButton button1 = new JRadioButton("text", iconpath, false);
But what it giving output is it's hiding radio button and just showing the image.
How to over come this problem, any suggestion? and can we Create something for similar problem for JCheckbox too?
Setting the icon of a JRadioButton or JCheckBox replaces the default glyph used by these controls - I know, annoying.
The simplest solution is to simply create a JLabel which can be associated with the JRadioButton, perhaps using some kind of Map to maintain the linkage between
A more, long term solution, might be to create a custom component which marries the concept into a custom and re-usable component, for example...
public class XRadioButton extends JPanel {
private JRadioButton radioButton;
private JLabel label;
public XRadioButton() {
setLayout(new GridBagLayout());
add(getRadioButton());
add(getLabel());
}
public XRadioButton(Icon icon, String text) {
this();
setIcon(icon);
setText(text);
}
protected JRadioButton getRadioButton() {
if (radioButton == null) {
radioButton = new JRadioButton();
}
return radioButton;
}
protected JLabel getLabel() {
if (label == null) {
label = new JLabel();
label.setLabelFor(getRadioButton());
}
return label;
}
public void addActionListener(ActionListener listener) {
getRadioButton().addActionListener(listener);
}
public void removeActionListener(ActionListener listener) {
getRadioButton().removeActionListener(listener);
}
public void setText(String text) {
getLabel().setText(text);
}
public String getText() {
return getLabel().getText();
}
public void setIcon(Icon icon) {
getLabel().setIcon(icon);
}
public Icon getIcon() {
return getLabel().getIcon();
}
}

Updating label of a ButtonField from PopupScreen

I have a ButtonField on MainScreen, from which I am pushing a PopupScreen where I have added an ObjectListfield. What I want to do is to update the label of ButtonField on MainScreen with the element selected from ObjectListfield of PopupScreen.
Please tell me if it is possible to do without using Dialog class (I really want to use PopupScreen and not Dialog class) and the method by which this can be done. I'd appreciate if some sample code will be provided.
I have added my code.
public final class MyScreen extends MainScreen {
HorizontalFieldManager hfm;
ButtonField btn;
public MyScreen() {
// Set the displayed title of the screen
super();
setTitle("MyTitle");
btn = new ButtonField("label",ButtonField.CONSUME_CLICK);
final mypopup mps = new mypopup();
btn.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field,int context) {
UiApplication.getUiApplication().pushModalScreen(mps);
}
});
hfm = new HorizontalFieldManager();
hfm.add(btn);
add(hfm);
}
public void setlabel(String labelnew) {
btn.setLabel(labelnew);
}
public String getlabel() {
return this.btn.getLabel();
}
}
class mypopup extends PopupScreen implements FieldChangeListener {
String it;
ObjectListField obj = new ObjectListField() {
public boolean navigationClick(int status,int time) {
int selectedindex=obj.getSelectedIndex();
it=(String)obj.get(obj, selectedindex);
UiApplication.getUiApplication().popScreen(UiApplication.getUiApplication().getActiveScreen());
/*MyScreen my=new MyScreen();
my.btn.setLabel(it);
my.invalidate(); */
//close();
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
/* This im doing to see that setlabel and getlabel are
working properly */
MyScreen my=new MyScreen();
my.setlabel(it);
String gt=my.getlabel();
Dialog.alert(gt);
my.hfm.invalidate();
//the label of button is changed but not updating in mainscreen.
}
});
return true;
}
};
public mypopup() {
super(new VerticalFieldManager());
String[] type=new String[] {"a","b","c","d"};
obj.set(type);
add(obj);
}
public void fieldChanged(Field field, int context) {
// TODO Auto-generated method stub
}
}
You need to change following block of code,
MyScreen my = new MyScreen();
my.setlabel(it);
String gt = my.getlabel();
Dialog.alert(gt);
my.hfm.invalidate();
With the code block,
Screen scr = UiApplication.getUiApplication().getActiveScreen();
if (scr instanceof MyScreen) {
MyScreen my = (MyScreen) scr;
my.setlabel(it);
my.invalidate();
}
Add the button in one Manager either HorizontalFieldManager or VerticalFieldManager and after setting text on button invalidate the managerlike this way
public final class MyScreen extends MainScreen
{
ButtonField btn;
public MyScreen()
{
// Set the displayed title of the screen
super();
setTitle("MyTitle");
btn=new ButtonField("label",ButtonField.CONSUME_CLICK);
final mypopup mps=new mypopup();
btn.setChangeListener(new FieldChangeListener()
{
public void fieldChanged(Field field,int context){
UiApplication.getUiApplication().pushModalScreen(mps);
}
});
HorizontalFieldManager hfmToholdButtons = new HorizontalFieldManager();
btn.setLabel(mps.gettext());
hfmToholdButtons.add(btn);
hfmToholdButtons.invalidate();
}
}

Dragging node from JTree and dropping onto JLabel to perform an action

I want to implement DnD on my system by dragging a node from a JTree and dropping it onto a JLabel.
The JLabel is an Icon with certain properties about a machine, and by dragging the information from the JTree node onto the JLabel I want it to be able to send a message to a client listening on that machine.
Any help is much appreciated!
Example of label method:
private void makeLabel(String html, final String version) {
// Create a button to link to the DR environment
//JButton button = new JButton(html);
JLabel machineLabel = new JLabel();
machineLabel.setTransferHandler(new TransferHandler("text"));
MouseListener listener = new DragMouseAdapter();
machineLabel.addMouseListener(listener);
machineLabel.setIcon(onlineIcon);
machineLabel.setToolTipText("IP: " + html);
//Add the button to the panel and make sure it appears
machineLabel.setSize(25, 10);
vecIcons.addElement(machineLabel);
buttonPanel.add(machineLabel);
buttonPanel.setVisible(true);
buttonPanel.validate();
dynaScrollPane.validate();
buttonPanel.repaint();
dynaScrollPane.repaint();
}
DragMouseAdapter method:
private class DragMouseAdapter extends MouseAdapter {
public void mousePressed(MouseEvent e) {
JComponent c = (JComponent) e.getSource();
TransferHandler handler = c.getTransferHandler();
handler.exportAsDrag(c, e, TransferHandler.LINK);
}
}
Then in order to make my tree draggable I just have:
exampleTree.setDragEnabled(true);
not sure I understand your setup: assuming you want the label to be a drop target, simply implement a custom Transferhandler which accepts the dataflavour as exported by the tree and do something with it
EDIT
To get hold of the TreePath use a custom Transferhandler on the tree as well: override its createTransferable which returns the TreePath:
final DataFlavor flavor =new DataFlavor(TreePath.class, "treePath");
TransferHandler treeHandler = new TransferHandler() {
DataFlavor[] pathFlavour = new DataFlavor[]
{flavor};
/**
* #inherited <p>
*/
#Override
protected Transferable createTransferable(JComponent c) {
JTree tree = (JTree) c;
final TreePath path = tree.getSelectionPath();
Transferable transferable = new Transferable() {
#Override
public DataFlavor[] getTransferDataFlavors() {
return pathFlavour;
}
#Override
public boolean isDataFlavorSupported(DataFlavor flavor) {
return pathFlavour[0].equals(flavor);
}
#Override
public Object getTransferData(DataFlavor flavor)
throws UnsupportedFlavorException, IOException {
return path;
}
};
return transferable;
}
public int getSourceActions(JComponent c) {
return COPY;
}
};
tree.setTransferHandler(treeHandler);
JLabel labelTarget = new JLabel("I'm a drop target!");
TransferHandler labelHandler = new TransferHandler() {
/**
* #inherited <p>
*/
#Override
public boolean importData(JComponent comp, Transferable t) {
try {
LOG.info("import from: " + t.getTransferData(flavor));
} catch (Exception e) {
e.printStackTrace();
}
return true;
}
/**
* #inherited <p>
*/
#Override
public boolean canImport(JComponent comp,
DataFlavor[] transferFlavors) {
return true;
}
};
labelTarget.setTransferHandler(labelHandler);
no need for an additional mouseListener

How would I go about highlighting an item in a JList? [duplicate]

I am trying to change JList rows dynamically. I need change nth row colour, highlight it(n is unknown during compilation). I saw a lot of examples with custom ListCellRenderer, but all were "static".
In other words I have JList with x rows. During runtime my "business logic" detects nth row is important. So I want make its background green, wait one second, and then make it white again. One more thing, don't wan change row selection.
What is the best way to do so?
Simple, set a custom ListCellRenderer to your JList using:
list.setCellRenderer(myListCellrenderer);
Now inside the overridden method getListCellRendererComponent() do something like this:
public Component getListCellRendererComponent(.....) {
Component c = super.getListCellRendererComponent();
c.setBackGround(Color.blue)
return c;
}
The above example assumed that your custom renderer overrid DefaultListCellRenderer
Based on ListDemo sample from SUN.
If you enter some text in the textfield which isn't in the list and you hit highlight it gets added.
If the text is in the list and you hit highlight the entry in the list gets temporarily highlighted blue.
Note the solution here with the match field is just for demo. For more correct implementation consider the other ideas proposed and consider using javax.swing.Timer
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class ListDemo extends JPanel {
private JList list;
private DefaultListModel listModel;
public String match = null;
private static final String hireString = "Highlight";
private JTextField employeeName;
public ListDemo() {
super(new BorderLayout());
listModel = new DefaultListModel();
listModel.addElement("Test1");
listModel.addElement("Test2");
listModel.addElement("Test3");
list = new JList(listModel);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setSelectedIndex(0);
list.setVisibleRowCount(5);
list.setCellRenderer(new MyListCellRenderer());
JScrollPane listScrollPane = new JScrollPane(list);
JButton hireButton = new JButton(hireString);
HireListener hireListener = new HireListener(hireButton);
hireButton.setActionCommand(hireString);
hireButton.addActionListener(hireListener);
hireButton.setEnabled(false);
employeeName = new JTextField(10);
employeeName.addActionListener(hireListener);
employeeName.getDocument().addDocumentListener(hireListener);
listModel.getElementAt(list.getSelectedIndex()).toString();
JPanel buttonPane = new JPanel();
buttonPane.setLayout(new BoxLayout(buttonPane,
BoxLayout.LINE_AXIS));
buttonPane.add(Box.createHorizontalStrut(5));
buttonPane.add(employeeName);
buttonPane.add(hireButton);
buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
add(listScrollPane, BorderLayout.CENTER);
add(buttonPane, BorderLayout.PAGE_END);
}
class MyListCellRenderer extends JLabel implements ListCellRenderer {
public MyListCellRenderer() {
setOpaque(true);
}
public Component getListCellRendererComponent(JList paramlist, Object value, int index, boolean isSelected, boolean cellHasFocus) {
setText(value.toString());
if (value.toString().equals(match)) {
setBackground(Color.BLUE);
SwingWorker worker = new SwingWorker() {
#Override
public Object doInBackground() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) { /*Who cares*/ }
return null;
}
#Override
public void done() {
match = null;
list.repaint();
}
};
worker.execute();
} else
setBackground(Color.RED);
return this;
}
}
class HireListener implements ActionListener, DocumentListener {
private boolean alreadyEnabled = false;
private JButton button;
public HireListener(JButton button) {
this.button = button;
}
public void actionPerformed(ActionEvent e) {
String name = employeeName.getText();
if (listModel.contains(name)) {
match = name;
list.repaint();
employeeName.requestFocusInWindow();
employeeName.selectAll();
return;
}
if (name.equals("")) {
Toolkit.getDefaultToolkit().beep();
employeeName.requestFocusInWindow();
employeeName.selectAll();
return;
}
int index = list.getSelectedIndex();
if (index == -1)
index = 0;
else
index++;
listModel.insertElementAt(employeeName.getText(), index);
employeeName.requestFocusInWindow();
employeeName.setText("");
list.setSelectedIndex(index);
list.ensureIndexIsVisible(index);
}
public void insertUpdate(DocumentEvent e) {
enableButton();
}
public void removeUpdate(DocumentEvent e) {
handleEmptyTextField(e);
}
public void changedUpdate(DocumentEvent e) {
if (!handleEmptyTextField(e))
enableButton();
}
private void enableButton() {
if (!alreadyEnabled)
button.setEnabled(true);
}
private boolean handleEmptyTextField(DocumentEvent e) {
if (e.getDocument().getLength() <= 0) {
button.setEnabled(false);
alreadyEnabled = false;
return true;
}
return false;
}
}
private static void createAndShowGUI() {
JFrame frame = new JFrame("ListDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JComponent newContentPane = new ListDemo();
newContentPane.setOpaque(true);
frame.setContentPane(newContentPane);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() { createAndShowGUI(); }
});
}
}
Your custom ListCellRenderer, which implements the method getListCellRendererComponent, will have access to both the JList and the value that it is redering. This gives you a couple options for how to determine when to paint the nth row green:
You could subclass JList and have the renderer ask it which color to use for the bg. The JList subclass could trigger a repaint when the business logic determines that it is time for the nth row to be green, and then start an Swing Timer to trigger a repaint returning the bg back to normal
When the business logic determines when you should show the row as green, you also have the option of setting state on the backing object of the row, and test it for that state within getListCellRendererComponent, setting the bg green if the state is correct. Again, you have the option of setting an Swing Timer to revert the state on the backing object.

Categories