gpt4 book ai didi

java - Swing 自定义组件虚拟鼠标监听器

转载 作者:行者123 更新时间:2023-11-30 04:24:32 27 4
gpt4 key购买 nike

我刚刚开始组装一个供我自己使用的日志工具,该工具可以记录健身房/运行的统计数据,而我对 swing/awt 的唯一经验是对游戏进行主动渲染,您可以完全控制 Graphics2D 对象,并且不要依赖于使用覆盖的绘制来实现 swing 组件。

不管怎样,我希望创建一个虚拟的 JComponent,我可以将其添加到我的一个面板中(该面板将显示图形、统计信息等,具体取决于我从另一个不同的侧面板中选择的选项),它除了监听之外什么也不做。 mouseevents 在前面提到的面板中,并在 mousedrags 上绘制一个选择矩形,以便在存在更高分辨率的情况下可以放大数据。我只是不知道如何,我已将组件添加到面板中,但它在面板内没有注册任何内容,相反,它似乎有一个仅限于面板/框架底部的本地空间。

这是组件

package gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import javax.swing.JComponent;

@SuppressWarnings("serial")
public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {

private boolean draw;
private int startX, endX, startY, endY;
private Color color = new Color(0, 255, 0, 100);

public MarkerRectangle(int width, int height) {
setPreferredSize(new Dimension(width, height));
this.addMouseListener(this);
this.addMouseMotionListener(this);
}

@Override
public void mouseClicked(MouseEvent e) {
System.out.println("Mouse clicked@ " + e.getX() + "," + e.getY());
}

@Override
public void mouseEntered(MouseEvent e) {
System.out.println("Mouse entered @ " + e.getX() + "," + e.getY());

}

@Override
public void mouseExited(MouseEvent e) {
System.out.println("Mouse left @ " + e.getX() + "," + e.getY());
}

@Override
public void mousePressed(MouseEvent e) {
System.out.println("Mouse pressed@ " + e.getX() + "," + e.getY());
}

@Override
public void mouseReleased(MouseEvent e) {
System.out.println("Mouse was released @ " + e.getX() + "," + e.getY());
}

@Override
public void mouseDragged(MouseEvent e) {
System.out.println("Mouse being dragged, currently@ " + e.getX() + ","
+ e.getY());

}

@Override
public void mouseMoved(MouseEvent e) {
System.out.println("I registered a move@ " + e.getX() + "," + e.getY());
}

@Override
// Draw rectangle
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.dispose();
}

}

面板

public class GraphPane extends JPanel {


public GraphPane(Graph graph) {
this.add(graph);
this.add(new MarkerRectangle(800, 600));
this.setBackground(Color.gray);
this.setPreferredSize(new Dimension(800, 600));
}


}

图表,保存随机数据 atm

public class Graph extends JComponent {
private GeneralPath data;
private Stroke stroke;

public Graph() {
this.data = new GeneralPath();
this.stroke = new BasicStroke(3f);
this.setPreferredSize(new Dimension(750, 550));
init();
}

private void init() {
data.moveTo(0, 0);
double cntr = 0;
double[][] points = new double[10][1];
for (double[] point : points) {
cntr += 100;
point[0] = Math.random() * 100;
point[1] = Math.random() * 100;
data.lineTo(cntr, point[1]);
}
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(stroke);
g2d.draw(data);
g2d.dispose();
}
}

我想实现类似上面的东西,因为最终我想象 GUI 会变得相当复杂,而像绘制矩形来标记数据这样的简单事件不应该出现在主 Controller 中(以防止大量的 if 测试和代码困惑)。

我得到的截图: enter image description here

我想要什么: enter image description here

编辑虽然下面接受的答案是更好的解决方案,但如果有人可能想要使用它,我会将其发布。如果您将 prefferedSize 调整得更小,它将不起作用。

public class Test {

public static void main(String[] args) {
GeneralJFrame frame = new GeneralJFrame(1200, 800);
frame.addPanel(new GraphPane(new Graph()), BorderLayout.CENTER);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.SOUTH);
frame.addPanel(new ButtonPane(), BorderLayout.WEST);
frame.addPanel(new ButtonPane(), BorderLayout.EAST);
frame.addPanel(new ButtonPane(), BorderLayout.NORTH);
frame.start();
}
}

