英文:
How can part of JComponent be obscured from Mouseevents? E.g. some region of JButton not reacting, rest is fine
问题
这个问题花费了我很多时间来识别,现在我很好奇是什么导致了这种奇怪的行为:
在这个示例中,有一个显示JPanel "page"的JFrame类,该JPanel本身引用了"parent" JFrame。
我的错误是在构建对象的过程中这样做的。
令人惊讶的是,在某些情况下,"page"上的JComponents(如JButtons、JRadioButtons、JCHeckboxes等)有时对鼠标的反应很好,有时根本不反应,有时只有一小部分表面可以工作。
所以我尝试在下面的最小示例中隔离它,我可以在JRE 1.8、JRE12和JRE13上的Windows 7 x64和Windows 10 x64上演示它。
为了重现这个问题,您可能需要调整按钮大小与JFrame.setSize()
。
在我的系统上,按钮对鼠标的反应非常好,有一些mouseEntered
的动画,鼠标点击将触发ActionEvent
。
但不是在按钮的右下角的固定大小区域。如果你用鼠标去那里,不会触发任何事件。
这个"死区"的大小在窗口大小和组件大小的变化下保持不变,您可以尝试在"page"代码中使用不同的LayoutManagers
。
其他触发事件的JComponents也是如此。
我的问题是:为什么ActionListening-System存在问题。如果监听完全破损或根本没有,那将更直观。
从答案中,我希望更多地了解JComponents中鼠标事件生成的内部情况,以便将来在我的程序中更加警惕。
这是主要的JFRame:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TESTFRAME extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TESTFRAME();
}
});
}
public TESTFRAME() {
super("TESTFRAME");
PAGE page = new PAGE();
/*
* the following line causes very strange behaviour!
*/
page.setParent(this);
JPanel DISPLAY = new JPanel(new BorderLayout());
DISPLAY.add(page);
add(DISPLAY);
setSize(800, 600);
setLocationByPlatform(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
}
FYI check also what happens when comment out the line page.setParent(this);
.
这是要在框架中显示的"page":
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PAGE extends JPanel implements ActionListener {
public TESTFRAME parent = null;
public PAGE() {
// !!! activate the following line setting the GridLayout, to make button large
// in the bottom right corners, I continue not being able to click
// setLayout(new GridLayout(1, 0));
JButton bt_large = new JButton("<html><br>large close button<br><br></html>");
bt_large.addActionListener(this);
add(bt_large);
JButton bt_small = new JButton("small button");
bt_small.addActionListener(this);
add(bt_small);
}
public TESTFRAME getParent() {
return parent;
}
public void setParent(TESTFRAME parent) {
this.parent = parent;
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("button click received!");
if (parent != null) {
parent.dispose();
}
}
}
感谢您的洞察力!
英文:
This issue cost me a lot of time to identify, now I am curious what causes this strange behaviour:
In the example, There is a JFrame class which displays a JPanel "page" which itself gets a reference to the "parent" JFrame.
My mistake was to do that in the process of constructing the objects.
What is stunning is that in some cases, the reaction of JComponents on the "page" (like JButtons, JRadioButtons, JCHeckboxes etc.), which some times reacted to the mouse just fine, sometimes not at all, and sometimes only a fraction of the surface was working.
So I tried to isolate this in a minimum example below, which I could demonstrate on JRE 1.8, JRE12 and JRE13 on both Windows 7 x64 and Windows 10 x64.
In order to reproduce, you might need to play with the button size vs. JFrame.setSize()
.
The behaviour on my systems is, that the button reacts very well to the mouse with some animation on mouseEntered
, and a click with the mouse will fire the ActionEvent
.
But not in a fixed-size area in the bottom right of the button. If you go there with the mouse, no event will be fired.
The size of that "dead" region remains constant under changes of windows size and component size, as you can try out with different LayoutManagers
in the "page" code.
The same applies for other JComponents that fire events.
My question is: why is there a problem with the ActionListening-System. It would be intuitive, if the Listening would either be entirely broken or not at all.
From the answer I hope to learn more about the inside of the mouse event-generation in JComponents so as to be more vigilant in my programs of the future.
Here is the main JFRame:
import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class TESTFRAME extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new TESTFRAME();
}
});
}
public TESTFRAME() {
super("TESTFRAME");
PAGE page = new PAGE();
/*
* the following line causes very strange behaviour!
*/
page.setParent(this);
JPanel DISPLAY = new JPanel(new BorderLayout());
DISPLAY.add(page);
add(DISPLAY);
setSize(800, 600);
setLocationByPlatform(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
}
}
FYI check also what happens when comment out the line page.setParent(this);
.
and this is the "page" to be displayed in the frame:
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JPanel;
public class PAGE extends JPanel implements ActionListener {
public TESTFRAME parent = null;
public PAGE() {
// !!! activate the following line setting the GridLayout, to make button large
// in the bottom right corners, I continue not being able to click
// setLayout(new GridLayout(1, 0));
JButton bt_large = new JButton("<html><br>large close button<br><br></html>");
bt_large.addActionListener(this);
add(bt_large);
JButton bt_small = new JButton("small button");
bt_small.addActionListener(this);
add(bt_small);
}
public TESTFRAME getParent() {
return parent;
}
public void setParent(TESTFRAME parent) {
this.parent = parent;
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("button click received!");
if (parent != null) {
parent.dispose();
}
}
}
Thank you for your insights!
答案1
得分: 2
问题在于getParent()
是Component
类的一个方法。
通过实现您自己的方法,会丢失默认功能,从而导致您正在遇到的问题。
尝试将您的方法重命名为getParentFrame()
和setParentFrame()
,以查看正常行为。
然而,您甚至不需要这些方法。相反,您可以使用JDK中的方法来访问面板的父框架。
在您的ActionListener
中,您可以编写如下代码:
Window window = SwingUtilities.windowForComponent(this);
window.dispose();
英文:
The problem is that getParent()
is a method of the Component
class.
By implementing you own method default functionality is lost, causing the problems you are experiencing.
Try renaming your methods to getParentFrame()
and setParentFrame()
to see the normal behaviour.
However, you don't even need those methods. Instead you can access the parent frame of the panel by using methods from the JDK.
In your ActionListener
you can have code like:
Window window = SwingUtilities.windowForComponent( this );
window.dispose();
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论