问题描述
我是编码新手,这个社区非常有益。这是我在阅读了不同的相关问题后第一次提问,我似乎仍然没有明白。
因此,当我点击 loginButton(在另一个名为 LoginPage 的类中设置)时,它会显示“welcomePage”卡片,welcomePage(卡片)有两个按钮 backButton 和 drawButton。 Jpanel 是主要容器,添加到 Jframe(也在类 LoginPage 中设置)。我正在尝试绘画和背景(颜色);单击 drawButton 时在welcomePage 上,但由于某种原因,当背景发生变化时,绘画会立即显示和消失。另外当我把paintComponent(welcomepanel.getGraphics());在没有“中断;”的 while 循环中的方法,绘画确实停留但窗口卡住(不关闭)并且背景没有改变(为什么?)。
public class WelcomePage implements ActionListener{
JPanel welcomepanel = new JPanel();
JButton backButton = new JButton("Back");
JButton drawButton = new JButton("DRAW");
//Other codes elided
WelcomePage (String userID) {
drawButton.addActionListener(this);
backButton.setBounds(50,100,25);
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LoginPage.cardlayout.show(LoginPage.container,"loginpage");
}
});
drawButton.setBounds(0,25);
drawButton.addActionListener(this);
welcomepanel.setSize(420,420);
welcomepanel.add(backButton); //backs to the prevIoUs page (card)
welcomepanel.add(drawButton);
} //end constructor
public void paintComponent(Graphics g) {
g = welcomepanel.getGraphics();
g.drawString("CHASE",200,90);
g.setColor(Color.yellow);
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; coL++) {
if (row % 2 == col % 2) {
g.setColor(Color.GRAY);
} else
g.setColor(Color.RED);
g.fillRect(100 + col * 40,100 + row * 40,40,40);
}
}
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("DRAW")) {
welcomepanel.setBackground(Color.black);
paintComponent(welcomepanel.getGraphics());
// while (true) {paintComponent(welcomepanel.getGraphics());}
welcomepanel.repaint();
welcomepanel.revalidate();
}
}
} //end class WelcomePage
我做错了什么?
我已经尝试将 welcompage 扩展到 Jpanel 并直接在其上绘图,这可行,但我想要一个特定的 Jpanel 实例(welcomepanel)来获取绘图。
我的第二个问题是,我想最终创建一个 GUI,“教师”将使用该 GUI 添加测验类型的问题,而学生将用于参加这些测验,我将根据他们的登录凭据或组合框确定谁是谁选择什么的。使用 cardlayout 和 Jpanel 作为主容器浏览不同的活动是个好主意还是我应该使用其他东西?
更新:这次更新我在 actionperformed 方法中使用了匿名类,但是当 drawButton 被点击时仍然没有绘制:
欢迎页面.java:
import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener;
public class WelcomePage implements ActionListener {
JPanel welcomepanel = new JPanel();
JLabel welcomeLabel = new JLabel("QUIZ");
JButton backButton = new JButton("Back");
JButton drawButton = new JButton("DRAW");
JButton whiteButton = new JButton("white");
WelcomePage(String userID) {
///super();
// welcomepanel.setLayout(new GroupLayout(welcomepanel));
welcomeLabel.setBounds(100,35);
welcomeLabel.setFont(new Font(null,Font.BOLD,25));
welcomeLabel.setText("Welcome " + userID);
backButton.setBounds(50,25);
// backButton.setHorizontalAlignment(JButton.soUTH);
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loginPage.cardlayout.show(loginPage.container,"loginpage");
}
});
drawButton.setBounds(0,25);
drawButton.addActionListener(this);
whiteButton.setBounds(200,25);
whiteButton.addActionListener(this);
welcomepanel.setSize(420,420);
welcomepanel.add(welcomeLabel);
welcomepanel.add(backButton);
welcomepanel.add(drawButton);
welcomepanel.add(whiteButton);
}
/**
* Invoked when an action occurs.
*
* @param e the event to be processed
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("DRAW")) {
welcomepanel = new JPanel() {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawString("CHASE",90);
g.setColor(Color.yellow);
for (int row = 0; row < 8; row++) {
for (int col = 0; col < 8; coL++) {
if (row % 2 == col % 2) {
g.setColor(Color.GRAY);
} else
g.setColor(Color.RED);
g.fillRect(100 + col * 40,40);
}
}
}
};
welcomepanel.setBackground(Color.black);
welcomepanel.repaint();
welcomepanel.revalidate();
} else if (e.getActionCommand().equals("white")) {
welcomepanel.setBackground(Color.blue);
}
}
}
我在下面的类中的 actionperformed 方法中创建了一个新的欢迎页面实例,并调用了welcomepages 的welcomePanel 来获得一个让用户满意的“欢迎页面”。我想要的只是当我点击 drawButton 时,paintcomponent 方法按照welcomepages 的 actionperformed 方法中的定义执行。我想探索在单个类中声明使用不同 Jpanel 的可能性。也可以对我的代码的任何其他部分发表评论。
loginPage.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
public class loginPage implements ActionListener {
static JFrame frame = new JFrame();
static JPanel container = new JPanel();
JPanel panel1 = new JPanel();
JPanel panel2 = new JPanel();
JPanel panel3 = new JPanel();
JButton loginButton = new JButton("Login");
JButton resetButton = new JButton("Reset");
JButton logoutButton = new JButton("logout");
JButton hoemButton = new JButton("HOME");
static cardlayout cardlayout = new cardlayout();
JTextField userIDField = new JTextField();
jpasswordfield userPasswordField = new jpasswordfield();
JLabel IdLabel = new JLabel("userID:");
JLabel userPasswordLabel = new JLabel("password:");
JLabel messageLabel = new JLabel();
HashMap<String,String> loginInfo = new HashMap<>(); //to hold the copy of the constructors' parameter value so it can be globally available for methods such as getters
loginPage(HashMap<String,String> copyOfLoginInfo) {
this.loginInfo = copyOfLoginInfo; //@parra value copied into a global variable
// this.container.setLayout(new BorderLayout());
container.setLayout(cardlayout);
IdLabel.setBounds(50,75,25);
IdLabel.setLocation(50,100);
userIDField.setBounds(125,25);
userPasswordLabel.setBounds(50,150,25);
userPasswordField.setBounds(125,25);
loginButton.setBounds(125,25);
loginButton.setFocusable(false);
loginButton.addActionListener(this);
hoemButton.setBounds(0,25);
logoutButton.setBounds(310,25);
logoutButton.setFocusable(false);
resetButton.setBounds(220,25);
resetButton.setFocusable(false);
resetButton.addActionListener(this);
messageLabel.setBounds(125,250,35);
messageLabel.setFont(new Font(null,Font.ITALIC,25));
setPanel1();
panel1.add(loginButton);
panel1.add(resetButton);
panel1.add(hoemButton);
panel1.add(IdLabel);
panel1.add(userIDField);
panel1.add(userPasswordLabel);
panel1.add(userPasswordField);
panel1.add(messageLabel);
panel2.add(logoutButton);
setPanel2();
//add panals to the JPanel container with their identifier string
container.add(panel1,"loginPageage");
container.add(panel2,"logoutpage");
//this show method of cardlayout determines which panel..
// ...should be shown at the start of the application,identifier string is used here
cardlayout.show(container,"loginPageage");
//when login is clicked go to logout page (panal 2)
hoemButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(container,"logoutpage");
}
});
//when logout is clicked go back to loginPageage
logoutButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cardlayout.show(container,"loginPageage");
}
});
//add container to Jframe:
frame.add(container);
frame.setDefaultCloSEOperation(JFrame.disPOSE_ON_CLOSE);
frame.setSize(520,520);
frame.setLocationRelativeto(null); //sets the window in the middle of pc screen
//frame.setLayout(null); //this will make the cardlayout not show!!
frame.setVisible(true);
frame.setResizable(false);
}
/**
* Invoked when an action occurs.
*
* @param e the event to be processed
*/
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == resetButton) {
userIDField.setText("");
userPasswordField.setText("");
}
if (e.getSource() == loginButton) {
String userID = userIDField.getText(); //gets user id text
String password = String.valueOf(userPasswordField.getpassword()); //gets the password from the password field and then converts it into a string
if (loginInfo.containsKey(userID)) {
if (loginInfo.get(userID).equals(password)) {
messageLabel.setForeground(Color.cyan);
messageLabel.setText(String.format("%30s","Login SUCCESSFUL"));
WelcomePage w = new WelcomePage(userID);
//add instance of welcome page to the Jpanel container,and
container.add(w.welcomepanel,"WelcomeP");
cardlayout.show(container,"WelcomeP");
}
else {
messageLabel.setForeground(Color.red);
messageLabel.setText(String.format("%34s","Invalid password!"));
}
} else {
messageLabel.setForeground(Color.red);
messageLabel.setText(String.format("%33s","username not found!"));
}
}
}
void setPanel1() {
panel1.setLayout(new BorderLayout()); //equivalent to setManaged(false)??
panel1.setBounds(100,420,420);
panel1.setBackground(new Color(150,150));
panel1.setBorder(BorderFactory.createBevelBorder(1));
}
void setPanel2(){
panel2.setLayout(new BorderLayout()); //equivalent to setManaged(false)??
panel2.setSize(420,420);
panel2.setBackground(Color.green);}
}
用户信息.java
import java.util.HashMap;
public class UserInfo {
HashMap<String,String> credentials = new HashMap<>();
UserInfo () {
credentials.put("user","user");
}
protected HashMap<String,String> getCredentials() {
return credentials;
}
}
Main.java:
public class Main {
public static void main(String[] args) {
UserInfo users = new UserInfo();
loginPage loginP = new loginPage(users.getCredentials());
}
}
解决方法
下面是一个示例,说明您可能希望重构代码的外观(我省略了示例中的非必要代码)以使其正常工作。最值得注意的是,您会看到我使用了 panel 的 JPanel
和 override paintComponent
,调用 super.paintComponent
然后完成所有绘图在里面工作。此外,我覆盖 getPreferredSize
以正确调整 JPanel
而不是 setSize
的大小。
更新:
根据您的评论:
首先我希望面板只显示按钮,然后当我点击 drawButton 时,我希望显示绘图。:
简单地创建一个初始设置为 false 的布尔值 canDraw
,在绘制之前在 paintComponent
中检查 canDraw
布尔值并返回如果它是 假。然后在 draw 按钮中 ActionListener
做 canDraw = true;
,然后调用 welcomPanel.repaint();
这将导致 paintComponent
被调用,因此因为 {{1 }} 是 true 它应该绘制图形而不是返回。
要记住的其他一些要点是:
- 不要使用
canDraw
/null
而是使用适当的 LayoutManager - 不要在组件上调用
AbsoluteLayout
或setBounds()
,如果您使用正确的布局管理器,这将为您处理 - 所有 Swing 组件都应该通过
setSize()
在 EDT 上调用(也许你会这样做,但我把它放在这里是为了安全) - 在将框架设置为可见之前调用
SwingUtilities.invokeLater
JFrame#pack()