public class GraphPane extends JPanel {


public GraphPane(Graph graph) {
GridBagConstraints c = new GridBagConstraints();
c.gridwidth = GridBagConstraints.REMAINDER;
c.gridheight = GridBagConstraints.REMAINDER;
c.gridx = 0;
c.gridy = 0;
this.setLayout(new GridBagLayout());
this.add(graph);
this.add(new MarkerRectangle(), c);
this.setBackground(new Color(205, 201, 201));
}



}

public class MarkerRectangle extends JComponent implements MouseListener,
MouseMotionListener {

private boolean draw;
private int startX, endX, startY, endY;

public MarkerRectangle() {
this.addMouseListener(this);
this.addMouseMotionListener(this);
setOpaque(false);
setPreferredSize(new Dimension(800, 600));
}

@Override
public void mouseClicked(MouseEvent e) {

}

@Override
public void mouseEntered(MouseEvent e) {

}

@Override
public void mouseExited(MouseEvent e) {

}

@Override
public void mousePressed(MouseEvent e) {
startX = e.getX();
startY = e.getY();
draw = true;
}

@Override
public void mouseReleased(MouseEvent e) {
draw = false;
repaint();
}

@Override
public void mouseDragged(MouseEvent e) {
endX = e.getX();
endY = e.getY();
repaint();
}

@Override
public void mouseMoved(MouseEvent e) {

}

@Override
// Draw rectangle
protected void paintComponent(Graphics g) {
System.out.println(getSize());
if (!draw)
return;
int w = endX-startX;
int h = endY - startY;
Graphics2D g2d = (Graphics2D) g.create();
g2d.setColor(new Color(255, 165, 0));
g2d.fillRect(startX, startY, w, h);
g2d.dispose();
}

}

public class ButtonPane extends JPanel {
public ButtonPane() {
add(new JButton("HELLO"));
setBackground(Color.gray);
setBorder(BorderFactory.createEtchedBorder(Color.white,
Color.gray.darker()));
}
}

public class GeneralJFrame {
private JFrame frame;

public GeneralJFrame(int width, int height) {
this.frame = new JFrame("Le Muscles");
this.frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}

public void addPanel(JPanel panel, String location) {
this.frame.add(panel, location);
}

public void start() {
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}

输出:(用鼠标拖动橙色) enter image description here

最佳答案

我还是不太明白你的问题。在我看来,你已经

  • 创建了多个 JPanel
  • 给定一个 JPanel、一个 MouseListener 和 MouseMotionListener
  • 您已将该 JPanel 添加到另一个 JPanel 的底部。
  • 位于底部的 JPanel 按照指示注册所有鼠标事件
  • 因此,您的程序根据您的代码按预期运行。

  • 我的问题是:它的行为为何不符合的预期?

