I'm having issues giving focus to a JScrollPane. I'm trying to do this when the window is created so that I can try out the key bindings I'm working on. Everything shows up where it's supposed to be and at the correct size. What I've got looks like this:
import java.awt.*;
import java.swing.*;
public class MyInterface extends JFrame {
public MyInterface() {}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI() {
// define custom table model
JTable table = new JTable(model);
MyScrollPane scrollPane = new MyScrollPane(table);
MyInterface frame = new MyInterface();
scrollPane.setPreferredSize(new Dimension(512, 512));
frame.getContentPane().add(scrollPane);
frame.pack();
frame.setVisible();
scrollPane.requestFocus();
}
}
public class MyScrollPane extends JScrollPane implements KeyListener {
public MyScrollPane(Component view) {
super(view, ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
}
// key event processing
}
I tried adding a window listener to the frame which would request focus for scrollPane after the window was finished opening, but it didn't help. Any ideas?
EDIT: Thought I should mention that scrollPane.isFocusable() and scrollPane.isRequestFocusEnabled both return true, so I should be able to give it focus.
EDIT: It seems I'm unable to give focus to anything (frame, table, etc.), so there's some other problem here. No matter what I try, this displays null:
Component compFocusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
System.out.println("focus owner: " + compFocusOwner);
I think that not possible to set the Focus to the JScrolPane, but set Focus to the JComponent, which is place into JScrolPane couldn't be problem
Runnable doRun = new Runnable() {
#Override
public void run() {
myComponent.requestFocus();//requestFocusInWindow
myComponent.grabFocus();
}
};
SwingUtilities.invokeLater(doRun);
Why do you need this? I think you should set focus on the component inside the JScrollPane. How do you detect that the focus isn't there? Scrollpane itself has no visible part (may be just 1 pixel frame is visible).
As noted in How to Use Key Bindings: How Key Bindings Work, composite components typically use the WHEN_ANCESTOR_OF_FOCUSED_COMPONENT map. You can even add bindings to the top-level component's root pane, as shown in Key Bindings.
I've no clue what the problem was; for lack of a better idea I deleted and retyped everything, and now it works. It is possible to focus a JScrollPane, in case anyone reading this wishes to. I assumed it was possible, since by default both .isFocusable() and isRequestFocusEnabled() are set to true. But yeah, I have no idea; at the very least I got a few good links for key binding. Thanks for the help!
Related
I want my button to run a whole new class that will do different things inside. I don't know if that is even possible cause i'm really bad at java. My code looks like this at the moment:
public class MainMenu {
private class GardenActivities {
public GardenActivities() {
JFrame GardenAct = new JFrame();
GardenAct.setSize(400, 400);
GardenAct.setVisible(true);
}
}
public static void main(String[] args) {
JFrame choice = new JFrame();
choice.setSize(700, 500);
choice.setLocationRelativeTo(null);
choice.setTitle("Seeds");
choice.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
panel.setLayout(new GridLayout(0, 1));
JButton Labora = new JButton();
Labora.setText("Laboratory");
Labora.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
GardenActivities();
}
});
JButton Garden = new JButton();
Garden.setText("Garden");
Garden.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
}
});
choice.getContentPane().add(panel);
ButtonGroup group = new ButtonGroup();
group.add(Garden);
group.add(Labora);
panel.add(Garden);
panel.add(Labora);
choice.setVisible(true);
}
}
Just like I said. I need something to run my GardenActivities class just by pressing Garden button.
Your code doesn't compile, does it? When that happens, you need to post compilation errors with your question so that we can help you with them.
You need to add the key word new before the GardenActivities() statement.
#Override
public void actionPerformed(ActionEvent ev) {
new GardenActivities(); // here
}
Also, put the GardenActivities in its own file. There's no reason for making it a private inner class and many reasons not to do this.
Having said this, I recommend against having one JFrame create and display another JFrame since an application should have usually only one JFrame. Instead consider swapping JPanel "views" using a CardLayout, or if you must show a different window, consider showing the second dependent window as a modal or non-modal dialog.
Also more unsolicited advice: Your main method is doing way too much. Most of the code inside of the static main method should go inside the non-static main gui class, whatever that is, perhaps in its constructor or in an initGui() method that the constructor calls. The main method should just create an instance of the main gui class, make it visible, and that's about it.
And regarding:
I don't know if that is even possible cause i'm really bad at java.
Keep writing lots and lots of code, a ton of code, and keep reviewing tutorials and textbooks, and this will change.
I think that you just need to add:
new GardenActivities();
Into your JButton's actionPerformed() method.
Good Luck!
One way to do what you want, we make the GardenActivities class implement ActionListener itself.
Then your code would look something like this:
Garden.addActionListener(new GardenActivities());
Otherwise, your plan should work.
NOTE
See comments for opposing opinions about why one would want to leave the ActionListener in the anonymouse inner class and have it call into GardenActivities.
Thank you #HovercraftFullOfEels
As others have pointed out, this:
#Override
public void actionPerformed(ActionEvent ev)
{
GardenActivities();
}
Should look like:
#Override
public void actionPerformed(ActionEvent ev)
{
new GardenActivities();
}
There is no reason to create an inner class, and GardenActivities can be, and should be, its own class.
I am writing a simple java snake-like game, and I ran into a problem even before I actually got to making the game. I can't seem to get input from the keyboard for some reason. My current code is:
public class GameWindow extends JFrame{
private SnakeCanvas snakeCanvas;
public GameWindow(StartWindow sw) {
getContentPane().addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
JOptionPane.showMessageDialog(null, "Key Pressed!");
}
});
getContentPane().setBackground(Color.BLACK);
this.setExtendedState(JFrame.MAXIMIZED_BOTH);
this.setUndecorated(true);
this.setVisible(true);
getContentPane().setLayout(null);
snakeCanvas = new SnakeCanvas();
snakeCanvas.setBounds(78, 72, 290, 195);
getContentPane().add(snakeCanvas);
snakeCanvas.setVisible(true);
snakeCanvas.repaint();
}
}
(a SnakeCanvas extends JPanel and has no other components on it)
I've tried also adding a key listener to the snakeCanvas and still no effect..
I've also tried to play with the focusable and the focus Traversal stuff but that also didn't do anything...
Can anyone please explain to me what I'm doing wrong?
Make sure you have set the components you want to receive keyboard events is focusable (setFocusable) & has focus (requestFocus)
KeyListener isn't proper listener for Swing JComponents, required focus in the window
you have to setFocusable for container
right and correct way is usage of KeyBindings, for example
I have a subclass of JFrame that uses a class extended from JPanel
public class HelloWorld extends JPanel implements KeyListener
I add an object of HelloWorld to the frame - app.add(helloWorld);. Now, when I press any keyboard key non of the KeyListener methods gets called and it seems that helloWorld doesn't have window focus. I have tried also to invoke helloWorld.requestFocusInWindow(); but still doesn't respond.
How can I make it respond to key press?
Did you set that KeyListener for your HelloWorld panel would be that panel itself? Also you probably need to set that panel focusable. I tested it by this code and it seems to work as it should
class HelloWorld extends JPanel implements KeyListener{
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped: "+e);
}
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed: "+e);
}
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased: "+e);
}
}
class MyFrame extends JFrame {
public MyFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200,200);
HelloWorld helloWorld=new HelloWorld();
helloWorld.addKeyListener(helloWorld);
helloWorld.setFocusable(true);
add(helloWorld);
setVisible(true);
}
public static void main(String[] args) {
new MyFrame();
}
}
JPanel is not Focusable by default. That is, it can not respond to focus related events, meaning that it can not respond to the keyevents.
I would suggest trying to setFocusable on the pane to true and trying again. Make sure you click the panel first to make sure it receives focus.
Understand though, you WILL get strange focus traversal issues, as the panel will now receive input focus as the user navigates through your forms, making it seem like the focus has been lost some where.
Also, KeyListeners tend to be unreliable in this kind of situation (due to the way that the focus manager works).
simple you have to add
addKeylistener(new HelloWorld());
add this in MyFrame method;
HelloWorld() helloWorld = new HelloWorld();
this.addKeyListener(helloWorld);
I have written the following example code:
import org.jdesktop.swingx.*;
import javax.swing.*;
import java.awt.*;
public class TaskPaneExample{
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new TaskPaneExample();
}});
}
public TaskPaneExample() {
JFrame frame = new JFrame("TaskPane Example 1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(doInit(), BorderLayout.CENTER);
frame.setLocationRelativeTo(null);
frame.pack();
frame.setVisible(true);
}
private Component doInit() {
JXTaskPaneContainer taskpanecontainer = new JXTaskPaneContainer();
taskpanecontainer.setLayout(new VerticalLayout(2));
final JXTaskPane taskpane1 = new JXTaskPane(){
public void setCollapsed(boolean w){
super.setCollapsed(w);
}};
taskpane1.setTitle("First TaskPane");
JPanel panel1 = new JPanel();
panel1.setBackground(Color.red);
panel1.setSize(100,100);
taskpane1.add(panel1);
taskpanecontainer.add(taskpane1);
JXTaskPane taskpane2 = new JXTaskPane(){
public void setCollapsed(boolean w){
super.setCollapsed(w);
}};
taskpane2.setTitle("My Tasks");
JPanel panel2 = new JPanel();
panel2.setBackground(Color.blue);
panel2.setSize(100,100);
taskpane2.add(panel2);
taskpanecontainer.add(taskpane2);
taskpanecontainer.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
return taskpanecontainer;
}
}
}
What I need are two things:
how do I change the bgcolor of the title? I think it is done with the taskpane2.setUI(..) option but I had no luck working with it.
how to set the border between the JXTaskPane and the Jpanel to zero?
Originally, the JXTaskPane was designed as a kind of "fixed-properties" component - it should look exactly like the corresponding native component (then of WinXP): custom appearance wasn't meant to be supported. As a consequence, the implementation of the title/border is deeply hidden in the XXTaskPaneUI - actually, everything boils down to be a Border.
1) as dogbane already mentioned, some of the properties can be changed on a per-application basis. Just beware: those are implementation details which might change or not be supported by concrete ui implementations (Nimbus is always a good candidate to not respecting them, even our not-really-synth implementation might not, forgot)
2) the "gap" is the border of the contentPane, you can set your own. Again a beware: might not survive an updateUI (could be that the ui delegates override them unconditionally, if so, please file an issue in the SwingX issuetracker)
((JComponent) taskpane2.getContentPane()).setBorder(BorderFactory.createEmptyBorder());
BTW: those panel.setSize have exactly no effect - layoutManagers rule ;-)
To change the bgcolour of the title, you can try setting the start and end background gradient colours in the UIManager:
UIManager.put("TaskPane.titleBackgroundGradientStart", Colors.White.color());
UIManager.put("TaskPane.titleBackgroundGradientEnd", Color.GREEN);
I also found an open swingx jira task for this: SWINGX-731 Support to define the color to JXTaskPane header.
Ok, I have a Java program, that displays some tiles that are SVGs in a FlowLayout. It does this by being a class ScrabbleRack, and extending JPanel, then adding JSVGCanvas tiles to this panel.
Afterwards I created a frame and added the panel, this. (packed it and displayed it). On appearing, the panel does not display properly. It just displays the first tile and then in the space where the rest of the tiles should be displayed, there is whitearea.
But if I resize the frame by any amount, the image will render correctly.
public class ScrabbleRackGUI extends JPanel{
ScrabbleRack rack=new ScrabbleRack();
JSVGCanvas rackContentsImages[]=new JSVGCanvas[8];
public ScrabbleRackGUI() {
setLayout(new FlowLayout());
createComponents();
}
public void createComponents() {
//INITIALISE SOURCE IMAGES
initImages();
for (int i=0;i<rackContentsImages.length;i++){
this.add(rackContentsImages[i]);
}
}
private void initImages(){
File tempImages[]=new File[8];
for(int i=0;i<8;i++){
tempImages[i]= new File("./src/res/rackBackground.svg");
rackContentsImages[i]=new JSVGCanvas();
try {
rackContentsImages[i].setURI(tempImages[i].toURL().toString());
} catch (MalformedURLException ex) {
Logger.getLogger(ScrabbleBoardGUI.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public static void main(String args[])
{
JFrame frame = new JFrame("ScrabbleTest");
ScrabbleRackGUI rack= new ScrabbleRackGUI(1);
frame.add(rack);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setSize(214,70);
frame.setVisible(true);
}
}
Any ideas on how I can get this panel to display properly, first time.
Or some hack that will resize it at the end of the program.
I used batik to render the SVGs in Java, for those who want to reproduce this problem.
You problem may be that the construction of your GUI is not being done on the EDT.
Your main should look something like:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyWindow window = new MyWindow();
MyWindow.setVisible(true);
}
});
}
and the rest of your code in your current main should be in the MyWindow constructor.
More detailed information can be found at http://leepoint.net/JavaBasics/gui/gui-commentary/guicom-main-thread.html (among other places)
This might be related to Batik issue 35922 reported here: https://issues.apache.org/bugzilla/show_bug.cgi?id=35922
If I understand that bug report correctly, you can workaround the problem by adding the JSVGCanvas instances (and the ScrabbleRackGUI instance) and calling pack() first, and then set the URIs on each JSVGCanvas.
First of all, you wrote:
ScrabbleRackGUI rack= new ScrabbleRackGUI(1);
and you don't have constructor that takes int.
Secondly, you're setting FlowLayout to JPanel component, and JPanel by default has FlowLayout as layout. better call super(); to get all the benefits of JPanel.
Try to run your application inside of Event Dispatching Thread (EDT), as others mentioned already.
SwingUtilities.invokeLater(new Runnable() {
// your code here
}
Also you should set your URI like this:
setURI(f.toURI().toURL().toString());
because f.toURL() is deprecated.
I hope it helps.