我建立了一个自定义组件,只显示一条线。该线是在paint方法中作为Line2D从左上角到右下角绘制的。背景是透明的。我扩展了JComponent。这些线组件可以拖动,并且当鼠标指针距离绘制的线段最多15个像素时,它们会改变其线颜色。
但是,如果我将多个这些组件添加到另一个扩展JPanel的自定义组件中,它们有时会重叠。我想实现的是,如果鼠标指针距离线条超过15个像素,则鼠标事件应穿过组件。如何让它穿过是我的问题。
这是否可能?
提前感谢!
提前感谢!
我希望实现的功能是,如果鼠标指针距离线条超过15像素,则鼠标事件应该穿透组件。
如果您的子组件有鼠标监听器,则它将拦截发生在其上的每个鼠标事件。如果您想将 MouseEvent 转发到父组件,则需要手动执行此操作。例如,您可以通过扩展 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);
}
}
}
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是直线的终点坐标。如果点击位置在离直线中心线厚度的一半之内,它将会返回真值;否则您必须单击直线正中间。
绘制形状只需要将JPanel的Graphics对象传递给每一个形状,然后使用该对象进行绘制即可。
我已经有一段时间没有涉及Swing了,但是我认为您需要在父组件中处理鼠标事件,然后使用lines循环遍历子组件并确定哪个组件应该处理该事件(当然,决定的逻辑仍然应该保留在line组件中,但父组件将显式调用该逻辑,直到其中一个组件接收到事件)。
我认为最简单的方法是捕获事件并调用parent.processEvent()
。这样,您的组件将对事件透明,因为它会将它们传播到父级。
我曾经为这种问题苦苦挣扎,尝试了所有与父级和glasspane有关的东西,直到我意识到重写contains
方法正是你想要的。因为当父级触发某种getcomponent
时,你的"Line"会回复它:"不,不是我,我不在那里!",然后循环将检查其他组件。
此外,当您需要为可拖动对象设置复杂的深度时,您可以使用JLayeredPane的后代。