  • 如果您期望添加附加了 MouseListeners 和 MouseMotionListeners 的 JPanel 将导致 GUI 的所有 JPanel 都被监听,那么当然这不会发生。要让更多的 GUI 注册鼠标事件,您必须将 MouseListeners 和 MouseMotionListeners 添加到这些组件。到目前为止,这就是我对你的问题的回答。如果我没有回答您当前面临的真实问题,请为我们澄清。
<小时/>

您声明:

What I want is an invisible (transparent) panel on top of the blue one in the above screenshot that is just as large as the blue one, not a subpanel that is sitting in the bottom. I want the blue one to contain this one (should not be a problem since it is just a jcomponent). What I hope to achieve is a sort over "invisible" overlay that registers mousevents so I don't have to implement these events in the blue panel.

为此考虑使用 JLayer。根据 JLayer API:

JLayer is a good solution if you only need to do custom painting over compound component or catch input events from its subcomponents.

<小时/>

好吧,我尝试了一下并想出了这样的结果:

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.Path2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Random;

import javax.swing.*;
import javax.swing.plaf.LayerUI;

@SuppressWarnings("serial")
public class GraphPane2 extends JPanel {
private static final int GRAPH_WIDTH = 1000;
private static final int GRAPH_HEIGHT = 750;
private Graph2 graph2 = new Graph2(GRAPH_WIDTH, GRAPH_HEIGHT);

public GraphPane2() {
LayerUI<Graph2> myLayerUI = new MyLayerUI<Graph2>();
JLayer<Graph2> panelLayer = new JLayer<Graph2>(graph2, myLayerUI);
setLayout(new BorderLayout());
add(panelLayer);

myLayerUI.addPropertyChangeListener(new PropertyChangeListener() {

@Override
public void propertyChange(PropertyChangeEvent evt) {
if (MyLayerUI.MOUSE_RELEASED.equals(evt.getPropertyName())) {
Rectangle rect = (Rectangle) evt.getNewValue();
System.out.println(rect);
}
}
});
}

private static void createAndShowGui() {
GraphPane2 mainPanel = new GraphPane2();

JFrame frame = new JFrame("Graph Pane2");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.setResizable(false);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

@SuppressWarnings("serial")
class MyLayerUI<V extends JComponent> extends LayerUI<V> {
private static final Color FILL_COLOR = new Color(0, 128, 0, 128);
public static final String MOUSE_RELEASED = "mouse released";
private Point pressedPt;
private Point draggedPt;
private Rectangle rect;

@Override
public void paint(Graphics g, JComponent c) {
super.paint(g, c);
if (rect != null) {
Graphics2D g2 = (Graphics2D) g;
g2.setColor(FILL_COLOR);
g2.fill(rect);
}
}

public void installUI(JComponent c) {
super.installUI(c);
((JLayer) c).setLayerEventMask(AWTEvent.MOUSE_MOTION_EVENT_MASK | AWTEvent.MOUSE_EVENT_MASK);
}

public void uninstallUI(JComponent c) {
super.uninstallUI(c);
((JLayer)c).setLayerEventMask(0);
}

@Override
public void eventDispatched(AWTEvent e, JLayer<? extends V> l) {
MouseEvent mEvt = (MouseEvent) e;
int id = mEvt.getID();
int btn = mEvt.getButton();
if (id == MouseEvent.MOUSE_PRESSED && btn == MouseEvent.BUTTON1) {
pressedPt = mEvt.getPoint();
rect = new Rectangle(pressedPt.x, pressedPt.y, 0, 0);
}
if (id == MouseEvent.MOUSE_PRESSED && btn != MouseEvent.BUTTON1) {
pressedPt = null;
}
if (id == MouseEvent.MOUSE_DRAGGED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
}
if (id == MouseEvent.MOUSE_RELEASED && pressedPt != null) {
draggedPt = mEvt.getPoint();
int x = Math.min(draggedPt.x, pressedPt.x);
int y = Math.min(draggedPt.y, pressedPt.y);
int width = Math.abs(draggedPt.x - pressedPt.x);
int height = Math.abs(draggedPt.y - pressedPt.y);
rect = new Rectangle(x, y, width, height);
firePropertyChange(MOUSE_RELEASED, null, rect);
}
l.repaint();
}
}

@SuppressWarnings("serial")
class Graph2 extends JPanel {
private static final int MAX_DATA_POINTS = 100;
private static final int STEP = 10;
private static final Stroke STROKE = new BasicStroke(3f);
private Path2D path2D;
private int width;
private int height;
private int[] data = new int[MAX_DATA_POINTS + 1];
private Random random = new Random();

public Graph2(int width, int height) {
this.width = width;
this.height = height;
init();

addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
path2D = new Path2D.Double();
int w = getWidth();
int h = getHeight();
double x = 0;
double y = ((double) MAX_DATA_POINTS - data[0]) * h
/ MAX_DATA_POINTS;
path2D.moveTo(x, y);
for (int i = 1; i < data.length; i++) {
x = (i * w) / (double) MAX_DATA_POINTS;
y = ((double) MAX_DATA_POINTS - data[i]) * h
/ (double) MAX_DATA_POINTS;
path2D.lineTo(x, y);
}
}
});
}

@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}

protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (path2D != null) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(STROKE);
g2d.draw(path2D);
}
};

private void init() {
// create and fill random data
data[0] = 0;
boolean up = true;
// max and min data values -- used for normalization
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
for (int i = 1; i < data.length; i++) {
up = random.nextInt(4) < 3 ? up : !up;
if (up) {
data[i] = data[i - 1] + random.nextInt(STEP);
} else {
data[i] = data[i - 1] - random.nextInt(STEP);
}

if (data[i] > max) {
max = data[i];
}
if (data[i] < min) {
min = data[i];
}
}

// normalize the data
for (int i = 0; i < data.length; i++) {
int datum = (MAX_DATA_POINTS * (data[i] - min)) / (max - min);
data[i] = datum;
}

}
}

这看起来像:

enter image description here

关于java - Swing 自定义组件虚拟鼠标监听器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16258175/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com