- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个带有重写的paintComponent
的JPanel
。我想让我在此面板上手动绘制的某些元素可聚焦,以便使用辅助技术的人可以使用键盘使用我的应用程序。
如果您能给我一些建议,那就太好了。
最佳答案
您可以执行以下操作:
JComponent
s。 LayoutManager
将您的面板发送至null
。然后,您将所有组件/元素添加到此面板中,并且可以使用方法 Component.setBounds(...)
自由移动它们。 。 MouseListener
在面板中,每次按下鼠标,都会将焦点转移到所选组件。 Component.getComponentAt(Point)
来确定哪个组件被按下。里面MouseListener
您的面板。FocusableComponent extends JComponent
,如果组件具有焦点,它会在组件周围绘制一个蓝色矩形(这是在方法 FocusableComponent.paintComponent(Graphics)
内完成的)。 FocusableComponent
并重写其paintComponent(Graphics)方法来绘制元素。确保您在其中调用“super.paintComponent(Graphics)
”以绘制蓝色矩形(如果它具有焦点)。 import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class FocusablePaintComps {
private static abstract class FocusableComponent extends JComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
if (hasFocus()) {
final Color prevColor = g.getColor();
g.setColor(Color.BLUE);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.setColor(prevColor);
}
}
}
private static class FocusableComponent1 extends FocusableComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
}
}
private static class FocusableComponent2 extends FocusableComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final int w = getWidth(), h = getHeight();
g.fillRect(20, 20, w - 40, h - 40);
g.fillArc(10, 10, w - 1, h - 1, 60, 150);
}
}
private static class YourPanel extends JPanel {
private Component previousFocusedComponent = null;
private YourPanel() {
super(null); //Null LayoutManager. This is important to be able to
//move added components around freelly (with the method setBounds(...)).
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent evt) {
final Component src = getComponentAt(evt.getPoint());
if (src instanceof FocusableComponent) {
final FocusableComponent fc = (FocusableComponent) src;
fc.requestFocusInWindow(); //Transfer focus to the pressed component.
if (previousFocusedComponent != null)
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
setComponentZOrder(fc, 0); //Update: To make fc paint over all others as
//the user http://stackoverflow.com/users/131872/camickr commented.
fc.repaint(); //Repaint the new (with focus now).
previousFocusedComponent = fc;
}
else { //If clicked on empty space, or a non-FocusableComponent:
requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
if (previousFocusedComponent != null) {
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
previousFocusedComponent = null;
}
}
}
});
setPreferredSize(new Dimension(250, 250));
add(new FocusableComponent1(), Color.RED, new Rectangle(10, 10, 200, 20));
add(new FocusableComponent1(), Color.GREEN, new Rectangle(40, 150, 50, 70));
add(new FocusableComponent2(), Color.GRAY, new Rectangle(60, 125, 90, 100));
add(new FocusableComponent2(), Color.MAGENTA, new Rectangle(150, 60, 80, 150));
}
private void add(final FocusableComponent fc, final Color fgColor, final Rectangle bounds) {
fc.setForeground(fgColor);
add(fc);
fc.setBounds(bounds);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("Focused Paint Comps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new YourPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
rapaint()
的顺序相关。 s 在 mousePressed(...)
内部被调用确定哪个组件周围有蓝色矩形,哪个没有。 Component.getElementAt(Point)
不“看穿”透明/非不透明像素。 注意:此更新是一个可选扩展(但也许是一个更加java-contract-confirm - 让我这么说)以上解决方案。您可以只阅读两种实现之一(以下“更新”实现 RandomLayout
,或者上面“预更新”实现 null
LayoutManager
)。
更新了上述代码,该代码使用自定义 LayoutManager
按照用户“Andrew Thompson”在评论中的建议,对容器中的组件进行布局。
与上面代码唯一的区别是,不是设置为 null
LayoutManager
YourPanel
建成后,自定义 LayoutManager
的新实例使用时,您无需设置每个组件的边界,而只需设置其大小。
我已将自定义命名为 LayoutManager
至RandomLayout
它将容器的所有组件放置在随机位置,同时考虑组件的大小和 Insets
容器的(这通过在 Border
中添加 YourPanel
来证明)。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.LineBorder;
public class FocusablePaintComps {
private static abstract class FocusableComponent extends JComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
if (hasFocus()) {
final Color prevColor = g.getColor();
g.setColor(Color.BLUE);
g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
g.setColor(prevColor);
}
}
}
private static class FocusableComponent1 extends FocusableComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
g.fillOval(0, 0, getWidth() - 1, getHeight() - 1);
}
}
private static class FocusableComponent2 extends FocusableComponent {
@Override protected void paintComponent(final Graphics g) {
super.paintComponent(g);
final int w = getWidth(), h = getHeight();
g.fillRect(20, 20, w - 40, h - 40);
g.fillArc(10, 10, w - 1, h - 1, 60, 150);
}
}
private static class YourPanel extends JPanel {
private Component previousFocusedComponent = null;
private YourPanel() {
super(new RandomLayout()); //RandomLayout: custom LayoutManager which lays
//out the components in random positions (takes Insets into account).
addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(final MouseEvent evt) {
final Component src = getComponentAt(evt.getPoint());
if (src instanceof FocusableComponent) {
final FocusableComponent fc = (FocusableComponent) src;
fc.requestFocusInWindow(); //Transfer focus to the pressed component.
if (previousFocusedComponent != null)
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
setComponentZOrder(fc, 0); //Update: To make fc paint over all others as
//the user http://stackoverflow.com/users/131872/camickr commented.
fc.repaint(); //Repaint the new (with focus now).
previousFocusedComponent = fc;
}
else { //If clicked on empty space, or a non-FocusableComponent:
requestFocusInWindow(); //Tranfer focus to somewhere else (e.g. the panel itself).
if (previousFocusedComponent != null) {
previousFocusedComponent.repaint(); //Repaint the last (without focus now).
previousFocusedComponent = null;
}
}
}
});
setBorder(new LineBorder(Color.LIGHT_GRAY, 20));
setPreferredSize(new Dimension(300, 250));
add(new FocusableComponent1(), Color.RED, new Dimension(200, 20));
add(new FocusableComponent1(), Color.GREEN, new Dimension(50, 70));
add(new FocusableComponent2(), Color.GRAY, new Dimension(90, 100));
add(new FocusableComponent2(), Color.MAGENTA, new Dimension(80, 150));
}
private void add(final FocusableComponent fc, final Color fgColor, final Dimension size) {
add(fc);
fc.setForeground(fgColor);
fc.setSize(size);
}
}
public static void main(final String[] args) {
final JFrame frame = new JFrame("Focused Paint Comps");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new YourPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
还有自定义LayoutManager
本身带有 JavaDoc(可能很大,但希望可以重用):
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.Point;
import java.util.Random;
/**
* A {@link java.awt.LayoutManager} which lays out randomly all the {@link java.awt.Component}s
* of its parent, taking into consideration the parent's {@link java.awt.Insets}.
* <p>
* Use {@link #setRandomizeOnce(boolean)} method to determine if the lastly laid-out parent will
* be only laid-out randomly once and not for each {@link #layoutContainer(java.awt.Container)}
* subsequent call for the same parent, or the opposite.
* </p>
*/
public class RandomLayout implements LayoutManager {
/**
* The {@link java.awt.Container} which was lastly laid-out.
*/
private Container lastParent;
/**
* The {@link java.awt.Insets} of {@code lastParent} the last time it was laid-out.
*/
private Insets lastInsets;
/**
* If {@code true} then this {@link java.awt.LayoutManager} keeps track of the
* {@link java.awt.Container}s laid-out to make sure that {@code lastParent} is
* only laid-out once. If the another {@link java.awt.Container} is laid-out, other
* than {@code lastParent}, then its components are laid-out randomly and the
* {@link java.awt.Container} becomes the {@code lastParent}.
*/
private boolean randomizeOnce;
/**
* Normal constructor of {@code RandomLayout} with explicit value for {@code randomizeOnce}.
*
* @param randomizeOnce {@code true} if the lastly laid-out parent will be only laid-out
* randomly once and not for each {@link #layoutContainer(java.awt.Container)} subsequent call
* for the same parent, otherwise {@code false} and each call to
* {@link #layoutContainer(java.awt.Container)} will lay out randomly the {@link java.awt.Container}.
*/
public RandomLayout(final boolean randomizeOnce) {
this.randomizeOnce = randomizeOnce;
}
/**
* Default constructor of {@code RandomLayout} with {@code randomizeOnce} set to {@code true}.
*/
public RandomLayout() {
this(true);
}
/**
* If {@code true} then this {@link java.awt.LayoutManager} keeps track of the
* {@link java.awt.Container}s laid-out to make sure that {@code lastParent} is
* only laid-out once. If the another {@link java.awt.Container} is laid-out, other
* than {@code lastParent}, then its components are laid-out randomly and the
* {@link java.awt.Container} becomes the {@code lastParent}.
*
* @param randomizeOnce {@code true} if the lastly laid-out parent will be only laid-out
* randomly once and not for each {@link #layoutContainer(java.awt.Container)} subsequent call
* for the same parent, otherwise {@code false}.
*/
public void setRandomizeOnce(final boolean randomizeOnce) {
this.randomizeOnce = randomizeOnce;
}
/**
* Tells if the lastly laid-out parent will be only laid-out randomly once and not for each
* {@link #layoutContainer(java.awt.Container)} subsequent call for the same parent, or the
* opposite.
*
* @return {@code true} if the lastly laid-out parent will be only laid-out randomly once and
* not for each {@link #layoutContainer(java.awt.Container)} subsequent call for the same
* parent, otherwise {@code false}.
*/
public boolean isRandomizeOnce() {
return randomizeOnce;
}
/**
* @return The {@link java.awt.Container} which was lastly laid-out.
*/
protected Container getLastParent() {
return lastParent;
}
/**
* @return The {@link java.awt.Insets} of {@code lastParent} the last time it was laid-out.
* @see #getLastParent()
*/
protected Insets getLastInsets() {
return lastInsets;
}
/**
* Adds the specified component with the specified name to the layout.
* @param name The name of the component.
* @param comp The {@link java.awt.Component} to be added.
*/
public void addLayoutComponent(final String name,
final Component comp) {
}
/**
* Removes the specified component from the layout.
* @param comp The {@link java.awt.Component} to be removed.
*/
public void removeLayoutComponent(final Component comp) {
}
/**
* {@inheritDoc}
* @return The preferred size dimensions for the specified {@link java.awt.Container}.
*/
@Override
public Dimension preferredLayoutSize(final Container parent) {
final Dimension prefDim = minimumLayoutSize(parent);
prefDim.width += 2; //+2 to spare.
prefDim.height += 2; //+2 to spare.
return prefDim;
}
/**
* {@inheritDoc}
* @return The minimum size dimensions for the specified {@link java.awt.Container}.
*/
@Override
public Dimension minimumLayoutSize(final Container parent) {
final Dimension minDim = new Dimension();
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i)
applyBigger(minDim, getPreferredSize(parent, parent.getComponent(i)));
final Insets parInsets = parent.getInsets();
minDim.width += (parInsets.left + parInsets.right);
minDim.height += (parInsets.top + parInsets.bottom);
return minDim;
}
/**
* {@inheritDoc}. If the another {@link java.awt.Container} is laid-out, other
* than {@code lastParent}, then its components are laid-out randomly and the
* {@link java.awt.Container} becomes the {@code lastParent}.
*/
@Override
public void layoutContainer(final Container parent) {
if (parent == null)
throw new IllegalArgumentException("Cannot lay out null.");
if (isRandomizeOnce() && lastParent == parent) { //At least take care of insets (if they have changed).
final Insets parentInsets = parent.getInsets();
if (!lastInsets.equals(parentInsets)) {
final int offx = parentInsets.left - lastInsets.left,
offy = parentInsets.top - lastInsets.top;
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i) {
final Component child = parent.getComponent(i);
final Point childLoca = child.getLocation();
childLoca.x += offx;
childLoca.y += offy;
child.setLocation(childLoca);
}
lastInsets = parentInsets;
}
}
else
layoutContainerRandomly(parent);
}
/**
* Explicitly lays out randomly the specified container.
* <p>
* This is equivalent of calling:
* <pre>
* boolean isRand1 = randomLayout.isRandomizeOnce();
* randomLayout.setRandomizeOnce(false);
* randomLayout.layoutContainer(parent);
* randomLayout.setRandomizeOnce(isRand1);
* </pre>
* {@code parent} becomes {@code lastParent}.
* </p>
* @param parent The container to be laid out.
*/
public void layoutContainerRandomly(final Container parent) { //Place each child at a random location for the "new" parent (lastParent != parent).
if (parent == null)
throw new IllegalArgumentException("Cannot lay out null.");
reset();
final Dimension parentSize = parent.getSize();
final Insets parentInsets = parent.getInsets();
final Dimension childSize = new Dimension();
final Point childLoca = new Point();
final Random rand = new Random();
final int childCnt = parent.getComponentCount();
for (int i=0; i<childCnt; ++i) {
final Component child = parent.getComponent(i);
child.getSize(childSize);
childLoca.x = parentInsets.left + 1;
childLoca.y = parentInsets.top + 1;
final int xBound = parentSize.width - parentInsets.left - parentInsets.right - childSize.width,
yBound = parentSize.height - parentInsets.top - parentInsets.bottom - childSize.height;
if (xBound > 0)
childLoca.x += rand.nextInt(xBound);
if (yBound > 0)
childLoca.y += rand.nextInt(yBound);
child.setLocation(childLoca);
}
lastParent = parent;
lastInsets = parentInsets;
}
/**
* Invalidates the tracking of the lastly laid-out {@link java.awt.Container} and its last
* {@link java.awt.Insets}.
* @see #getLastParent()
* @see #getLastInsets()
*/
protected void reset() {
lastParent = null;
lastInsets = null;
}
private static void applyBigger(final Dimension inputOutput,
final Dimension input) {
if (inputOutput != null && input != null) {
inputOutput.width = (int) Math.max(inputOutput.width, input.width);
inputOutput.height = (int) Math.max(inputOutput.height, input.height);
}
}
private static void applyIfBetter(final Dimension inputOutput,
final Dimension input) {
if (inputOutput != null && input != null
&& (input.width > inputOutput.width
|| input.height > inputOutput.height)) {
inputOutput.width = input.width;
inputOutput.height = input.height;
}
}
/**
* Tries to determine the best size for {@code child}.
* @param parnt The parent {@link java.awt.Container} being laid-out.
* @param child The child {@link java.awt.Component} of {@code parnt} being laid-out.
* @return A preferred size for the {@code child} to be laid-out.
*/
protected static Dimension getPreferredSize(final Container parnt,
final Component child) {
final Dimension minDim = new Dimension();
if (child != null) {
applyIfBetter(minDim, child.getMinimumSize());
applyIfBetter(minDim, child.getSize());
applyIfBetter(minDim, child.getPreferredSize());
}
return minDim;
}
}
这是新的屏幕截图(没有大的视觉差异):
请注意,这是我的第一个自定义 LayoutManager
,但我已阅读文档,并且还 GridLayout
和SpringLayout
作为示例(因为,在我看来, LayoutManager
的文档还不够),当然我测试了它。就目前情况而言,我找不到任何问题。当然,如有任何改进建议或建议,我们将不胜感激。
关于java - 如何使绘制的 JPanel 上的元素可聚焦,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39190830/
在开发中的网页上,我在 IE 上遇到此错误 element = $(element); 此代码位于prototype.js 预期对象 如何消除此错误。 更新: 现场也使用了 jQuery。 最佳答
我有两个大小相同的嵌套数组: Array1 =[[1, 2], [], [2, 3]] Array2= [[1, 4], [8, 11], [3, 6]] 我需要将它们合并到一个数组中,如下所示: A
我有一些 jQuery 代码,当单击具有特定 ID 的项目时运行。当 ID 是 的一部分时,它就可以工作。元素,但当它位于 中时则不然元素。为什么会这样呢?我想使用 an,因为如果用户关闭了 Ja
Flex-box 规范 3声明 flex 元素不是 block 容器: A flex item establishes a new formatting context for its content
我遇到了一个意想不到的问题。 HTML JS $(function() { var $divs = $('.myDiv'); // create new div not in
我使用 Bootstrap 和 Ember.js 得到了一个无序列表。每个列表项都是一个显示新帖子的链接,每当您单击该链接时,Ember 都会添加类 active默认情况下。我正在使用 Bootstr
我正在尝试让一个函数正常工作,但运气不佳,所以我想向 Stackoverflow 智囊团提出一个新手问题! 基本上,我有一个表单,并且循环遍历所有元素以查看是否存在自定义数据属性。如果存在,则保持该元
我想映射一个可选数组,删除那些 nil 值,并使用另一个函数映射非 nil 值。 我知道我可以通过使用 compactMap 然后使用常规 map 来实现这一点,但我只想遍历数组一次。 我为此实现了一
我如何定位 li 元素,除非它们出现在 之后元素?换句话说,我想针对步骤而不是注释。 我尝试向 OL 添加一个我想从选择中排除的类,但我想出的代码不起作用。 (顺便说一句,重构 html 不是一种选
Warning 1 The element 'system.webServer' has invalid child element 'rewrite'. List of possible eleme
我正在尝试编写一个脚本,该脚本将遍历 HTML 源并创建 DOM 的 JSON 文件,然后使用 d3.js 在 TreeView 中显示该文件。我遇到的问题是不仅希望显示元素(TITLE、P、LI 等
我有以下 HTML 表单:- Option 1 Option 2
我试图在选定的 HTML 元素之后选择下一个具有类名 slider-value 的 span 元素。我尝试了多种解决方案,但没有一个有效。 我可以通过 id 选择它,但我不希望那样做使代码冗余。 $(
如果电子邮件地址无效,我想在屏幕上显示一条消息“请输入有效的电子邮件地址”。 body 元素的innerHTML 语句工作正常,但我用于p 元素的innerHTML 语句不起作用。 有一次,当我测试它
以下 jQuery 代码调用 ul 元素,查找元素内的前 三个 li 列表项,并隐藏剩余的 li 项目。然后,它附加一个 li 元素,其中显示“显示更多...”,并且在单击时显示之前隐藏的列表项。 (
我问了a question早些时候关于将编辑/删除链接与 h1 元素内联的最佳方法。我能够通过给出的答案实现这一点,但我现在有额外的要求,我需要在 h1 下方显示一个段落并编辑/删除链接。 到目前为止
我使用 MVC 4 和 knockout.js 库版本 2.1.0 显示从服务器检索到的大量文件的表中的以下摘录。 0)"> 正在正确检索数据,
我创建了一个脚本,该脚本在鼠标悬停在父容器上时激活,并且应该将其子元素移离鼠标。我目前已经让它工作了,但是代码的某些部分似乎与 REACT 代码应该是什么样子相矛盾。特别是两个部分。 我在渲染函数中使
我是 JS 新手,正在尝试理解项目 https://github.com/tastejs/todomvc 的代码 请参阅屏幕截图,我尝试对 button X 以及其父元素 div 设置断点,但在这两种
例如,假设有一个带有奇特颜色的标记: Something written here 使用 Visual Studio 2017 和 MVC 5 元素,有没有办法检查和定位当前应用了哪些样式,以及负责它
我是一名优秀的程序员,十分优秀!