英文:
Java Swing: getting reference to GUI component
问题
我已经开始学习Java,因此也学习了Swing。我一直在研究如何构建GUI,并且想知道,在创建GUI组件后,如何获得对其进行修改/读取/删除的引用。我是否必须保留创建组件时获得的引用?或者是否有类似于JavaScript中的功能:document.querySelector(),.querySelectorAll(),.getElementBy...()
?
以一个按钮和一个标签作为示例。当我点击按钮时,我想要更改标签。在这个示例中,每个人似乎都会保留创建组件时获得的引用。
我已经阅读了关于MVC等内容,但对我来说,那似乎更高级,更适用于更大的应用程序。
请您还可以指点我学习Swing的正确方向 - 可靠的信息来源 -(有大量的教程,但并非所有教程都具有足够的质量)。
另外,我知道我将不得不学习MVC以创建更复杂的GUI。因此,如果您可以分享一些关于该主题的可靠链接,我也将非常感激。
谢谢。
英文:
I have started to learn Java and thus Swing as well. I have been looking into building a GUI and wondering, how can I get the reference of GUI component to modify/read/delete it after I created it. Do I have to hold on to the reference I get when creating the component? Or is there something like in Javascript: document.querySelector(), .querySelectorAll(), .getElementBy...()
?
As an example we can use a button and a label. When I click the button, I want to change the label. Everyone in this example seems to just hold on to the reference they got when creating the components.
I have read about MVC and so on, but that seems to me that it is even more advanced and more suitable for bigger apps.
Could you please also point me in the right direction of learning Swing - reliable source of information - (there are tons of tutorials, but not all of them seem to be of sufficient quality).
Also I am aware that I will have to learn MVC at some point to create more sophisticated GUIs. So if you could share some reliable links on that topic I would also be very grateful.
Thank you.
答案1
得分: 0
JButton button = new JButton();
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
// 按钮被按下时执行的代码
JButton pressed = (JButton)e.getSource();
}
});
可以为按钮添加一个 ActionListener,然后从事件 e 中获取按钮实例。
JFrame f = new JFrame();
f.setSize(500, 500);
f.setVisible(true);
JButton button = new JButton();
button.setBounds(0, 0, 100, 100);
f.add(button);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("pressed");
JButton b = (JButton)e.getSource();
b.setSize(200,200);
}
});
这就是我测试的方式,而且它能够正常工作。
英文:
JButton button = new JButton();
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
//runs when button is pressed
button pressed = (JButton)e.getSourse();
}
});
you can add a actionListener to a button and then get the button instance from the Event e
JFrame f = new JFrame();
f.setSize(500, 500);
f.setVisible(true);
JButton button = new JButton();
button.setBounds(0, 0, 100, 100);
f.add(button);
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("pressed");
JButton b = (JButton)e.getSource();
b.setSize(200,200);
}
});
thats how I tested it, and it just works fine
答案2
得分: 0
正如评论中所提到的,获得对所需组件的引用的一种简单方法是自己存储引用。对于您的示例,其中一个按钮更新一个标签,您可以在代码中的某个地方保留对标签的引用。例如:
import java.awt.Font;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main {
//创建一个带有随机内容的字符串的实用方法:
private static String randomString(final int length) {
//创建字母表:
String alphabet = "abcdefghijklmnopqrstuvwxyz";
alphabet += alphabet.toUpperCase();
alphabet += "0123456789";
final int alphabetLength = alphabet.length();
final Random rand = new Random();
final char[] chars = new char[length];
//填充随机字符串:
for (int i = 0; i < chars.length; ++i)
chars[i] = alphabet.charAt(rand.nextInt(alphabetLength));
return new String(chars);
}
private static void createAndShowGUI() {
//使用随机文本初始化JLabel:
final JLabel label = new JLabel(randomString(10));
//将字体更改为MONOSPACED BOLD(具有当前大小):
label.setFont(new Font(Font.MONOSPACED, Font.BOLD, label.getFont().getSize()));
//创建JButton:
final JButton button = new JButton("单击以更改标签文本");
//在lambda表达式中维护对标签的引用:
button.addActionListener(event -> label.setText(randomString(10)));
//为按钮和标签创建一个容器(JPanel是Container):
final JPanel contents = new JPanel(); //默认为FlowLayout。
contents.add(button);
contents.add(label);
final JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //声明单击帧的关闭图标时应用程序将退出。
frame.getContentPane().add(contents);
frame.pack(); //根据其内容调整帧的大小。
frame.setLocationRelativeTo(null); //使帧居中于屏幕。
frame.setVisible(true); //显示帧。
}
public static void main(final String[] args) {
//始终在EDT上调用与Swing相关的代码。一种实现这一点的方法是通过像这样调用invokeLater:
SwingUtilities.invokeLater(Main::createAndShowGUI); //Main::createAndShowGUI只是另一种lambda表达式。
}
}
根据我的知识,Swing的最可靠的信息来源是Oracle的官方教程,位于以下链接:https://docs.oracle.com/javase/tutorial/uiswing/index.html,该链接引导至许多关于Swing的主题的教程链接。
至于除当前组件外获取其他Component
、Window
等引用的助手方法,您可以使用SwingUtilities
类中的方法,例如:
getAncestorNamed
:每个Component
都有一个对应的名称,以及对应的访问器方法和修改器方法。因此,您可以通过名称获取对Component
的引用。getRoot
:当您创建Component
并将其添加到Container
,实际上是Window
时,您会创建一个Component
树层次结构。您可以通过调用此方法获取给定Component
的根Component
。getUnwrappedParent
:属于Component
树层次结构的每个Component
都有一个祖先(除非它是根Component
或尚未属于任何层次结构的Component
)。您可以使用此方法获取其祖先。getWindowAncestor
和windowForComponent
:通过这两个等效的方法,您可以获取Component
的第一个**Window
**祖先(反过来已经属于Component
树层次结构)。
但最常见的情况是,您很少使用这些方法(取决于您的编程风格),通常会在类中保留对所有所需Component
的引用。
最后,还有一些用于访问Container
中的所有Component
的常见方法,例如getComponents
,它返回Container
(请注意,JFrame
是Window
,Window
是Container
)中的所有Component
。
相反的操作(即获取Component
所属的父Container
)是在Component
上执行的getParent
。
这些方法中的大多数是在将Component
添加到树层次结构后使用的。例如,在不将Component
添加到任何Window
的情况下,获取Component
的窗口祖先是没有意义的。
英文:
As mentioned in the comments, an easy way of acquiring a reference to a desired component, is just to store the reference yourself. For your example where a button updates a label, you can maintain somewhere the reference to the label in your code. For example:
import java.awt.Font;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Main {
//Utility method to create a String with random contents:
private static String randomString(final int length) {
//Create the alphabet:
String alphabet = "abcdefghijklmnopqrstuvwxyz";
alphabet += alphabet.toUpperCase();
alphabet += "0123456789";
final int alphabetLength = alphabet.length();
final Random rand = new Random();
final char[] chars = new char[length];
//Fill the random String:
for (int i = 0; i < chars.length; ++i)
chars[i] = alphabet.charAt(rand.nextInt(alphabetLength));
return new String(chars);
}
private static void createAndShowGUI() {
//Initialize a JLabel with a random text:
final JLabel label = new JLabel(randomString(10));
//Change font to MONOSPACED BOLD (of the current size):
label.setFont(new Font(Font.MONOSPACED, Font.BOLD, label.getFont().getSize()));
//Create the JButton:
final JButton button = new JButton("Click to change label text");
//See here we maintain a reference to the label in the lambda expression:
button.addActionListener(event -> label.setText(randomString(10)));
//Create a Container (JPanel is-a Container) for the button and the label:
final JPanel contents = new JPanel(); //FlowLayout by default.
contents.add(button);
contents.add(label);
final JFrame frame = new JFrame("Main");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //Declares that the application will exit when we click the close icon of the frame.
frame.getContentPane().add(contents);
frame.pack(); //Adjust the size of the frame according to its contents.
frame.setLocationRelativeTo(null); //Make the frame centered in screen.
frame.setVisible(true); //Show the frame.
}
public static void main(final String[] args) {
//Always call Swing related code on the EDT. On way to achieve this is by calling invokeLater like so:
SwingUtilities.invokeLater(Main::createAndShowGUI); //Main::createAndShowGUI is just another lambda expression.
}
}
The most reliable source of information for Swing, according to my knowledge, is the official turorial of Oracle in the following link: https://docs.oracle.com/javase/tutorial/uiswing/index.html which leads to many more links of tutorials about many topics on Swing.
As for the helper methods to get a reference of a Component
, Window
, etc other than the current one, you can use the methods in SwingUtilities
class, such as:
getAncestorNamed
: EveryComponent
has-a name with corresponding accessor and mutator methods. As such, you can get a refernce to aComponent
by name.getRoot
: When you are creatingComponent
s and adding the toContainer
s, and essentiallyWindow
s, you create aComponent
tree hierarchy. You can access the rootComponent
of that hiearchy for any givenComponent
via a call to this method.getUnwrappedParent
: EveryComponent
belonging to a tree hierarchy ofComponent
s has an ancestor (unless it is the rootComponent
or aComponent
not belonging to any hierarchy yet). You can get its ancestor with this method.getWindowAncestor
andwindowForComponent
: With those two equivalent methods, you can get the firstWindow
ancestor of aComponent
(which in turn already belongs to a tree hierarchy ofComponent
s).
But the most common case is that you will rarely use those methods (depending on your programming style) and usually maintain a reference, to all the Component
s you need, in your class.
Finally there are also some common methods for accessing all Component
s of a Container
such as getComponents
which returns all the Component
s inside a Container
(and note here JFrame
is-a Window
which is-a Container
).
The reverse operation (ie getting the parent Container
on which a Component
belongs to) is performed with getParent
on a Component
.
Most of those methods are used after you add your Component
s to the tree hierarchy. For example there is not point in getting the window ancestor of a Component
which is not added to any Window
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论