我构建了一个只显示一行的自定义组件。该线条从左上角到右下角绘制为paint方法中的Line2D。背景是透明的。我扩展了JComponent。当鼠标指针位于最大值时,这些线条组件可拖动并更改其线条颜色。距绘制线15个像素。 但是如果我将多个这些组件添加到另一个扩展JPanel的自定义组件中,它们有时会重叠。我想实现,如果鼠标指针距离线超过15个像素,鼠标事件应该通过组件落下。如何让它落空是我的问题。 这甚至可能吗?
提前致谢!
答案 0 :(得分:3)
如果鼠标指针超过15像素,我想实现它 远离线条,鼠标事件应该通过组件落下。
如果您的子组件具有鼠标侦听器,则它将拦截在其上发生的每个鼠标事件。如果要将MouseEvent转发到父Component,则应手动执行。例如,您可以实现扩展MouseAdapter的自定义鼠标侦听器:
public class yourMouseListener extends MouseAdapter{
//this will be called when mouse is pressed on the component
public void mousePressed(MouseEvent me) {
if (/*do your controls to decide if you want to propagate the event*/){
Component child = me.getComponent();
Component parent = child.getParent();
//transform the mouse coordinate to be relative to the parent component:
int deltax = child.getX() + me.getX();
int deltay = child.getY() + me.getY();
//build new mouse event:
MouseEvent parentMouseEvent =new MouseEvent(parent, MouseEvent.MOUSE_PRESSED, me.getWhen(), me.getModifiers(),deltax, deltay, me.getClickCount(), false)
//dispatch it to the parent component
parent.dispatchEvent( parentMouseEvent);
}
}
}
答案 1 :(得分:2)
我触摸Swing已经有一段时间了,但我认为您需要在父组件中处理鼠标事件,然后使用行循环遍历子组件并确定它们中的哪一个应该处理事件(嗯,决定逻辑应该仍然保留在行组件中,但是父将显式调用该逻辑,直到其中一个组件接受事件)。
答案 2 :(得分:2)
对于我在大学的最后一年项目,我做了一个白板程序并遇到了同样的问题。对于用户绘制的每个形状,我创建了一个JComponent,它在绘制矩形时很好,但使用自由形式线工具则更难。
我最终修复它的方法是完全取消JComponents。我有一个JPanel,它持有Vector(我认为)自定义Shape对象。每个物体都有自己的坐标和线条厚度等。当用户单击板时,JPanel上的鼠标侦听器触发并遍历每个Shape,在每个Shape上调用一个contains(int x,int y)方法(x和y是事件的坐标)。因为Shapes在绘制时被添加到Vector中,所以我知道返回true的最后一个是最顶层的Shape。
这是我用于直线包含方法的内容。数学可能有点不确定,但它对我有用。
public boolean contains(int x, int y) {
// Check if line is a point
if(posX == endX && posY == endY){
if(Math.abs(posY - y) <= lineThickness / 2 && Math.abs(posX - x) <= lineThickness / 2)
return true;
else
return false;
}
int x1, x2, y1, y2;
if(posX < endX){
x1 = posX;
y1 = posY;
x2 = endX;
y2 = endY;
}
else{
x1 = endX;
y1 = endY;
x2 = posX;
y2 = posY;
}
/**** USING MATRIX TRANSFORMATIONS ****/
double r_numerator = (x-x1)*(x2-x1) + (y-y1)*(y2-y1);
double r_denomenator = (x2-x1)*(x2-x1) + (y2-y1)*(y2-y1);
double r = r_numerator / r_denomenator;
// s is the position of the perpendicular projection of the point along
// the line: s < 0 = point is left of the line; s > 0 = point is right of
// the line; s = 0 = the point is along the line
double s = ((y1-y)*(x2-x1)-(x1-x)*(y2-y1) ) / r_denomenator;
double distance = Math.abs(s)*Math.sqrt(r_denomenator);
// Point is along the length of the line
if ( (r >= 0) && (r <= 1) )
{
if(Math.abs(distance) <= lineThickness / 2){
return true;
}
else
return false;
}
// else point is at one end of the line
else{
double dist1 = (x-x1)*(x-x1) + (y-y1)*(y-y1); // distance to start of line
double dist2 = (x-x2)*(x-x2) + (y-y2)*(y-y2); // distance to end of line
if (dist1 < dist2){
distance = Math.sqrt(dist1);
}
else{
distance = Math.sqrt(dist2);
}
if(distance <= lineThickness / 2){
return true;
}
else
return false;
}
/**** END USING MATRIX TRANSFORMATIONS****/
}
posX和posY组成行开头的坐标,endX和endY是行的结尾。如果单击位于线条中心的lineThickness / 2范围内,则返回true,否则您必须沿着线条的正中间单击。
绘制形状是将JPanel的Graphics对象传递给每个Shape并使用它进行绘制的情况。
答案 3 :(得分:1)
我认为最简单的方法是捕捉事件并致电parent.processEvent()
。因此,您的组件对于事件将是透明的,因为它会将它们传播到父级。
答案 4 :(得分:0)
我正在努力解决这类问题,并尝试了所有与父母和玻璃窗的东西,直到我意识到覆盖contains
方法正是你想要的。因为当父母点燃某种getcomponent
你的'Line'会回复它:'不,它不是我,我不在那里!'并且循环将检查其他组件。
此外,当您需要为可拖动对象设置复杂深度时,可以使用JLayeredPane后代。